Merge "Fix clipboard dismiss button text color in dark mode" into tm-dev
diff --git a/Android.bp b/Android.bp
index 753cefc..cd110de 100644
--- a/Android.bp
+++ b/Android.bp
@@ -97,6 +97,7 @@
         ":platform-compat-native-aidl",
 
         // AIDL sources from external directories
+        ":android.hardware.gnss-V2-java-source",
         ":android.hardware.graphics.common-V3-java-source",
         ":android.hardware.security.keymint-V2-java-source",
         ":android.hardware.security.secureclock-V1-java-source",
@@ -271,8 +272,6 @@
         include_dirs: [
             "frameworks/av/aidl",
             "frameworks/native/libs/permission/aidl",
-            // TODO: remove when moved to the below package
-            "frameworks/base/packages/ConnectivityT/framework-t/aidl-export",
             "packages/modules/Bluetooth/framework/aidl-export",
             "packages/modules/Connectivity/framework/aidl-export",
             "packages/modules/Media/apex/aidl/stable",
@@ -328,6 +327,7 @@
         "modules-utils-preconditions",
         "modules-utils-synchronous-result-receiver",
         "modules-utils-os",
+        "modules-utils-uieventlogger-interface",
         "framework-permission-aidl-java",
         "spatializer-aidl-java",
         "audiopolicy-types-aidl-java",
@@ -529,8 +529,6 @@
         include_dirs: [
             "frameworks/av/aidl",
             "frameworks/native/libs/permission/aidl",
-            // TODO: remove when moved to the below package
-            "frameworks/base/packages/ConnectivityT/framework-t/aidl-export",
             "packages/modules/Bluetooth/framework/aidl-export",
             "packages/modules/Connectivity/framework/aidl-export",
             "packages/modules/Media/apex/aidl/stable",
diff --git a/apct-tests/perftests/packagemanager/src/android/content/pm/PackageInstallerBenchmark.java b/apct-tests/perftests/packagemanager/src/android/content/pm/PackageInstallerBenchmark.java
index 3b4f72b..e20f30d 100644
--- a/apct-tests/perftests/packagemanager/src/android/content/pm/PackageInstallerBenchmark.java
+++ b/apct-tests/perftests/packagemanager/src/android/content/pm/PackageInstallerBenchmark.java
@@ -17,10 +17,12 @@
 package android.content.pm;
 
 import android.Manifest;
+import android.app.UiAutomation;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender;
 import android.os.HandlerThread;
+import android.os.ParcelFileDescriptor;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 import android.util.Log;
@@ -39,7 +41,10 @@
 import org.junit.Rule;
 import org.junit.Test;
 
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
@@ -203,13 +208,33 @@
     }
 
     private void uninstallSession(BenchmarkState state, String...packageNames)
-            throws InterruptedException {
+            throws Exception {
         state.pauseTiming();
         uninstall(true /* stop at fail */, packageNames);
         mPackageInstaller.unregisterSessionCallback(mSessionCallback);
+        executeShellCommand("pm gc");
         state.resumeTiming();
     }
 
+    private static String executeShellCommand(String command) throws IOException {
+        UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        final ParcelFileDescriptor stdout = uiAutomation.executeShellCommand(command);
+        try (InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(stdout);
+             ByteArrayOutputStream result = new ByteArrayOutputStream()) {
+            writeFullStream(inputStream, result);
+            return result.toString("UTF-8");
+        }
+    }
+
+    private static void writeFullStream(InputStream inputStream, OutputStream outputStream)
+            throws IOException {
+        final byte[] buffer = new byte[1024];
+        int length;
+        while ((length = inputStream.read(buffer)) != -1) {
+            outputStream.write(buffer, 0, length);
+        }
+    }
+
     @Test(timeout = 600_000L)
     public void commit_aSingleApkSession_untilFinishBenchmark() throws Exception {
         uninstall(false /* stop at fail */, TestApp.A);
@@ -247,8 +272,7 @@
     }
 
     @Test(timeout = 600_000L)
-    public void commit_aMultiplePackagesSession_untilFinishBenchmark()
-            throws IOException, InterruptedException {
+    public void commit_aMultiplePackagesSession_untilFinishBenchmark() throws Exception {
         uninstall(false /* stop at fail */, TestApp.A, TestApp.B, TestApp.C);
 
         final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
@@ -269,8 +293,7 @@
     }
 
     @Test(timeout = 600_000L)
-    public void commit_threeMultiplePackageSessions_untilFinishBenchmark()
-            throws Exception {
+    public void commit_threeMultiplePackageSessions_untilFinishBenchmark() throws Exception {
         uninstall(false /* stop at fail */, TestApp.A, TestApp.B, TestApp.C);
 
         final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
@@ -293,8 +316,7 @@
     }
 
     @Test(timeout = 600_000L)
-    public void commit_aMultipleApksSession_untilFinishBenchmark()
-            throws IOException, InterruptedException {
+    public void commit_aMultipleApksSession_untilFinishBenchmark() throws Exception {
         uninstall(false /* stop at fail */, TestApp.A);
 
         final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
index 4ad015d..c92c634 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
@@ -20,6 +20,7 @@
 
 import android.app.Activity;
 import android.content.Context;
+import android.os.Bundle;
 import android.os.RemoteException;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
@@ -153,7 +154,8 @@
             while (state.keepRunning()) {
                 session.relayout(mWindow, mParams, mWidth, mHeight,
                         mViewVisibility.getAsInt(), mFlags, mOutFrames,
-                        mOutMergedConfiguration, mOutSurfaceControl, mOutInsetsState, mOutControls);
+                        mOutMergedConfiguration, mOutSurfaceControl, mOutInsetsState, mOutControls,
+                        new Bundle());
             }
         }
     }
diff --git a/apex/jobscheduler/framework/java/android/app/AlarmManager.java b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
index 66767e2..da429af 100644
--- a/apex/jobscheduler/framework/java/android/app/AlarmManager.java
+++ b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
@@ -210,6 +210,8 @@
      * on how frequently it can be scheduled.  Only available (and automatically applied) to
      * system alarms.
      *
+     * <p>Note that alarms set with a {@link WorkSource} <b>do not</b> get this flag.
+     *
      * @hide
      */
     @UnsupportedAppUsage
diff --git a/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java b/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
index 88082f7..dd0d07f 100644
--- a/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
+++ b/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
@@ -284,9 +284,9 @@
     /** @hide */
     public static final int DEFAULT_AM_MAX_SATIATED_BALANCE = 1440;
     /** @hide */
-    public static final int DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT = 28800;
+    public static final int DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT = 4000;
     /** @hide */
-    public static final int DEFAULT_AM_HARD_CONSUMPTION_LIMIT = 52000;
+    public static final int DEFAULT_AM_HARD_CONSUMPTION_LIMIT = 28_800;
     // TODO: add AlarmManager modifier default values
     /** @hide */
     public static final int DEFAULT_AM_REWARD_TOP_ACTIVITY_INSTANT = 0;
@@ -373,9 +373,9 @@
     /** @hide */
     public static final int DEFAULT_JS_MAX_SATIATED_BALANCE = 60000;
     /** @hide */
-    public static final int DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT = 460_000;
+    public static final int DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT = 100_000;
     /** @hide */
-    public static final int DEFAULT_JS_HARD_CONSUMPTION_LIMIT = 900_000;
+    public static final int DEFAULT_JS_HARD_CONSUMPTION_LIMIT = 460_000;
     // TODO: add JobScheduler modifier default values
     /** @hide */
     public static final int DEFAULT_JS_REWARD_TOP_ACTIVITY_INSTANT = 0;
diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
index e2426c2..5681107 100644
--- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
@@ -2,6 +2,7 @@
 
 import android.annotation.CurrentTimeMillisLong;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager.ProcessState;
 import android.app.usage.AppStandbyInfo;
@@ -237,4 +238,14 @@
      */
     @ProcessState
     int getBroadcastResponseFgThresholdState();
+
+    /**
+     * Return the last known value corresponding to the {@code key} from
+     * {@link android.provider.DeviceConfig#NAMESPACE_APP_STANDBY} in AppStandbyController.
+     */
+    @Nullable
+    String getAppStandbyConstant(@NonNull String key);
+
+    /** Clears the last used timestamps data for the given {@code packageName}. */
+    void clearLastUsedTimestampsForTest(@NonNull String packageName, @UserIdInt int userId);
 }
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 90ec700..a09f39f 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -348,7 +348,8 @@
             new SparseArray<>();
 
     private AppStateTrackerImpl mAppStateTracker;
-    private boolean mAppStandbyParole;
+    @VisibleForTesting
+    boolean mAppStandbyParole;
 
     /**
      * A container to keep rolling window history of previous times when an alarm was sent to
@@ -1891,6 +1892,9 @@
                         (AppStateTrackerImpl) LocalServices.getService(AppStateTracker.class);
                 mAppStateTracker.addListener(mForceAppStandbyListener);
 
+                final BatteryManager bm = getContext().getSystemService(BatteryManager.class);
+                mAppStandbyParole = bm.isCharging();
+
                 mClockReceiver.scheduleTimeTickEvent();
                 mClockReceiver.scheduleDateChangedEvent();
             }
@@ -4891,13 +4895,15 @@
             filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
             filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
             filter.addDataScheme(IntentFilter.SCHEME_PACKAGE);
-            getContext().registerReceiver(this, filter);
+            getContext().registerReceiverForAllUsers(this, filter,
+                    /* broadcastPermission */ null, /* scheduler */ null);
             // Register for events related to sdcard installation.
             IntentFilter sdFilter = new IntentFilter();
             sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
             sdFilter.addAction(Intent.ACTION_USER_STOPPED);
             sdFilter.addAction(Intent.ACTION_UID_REMOVED);
-            getContext().registerReceiver(this, sdFilter);
+            getContext().registerReceiverForAllUsers(this, sdFilter,
+                    /* broadcastPermission */ null, /* scheduler */ null);
         }
 
         @Override
@@ -4915,9 +4921,6 @@
                             }
                         }
                         return;
-                    case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
-                        pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
-                        break;
                     case Intent.ACTION_USER_STOPPED:
                         final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
                         if (userHandle >= 0) {
@@ -4932,6 +4935,18 @@
                         mRemovalHistory.delete(uid);
                         mLastOpScheduleExactAlarm.delete(uid);
                         return;
+                    case Intent.ACTION_PACKAGE_ADDED:
+                        if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+                            final String packageUpdated = intent.getData().getSchemeSpecificPart();
+                            mHandler.obtainMessage(
+                                    AlarmHandler.CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE, uid, -1,
+                                    packageUpdated).sendToTarget();
+                        }
+                        mHandler.sendEmptyMessage(AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES);
+                        return;
+                    case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
+                        pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                        break;
                     case Intent.ACTION_PACKAGE_REMOVED:
                         if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
                             // This package is being updated; don't kill its alarms.
@@ -4950,15 +4965,6 @@
                             }
                         }
                         break;
-                    case Intent.ACTION_PACKAGE_ADDED:
-                        if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
-                            final String packageUpdated = intent.getData().getSchemeSpecificPart();
-                            mHandler.obtainMessage(
-                                    AlarmHandler.CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE, uid, -1,
-                                    packageUpdated).sendToTarget();
-                        }
-                        mHandler.sendEmptyMessage(AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES);
-                        return;
                 }
                 if (pkgList != null && (pkgList.length > 0)) {
                     for (String pkg : pkgList) {
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 18f63b7..dfd019d 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -17,6 +17,7 @@
 package com.android.server.job;
 
 import static com.android.server.job.JobSchedulerService.MAX_JOB_CONTEXTS_COUNT;
+import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
 import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
 
 import android.annotation.IntDef;
@@ -32,9 +33,11 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.UserInfo;
+import android.os.BatteryStats;
 import android.os.Handler;
 import android.os.PowerManager;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
 import android.util.ArraySet;
@@ -51,19 +54,23 @@
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.IBatteryStats;
 import com.android.internal.app.procstats.ProcessStats;
 import com.android.internal.util.StatLogger;
 import com.android.server.JobSchedulerBackgroundThread;
 import com.android.server.LocalServices;
 import com.android.server.job.controllers.JobStatus;
 import com.android.server.job.controllers.StateController;
+import com.android.server.job.restrictions.JobRestriction;
 import com.android.server.pm.UserManagerInternal;
 
+import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.Iterator;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.function.Consumer;
+import java.util.function.Predicate;
 
 /**
  * This class decides, given the various configuration and the system status, which jobs can start
@@ -258,25 +265,21 @@
                     )
             );
 
+    private final ArraySet<ContextAssignment> mRecycledChanged = new ArraySet<>();
+    private final ArraySet<ContextAssignment> mRecycledIdle = new ArraySet<>();
+    private final ArraySet<ContextAssignment> mRecycledPreferredUidOnly = new ArraySet<>();
+    private final ArraySet<ContextAssignment> mRecycledStoppable = new ArraySet<>();
+
+    private final Pools.Pool<ContextAssignment> mContextAssignmentPool =
+            new Pools.SimplePool<>(MAX_JOB_CONTEXTS_COUNT);
+
     /**
-     * This array essentially stores the state of mActiveServices array.
-     * The ith index stores the job present on the ith JobServiceContext.
-     * We manipulate this array until we arrive at what jobs should be running on
-     * what JobServiceContext.
+     * Set of JobServiceContexts that are actively running jobs.
      */
-    JobStatus[] mRecycledAssignContextIdToJobMap = new JobStatus[MAX_JOB_CONTEXTS_COUNT];
+    final List<JobServiceContext> mActiveServices = new ArrayList<>();
 
-    boolean[] mRecycledSlotChanged = new boolean[MAX_JOB_CONTEXTS_COUNT];
-
-    int[] mRecycledPreferredUidForContext = new int[MAX_JOB_CONTEXTS_COUNT];
-
-    int[] mRecycledWorkTypeForContext = new int[MAX_JOB_CONTEXTS_COUNT];
-
-    String[] mRecycledPreemptReasonForContext = new String[MAX_JOB_CONTEXTS_COUNT];
-
-    int[] mRecycledPreemptReasonCodeForContext = new int[MAX_JOB_CONTEXTS_COUNT];
-
-    String[] mRecycledShouldStopJobReason = new String[MAX_JOB_CONTEXTS_COUNT];
+    /** Set of JobServiceContexts that aren't currently running any jobs. */
+    final ArraySet<JobServiceContext> mIdleContexts = new ArraySet<>();
 
     private final ArraySet<JobStatus> mRunningJobs = new ArraySet<>();
 
@@ -358,6 +361,20 @@
         onInteractiveStateChanged(mPowerManager.isInteractive());
     }
 
+    /**
+     * Called when the boot phase reaches
+     * {@link com.android.server.SystemService#PHASE_THIRD_PARTY_APPS_CAN_START}.
+     */
+    void onThirdPartyAppsCanStart() {
+        final IBatteryStats batteryStats = IBatteryStats.Stub.asInterface(
+                ServiceManager.getService(BatteryStats.SERVICE_NAME));
+        for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
+            mIdleContexts.add(
+                    new JobServiceContext(mService, this, batteryStats,
+                            mService.mJobPackageTracker, mContext.getMainLooper()));
+        }
+    }
+
     @GuardedBy("mLock")
     void onAppRemovedLocked(String pkgName, int uid) {
         final PackageStats packageStats = mActivePkgStats.get(UserHandle.getUserId(uid), pkgName);
@@ -390,6 +407,7 @@
                 case PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED:
                     if (mPowerManager != null && mPowerManager.isDeviceIdleMode()) {
                         synchronized (mLock) {
+                            stopUnexemptedJobsForDoze();
                             stopLongRunningJobsLocked("deep doze");
                         }
                     }
@@ -471,6 +489,11 @@
     }
 
     @GuardedBy("mLock")
+    ArraySet<JobStatus> getRunningJobsLocked() {
+        return mRunningJobs;
+    }
+
+    @GuardedBy("mLock")
     boolean isJobRunningLocked(JobStatus job) {
         return mRunningJobs.contains(job);
     }
@@ -545,17 +568,14 @@
             Slog.d(TAG, printPendingQueueLocked());
         }
 
-        final List<JobStatus> pendingJobs = mService.mPendingJobs;
-        final List<JobServiceContext> activeServices = mService.mActiveServices;
+        final PendingJobQueue pendingJobQueue = mService.mPendingJobQueue;
+        final List<JobServiceContext> activeServices = mActiveServices;
 
         // To avoid GC churn, we recycle the arrays.
-        JobStatus[] contextIdToJobMap = mRecycledAssignContextIdToJobMap;
-        boolean[] slotChanged = mRecycledSlotChanged;
-        int[] preferredUidForContext = mRecycledPreferredUidForContext;
-        int[] workTypeForContext = mRecycledWorkTypeForContext;
-        String[] preemptReasonForContext = mRecycledPreemptReasonForContext;
-        int[] preemptReasonCodeForContext = mRecycledPreemptReasonCodeForContext;
-        String[] shouldStopJobReason = mRecycledShouldStopJobReason;
+        final ArraySet<ContextAssignment> changed = mRecycledChanged;
+        final ArraySet<ContextAssignment> idle = mRecycledIdle;
+        final ArraySet<ContextAssignment> preferredUidOnly = mRecycledPreferredUidOnly;
+        final ArraySet<ContextAssignment> stoppable = mRecycledStoppable;
 
         updateCounterConfigLocked();
         // Reset everything since we'll re-evaluate the current state.
@@ -564,164 +584,256 @@
         // Update the priorities of jobs that aren't running, and also count the pending work types.
         // Do this before the following loop to hopefully reduce the cost of
         // shouldStopRunningJobLocked().
-        updateNonRunningPrioritiesLocked(pendingJobs, true);
+        updateNonRunningPrioritiesLocked(pendingJobQueue, true);
 
-        for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
-            final JobServiceContext js = activeServices.get(i);
-            final JobStatus status = js.getRunningJobLocked();
+        final int numRunningJobs = activeServices.size();
+        for (int i = 0; i < numRunningJobs; ++i) {
+            final JobServiceContext jsc = activeServices.get(i);
+            final JobStatus js = jsc.getRunningJobLocked();
 
-            if ((contextIdToJobMap[i] = status) != null) {
-                mWorkCountTracker.incrementRunningJobCount(js.getRunningJobWorkType());
-                workTypeForContext[i] = js.getRunningJobWorkType();
+            ContextAssignment assignment = mContextAssignmentPool.acquire();
+            if (assignment == null) {
+                assignment = new ContextAssignment();
             }
 
-            slotChanged[i] = false;
-            preferredUidForContext[i] = js.getPreferredUid();
-            preemptReasonForContext[i] = null;
-            preemptReasonCodeForContext[i] = JobParameters.STOP_REASON_UNDEFINED;
-            shouldStopJobReason[i] = shouldStopRunningJobLocked(js);
+            assignment.context = jsc;
+
+            if (js != null) {
+                mWorkCountTracker.incrementRunningJobCount(jsc.getRunningJobWorkType());
+                assignment.workType = jsc.getRunningJobWorkType();
+            }
+
+            assignment.preferredUid = jsc.getPreferredUid();
+            if ((assignment.shouldStopJobReason = shouldStopRunningJobLocked(jsc)) != null) {
+                stoppable.add(assignment);
+            } else {
+                preferredUidOnly.add(assignment);
+            }
+        }
+        for (int i = numRunningJobs; i < MAX_JOB_CONTEXTS_COUNT; ++i) {
+            final JobServiceContext jsc;
+            final int numIdleContexts = mIdleContexts.size();
+            if (numIdleContexts > 0) {
+                jsc = mIdleContexts.removeAt(numIdleContexts - 1);
+            } else {
+                Slog.wtf(TAG, "Had fewer than " + MAX_JOB_CONTEXTS_COUNT + " in existence");
+                jsc = createNewJobServiceContext();
+            }
+
+            ContextAssignment assignment = mContextAssignmentPool.acquire();
+            if (assignment == null) {
+                assignment = new ContextAssignment();
+            }
+
+            assignment.context = jsc;
+            idle.add(assignment);
         }
         if (DEBUG) {
-            Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs initial"));
+            Slog.d(TAG, printAssignments("running jobs initial", stoppable, preferredUidOnly));
         }
 
         mWorkCountTracker.onCountDone();
 
-        for (int i = 0; i < pendingJobs.size(); i++) {
-            final JobStatus nextPending = pendingJobs.get(i);
-
+        JobStatus nextPending;
+        pendingJobQueue.resetIterator();
+        while ((nextPending = pendingJobQueue.next()) != null) {
             if (mRunningJobs.contains(nextPending)) {
                 continue;
             }
 
-            // Find an available slot for nextPending. The context should be available OR
-            // it should have the lowest bias among all running jobs
-            // (sharing the same Uid as nextPending)
-            int minBiasForPreemption = Integer.MAX_VALUE;
-            int selectedContextId = -1;
-            int allWorkTypes = getJobWorkTypes(nextPending);
-            int workType = mWorkCountTracker.canJobStart(allWorkTypes);
-            boolean startingJob = false;
-            int preemptReasonCode = JobParameters.STOP_REASON_UNDEFINED;
-            String preemptReason = null;
+            // Find an available slot for nextPending. The context should be one of the following:
+            // 1. Unused
+            // 2. Its job should have used up its minimum execution guarantee so it
+            // 3. Its job should have the lowest bias among all running jobs (sharing the same UID
+            //    as nextPending)
+            ContextAssignment selectedContext = null;
+            final int allWorkTypes = getJobWorkTypes(nextPending);
             final boolean pkgConcurrencyOkay = !isPkgConcurrencyLimitedLocked(nextPending);
-            // TODO(141645789): rewrite this to look at empty contexts first so we don't
-            // unnecessarily preempt
-            for (int j = 0; j < MAX_JOB_CONTEXTS_COUNT; j++) {
-                JobStatus job = contextIdToJobMap[j];
-                int preferredUid = preferredUidForContext[j];
-                if (job == null) {
-                    final boolean preferredUidOkay = (preferredUid == nextPending.getUid())
-                            || (preferredUid == JobServiceContext.NO_PREFERRED_UID);
-
-                    if (preferredUidOkay && pkgConcurrencyOkay && workType != WORK_TYPE_NONE) {
-                        // This slot is free, and we haven't yet hit the limit on
-                        // concurrent jobs...  we can just throw the job in to here.
-                        selectedContextId = j;
-                        startingJob = true;
-                        break;
-                    }
-                    // No job on this context, but nextPending can't run here because
-                    // the context has a preferred Uid or we have reached the limit on
-                    // concurrent jobs.
-                    continue;
+            boolean startingJob = false;
+            if (idle.size() > 0) {
+                final int idx = idle.size() - 1;
+                final ContextAssignment assignment = idle.valueAt(idx);
+                final boolean preferredUidOkay = (assignment.preferredUid == nextPending.getUid())
+                        || (assignment.preferredUid == JobServiceContext.NO_PREFERRED_UID);
+                int workType = mWorkCountTracker.canJobStart(allWorkTypes);
+                if (preferredUidOkay && pkgConcurrencyOkay && workType != WORK_TYPE_NONE) {
+                    // This slot is free, and we haven't yet hit the limit on
+                    // concurrent jobs...  we can just throw the job in to here.
+                    selectedContext = assignment;
+                    startingJob = true;
+                    idle.removeAt(idx);
+                    assignment.newJob = nextPending;
+                    assignment.newWorkType = workType;
                 }
-                if (job.getUid() != nextPending.getUid()) {
+            }
+            if (selectedContext == null) {
+                for (int s = stoppable.size() - 1; s >= 0; --s) {
+                    ContextAssignment assignment = stoppable.valueAt(s);
+                    JobStatus runningJob = assignment.context.getRunningJobLocked();
                     // Maybe stop the job if it has had its day in the sun. Don't let a different
                     // app preempt jobs started for TOP apps though.
-                    final String reason = shouldStopJobReason[j];
-                    if (job.lastEvaluatedBias < JobInfo.BIAS_TOP_APP
-                            && reason != null && mWorkCountTracker.canJobStart(allWorkTypes,
-                            activeServices.get(j).getRunningJobWorkType()) != WORK_TYPE_NONE) {
-                        // Right now, the way the code is set up, we don't need to explicitly
-                        // assign the new job to this context since we'll reassign when the
-                        // preempted job finally stops.
-                        preemptReason = reason;
-                        preemptReasonCode = JobParameters.STOP_REASON_DEVICE_STATE;
+                    if (runningJob.lastEvaluatedBias < JobInfo.BIAS_TOP_APP
+                            && assignment.shouldStopJobReason != null) {
+                        int replaceWorkType = mWorkCountTracker.canJobStart(allWorkTypes,
+                                assignment.context.getRunningJobWorkType());
+                        if (replaceWorkType != WORK_TYPE_NONE) {
+                            // Right now, the way the code is set up, we don't need to explicitly
+                            // assign the new job to this context since we'll reassign when the
+                            // preempted job finally stops.
+                            assignment.preemptReason = assignment.shouldStopJobReason;
+                            assignment.preemptReasonCode = JobParameters.STOP_REASON_DEVICE_STATE;
+                            selectedContext = assignment;
+                            stoppable.removeAt(s);
+                            assignment.newJob = nextPending;
+                            assignment.newWorkType = replaceWorkType;
+                            // Don't preserve the UID since we're stopping the job because
+                            // something is pending (eg. EJs).
+                            assignment.context.clearPreferredUid();
+                            break;
+                        }
                     }
-                    continue;
                 }
+            }
+            if (selectedContext == null) {
+                int lowestBiasSeen = Integer.MAX_VALUE;
+                for (int p = preferredUidOnly.size() - 1; p >= 0; --p) {
+                    final ContextAssignment assignment = preferredUidOnly.valueAt(p);
+                    final JobStatus runningJob = assignment.context.getRunningJobLocked();
+                    if (runningJob.getUid() != nextPending.getUid()) {
+                        continue;
+                    }
+                    final int jobBias = mService.evaluateJobBiasLocked(runningJob);
+                    if (jobBias >= nextPending.lastEvaluatedBias) {
+                        continue;
+                    }
 
-                final int jobBias = mService.evaluateJobBiasLocked(job);
-                if (jobBias >= nextPending.lastEvaluatedBias) {
-                    continue;
+                    if (selectedContext == null || lowestBiasSeen > jobBias) {
+                        // Step down the preemption threshold - wind up replacing
+                        // the lowest-bias running job
+                        lowestBiasSeen = jobBias;
+                        selectedContext = assignment;
+                        assignment.preemptReason = "higher bias job found";
+                        assignment.preemptReasonCode = JobParameters.STOP_REASON_PREEMPT;
+                        // In this case, we're just going to preempt a low bias job, we're not
+                        // actually starting a job, so don't set startingJob to true.
+                    }
                 }
-
-                if (minBiasForPreemption > jobBias) {
-                    // Step down the preemption threshold - wind up replacing
-                    // the lowest-bias running job
-                    minBiasForPreemption = jobBias;
-                    selectedContextId = j;
-                    preemptReason = "higher bias job found";
-                    preemptReasonCode = JobParameters.STOP_REASON_PREEMPT;
-                    // In this case, we're just going to preempt a low bias job, we're not
-                    // actually starting a job, so don't set startingJob.
+                if (selectedContext != null) {
+                    selectedContext.newJob = nextPending;
+                    preferredUidOnly.remove(selectedContext);
                 }
             }
             final PackageStats packageStats = getPkgStatsLocked(
                     nextPending.getSourceUserId(), nextPending.getSourcePackageName());
-            if (selectedContextId != -1) {
-                contextIdToJobMap[selectedContextId] = nextPending;
-                slotChanged[selectedContextId] = true;
-                preemptReasonCodeForContext[selectedContextId] = preemptReasonCode;
-                preemptReasonForContext[selectedContextId] = preemptReason;
+            if (selectedContext != null) {
+                changed.add(selectedContext);
                 packageStats.adjustStagedCount(true, nextPending.shouldTreatAsExpeditedJob());
             }
             if (startingJob) {
                 // Increase the counters when we're going to start a job.
-                workTypeForContext[selectedContextId] = workType;
-                mWorkCountTracker.stageJob(workType, allWorkTypes);
+                mWorkCountTracker.stageJob(selectedContext.newWorkType, allWorkTypes);
                 mActivePkgStats.add(
                         nextPending.getSourceUserId(), nextPending.getSourcePackageName(),
                         packageStats);
             }
         }
         if (DEBUG) {
-            Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs final"));
+            Slog.d(TAG, printAssignments("running jobs final",
+                    stoppable, preferredUidOnly, changed));
 
             Slog.d(TAG, "assignJobsToContexts: " + mWorkCountTracker.toString());
         }
 
-        for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
-            boolean preservePreferredUid = false;
-            if (slotChanged[i]) {
-                JobStatus js = activeServices.get(i).getRunningJobLocked();
-                if (js != null) {
-                    if (DEBUG) {
-                        Slog.d(TAG, "preempting job: "
-                                + activeServices.get(i).getRunningJobLocked());
-                    }
-                    // preferredUid will be set to uid of currently running job.
-                    activeServices.get(i).cancelExecutingJobLocked(
-                            preemptReasonCodeForContext[i],
-                            JobParameters.INTERNAL_STOP_REASON_PREEMPT, preemptReasonForContext[i]);
-                    // Only preserve the UID if we're preempting for the same UID. If we're stopping
-                    // the job because something is pending (eg. EJs), then we shouldn't preserve
-                    // the UID.
-                    preservePreferredUid =
-                            preemptReasonCodeForContext[i] == JobParameters.STOP_REASON_PREEMPT;
-                } else {
-                    final JobStatus pendingJob = contextIdToJobMap[i];
-                    if (DEBUG) {
-                        Slog.d(TAG, "About to run job on context "
-                                + i + ", job: " + pendingJob);
-                    }
-                    startJobLocked(activeServices.get(i), pendingJob, workTypeForContext[i]);
+        for (int c = changed.size() - 1; c >= 0; --c) {
+            final ContextAssignment assignment = changed.valueAt(c);
+            final JobStatus js = assignment.context.getRunningJobLocked();
+            if (js != null) {
+                if (DEBUG) {
+                    Slog.d(TAG, "preempting job: " + js);
                 }
+                // preferredUid will be set to uid of currently running job.
+                assignment.context.cancelExecutingJobLocked(
+                        assignment.preemptReasonCode,
+                        JobParameters.INTERNAL_STOP_REASON_PREEMPT, assignment.preemptReason);
+            } else {
+                final JobStatus pendingJob = assignment.newJob;
+                if (DEBUG) {
+                    Slog.d(TAG, "About to run job on context "
+                            + assignment.context.getId() + ", job: " + pendingJob);
+                }
+                startJobLocked(assignment.context, pendingJob, assignment.newWorkType);
             }
-            if (!preservePreferredUid) {
-                activeServices.get(i).clearPreferredUid();
-            }
+
+            assignment.clear();
+            mContextAssignmentPool.release(assignment);
         }
+        for (int s = stoppable.size() - 1; s >= 0; --s) {
+            final ContextAssignment assignment = stoppable.valueAt(s);
+            assignment.context.clearPreferredUid();
+            assignment.clear();
+            mContextAssignmentPool.release(assignment);
+        }
+        for (int p = preferredUidOnly.size() - 1; p >= 0; --p) {
+            final ContextAssignment assignment = preferredUidOnly.valueAt(p);
+            assignment.context.clearPreferredUid();
+            assignment.clear();
+            mContextAssignmentPool.release(assignment);
+        }
+        for (int i = idle.size() - 1; i >= 0; --i) {
+            final ContextAssignment assignment = idle.valueAt(i);
+            mIdleContexts.add(assignment.context);
+            assignment.context.clearPreferredUid();
+            assignment.clear();
+            mContextAssignmentPool.release(assignment);
+        }
+        changed.clear();
+        idle.clear();
+        stoppable.clear();
+        preferredUidOnly.clear();
         mWorkCountTracker.resetStagingCount();
         mActivePkgStats.forEach(mPackageStatsStagingCountClearer);
         noteConcurrency();
     }
 
     @GuardedBy("mLock")
+    boolean stopJobOnServiceContextLocked(JobStatus job,
+            @JobParameters.StopReason int reason, int internalReasonCode, String debugReason) {
+        if (!mRunningJobs.contains(job)) {
+            return false;
+        }
+
+        for (int i = 0; i < mActiveServices.size(); i++) {
+            JobServiceContext jsc = mActiveServices.get(i);
+            final JobStatus executing = jsc.getRunningJobLocked();
+            if (executing != null && executing.matches(job.getUid(), job.getJobId())) {
+                jsc.cancelExecutingJobLocked(reason, internalReasonCode, debugReason);
+                return true;
+            }
+        }
+        Slog.wtf(TAG, "Couldn't find running job on a context");
+        mRunningJobs.remove(job);
+        return false;
+    }
+
+    @GuardedBy("mLock")
+    private void stopUnexemptedJobsForDoze() {
+        // When becoming idle, make sure no jobs are actively running,
+        // except those using the idle exemption flag.
+        for (int i = 0; i < mActiveServices.size(); i++) {
+            JobServiceContext jsc = mActiveServices.get(i);
+            final JobStatus executing = jsc.getRunningJobLocked();
+            if (executing != null && !executing.canRunInDoze()) {
+                jsc.cancelExecutingJobLocked(JobParameters.STOP_REASON_DEVICE_STATE,
+                        JobParameters.INTERNAL_STOP_REASON_DEVICE_IDLE,
+                        "cancelled due to doze");
+            }
+        }
+    }
+
+    @GuardedBy("mLock")
     private void stopLongRunningJobsLocked(@NonNull String debugReason) {
-        for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; ++i) {
-            final JobServiceContext jsc = mService.mActiveServices.get(i);
+        for (int i = 0; i < mActiveServices.size(); ++i) {
+            final JobServiceContext jsc = mActiveServices.get(i);
             final JobStatus jobStatus = jsc.getRunningJobLocked();
 
             if (jobStatus != null && !jsc.isWithinExecutionGuaranteeTime()) {
@@ -731,6 +843,41 @@
         }
     }
 
+    @GuardedBy("mLock")
+    void stopNonReadyActiveJobsLocked() {
+        for (int i = 0; i < mActiveServices.size(); i++) {
+            JobServiceContext serviceContext = mActiveServices.get(i);
+            final JobStatus running = serviceContext.getRunningJobLocked();
+            if (running == null) {
+                continue;
+            }
+            if (!running.isReady()) {
+                if (running.getEffectiveStandbyBucket() == RESTRICTED_INDEX
+                        && running.getStopReason() == JobParameters.STOP_REASON_APP_STANDBY) {
+                    serviceContext.cancelExecutingJobLocked(
+                            running.getStopReason(),
+                            JobParameters.INTERNAL_STOP_REASON_RESTRICTED_BUCKET,
+                            "cancelled due to restricted bucket");
+                } else {
+                    serviceContext.cancelExecutingJobLocked(
+                            running.getStopReason(),
+                            JobParameters.INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED,
+                            "cancelled due to unsatisfied constraints");
+                }
+            } else {
+                final JobRestriction restriction = mService.checkIfRestricted(running);
+                if (restriction != null) {
+                    final int internalReasonCode = restriction.getInternalReason();
+                    serviceContext.cancelExecutingJobLocked(restriction.getReason(),
+                            internalReasonCode,
+                            "restricted due to "
+                                    + JobParameters.getInternalReasonCodeDescription(
+                                    internalReasonCode));
+                }
+            }
+        }
+    }
+
     private void noteConcurrency() {
         mService.mJobPackageTracker.noteConcurrency(mRunningJobs.size(),
                 // TODO: log per type instead of only TOP
@@ -738,10 +885,11 @@
     }
 
     @GuardedBy("mLock")
-    private void updateNonRunningPrioritiesLocked(@NonNull final List<JobStatus> pendingJobs,
+    private void updateNonRunningPrioritiesLocked(@NonNull final PendingJobQueue jobQueue,
             boolean updateCounter) {
-        for (int i = 0; i < pendingJobs.size(); i++) {
-            final JobStatus pending = pendingJobs.get(i);
+        JobStatus pending;
+        jobQueue.resetIterator();
+        while ((pending = jobQueue.next()) != null) {
 
             // If job is already running, go to next job.
             if (mRunningJobs.contains(pending)) {
@@ -779,7 +927,8 @@
         }
         // Use < instead of <= as that gives us a little wiggle room in case a new job comes
         // along very shortly.
-        if (mService.mPendingJobs.size() + mRunningJobs.size() < mWorkTypeConfig.getMaxTotal()) {
+        if (mService.mPendingJobQueue.size() + mRunningJobs.size()
+                < mWorkTypeConfig.getMaxTotal()) {
             // Don't artificially limit a single package if we don't even have enough jobs to use
             // the maximum number of slots. We'll preempt the job later if we need the slot.
             return false;
@@ -827,14 +976,15 @@
                 }
             } else {
                 mRunningJobs.add(jobStatus);
+                mActiveServices.add(worker);
+                mIdleContexts.remove(worker);
                 mWorkCountTracker.onJobStarted(workType);
                 packageStats.adjustRunningCount(true, jobStatus.shouldTreatAsExpeditedJob());
                 mActivePkgStats.add(
                         jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(),
                         packageStats);
             }
-            final List<JobStatus> pendingJobs = mService.mPendingJobs;
-            if (pendingJobs.remove(jobStatus)) {
+            if (mService.mPendingJobQueue.remove(jobStatus)) {
                 mService.mJobPackageTracker.noteNonpending(jobStatus);
             }
         } finally {
@@ -847,6 +997,8 @@
             @WorkType final int workType) {
         mWorkCountTracker.onJobFinished(workType);
         mRunningJobs.remove(jobStatus);
+        mActiveServices.remove(worker);
+        mIdleContexts.add(worker);
         final PackageStats packageStats =
                 mActivePkgStats.get(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName());
         if (packageStats == null) {
@@ -859,11 +1011,11 @@
             }
         }
 
-        final List<JobStatus> pendingJobs = mService.mPendingJobs;
+        final PendingJobQueue pendingJobQueue = mService.mPendingJobQueue;
         if (worker.getPreferredUid() != JobServiceContext.NO_PREFERRED_UID) {
             updateCounterConfigLocked();
             // Preemption case needs special care.
-            updateNonRunningPrioritiesLocked(pendingJobs, false);
+            updateNonRunningPrioritiesLocked(pendingJobQueue, false);
 
             JobStatus highestBiasJob = null;
             int highBiasWorkType = workType;
@@ -871,9 +1023,10 @@
             JobStatus backupJob = null;
             int backupWorkType = WORK_TYPE_NONE;
             int backupAllWorkTypes = WORK_TYPE_NONE;
-            for (int i = 0; i < pendingJobs.size(); i++) {
-                final JobStatus nextPending = pendingJobs.get(i);
 
+            JobStatus nextPending;
+            pendingJobQueue.resetIterator();
+            while ((nextPending = pendingJobQueue.next()) != null) {
                 if (mRunningJobs.contains(nextPending)) {
                     continue;
                 }
@@ -938,16 +1091,18 @@
                     startJobLocked(worker, backupJob, backupWorkType);
                 }
             }
-        } else if (pendingJobs.size() > 0) {
+        } else if (pendingJobQueue.size() > 0) {
             updateCounterConfigLocked();
-            updateNonRunningPrioritiesLocked(pendingJobs, false);
+            updateNonRunningPrioritiesLocked(pendingJobQueue, false);
 
             // This slot is now free and we have pending jobs. Start the highest bias job we find.
             JobStatus highestBiasJob = null;
             int highBiasWorkType = workType;
             int highBiasAllWorkTypes = workType;
-            for (int i = 0; i < pendingJobs.size(); i++) {
-                final JobStatus nextPending = pendingJobs.get(i);
+
+            JobStatus nextPending;
+            pendingJobQueue.resetIterator();
+            while ((nextPending = pendingJobQueue.next()) != null) {
 
                 if (mRunningJobs.contains(nextPending)) {
                     continue;
@@ -987,7 +1142,7 @@
     /**
      * Returns {@code null} if the job can continue running and a non-null String if the job should
      * be stopped. The non-null String details the reason for stopping the job. A job will generally
-     * be stopped if there similar job types waiting to be run and stopping this job would allow
+     * be stopped if there are similar job types waiting to be run and stopping this job would allow
      * another job to run, or if system state suggests the job should stop.
      */
     @Nullable
@@ -1024,8 +1179,8 @@
             return "too many jobs running";
         }
 
-        final List<JobStatus> pendingJobs = mService.mPendingJobs;
-        final int numPending = pendingJobs.size();
+        final PendingJobQueue pendingJobQueue = mService.mPendingJobQueue;
+        final int numPending = pendingJobQueue.size();
         if (numPending == 0) {
             // All quiet. We can let this job run to completion.
             return null;
@@ -1060,8 +1215,9 @@
 
         // Harder check. We need to see if a different work type can replace this job.
         int remainingWorkTypes = ALL_WORK_TYPES;
-        for (int i = 0; i < numPending; ++i) {
-            final JobStatus pending = pendingJobs.get(i);
+        JobStatus pending;
+        pendingJobQueue.resetIterator();
+        while ((pending = pendingJobQueue.next()) != null) {
             final int workTypes = getJobWorkTypes(pending);
             if ((workTypes & remainingWorkTypes) > 0
                     && mWorkCountTracker.canJobStart(workTypes, workType) != WORK_TYPE_NONE) {
@@ -1078,11 +1234,38 @@
     }
 
     @GuardedBy("mLock")
+    boolean executeTimeoutCommandLocked(PrintWriter pw, String pkgName, int userId,
+            boolean hasJobId, int jobId) {
+        boolean foundSome = false;
+        for (int i = 0; i < mActiveServices.size(); i++) {
+            final JobServiceContext jc = mActiveServices.get(i);
+            final JobStatus js = jc.getRunningJobLocked();
+            if (jc.timeoutIfExecutingLocked(pkgName, userId, hasJobId, jobId, "shell")) {
+                foundSome = true;
+                pw.print("Timing out: ");
+                js.printUniqueId(pw);
+                pw.print(" ");
+                pw.println(js.getServiceComponent().flattenToShortString());
+            }
+        }
+        return foundSome;
+    }
+
+    @NonNull
+    private JobServiceContext createNewJobServiceContext() {
+        return new JobServiceContext(mService, this,
+                IBatteryStats.Stub.asInterface(
+                        ServiceManager.getService(BatteryStats.SERVICE_NAME)),
+                mService.mJobPackageTracker, mContext.getMainLooper());
+    }
+
+    @GuardedBy("mLock")
     private String printPendingQueueLocked() {
         StringBuilder s = new StringBuilder("Pending queue: ");
-        Iterator<JobStatus> it = mService.mPendingJobs.iterator();
-        while (it.hasNext()) {
-            JobStatus js = it.next();
+        PendingJobQueue pendingJobQueue = mService.mPendingJobQueue;
+        JobStatus js;
+        pendingJobQueue.resetIterator();
+        while ((js = pendingJobQueue.next()) != null) {
             s.append("(")
                     .append(js.getJob().getId())
                     .append(", ")
@@ -1092,13 +1275,26 @@
         return s.toString();
     }
 
-    private static String printContextIdToJobMap(JobStatus[] map, String initial) {
-        StringBuilder s = new StringBuilder(initial + ": ");
-        for (int i=0; i<map.length; i++) {
-            s.append("(")
-                    .append(map[i] == null? -1: map[i].getJobId())
-                    .append(map[i] == null? -1: map[i].getUid())
-                    .append(")" );
+    private static String printAssignments(String header, ArraySet<ContextAssignment>... list) {
+        final StringBuilder s = new StringBuilder(header + ": ");
+        for (int l = 0; l < list.length; ++l) {
+            ArraySet<ContextAssignment> assignments = list[l];
+            for (int c = 0; c < assignments.size(); ++c) {
+                final ContextAssignment assignment = assignments.valueAt(c);
+                final JobStatus job = assignment.newJob == null
+                        ? assignment.context.getRunningJobLocked() : assignment.newJob;
+
+                if (l > 0 || c > 0) {
+                    s.append(" ");
+                }
+                s.append("(").append(assignment.context.getId()).append("=");
+                if (job == null) {
+                    s.append("nothing");
+                } else {
+                    s.append(job.getJobId()).append("/").append(job.getUid());
+                }
+                s.append(")");
+            }
         }
         return s.toString();
     }
@@ -1200,6 +1396,60 @@
         }
     }
 
+    @GuardedBy("mLock")
+    void dumpContextInfoLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate,
+            long nowElapsed, long nowUptime) {
+        pw.println("Active jobs:");
+        pw.increaseIndent();
+        if (mActiveServices.size() == 0) {
+            pw.println("N/A");
+        }
+        for (int i = 0; i < mActiveServices.size(); i++) {
+            JobServiceContext jsc = mActiveServices.get(i);
+            final JobStatus job = jsc.getRunningJobLocked();
+
+            if (job != null && !predicate.test(job)) {
+                continue;
+            }
+
+            pw.print("Slot #"); pw.print(i);
+            pw.print("(ID="); pw.print(jsc.getId()); pw.print("): ");
+            jsc.dumpLocked(pw, nowElapsed);
+
+            if (job != null) {
+                pw.increaseIndent();
+
+                pw.increaseIndent();
+                job.dump(pw, false, nowElapsed);
+                pw.decreaseIndent();
+
+                pw.print("Evaluated bias: ");
+                pw.println(JobInfo.getBiasString(job.lastEvaluatedBias));
+
+                pw.print("Active at ");
+                TimeUtils.formatDuration(job.madeActive - nowUptime, pw);
+                pw.print(", pending for ");
+                TimeUtils.formatDuration(job.madeActive - job.madePending, pw);
+                pw.decreaseIndent();
+                pw.println();
+            }
+        }
+        pw.decreaseIndent();
+
+        pw.println();
+        pw.print("Idle contexts (");
+        pw.print(mIdleContexts.size());
+        pw.println("):");
+        pw.increaseIndent();
+        for (int i = 0; i < mIdleContexts.size(); i++) {
+            JobServiceContext jsc = mIdleContexts.valueAt(i);
+
+            pw.print("ID="); pw.print(jsc.getId()); pw.print(": ");
+            jsc.dumpLocked(pw, nowElapsed);
+        }
+        pw.decreaseIndent();
+    }
+
     public void dumpProtoLocked(ProtoOutputStream proto, long tag, long now, long nowRealtime) {
         final long token = proto.start(tag);
 
@@ -1826,4 +2076,26 @@
             pw.println("}");
         }
     }
+
+    private static final class ContextAssignment {
+        public JobServiceContext context;
+        public int preferredUid = JobServiceContext.NO_PREFERRED_UID;
+        public int workType = WORK_TYPE_NONE;
+        public String preemptReason;
+        public int preemptReasonCode = JobParameters.STOP_REASON_UNDEFINED;
+        public String shouldStopJobReason;
+        public JobStatus newJob;
+        public int newWorkType = WORK_TYPE_NONE;
+
+        void clear() {
+            context = null;
+            preferredUid = JobServiceContext.NO_PREFERRED_UID;
+            workType = WORK_TYPE_NONE;
+            preemptReason = null;
+            preemptReasonCode = JobParameters.STOP_REASON_UNDEFINED;
+            shouldStopJobReason = null;
+            newJob = null;
+            newWorkType = WORK_TYPE_NONE;
+        }
+    }
 }
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 b936278..0b8162a 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -21,7 +21,6 @@
 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 
-import android.annotation.ElapsedRealtimeLong;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -57,7 +56,6 @@
 import android.net.Uri;
 import android.os.BatteryManager;
 import android.os.BatteryManagerInternal;
-import android.os.BatteryStats;
 import android.os.BatteryStatsInternal;
 import android.os.Binder;
 import android.os.Handler;
@@ -67,7 +65,6 @@
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.WorkSource;
@@ -83,14 +80,12 @@
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
-import android.util.SparseLongArray;
 import android.util.SparseSetArray;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.IBatteryStats;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
@@ -100,7 +95,6 @@
 import com.android.server.DeviceIdleInternal;
 import com.android.server.JobSchedulerBackgroundThread;
 import com.android.server.LocalServices;
-import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob;
 import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob;
 import com.android.server.job.controllers.BackgroundJobsController;
 import com.android.server.job.controllers.BatteryController;
@@ -243,12 +237,6 @@
     static final int MSG_CHECK_CHANGED_JOB_LIST = 8;
     static final int MSG_CHECK_MEDIA_EXEMPTION = 9;
 
-    /**
-     * Track Services that have currently active or pending jobs. The index is provided by
-     * {@link JobStatus#getServiceToken()}
-     */
-    final List<JobServiceContext> mActiveServices = new ArrayList<>();
-
     /** List of controllers that will notify this service of updates to jobs. */
     final List<StateController> mControllers;
     /**
@@ -298,7 +286,7 @@
      * Queue of pending jobs. The JobServiceContext class will receive jobs from this list
      * when ready to execute them.
      */
-    final ArrayList<JobStatus> mPendingJobs = new ArrayList<>();
+    final PendingJobQueue mPendingJobQueue = new PendingJobQueue();
 
     int[] mStartedUsers = EmptyArray.INT;
 
@@ -307,7 +295,6 @@
 
     PackageManagerInternal mLocalPM;
     ActivityManagerInternal mActivityManagerInternal;
-    IBatteryStats mBatteryStats;
     DeviceIdleInternal mLocalDeviceIdleController;
     @VisibleForTesting
     AppStateTrackerImpl mAppStateTracker;
@@ -839,189 +826,6 @@
     final Constants mConstants;
     final ConstantsObserver mConstantsObserver;
 
-    @VisibleForTesting
-    class PendingJobComparator implements Comparator<JobStatus> {
-        private static final int EJ_PRIORITY_MODIFIER = 10;
-
-        /** Cache of the earliest non-PRIORITY_MAX enqueue time found per UID. */
-        private final SparseLongArray mEarliestNonMaxEnqueueTimeCache = new SparseLongArray();
-        /**
-         * Cache of the last enqueue time of each priority for each UID. The SparseArray is keyed
-         * by UID and the SparseLongArray is keyed by the priority.
-         */
-        private final SparseArray<SparseLongArray> mLastPriorityEnqueueTimeCache =
-                new SparseArray<>();
-        /**
-         * The earliest enqueue time each UID's priority's jobs should use. The SparseArray is keyed
-         * by UID and the SparseLongArray is keyed by the value returned from
-         * {@link #getPriorityIndex(int, boolean)}.
-         */
-        private final SparseArray<SparseLongArray> mEarliestAllowedEnqueueTimes =
-                new SparseArray<>();
-
-        private int getPriorityIndex(int priority, boolean isEJ) {
-            // We need to separate HIGH priority EJs from HIGH priority regular jobs.
-            if (isEJ) {
-                return priority * EJ_PRIORITY_MODIFIER;
-            }
-            return priority;
-        }
-
-        /**
-         * Refresh sorting determinants based on the current state of {@link #mPendingJobs}.
-         */
-        @GuardedBy("mLock")
-        @VisibleForTesting
-        void refreshLocked() {
-            mEarliestNonMaxEnqueueTimeCache.clear();
-            for (int i = 0; i < mPendingJobs.size(); ++i) {
-                final JobStatus job = mPendingJobs.get(i);
-                final int uid = job.getSourceUid();
-                if (job.getEffectivePriority() < JobInfo.PRIORITY_MAX) {
-                    final long earliestEnqueueTime =
-                            mEarliestNonMaxEnqueueTimeCache.get(uid, Long.MAX_VALUE);
-                    mEarliestNonMaxEnqueueTimeCache.put(uid,
-                            Math.min(earliestEnqueueTime, job.enqueueTime));
-                }
-
-                final int pIdx =
-                        getPriorityIndex(job.getEffectivePriority(), job.isRequestedExpeditedJob());
-                SparseLongArray lastPriorityEnqueueTime = mLastPriorityEnqueueTimeCache.get(uid);
-                if (lastPriorityEnqueueTime == null) {
-                    lastPriorityEnqueueTime = new SparseLongArray();
-                    mLastPriorityEnqueueTimeCache.put(uid, lastPriorityEnqueueTime);
-                }
-                lastPriorityEnqueueTime.put(pIdx,
-                        Math.max(job.enqueueTime, lastPriorityEnqueueTime.get(pIdx, 0)));
-            }
-
-            // Move lower priority jobs behind higher priority jobs (instead of moving higher
-            // priority jobs ahead of lower priority jobs), except for EJs.
-            for (int i = 0; i < mLastPriorityEnqueueTimeCache.size(); ++i) {
-                final int uid = mLastPriorityEnqueueTimeCache.keyAt(i);
-                SparseLongArray lastEnqueueTimes = mLastPriorityEnqueueTimeCache.valueAt(i);
-                SparseLongArray earliestAllowedEnqueueTimes = new SparseLongArray();
-                mEarliestAllowedEnqueueTimes.put(uid, earliestAllowedEnqueueTimes);
-                long earliestAllowedEnqueueTime = mEarliestNonMaxEnqueueTimeCache.get(uid,
-                        lastEnqueueTimes.get(getPriorityIndex(JobInfo.PRIORITY_MAX, true), -1));
-                earliestAllowedEnqueueTimes.put(getPriorityIndex(JobInfo.PRIORITY_MAX, true),
-                        earliestAllowedEnqueueTime);
-                earliestAllowedEnqueueTime = 1
-                        + Math.max(earliestAllowedEnqueueTime,
-                        lastEnqueueTimes.get(getPriorityIndex(JobInfo.PRIORITY_HIGH, true), -1));
-                earliestAllowedEnqueueTimes.put(getPriorityIndex(JobInfo.PRIORITY_HIGH, true),
-                        earliestAllowedEnqueueTime);
-                earliestAllowedEnqueueTime++;
-                for (int p = JobInfo.PRIORITY_HIGH; p >= JobInfo.PRIORITY_MIN; --p) {
-                    final int pIdx = getPriorityIndex(p, false);
-                    earliestAllowedEnqueueTimes.put(pIdx, earliestAllowedEnqueueTime);
-                    final long lastEnqueueTime = lastEnqueueTimes.get(pIdx, -1);
-                    if (lastEnqueueTime != -1) {
-                        // Add additional millisecond for the next priority to ensure sorting is
-                        // stable/accurate when comparing to other apps.
-                        earliestAllowedEnqueueTime = 1
-                                + Math.max(earliestAllowedEnqueueTime, lastEnqueueTime);
-                    }
-                }
-            }
-
-            // Clear intermediate state that we don't need to reduce steady state memory usage.
-            mLastPriorityEnqueueTimeCache.clear();
-        }
-
-        @ElapsedRealtimeLong
-        private long getEffectiveEnqueueTime(@NonNull JobStatus job) {
-            // Move lower priority jobs behind higher priority jobs (instead of moving higher
-            // priority jobs ahead of lower priority jobs), except for MAX EJs.
-            final int uid = job.getSourceUid();
-            if (job.isRequestedExpeditedJob()
-                    && job.getEffectivePriority() == JobInfo.PRIORITY_MAX) {
-                return Math.min(job.enqueueTime,
-                        mEarliestNonMaxEnqueueTimeCache.get(uid, Long.MAX_VALUE));
-            }
-            final int priorityIdx =
-                    getPriorityIndex(job.getEffectivePriority(), job.isRequestedExpeditedJob());
-            final SparseLongArray earliestAllowedEnqueueTimes =
-                    mEarliestAllowedEnqueueTimes.get(uid);
-            if (earliestAllowedEnqueueTimes == null) {
-                // We're probably trying to insert directly without refreshing the internal arrays.
-                // Since we haven't seen this UID before, we can just use the job's enqueue time.
-                return job.enqueueTime;
-            }
-            return Math.max(job.enqueueTime, earliestAllowedEnqueueTimes.get(priorityIdx));
-        }
-
-        @Override
-        public int compare(JobStatus o1, JobStatus o2) {
-            if (o1 == o2) {
-                return 0;
-            }
-            // Jobs with an override state set (via adb) should be put first as tests/developers
-            // expect the jobs to run immediately.
-            if (o1.overrideState != o2.overrideState) {
-                // Higher override state (OVERRIDE_FULL) should be before lower state
-                // (OVERRIDE_SOFT)
-                return o2.overrideState - o1.overrideState;
-            }
-            final boolean o1EJ = o1.isRequestedExpeditedJob();
-            final boolean o2EJ = o2.isRequestedExpeditedJob();
-            if (o1.getSourceUid() == o2.getSourceUid()) {
-                if (o1EJ != o2EJ) {
-                    // Attempt to run requested expedited jobs ahead of regular jobs, regardless of
-                    // expedited job quota.
-                    return o1EJ ? -1 : 1;
-                }
-                if (o1.getEffectivePriority() != o2.getEffectivePriority()) {
-                    // Use the priority set by an app for intra-app job ordering. Higher
-                    // priority should be before lower priority.
-                    return o2.getEffectivePriority() - o1.getEffectivePriority();
-                }
-            } else {
-                // TODO: see if we can simplify this using explicit topological sorting
-                // Since we order jobs within a UID by the job's priority, in order to satisfy the
-                // transitivity constraint of the comparator, we must ensure consistent/appropriate
-                // ordering between apps as well. That is, if a job is ordered before or behind
-                // another job because of its priority, that ordering must translate to the
-                // relative ordering against other jobs.
-                // The effective ordering implementation here is to use HIGH priority EJs as a
-                // pivot point. MAX priority EJs are moved *ahead* of HIGH priority EJs. All
-                // regular jobs are moved *behind* HIGH priority EJs. The intention for moving jobs
-                // "behind" the EJs instead of moving all high priority jobs before lower priority
-                // jobs is to reduce any potential abuse (or just unfortunate execution) cases where
-                // there are early low priority jobs that don't get to run because so many of the
-                // app's high priority jobs are pushed before low priority job. This may still
-                // happen because of the job ordering mechanism, but moving jobs back prevents
-                // one app's jobs from always being at the front (due to the early scheduled low
-                // priority job and our base case of sorting by enqueue time).
-
-                final long o1EffectiveEnqueueTime = getEffectiveEnqueueTime(o1);
-                final long o2EffectiveEnqueueTime = getEffectiveEnqueueTime(o2);
-
-                if (o1EffectiveEnqueueTime < o2EffectiveEnqueueTime) {
-                    return -1;
-                } else if (o1EffectiveEnqueueTime > o2EffectiveEnqueueTime) {
-                    return 1;
-                }
-            }
-
-            if (o1.enqueueTime < o2.enqueueTime) {
-                return -1;
-            }
-            return o1.enqueueTime > o2.enqueueTime ? 1 : 0;
-        }
-    }
-
-    @VisibleForTesting
-    final PendingJobComparator mPendingJobComparator = new PendingJobComparator();
-
-    static <T> void addOrderedItem(ArrayList<T> array, T newItem, Comparator<T> comparator) {
-        int where = Collections.binarySearch(array, newItem, comparator);
-        if (where < 0) {
-            where = ~where;
-        }
-        array.add(where, newItem);
-    }
-
     /**
      * Cleans up outstanding jobs when a package is removed. Even if it's being replaced later we
      * still clean up. On reinstall the package will have a new uid.
@@ -1445,7 +1249,7 @@
                 // This is a new job, we can just immediately put it on the pending
                 // list and try to run it.
                 mJobPackageTracker.notePending(jobStatus);
-                addOrderedItem(mPendingJobs, jobStatus, mPendingJobComparator);
+                mPendingJobQueue.add(jobStatus);
                 maybeRunPendingJobsLocked();
             } else {
                 evaluateControllerStatesLocked(jobStatus);
@@ -1574,11 +1378,12 @@
         cancelled.unprepareLocked();
         stopTrackingJobLocked(cancelled, incomingJob, true /* writeBack */);
         // Remove from pending queue.
-        if (mPendingJobs.remove(cancelled)) {
+        if (mPendingJobQueue.remove(cancelled)) {
             mJobPackageTracker.noteNonpending(cancelled);
         }
         // Cancel if running.
-        stopJobOnServiceContextLocked(cancelled, reason, internalReasonCode, debugReason);
+        mConcurrencyManager.stopJobOnServiceContextLocked(
+                cancelled, reason, internalReasonCode, debugReason);
         // If this is a replacement, bring in the new version of the job
         if (incomingJob != null) {
             if (DEBUG) Slog.i(TAG, "Tracking replacement job " + incomingJob.toShortString());
@@ -1627,19 +1432,7 @@
             if (DEBUG) {
                 Slog.d(TAG, "Doze state changed: " + deviceIdle);
             }
-            if (deviceIdle) {
-                // When becoming idle, make sure no jobs are actively running,
-                // except those using the idle exemption flag.
-                for (int i=0; i<mActiveServices.size(); i++) {
-                    JobServiceContext jsc = mActiveServices.get(i);
-                    final JobStatus executing = jsc.getRunningJobLocked();
-                    if (executing != null && !executing.canRunInDoze()) {
-                        jsc.cancelExecutingJobLocked(JobParameters.STOP_REASON_DEVICE_STATE,
-                                JobParameters.INTERNAL_STOP_REASON_DEVICE_IDLE,
-                                "cancelled due to doze");
-                    }
-                }
-            } else {
+            if (!deviceIdle) {
                 // When coming out of idle, allow thing to start back up.
                 if (mReadyToRock) {
                     if (mLocalDeviceIdleController != null) {
@@ -1680,12 +1473,12 @@
 
     void reportActiveLocked() {
         // active is true if pending queue contains jobs OR some job is running.
-        boolean active = mPendingJobs.size() > 0;
-        if (mPendingJobs.size() <= 0) {
-            for (int i=0; i<mActiveServices.size(); i++) {
-                final JobServiceContext jsc = mActiveServices.get(i);
-                final JobStatus job = jsc.getRunningJobLocked();
-                if (job != null && !job.canRunInDoze()) {
+        boolean active = mPendingJobQueue.size() > 0;
+        if (!active) {
+            final ArraySet<JobStatus> runningJobs = mConcurrencyManager.getRunningJobsLocked();
+            for (int i = runningJobs.size() - 1; i >= 0; --i) {
+                final JobStatus job = runningJobs.valueAt(i);
+                if (!job.canRunInDoze()) {
                     // We will report active if we have a job running and it does not have an
                     // exception that allows it to run in Doze.
                     active = true;
@@ -1895,16 +1688,9 @@
             synchronized (mLock) {
                 // Let's go!
                 mReadyToRock = true;
-                mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
-                        BatteryStats.SERVICE_NAME));
                 mLocalDeviceIdleController =
                         LocalServices.getService(DeviceIdleInternal.class);
-                // Create the "runners".
-                for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
-                    mActiveServices.add(
-                            new JobServiceContext(this, mConcurrencyManager, mBatteryStats,
-                                    mJobPackageTracker, getContext().getMainLooper()));
-                }
+                mConcurrencyManager.onThirdPartyAppsCanStart();
                 // Attach jobs to their controllers.
                 mJobs.forEachJob((job) -> {
                     for (int controller = 0; controller < mControllers.size(); controller++) {
@@ -1961,19 +1747,6 @@
         return removed;
     }
 
-    private boolean stopJobOnServiceContextLocked(JobStatus job,
-            @JobParameters.StopReason int reason, int internalReasonCode, String debugReason) {
-        for (int i = 0; i < mActiveServices.size(); i++) {
-            JobServiceContext jsc = mActiveServices.get(i);
-            final JobStatus executing = jsc.getRunningJobLocked();
-            if (executing != null && executing.matches(job.getUid(), job.getJobId())) {
-                jsc.cancelExecutingJobLocked(reason, internalReasonCode, debugReason);
-                return true;
-            }
-        }
-        return false;
-    }
-
     /** Return {@code true} if the specified job is currently executing. */
     @GuardedBy("mLock")
     public boolean isCurrentlyRunningLocked(JobStatus job) {
@@ -1994,10 +1767,13 @@
         mJobPackageTracker.noteNonpending(job);
     }
 
-    void noteJobsNonpending(List<JobStatus> jobs) {
-        for (int i = jobs.size() - 1; i >= 0; i--) {
-            noteJobNonPending(jobs.get(i));
+    private void clearPendingJobQueue() {
+        JobStatus job;
+        mPendingJobQueue.resetIterator();
+        while ((job = mPendingJobQueue.next()) != null) {
+            noteJobNonPending(job);
         }
+        mPendingJobQueue.clear();
     }
 
     /**
@@ -2278,7 +2054,7 @@
                         if (js != null) {
                             if (isReadyToBeExecutedLocked(js)) {
                                 mJobPackageTracker.notePending(js);
-                                addOrderedItem(mPendingJobs, js, mPendingJobComparator);
+                                mPendingJobQueue.add(js);
                             }
                             mChangedJobList.remove(js);
                         } else {
@@ -2383,7 +2159,8 @@
      * - if passes all the restrictions or has {@link JobInfo#BIAS_FOREGROUND_SERVICE} bias
      * or higher.
      */
-    private JobRestriction checkIfRestricted(JobStatus job) {
+    @GuardedBy("mLock")
+    JobRestriction checkIfRestricted(JobStatus job) {
         if (evaluateJobBiasLocked(job) >= JobInfo.BIAS_FOREGROUND_SERVICE) {
             // Jobs with BIAS_FOREGROUND_SERVICE or higher should not be restricted
             return null;
@@ -2397,38 +2174,9 @@
         return null;
     }
 
+    @GuardedBy("mLock")
     private void stopNonReadyActiveJobsLocked() {
-        for (int i=0; i<mActiveServices.size(); i++) {
-            JobServiceContext serviceContext = mActiveServices.get(i);
-            final JobStatus running = serviceContext.getRunningJobLocked();
-            if (running == null) {
-                continue;
-            }
-            if (!running.isReady()) {
-                if (running.getEffectiveStandbyBucket() == RESTRICTED_INDEX
-                        && running.getStopReason() == JobParameters.STOP_REASON_APP_STANDBY) {
-                    serviceContext.cancelExecutingJobLocked(
-                            running.getStopReason(),
-                            JobParameters.INTERNAL_STOP_REASON_RESTRICTED_BUCKET,
-                            "cancelled due to restricted bucket");
-                } else {
-                    serviceContext.cancelExecutingJobLocked(
-                            running.getStopReason(),
-                            JobParameters.INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED,
-                            "cancelled due to unsatisfied constraints");
-                }
-            } else {
-                final JobRestriction restriction = checkIfRestricted(running);
-                if (restriction != null) {
-                    final int internalReasonCode = restriction.getInternalReason();
-                    serviceContext.cancelExecutingJobLocked(restriction.getReason(),
-                            internalReasonCode,
-                            "restricted due to "
-                                    + JobParameters.getInternalReasonCodeDescription(
-                                    internalReasonCode));
-                }
-            }
-        }
+        mConcurrencyManager.stopNonReadyActiveJobsLocked();
     }
 
     /**
@@ -2452,14 +2200,13 @@
         if (DEBUG) {
             Slog.d(TAG, "queuing all ready jobs for execution:");
         }
-        noteJobsNonpending(mPendingJobs);
-        mPendingJobs.clear();
+        clearPendingJobQueue();
         stopNonReadyActiveJobsLocked();
         mJobs.forEachJob(mReadyQueueFunctor);
         mReadyQueueFunctor.postProcessLocked();
 
         if (DEBUG) {
-            final int queuedJobs = mPendingJobs.size();
+            final int queuedJobs = mPendingJobQueue.size();
             if (queuedJobs == 0) {
                 Slog.d(TAG, "No jobs pending.");
             } else {
@@ -2486,11 +2233,7 @@
         @GuardedBy("mLock")
         private void postProcessLocked() {
             noteJobsPending(newReadyJobs);
-            mPendingJobs.addAll(newReadyJobs);
-            mPendingJobComparator.refreshLocked();
-            if (mPendingJobs.size() > 1) {
-                mPendingJobs.sort(mPendingJobComparator);
-            }
+            mPendingJobQueue.addAll(newReadyJobs);
 
             newReadyJobs.clear();
         }
@@ -2523,7 +2266,7 @@
                         mHandler.obtainMessage(MSG_STOP_JOB,
                                 JobParameters.STOP_REASON_BACKGROUND_RESTRICTION, 0, job)
                                 .sendToTarget();
-                    } else if (mPendingJobs.remove(job)) {
+                    } else if (mPendingJobQueue.remove(job)) {
                         noteJobNonPending(job);
                     }
                     return;
@@ -2598,9 +2341,9 @@
                             debugReason = "couldn't figure out why the job should stop running";
                         }
                     }
-                    stopJobOnServiceContextLocked(job, job.getStopReason(),
+                    mConcurrencyManager.stopJobOnServiceContextLocked(job, job.getStopReason(),
                             internalStopReason, debugReason);
-                } else if (mPendingJobs.remove(job)) {
+                } else if (mPendingJobQueue.remove(job)) {
                     noteJobNonPending(job);
                 }
                 evaluateControllerStatesLocked(job);
@@ -2616,11 +2359,7 @@
                     Slog.d(TAG, "maybeQueueReadyJobsForExecutionLocked: Running jobs.");
                 }
                 noteJobsPending(runnableJobs);
-                mPendingJobs.addAll(runnableJobs);
-                mPendingJobComparator.refreshLocked();
-                if (mPendingJobs.size() > 1) {
-                    mPendingJobs.sort(mPendingJobComparator);
-                }
+                mPendingJobQueue.addAll(runnableJobs);
             } else {
                 if (DEBUG) {
                     Slog.d(TAG, "maybeQueueReadyJobsForExecutionLocked: Not running anything.");
@@ -2644,14 +2383,13 @@
     @GuardedBy("mLock")
     private void maybeQueueReadyJobsForExecutionLocked() {
         mHandler.removeMessages(MSG_CHECK_JOB);
-        // This method will evaluate all jobs, so we don't need to keep any messages for a suubset
+        // This method will evaluate all jobs, so we don't need to keep any messages for a subset
         // of jobs in the queue.
         mHandler.removeMessages(MSG_CHECK_CHANGED_JOB_LIST);
         mChangedJobList.clear();
         if (DEBUG) Slog.d(TAG, "Maybe queuing ready jobs...");
 
-        noteJobsNonpending(mPendingJobs);
-        mPendingJobs.clear();
+        clearPendingJobQueue();
         stopNonReadyActiveJobsLocked();
         mJobs.forEachJob(mMaybeQueueFunctor);
         mMaybeQueueFunctor.postProcessLocked();
@@ -2752,7 +2490,7 @@
             return false;
         }
 
-        final boolean jobPending = mPendingJobs.contains(job);
+        final boolean jobPending = mPendingJobQueue.contains(job);
         final boolean jobActive = rejectActive && mConcurrencyManager.isJobRunningLocked(job);
 
         if (DEBUG) {
@@ -2872,7 +2610,7 @@
      */
     void maybeRunPendingJobsLocked() {
         if (DEBUG) {
-            Slog.d(TAG, "pending queue: " + mPendingJobs.size() + " jobs.");
+            Slog.d(TAG, "pending queue: " + mPendingJobQueue.size() + " jobs.");
         }
         mConcurrencyManager.assignJobsToContextsLocked();
         reportActiveLocked();
@@ -3516,9 +3254,11 @@
             final ArrayList<JobInfo> runningJobs;
 
             synchronized (mLock) {
-                runningJobs = new ArrayList<>(mActiveServices.size());
-                for (JobServiceContext jsc : mActiveServices) {
-                    final JobStatus job = jsc.getRunningJobLocked();
+                final ArraySet<JobStatus> runningJobStatuses =
+                        mConcurrencyManager.getRunningJobsLocked();
+                runningJobs = new ArrayList<>(runningJobStatuses.size());
+                for (int i = runningJobStatuses.size() - 1; i >= 0; --i) {
+                    final JobStatus job = runningJobStatuses.valueAt(i);
                     if (job != null) {
                         runningJobs.add(job.getJob());
                     }
@@ -3599,18 +3339,8 @@
         }
 
         synchronized (mLock) {
-            boolean foundSome = false;
-            for (int i = 0; i < mActiveServices.size(); i++) {
-                final JobServiceContext jc = mActiveServices.get(i);
-                final JobStatus js = jc.getRunningJobLocked();
-                if (jc.timeoutIfExecutingLocked(pkgName, userId, hasJobId, jobId, "shell")) {
-                    foundSome = true;
-                    pw.print("Timing out: ");
-                    js.printUniqueId(pw);
-                    pw.print(" ");
-                    pw.println(js.getServiceComponent().flattenToShortString());
-                }
-            }
+            final boolean foundSome = mConcurrencyManager.executeTimeoutCommandLocked(pw,
+                    pkgName, userId, hasJobId, jobId);
             if (!foundSome) {
                 pw.println("No matching executing jobs found.");
             }
@@ -3712,7 +3442,7 @@
                 }
 
                 boolean printed = false;
-                if (mPendingJobs.contains(js)) {
+                if (mPendingJobQueue.contains(js)) {
                     pw.print("pending");
                     printed = true;
                 }
@@ -3914,7 +3644,7 @@
                     pw.print(" !restricted=");
                     pw.print(!isRestricted);
                     pw.print(" !pending=");
-                    pw.print(!mPendingJobs.contains(job));
+                    pw.print(!mPendingJobQueue.contains(job));
                     pw.print(" !active=");
                     pw.print(!mConcurrencyManager.isJobRunningLocked(job));
                     pw.print(" !backingup=");
@@ -4007,8 +3737,11 @@
             boolean pendingPrinted = false;
             pw.println("Pending queue:");
             pw.increaseIndent();
-            for (int i = 0; i < mPendingJobs.size(); i++) {
-                JobStatus job = mPendingJobs.get(i);
+            JobStatus job;
+            int pendingIdx = 0;
+            mPendingJobQueue.resetIterator();
+            while ((job = mPendingJobQueue.next()) != null) {
+                pendingIdx++;
                 if (!predicate.test(job)) {
                     continue;
                 }
@@ -4016,7 +3749,7 @@
                     pendingPrinted = true;
                 }
 
-                pw.print("Pending #"); pw.print(i); pw.print(": ");
+                pw.print("Pending #"); pw.print(pendingIdx); pw.print(": ");
                 pw.println(job.toShortString());
 
                 pw.increaseIndent();
@@ -4037,38 +3770,7 @@
             pw.decreaseIndent();
 
             pw.println();
-            pw.println("Active jobs:");
-            pw.increaseIndent();
-            for (int i=0; i<mActiveServices.size(); i++) {
-                JobServiceContext jsc = mActiveServices.get(i);
-                final JobStatus job = jsc.getRunningJobLocked();
-
-                if (job != null && !predicate.test(job)) {
-                    continue;
-                }
-
-                pw.print("Slot #"); pw.print(i); pw.print(": ");
-                jsc.dumpLocked(pw, nowElapsed);
-
-                if (job != null) {
-                    pw.increaseIndent();
-
-                    pw.increaseIndent();
-                    job.dump(pw, false, nowElapsed);
-                    pw.decreaseIndent();
-
-                    pw.print("Evaluated bias: ");
-                    pw.println(JobInfo.getBiasString(job.lastEvaluatedBias));
-
-                    pw.print("Active at ");
-                    TimeUtils.formatDuration(job.madeActive - nowUptime, pw);
-                    pw.print(", pending for ");
-                    TimeUtils.formatDuration(job.madeActive - job.madePending, pw);
-                    pw.decreaseIndent();
-                    pw.println();
-                }
-            }
-            pw.decreaseIndent();
+            mConcurrencyManager.dumpContextInfoLocked(pw, predicate, nowElapsed, nowUptime);
 
             pw.println();
             boolean recentPrinted = false;
@@ -4078,7 +3780,7 @@
                 // Print most recent first
                 final int idx = (mLastCompletedJobIndex + NUM_COMPLETED_JOB_HISTORY - r)
                         % NUM_COMPLETED_JOB_HISTORY;
-                final JobStatus job = mLastCompletedJobs[idx];
+                job = mLastCompletedJobs[idx];
                 if (job != null) {
                     if (!predicate.test(job)) {
                         continue;
@@ -4171,7 +3873,7 @@
                             JobSchedulerServiceDumpProto.RegisteredJob.IS_JOB_RESTRICTED,
                             checkIfRestricted(job) != null);
                     proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_JOB_PENDING,
-                            mPendingJobs.contains(job));
+                            mPendingJobQueue.contains(job));
                     proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_JOB_CURRENTLY_ACTIVE,
                             mConcurrencyManager.isJobRunningLocked(job));
                     proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_UID_BACKING_UP,
@@ -4218,7 +3920,9 @@
             mJobPackageTracker.dumpHistory(proto, JobSchedulerServiceDumpProto.HISTORY,
                     filterAppId);
 
-            for (JobStatus job : mPendingJobs) {
+            JobStatus job;
+            mPendingJobQueue.resetIterator();
+            while ((job = mPendingJobQueue.next()) != null) {
                 final long pjToken = proto.start(JobSchedulerServiceDumpProto.PENDING_JOBS);
 
                 job.writeToShortProto(proto, PendingJob.INFO);
@@ -4228,45 +3932,6 @@
 
                 proto.end(pjToken);
             }
-            for (JobServiceContext jsc : mActiveServices) {
-                final long ajToken = proto.start(JobSchedulerServiceDumpProto.ACTIVE_JOBS);
-                final JobStatus job = jsc.getRunningJobLocked();
-
-                if (job == null) {
-                    final long ijToken = proto.start(ActiveJob.INACTIVE);
-
-                    proto.write(ActiveJob.InactiveJob.TIME_SINCE_STOPPED_MS,
-                            nowElapsed - jsc.mStoppedTime);
-                    if (jsc.mStoppedReason != null) {
-                        proto.write(ActiveJob.InactiveJob.STOPPED_REASON,
-                                jsc.mStoppedReason);
-                    }
-
-                    proto.end(ijToken);
-                } else {
-                    final long rjToken = proto.start(ActiveJob.RUNNING);
-
-                    job.writeToShortProto(proto, ActiveJob.RunningJob.INFO);
-
-                    proto.write(ActiveJob.RunningJob.RUNNING_DURATION_MS,
-                            nowElapsed - jsc.getExecutionStartTimeElapsed());
-                    proto.write(ActiveJob.RunningJob.TIME_UNTIL_TIMEOUT_MS,
-                            jsc.getTimeoutElapsed() - nowElapsed);
-
-                    job.dump(proto, ActiveJob.RunningJob.DUMP, false, nowElapsed);
-
-                    proto.write(ActiveJob.RunningJob.EVALUATED_PRIORITY,
-                            evaluateJobBiasLocked(job));
-
-                    proto.write(ActiveJob.RunningJob.TIME_SINCE_MADE_ACTIVE_MS,
-                            nowUptime - job.madeActive);
-                    proto.write(ActiveJob.RunningJob.PENDING_DURATION_MS,
-                            job.madeActive - job.madePending);
-
-                    proto.end(rjToken);
-                }
-                proto.end(ajToken);
-            }
             if (filterUid == -1) {
                 proto.write(JobSchedulerServiceDumpProto.IS_READY_TO_ROCK, mReadyToRock);
                 proto.write(JobSchedulerServiceDumpProto.REPORTED_ACTIVE, mReportedActive);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index 00d1bff..54e0a4c 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -433,6 +433,10 @@
         mPreferredUid = NO_PREFERRED_UID;
     }
 
+    int getId() {
+        return hashCode();
+    }
+
     long getExecutionStartTimeElapsed() {
         return mExecutionStartTimeElapsed;
     }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index a8dd752..dfa1442 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -548,7 +548,7 @@
             out.attribute(null, "sourceUserId", String.valueOf(jobStatus.getSourceUserId()));
             out.attribute(null, "uid", Integer.toString(jobStatus.getUid()));
             out.attribute(null, "bias", String.valueOf(jobStatus.getBias()));
-            out.attribute(null, "priority", String.valueOf(jobStatus.getEffectivePriority()));
+            out.attribute(null, "priority", String.valueOf(jobStatus.getJob().getPriority()));
             out.attribute(null, "flags", String.valueOf(jobStatus.getFlags()));
             if (jobStatus.getInternalFlags() != 0) {
                 out.attribute(null, "internalFlags", String.valueOf(jobStatus.getInternalFlags()));
diff --git a/apex/jobscheduler/service/java/com/android/server/job/PendingJobQueue.java b/apex/jobscheduler/service/java/com/android/server/job/PendingJobQueue.java
new file mode 100644
index 0000000..daf1ee1
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/job/PendingJobQueue.java
@@ -0,0 +1,468 @@
+/*
+ * 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.server.job;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Pools;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.job.controllers.JobStatus;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.PriorityQueue;
+
+/**
+ * A utility class to maintain a sorted list of currently pending jobs. The sorting system is
+ * modeled after topological sort, so the returned order may not always be consistent.
+ */
+class PendingJobQueue {
+    private final Pools.Pool<AppJobQueue> mAppJobQueuePool = new Pools.SimplePool<>(8);
+
+    /** Set of currently used queues, keyed by source UID. */
+    private final SparseArray<AppJobQueue> mCurrentQueues = new SparseArray<>();
+    /**
+     * Same set of AppJobQueues as in {@link #mCurrentQueues}, but ordered by the next timestamp
+     * to make iterating through the job list faster.
+     */
+    private final PriorityQueue<AppJobQueue> mOrderedQueues = new PriorityQueue<>(
+            (ajq1, ajq2) -> {
+                final long t1 = ajq1.peekNextTimestamp();
+                final long t2 = ajq2.peekNextTimestamp();
+                if (t1 == AppJobQueue.NO_NEXT_TIMESTAMP) {
+                    if (t2 == AppJobQueue.NO_NEXT_TIMESTAMP) {
+                        return 0;
+                    }
+                    return 1;
+                } else if (t2 == AppJobQueue.NO_NEXT_TIMESTAMP) {
+                    return -1;
+                }
+                final int o1 = ajq1.peekNextOverrideState();
+                final int o2 = ajq2.peekNextOverrideState();
+                if (o1 != o2) {
+                    // Higher override state (OVERRIDE_FULL) should be before lower state
+                    // (OVERRIDE_SOFT)
+                    return Integer.compare(o2, o1);
+                }
+                return Long.compare(t1, t2);
+            });
+
+    private int mSize = 0;
+
+    /**
+     * Whether to batch iteration so that we pull several of an app's jobs from the queue at the
+     * same time (resulting in some out of order pulls) instead of pulling purely based on the
+     * sort order. Batching it this way will mean we try to run several jobs of the same app at the
+     * same, resulting in fewer process restarts, and can allow the iteration runtime to amortize
+     * to O(A*J) instead of O(A*J*log(A)), where A = # apps and J = average # jobs per app.
+     */
+    private boolean mOptimizeIteration = true;
+
+    /**
+     * Number of jobs that have been pulled from the queue in succession. Used when
+     * {@link #mOptimizeIteration} is true to know when to switch to the next AppJobQueue.
+     */
+    private int mPullCount = 0;
+
+    private boolean mNeedToResetIterators = false;
+
+    void add(@NonNull JobStatus job) {
+        final AppJobQueue ajq = getAppJobQueue(job.getSourceUid(), true);
+        final long prevTimestamp = ajq.peekNextTimestamp();
+        ajq.add(job);
+        mSize++;
+        if (prevTimestamp != ajq.peekNextTimestamp()) {
+            mOrderedQueues.remove(ajq);
+            mOrderedQueues.offer(ajq);
+        }
+    }
+
+    void addAll(@NonNull List<JobStatus> jobs) {
+        final SparseArray<List<JobStatus>> jobsByUid = new SparseArray<>();
+        for (int i = jobs.size() - 1; i >= 0; --i) {
+            final JobStatus job = jobs.get(i);
+            List<JobStatus> appJobs = jobsByUid.get(job.getSourceUid());
+            if (appJobs == null) {
+                appJobs = new ArrayList<>();
+                jobsByUid.put(job.getSourceUid(), appJobs);
+            }
+            appJobs.add(job);
+        }
+        for (int i = jobsByUid.size() - 1; i >= 0; --i) {
+            final AppJobQueue ajq = getAppJobQueue(jobsByUid.keyAt(i), true);
+            ajq.addAll(jobsByUid.valueAt(i));
+        }
+        mSize += jobs.size();
+        mOrderedQueues.clear();
+    }
+
+    void clear() {
+        mSize = 0;
+        for (int i = mCurrentQueues.size() - 1; i >= 0; --i) {
+            final AppJobQueue ajq = mCurrentQueues.valueAt(i);
+            ajq.clear();
+            mAppJobQueuePool.release(ajq);
+        }
+        mCurrentQueues.clear();
+        mOrderedQueues.clear();
+    }
+
+    boolean contains(@NonNull JobStatus job) {
+        final AppJobQueue ajq = mCurrentQueues.get(job.getSourceUid());
+        if (ajq == null) {
+            return false;
+        }
+        return ajq.contains(job);
+    }
+
+    private AppJobQueue getAppJobQueue(int uid, boolean create) {
+        AppJobQueue ajq = mCurrentQueues.get(uid);
+        if (ajq == null && create) {
+            ajq = mAppJobQueuePool.acquire();
+            if (ajq == null) {
+                ajq = new AppJobQueue();
+            }
+            mCurrentQueues.put(uid, ajq);
+        }
+        return ajq;
+    }
+
+    @Nullable
+    JobStatus next() {
+        if (mNeedToResetIterators) {
+            mOrderedQueues.clear();
+            for (int i = mCurrentQueues.size() - 1; i >= 0; --i) {
+                final AppJobQueue ajq = mCurrentQueues.valueAt(i);
+                ajq.resetIterator(0);
+                mOrderedQueues.offer(ajq);
+            }
+            mNeedToResetIterators = false;
+            // Reset the pull count when the front of the queue changes.
+            mPullCount = 0;
+        } else if (mOrderedQueues.size() == 0) {
+            // Something significant changed, so the priority queue was cleared. Lazily regenerate
+            // the queue.
+            for (int i = mCurrentQueues.size() - 1; i >= 0; --i) {
+                final AppJobQueue ajq = mCurrentQueues.valueAt(i);
+                mOrderedQueues.offer(ajq);
+            }
+            // Reset the pull count when the front of the queue changes.
+            mPullCount = 0;
+        }
+        final int numQueues = mOrderedQueues.size();
+        if (numQueues == 0) {
+            return null;
+        }
+
+        // Increase the pull limit at a slightly faster rate than log(A) increases (until A>=33).
+        // The pull limit increase is intended to balance fairness (one app can't starve out others)
+        // with efficiency (reducing process restarts).
+        // 1-4 apps --> pullLimit = 1, 5-8 apps --> pullLimit = 2, 9+ apps --> pullLimit = 3
+        final int pullLimit = mOptimizeIteration ? Math.min(3, ((numQueues - 1) >>> 2) + 1) : 1;
+
+        final AppJobQueue earliestQueue = mOrderedQueues.peek();
+        if (earliestQueue != null) {
+            final JobStatus job = earliestQueue.next();
+            // Change the front of the queue if we've pulled pullLimit jobs from the current head
+            // or we're dealing with test jobs
+            // or the current head has no more jobs to provide.
+            if (++mPullCount >= pullLimit
+                    || (job != null && earliestQueue.peekNextOverrideState() != job.overrideState)
+                    || earliestQueue.peekNextTimestamp() == AppJobQueue.NO_NEXT_TIMESTAMP) {
+                mOrderedQueues.poll();
+                if (earliestQueue.peekNextTimestamp() != AppJobQueue.NO_NEXT_TIMESTAMP) {
+                    // No need to put back in the queue if it has no more jobs to give.
+                    mOrderedQueues.offer(earliestQueue);
+                }
+                // Reset the pull count when the front of the queue changes.
+                mPullCount = 0;
+            }
+            return job;
+        }
+        return null;
+    }
+
+    boolean remove(@NonNull JobStatus job) {
+        final AppJobQueue ajq = getAppJobQueue(job.getSourceUid(), false);
+        if (ajq == null) {
+            return false;
+        }
+
+        final long prevTimestamp = ajq.peekNextTimestamp();
+        if (!ajq.remove(job)) {
+            return false;
+        }
+
+        mSize--;
+        if (ajq.size() == 0) {
+            mCurrentQueues.remove(job.getSourceUid());
+            mOrderedQueues.remove(ajq);
+            ajq.clear();
+            mAppJobQueuePool.release(ajq);
+        } else if (prevTimestamp != ajq.peekNextTimestamp()) {
+            mOrderedQueues.remove(ajq);
+            mOrderedQueues.offer(ajq);
+        }
+
+        return true;
+    }
+
+    /** Resets the iterating index to the front of the queue. */
+    void resetIterator() {
+        // Lazily reset the iterating indices (avoid looping through all the current queues until
+        // absolutely necessary).
+        mNeedToResetIterators = true;
+    }
+
+    @VisibleForTesting
+    void setOptimizeIteration(boolean optimize) {
+        mOptimizeIteration = optimize;
+    }
+
+    int size() {
+        return mSize;
+    }
+
+    private static final class AppJobQueue {
+        static final long NO_NEXT_TIMESTAMP = -1L;
+        static final int NO_NEXT_OVERRIDE_STATE = -1;
+
+        private static class AdjustedJobStatus {
+            public long adjustedEnqueueTime;
+            public JobStatus job;
+
+            void clear() {
+                adjustedEnqueueTime = 0;
+                job = null;
+            }
+        }
+
+        private static final Comparator<AdjustedJobStatus> sJobComparator = (aj1, aj2) -> {
+            if (aj1 == aj2) {
+                return 0;
+            }
+            final JobStatus job1 = aj1.job;
+            final JobStatus job2 = aj2.job;
+            // Jobs with an override state set (via adb) should be put first as tests/developers
+            // expect the jobs to run immediately.
+            if (job1.overrideState != job2.overrideState) {
+                // Higher override state (OVERRIDE_FULL) should be before lower state
+                // (OVERRIDE_SOFT)
+                return Integer.compare(job2.overrideState, job1.overrideState);
+            }
+
+            final boolean job1EJ = job1.isRequestedExpeditedJob();
+            final boolean job2EJ = job2.isRequestedExpeditedJob();
+            if (job1EJ != job2EJ) {
+                // Attempt to run requested expedited jobs ahead of regular jobs, regardless of
+                // expedited job quota.
+                return job1EJ ? -1 : 1;
+            }
+
+            final int job1Priority = job1.getEffectivePriority();
+            final int job2Priority = job2.getEffectivePriority();
+            if (job1Priority != job2Priority) {
+                // Use the priority set by an app for intra-app job ordering. Higher
+                // priority should be before lower priority.
+                return Integer.compare(job2Priority, job1Priority);
+            }
+
+            if (job1.lastEvaluatedBias != job2.lastEvaluatedBias) {
+                // Higher bias should go first.
+                return Integer.compare(job2.lastEvaluatedBias, job1.lastEvaluatedBias);
+            }
+
+            return Long.compare(job1.enqueueTime, job2.enqueueTime);
+        };
+
+        private static final Pools.Pool<AdjustedJobStatus> mAdjustedJobStatusPool =
+                new Pools.SimplePool<>(16);
+
+        private final List<AdjustedJobStatus> mJobs = new ArrayList<>();
+        private int mCurIndex = 0;
+
+        void add(@NonNull JobStatus jobStatus) {
+            AdjustedJobStatus adjustedJobStatus = mAdjustedJobStatusPool.acquire();
+            if (adjustedJobStatus == null) {
+                adjustedJobStatus = new AdjustedJobStatus();
+            }
+            adjustedJobStatus.adjustedEnqueueTime = jobStatus.enqueueTime;
+            adjustedJobStatus.job = jobStatus;
+
+            int where = Collections.binarySearch(mJobs, adjustedJobStatus, sJobComparator);
+            if (where < 0) {
+                where = ~where;
+            }
+            mJobs.add(where, adjustedJobStatus);
+            if (where < mCurIndex) {
+                // Shift the current index back to make sure the new job is evaluated on the next
+                // iteration.
+                mCurIndex = where;
+            }
+
+            if (where > 0) {
+                final long prevTimestamp = mJobs.get(where - 1).adjustedEnqueueTime;
+                adjustedJobStatus.adjustedEnqueueTime =
+                        Math.max(prevTimestamp, adjustedJobStatus.adjustedEnqueueTime);
+            }
+            final int numJobs = mJobs.size();
+            if (where < numJobs - 1) {
+                // Potentially need to adjust following job timestamps as well.
+                for (int i = where; i < numJobs; ++i) {
+                    final AdjustedJobStatus ajs = mJobs.get(i);
+                    if (adjustedJobStatus.adjustedEnqueueTime < ajs.adjustedEnqueueTime) {
+                        // No further need to adjust.
+                        break;
+                    }
+                    ajs.adjustedEnqueueTime = adjustedJobStatus.adjustedEnqueueTime;
+                }
+            }
+        }
+
+        void addAll(@NonNull List<JobStatus> jobs) {
+            int earliestIndex = Integer.MAX_VALUE;
+
+            for (int i = jobs.size() - 1; i >= 0; --i) {
+                final JobStatus job = jobs.get(i);
+
+                AdjustedJobStatus adjustedJobStatus = mAdjustedJobStatusPool.acquire();
+                if (adjustedJobStatus == null) {
+                    adjustedJobStatus = new AdjustedJobStatus();
+                }
+                adjustedJobStatus.adjustedEnqueueTime = job.enqueueTime;
+                adjustedJobStatus.job = job;
+
+                int where = Collections.binarySearch(mJobs, adjustedJobStatus, sJobComparator);
+                if (where < 0) {
+                    where = ~where;
+                }
+                mJobs.add(where, adjustedJobStatus);
+                if (where < mCurIndex) {
+                    // Shift the current index back to make sure the new job is evaluated on the
+                    // next iteration.
+                    mCurIndex = where;
+                }
+                earliestIndex = Math.min(earliestIndex, where);
+            }
+
+            final int numJobs = mJobs.size();
+            for (int i = Math.max(earliestIndex, 1); i < numJobs; ++i) {
+                final AdjustedJobStatus ajs = mJobs.get(i);
+                final AdjustedJobStatus prev = mJobs.get(i - 1);
+                ajs.adjustedEnqueueTime =
+                        Math.max(ajs.adjustedEnqueueTime, prev.adjustedEnqueueTime);
+            }
+        }
+
+        void clear() {
+            mJobs.clear();
+            mCurIndex = 0;
+        }
+
+        boolean contains(@NonNull JobStatus job) {
+            return indexOf(job) >= 0;
+        }
+
+        private int indexOf(@NonNull JobStatus jobStatus) {
+            AdjustedJobStatus adjustedJobStatus = mAdjustedJobStatusPool.acquire();
+            if (adjustedJobStatus == null) {
+                adjustedJobStatus = new AdjustedJobStatus();
+            }
+            adjustedJobStatus.adjustedEnqueueTime = jobStatus.enqueueTime;
+            adjustedJobStatus.job = jobStatus;
+
+            int where = Collections.binarySearch(mJobs, adjustedJobStatus, sJobComparator);
+            adjustedJobStatus.clear();
+            mAdjustedJobStatusPool.release(adjustedJobStatus);
+            return where;
+        }
+
+        @Nullable
+        JobStatus next() {
+            if (mCurIndex >= mJobs.size()) {
+                return null;
+            }
+            return mJobs.get(mCurIndex++).job;
+        }
+
+        int peekNextOverrideState() {
+            if (mCurIndex >= mJobs.size()) {
+                return NO_NEXT_OVERRIDE_STATE;
+            }
+            return mJobs.get(mCurIndex).job.overrideState;
+        }
+
+        long peekNextTimestamp() {
+            if (mCurIndex >= mJobs.size()) {
+                return NO_NEXT_TIMESTAMP;
+            }
+            return mJobs.get(mCurIndex).adjustedEnqueueTime;
+        }
+
+        boolean remove(@NonNull JobStatus jobStatus) {
+            final int idx = indexOf(jobStatus);
+            if (idx < 0) {
+                // Doesn't exist...
+                return false;
+            }
+            final AdjustedJobStatus adjustedJobStatus = mJobs.remove(idx);
+            adjustedJobStatus.clear();
+            mAdjustedJobStatusPool.release(adjustedJobStatus);
+            if (idx < mCurIndex) {
+                mCurIndex--;
+            }
+            return true;
+        }
+
+        /**
+         * Resets the internal index to point to the first JobStatus whose adjusted time is equal to
+         * or after the given timestamp.
+         */
+        void resetIterator(long earliestEnqueueTime) {
+            if (earliestEnqueueTime == 0 || mJobs.size() == 0) {
+                mCurIndex = 0;
+                return;
+            }
+
+            // Binary search
+            int low = 0;
+            int high = mJobs.size() - 1;
+
+            while (low < high) {
+                int mid = (low + high) >>> 1;
+                AdjustedJobStatus midVal = mJobs.get(mid);
+
+                if (midVal.adjustedEnqueueTime < earliestEnqueueTime) {
+                    low = mid + 1;
+                } else if (midVal.adjustedEnqueueTime > earliestEnqueueTime) {
+                    high = mid - 1;
+                } else {
+                    high = mid;
+                }
+            }
+            mCurIndex = high;
+        }
+
+        int size() {
+            return mJobs.size();
+        }
+    }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index efcf14f..30fdb1e 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -441,11 +441,6 @@
     /** The reason a job most recently went from ready to not ready. */
     private int mReasonReadyToUnready = JobParameters.STOP_REASON_UNDEFINED;
 
-    /** Provide a handle to the service that this job will be run on. */
-    public int getServiceToken() {
-        return callingUid;
-    }
-
     /**
      * Core constructor for JobStatus instances.  All other ctors funnel down to this one.
      *
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java b/apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java
index 67a3dc6..5ec2f56 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java
@@ -146,8 +146,11 @@
                 return 0;
             case PROC_STATE_BUCKET_FGS:
                 // Can't get notification priority. Just use CTP for now.
-                return ctp;
+                return Math.min(ctp, price);
             case PROC_STATE_BUCKET_BFGS:
+                if (price <= ctp) {
+                    return price;
+                }
                 return (long) (ctp + .5 * (price - ctp));
             case PROC_STATE_BUCKET_BG:
             default:
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 dd102bd..80f3fea 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
@@ -384,14 +384,16 @@
         return userHistory;
     }
 
+    // TODO (206518483): Remove unused parameter 'elapsedRealtime'.
     private AppUsageHistory getPackageHistory(ArrayMap<String, AppUsageHistory> userHistory,
             String packageName, long elapsedRealtime, boolean create) {
         AppUsageHistory appUsageHistory = userHistory.get(packageName);
         if (appUsageHistory == null && create) {
             appUsageHistory = new AppUsageHistory();
-            appUsageHistory.lastUsedElapsedTime = getElapsedTime(elapsedRealtime);
-            appUsageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime);
-            appUsageHistory.lastPredictedTime = getElapsedTime(0);
+            appUsageHistory.lastUsedByUserElapsedTime = Integer.MIN_VALUE;
+            appUsageHistory.lastUsedElapsedTime = Integer.MIN_VALUE;
+            appUsageHistory.lastUsedScreenTime = Integer.MIN_VALUE;
+            appUsageHistory.lastPredictedTime = Integer.MIN_VALUE;
             appUsageHistory.currentBucket = STANDBY_BUCKET_NEVER;
             appUsageHistory.bucketingReason = REASON_MAIN_DEFAULT;
             appUsageHistory.lastInformedBucket = -1;
@@ -544,7 +546,7 @@
         AppUsageHistory appUsageHistory =
                 getPackageHistory(userHistory, packageName, elapsedRealtime, false);
         if (appUsageHistory == null || appUsageHistory.lastUsedByUserElapsedTime == Long.MIN_VALUE
-                || appUsageHistory.lastUsedByUserElapsedTime == 0) {
+                || appUsageHistory.lastUsedByUserElapsedTime <= 0) {
             return Long.MAX_VALUE;
         }
         return getElapsedTime(elapsedRealtime) - appUsageHistory.lastUsedByUserElapsedTime;
@@ -621,7 +623,8 @@
      * @param elapsedRealtime current time
      * @param screenTimeThresholds Array of screen times, in ascending order, first one is 0
      * @param elapsedTimeThresholds Array of elapsed time, in ascending order, first one is 0
-     * @return The index whose values the app's used time exceeds (in both arrays)
+     * @return The index whose values the app's used time exceeds (in both arrays) or {@code -1} to
+     *         indicate that the app has never been used.
      */
     int getThresholdIndex(String packageName, int userId, long elapsedRealtime,
             long[] screenTimeThresholds, long[] elapsedTimeThresholds) {
@@ -629,7 +632,10 @@
         AppUsageHistory appUsageHistory = getPackageHistory(userHistory, packageName,
                 elapsedRealtime, false);
         // If we don't have any state for the app, assume never used
-        if (appUsageHistory == null) return screenTimeThresholds.length - 1;
+        if (appUsageHistory == null || appUsageHistory.lastUsedElapsedTime < 0
+                || appUsageHistory.lastUsedScreenTime < 0) {
+            return -1;
+        }
 
         long screenOnDelta = getScreenOnTime(elapsedRealtime) - appUsageHistory.lastUsedScreenTime;
         long elapsedDelta = getElapsedTime(elapsedRealtime) - appUsageHistory.lastUsedElapsedTime;
@@ -667,8 +673,8 @@
     long getBucketExpiryTimeMs(String packageName, int userId, int bucket, long elapsedRealtimeMs) {
         ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
         AppUsageHistory appUsageHistory = getPackageHistory(userHistory, packageName,
-                elapsedRealtimeMs, true);
-        if (appUsageHistory.bucketExpiryTimesMs == null) {
+                elapsedRealtimeMs, false /* create */);
+        if (appUsageHistory == null || appUsageHistory.bucketExpiryTimesMs == null) {
             return 0;
         }
         return appUsageHistory.bucketExpiryTimesMs.get(bucket, 0);
@@ -680,6 +686,17 @@
                 Integer.toString(userId)), APP_IDLE_FILENAME);
     }
 
+    void clearLastUsedTimestamps(String packageName, int userId) {
+        ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
+        AppUsageHistory appUsageHistory = getPackageHistory(userHistory, packageName,
+                SystemClock.elapsedRealtime(), false /* create */);
+        if (appUsageHistory != null) {
+            appUsageHistory.lastUsedByUserElapsedTime = Integer.MIN_VALUE;
+            appUsageHistory.lastUsedElapsedTime = Integer.MIN_VALUE;
+            appUsageHistory.lastUsedScreenTime = Integer.MIN_VALUE;
+        }
+    }
+
     /**
      * Check if App Idle File exists on disk
      * @param userId
@@ -951,14 +968,14 @@
                     + " reason="
                     + UsageStatsManager.reasonToString(appUsageHistory.bucketingReason));
             idpw.print(" used=");
-            TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastUsedElapsedTime, idpw);
+            printLastActionElapsedTime(idpw, totalElapsedTime, appUsageHistory.lastUsedElapsedTime);
             idpw.print(" usedByUser=");
-            TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastUsedByUserElapsedTime,
-                    idpw);
+            printLastActionElapsedTime(idpw, totalElapsedTime,
+                    appUsageHistory.lastUsedByUserElapsedTime);
             idpw.print(" usedScr=");
-            TimeUtils.formatDuration(screenOnTime - appUsageHistory.lastUsedScreenTime, idpw);
+            printLastActionElapsedTime(idpw, totalElapsedTime, appUsageHistory.lastUsedScreenTime);
             idpw.print(" lastPred=");
-            TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastPredictedTime, idpw);
+            printLastActionElapsedTime(idpw, totalElapsedTime, appUsageHistory.lastPredictedTime);
             dumpBucketExpiryTimes(idpw, appUsageHistory, totalElapsedTime);
             idpw.print(" lastJob=");
             TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastJobRunTime, idpw);
@@ -986,6 +1003,15 @@
         idpw.decreaseIndent();
     }
 
+    private void printLastActionElapsedTime(IndentingPrintWriter idpw, long totalElapsedTimeMS,
+            long lastActionTimeMs) {
+        if (lastActionTimeMs < 0) {
+            idpw.print("<uninitialized>");
+        } else {
+            TimeUtils.formatDuration(totalElapsedTimeMS - lastActionTimeMs, idpw);
+        }
+    }
+
     private void dumpBucketExpiryTimes(IndentingPrintWriter idpw, AppUsageHistory appUsageHistory,
             long totalElapsedTimeMs) {
         idpw.print(" expiryTimes=");
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 849354b..1e4ecc2 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -78,6 +78,7 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
+import android.content.pm.ResolveInfo;
 import android.database.ContentObserver;
 import android.hardware.display.DisplayManager;
 import android.net.NetworkScoreManager;
@@ -99,6 +100,7 @@
 import android.provider.DeviceConfig;
 import android.provider.Settings.Global;
 import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.IndentingPrintWriter;
 import android.util.Slog;
@@ -129,6 +131,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 
@@ -219,7 +222,8 @@
 
     private static final int HEADLESS_APP_CHECK_FLAGS =
             PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
-                    | PackageManager.GET_ACTIVITIES | PackageManager.MATCH_DISABLED_COMPONENTS;
+                    | PackageManager.MATCH_DISABLED_COMPONENTS
+                    | PackageManager.MATCH_SYSTEM_ONLY;
 
     // To name the lock for stack traces
     static class Lock {}
@@ -253,7 +257,7 @@
     private final SparseArray<Set<String>> mActiveAdminApps = new SparseArray<>();
 
     /**
-     * Set of system apps that are headless (don't have any declared activities, enabled or
+     * Set of system apps that are headless (don't have any "front door" activities, enabled or
      * disabled). Presence in this map indicates that the app is a headless system app.
      */
     @GuardedBy("mHeadlessSystemApps")
@@ -373,6 +377,15 @@
             ConstantsObserver.DEFAULT_BROADCAST_RESPONSE_FG_THRESHOLD_STATE;
 
     /**
+     * Map of last known values of keys in {@link DeviceConfig#NAMESPACE_APP_STANDBY}.
+     *
+     * Note: We are intentionally not guarding this by any lock since this is only updated on
+     * a handler thread and when querying, if we do end up seeing slightly older values, it is fine
+     * since the values are only used in tests and doesn't need to be queried in any other cases.
+     */
+    private final Map<String, String> mAppStandbyProperties = new ArrayMap<>();
+
+    /**
      * Whether we should allow apps into the
      * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} bucket or not.
      * If false, any attempts to put an app into the bucket will put the app into the
@@ -885,7 +898,8 @@
                     }
                 }
 
-                if (app.lastRestrictAttemptElapsedTime > app.lastUsedByUserElapsedTime
+                if (app.lastUsedByUserElapsedTime >= 0
+                        && app.lastRestrictAttemptElapsedTime > app.lastUsedByUserElapsedTime
                         && elapsedTimeAdjusted - app.lastUsedByUserElapsedTime
                         >= mInjector.getAutoRestrictedBucketDelayMs()) {
                     newBucket = STANDBY_BUCKET_RESTRICTED;
@@ -958,7 +972,7 @@
             long elapsedRealtime) {
         int bucketIndex = mAppIdleHistory.getThresholdIndex(packageName, userId,
                 elapsedRealtime, mAppStandbyScreenThresholds, mAppStandbyElapsedThresholds);
-        return THRESHOLD_BUCKETS[bucketIndex];
+        return bucketIndex >= 0 ? THRESHOLD_BUCKETS[bucketIndex] : STANDBY_BUCKET_NEVER;
     }
 
     private void notifyBatteryStats(String packageName, int userId, boolean idle) {
@@ -1573,8 +1587,10 @@
                     (reason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_SYSTEM;
 
             if (app.currentBucket == newBucket && wasForcedBySystem && isForcedBySystem) {
-                mAppIdleHistory
-                        .noteRestrictionAttempt(packageName, userId, elapsedRealtime, reason);
+                if (newBucket == STANDBY_BUCKET_RESTRICTED) {
+                    mAppIdleHistory
+                            .noteRestrictionAttempt(packageName, userId, elapsedRealtime, reason);
+                }
                 // Keep track of all restricting reasons
                 reason = REASON_MAIN_FORCED_BY_SYSTEM
                         | (app.bucketingReason & REASON_SUB_MASK)
@@ -1833,6 +1849,19 @@
     }
 
     @Override
+    @Nullable
+    public String getAppStandbyConstant(@NonNull String key) {
+        return mAppStandbyProperties.get(key);
+    }
+
+    @Override
+    public void clearLastUsedTimestampsForTest(@NonNull String packageName, @UserIdInt int userId) {
+        synchronized (mAppIdleLock) {
+            mAppIdleHistory.clearLastUsedTimestamps(packageName, userId);
+        }
+    }
+
+    @Override
     public void flushToDisk() {
         synchronized (mAppIdleLock) {
             mAppIdleHistory.writeAppIdleTimes(mInjector.elapsedRealtime());
@@ -1942,7 +1971,7 @@
         try {
             PackageInfo pi = mPackageManager.getPackageInfoAsUser(
                     packageName, HEADLESS_APP_CHECK_FLAGS, userId);
-            evaluateSystemAppException(pi);
+            maybeUpdateHeadlessSystemAppCache(pi);
         } catch (PackageManager.NameNotFoundException e) {
             synchronized (mHeadlessSystemApps) {
                 mHeadlessSystemApps.remove(packageName);
@@ -1950,19 +1979,31 @@
         }
     }
 
-    /** Returns true if the exception status changed. */
-    private boolean evaluateSystemAppException(@Nullable PackageInfo pkgInfo) {
+    /**
+     * Update the "headless system app" cache.
+     *
+     * @return true if the cache is updated.
+     */
+    private boolean maybeUpdateHeadlessSystemAppCache(@Nullable PackageInfo pkgInfo) {
         if (pkgInfo == null || pkgInfo.applicationInfo == null
                 || (!pkgInfo.applicationInfo.isSystemApp()
                         && !pkgInfo.applicationInfo.isUpdatedSystemApp())) {
             return false;
         }
+        final Intent frontDoorActivityIntent = new Intent(Intent.ACTION_MAIN)
+                .addCategory(Intent.CATEGORY_LAUNCHER)
+                .setPackage(pkgInfo.packageName);
+        List<ResolveInfo> res = mPackageManager.queryIntentActivitiesAsUser(frontDoorActivityIntent,
+                HEADLESS_APP_CHECK_FLAGS, UserHandle.USER_SYSTEM);
+        return updateHeadlessSystemAppCache(pkgInfo.packageName, ArrayUtils.isEmpty(res));
+    }
+
+    private boolean updateHeadlessSystemAppCache(String packageName, boolean add) {
         synchronized (mHeadlessSystemApps) {
-            if (pkgInfo.activities == null || pkgInfo.activities.length == 0) {
-                // Headless system app.
-                return mHeadlessSystemApps.add(pkgInfo.packageName);
+            if (add) {
+                return mHeadlessSystemApps.add(packageName);
             } else {
-                return mHeadlessSystemApps.remove(pkgInfo.packageName);
+                return mHeadlessSystemApps.remove(packageName);
             }
         }
     }
@@ -1999,20 +2040,45 @@
         }
     }
 
+    /** Returns the packages that have launcher icons. */
+    private Set<String> getSystemPackagesWithLauncherActivities() {
+        final Intent intent = new Intent(Intent.ACTION_MAIN)
+                .addCategory(Intent.CATEGORY_LAUNCHER);
+        List<ResolveInfo> activities = mPackageManager.queryIntentActivitiesAsUser(intent,
+                HEADLESS_APP_CHECK_FLAGS, UserHandle.USER_SYSTEM);
+        final ArraySet<String> ret = new ArraySet<>();
+        for (ResolveInfo ri : activities) {
+            ret.add(ri.activityInfo.packageName);
+        }
+        return ret;
+    }
+
     /** Call on system boot to get the initial set of headless system apps. */
     private void loadHeadlessSystemAppCache() {
-        Slog.d(TAG, "Loading headless system app cache. appIdleEnabled=" + mAppIdleEnabled);
+        final long start = SystemClock.uptimeMillis();
         final List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
                 HEADLESS_APP_CHECK_FLAGS, UserHandle.USER_SYSTEM);
+
+        final Set<String> systemLauncherActivities = getSystemPackagesWithLauncherActivities();
+
         final int packageCount = packages.size();
         for (int i = 0; i < packageCount; i++) {
-            PackageInfo pkgInfo = packages.get(i);
-            if (pkgInfo != null && evaluateSystemAppException(pkgInfo)) {
+            final PackageInfo pkgInfo = packages.get(i);
+            if (pkgInfo == null) {
+                continue;
+            }
+            final String pkg = pkgInfo.packageName;
+            final boolean isHeadLess = !systemLauncherActivities.contains(pkg);
+
+            if (updateHeadlessSystemAppCache(pkg, isHeadLess)) {
                 mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE,
-                        UserHandle.USER_SYSTEM, -1, pkgInfo.packageName)
+                        UserHandle.USER_SYSTEM, -1, pkg)
                     .sendToTarget();
             }
         }
+        final long end = SystemClock.uptimeMillis();
+        Slog.d(TAG, "Loaded headless system app cache in " + (end - start) + " ms:"
+                + " appIdleEnabled=" + mAppIdleEnabled);
     }
 
     @Override
@@ -2035,6 +2101,13 @@
                 .sendToTarget();
     }
 
+    @VisibleForTesting
+    AppIdleHistory getAppIdleHistoryForTest() {
+        synchronized (mAppIdleLock) {
+            return mAppIdleHistory;
+        }
+    }
+
     @Override
     public void dumpUsers(IndentingPrintWriter idpw, int[] userIds, List<String> pkgs) {
         synchronized (mAppIdleLock) {
@@ -2733,6 +2806,7 @@
                             }
                             break;
                     }
+                    mAppStandbyProperties.put(name, properties.getString(name, null));
                 }
             }
         }
diff --git a/boot/hiddenapi/hiddenapi-max-target-o.txt b/boot/hiddenapi/hiddenapi-max-target-o.txt
index d3b5be9..3c16915 100644
--- a/boot/hiddenapi/hiddenapi-max-target-o.txt
+++ b/boot/hiddenapi/hiddenapi-max-target-o.txt
@@ -32472,14 +32472,6 @@
 Landroid/net/DhcpResults;->setServerAddress(Ljava/lang/String;)Z
 Landroid/net/DhcpResults;->setVendorInfo(Ljava/lang/String;)V
 Landroid/net/DhcpResults;->TAG:Ljava/lang/String;
-Landroid/net/EthernetManager;-><init>(Landroid/content/Context;Landroid/net/IEthernetManager;)V
-Landroid/net/EthernetManager;->mContext:Landroid/content/Context;
-Landroid/net/EthernetManager;->mHandler:Landroid/os/Handler;
-Landroid/net/EthernetManager;->mListeners:Ljava/util/ArrayList;
-Landroid/net/EthernetManager;->mService:Landroid/net/IEthernetManager;
-Landroid/net/EthernetManager;->mServiceListener:Landroid/net/IEthernetServiceListener$Stub;
-Landroid/net/EthernetManager;->MSG_AVAILABILITY_CHANGED:I
-Landroid/net/EthernetManager;->TAG:Ljava/lang/String;
 Landroid/net/EventLogTags;-><init>()V
 Landroid/net/EventLogTags;->NTP_FAILURE:I
 Landroid/net/EventLogTags;->NTP_SUCCESS:I
@@ -32513,39 +32505,6 @@
 Landroid/net/http/X509TrustManagerExtensions;->mDelegate:Lcom/android/org/conscrypt/TrustManagerImpl;
 Landroid/net/http/X509TrustManagerExtensions;->mIsSameTrustConfiguration:Ljava/lang/reflect/Method;
 Landroid/net/http/X509TrustManagerExtensions;->mTrustManager:Ljavax/net/ssl/X509TrustManager;
-Landroid/net/IEthernetManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/net/IEthernetManager$Stub$Proxy;->addListener(Landroid/net/IEthernetServiceListener;)V
-Landroid/net/IEthernetManager$Stub$Proxy;->getAvailableInterfaces()[Ljava/lang/String;
-Landroid/net/IEthernetManager$Stub$Proxy;->getConfiguration(Ljava/lang/String;)Landroid/net/IpConfiguration;
-Landroid/net/IEthernetManager$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/net/IEthernetManager$Stub$Proxy;->isAvailable(Ljava/lang/String;)Z
-Landroid/net/IEthernetManager$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/net/IEthernetManager$Stub$Proxy;->removeListener(Landroid/net/IEthernetServiceListener;)V
-Landroid/net/IEthernetManager$Stub$Proxy;->setConfiguration(Ljava/lang/String;Landroid/net/IpConfiguration;)V
-Landroid/net/IEthernetManager$Stub;-><init>()V
-Landroid/net/IEthernetManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/IEthernetManager;
-Landroid/net/IEthernetManager$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/net/IEthernetManager$Stub;->TRANSACTION_addListener:I
-Landroid/net/IEthernetManager$Stub;->TRANSACTION_getAvailableInterfaces:I
-Landroid/net/IEthernetManager$Stub;->TRANSACTION_getConfiguration:I
-Landroid/net/IEthernetManager$Stub;->TRANSACTION_isAvailable:I
-Landroid/net/IEthernetManager$Stub;->TRANSACTION_removeListener:I
-Landroid/net/IEthernetManager$Stub;->TRANSACTION_setConfiguration:I
-Landroid/net/IEthernetManager;->addListener(Landroid/net/IEthernetServiceListener;)V
-Landroid/net/IEthernetManager;->getAvailableInterfaces()[Ljava/lang/String;
-Landroid/net/IEthernetManager;->getConfiguration(Ljava/lang/String;)Landroid/net/IpConfiguration;
-Landroid/net/IEthernetManager;->isAvailable(Ljava/lang/String;)Z
-Landroid/net/IEthernetManager;->removeListener(Landroid/net/IEthernetServiceListener;)V
-Landroid/net/IEthernetManager;->setConfiguration(Ljava/lang/String;Landroid/net/IpConfiguration;)V
-Landroid/net/IEthernetServiceListener$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/net/IEthernetServiceListener$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/net/IEthernetServiceListener$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/net/IEthernetServiceListener$Stub$Proxy;->onAvailabilityChanged(Ljava/lang/String;Z)V
-Landroid/net/IEthernetServiceListener$Stub;-><init>()V
-Landroid/net/IEthernetServiceListener$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/IEthernetServiceListener;
-Landroid/net/IEthernetServiceListener$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/net/IEthernetServiceListener$Stub;->TRANSACTION_onAvailabilityChanged:I
-Landroid/net/IEthernetServiceListener;->onAvailabilityChanged(Ljava/lang/String;Z)V
 Landroid/net/IIpConnectivityMetrics$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/net/IIpConnectivityMetrics$Stub$Proxy;->addNetdEventCallback(ILandroid/net/INetdEventCallback;)Z
 Landroid/net/IIpConnectivityMetrics$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index c5410a0..b8d24e3 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -191,6 +191,8 @@
                 instrument.noRestart = true;
             } else if (opt.equals("--always-check-signature")) {
                 instrument.alwaysCheckSignature = true;
+            } else if (opt.equals("--instrument-sdk-sandbox")) {
+                instrument.instrumentSdkSandbox = true;
             } else {
                 System.err.println("Error: Unknown option: " + opt);
                 return;
diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java
index a0562d9..7ff4bc4 100644
--- a/cmds/am/src/com/android/commands/am/Instrument.java
+++ b/cmds/am/src/com/android/commands/am/Instrument.java
@@ -20,6 +20,7 @@
 import static android.app.ActivityManager.INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS;
 import static android.app.ActivityManager.INSTR_FLAG_DISABLE_ISOLATED_STORAGE;
 import static android.app.ActivityManager.INSTR_FLAG_DISABLE_TEST_API_CHECKS;
+import static android.app.ActivityManager.INSTR_FLAG_INSTRUMENT_SDK_SANDBOX;
 import static android.app.ActivityManager.INSTR_FLAG_NO_RESTART;
 
 import android.app.IActivityManager;
@@ -97,6 +98,7 @@
     // Required
     public String componentNameArg;
     public boolean alwaysCheckSignature = false;
+    public boolean instrumentSdkSandbox = false;
 
     /**
      * Construct the instrument command runner.
@@ -524,6 +526,9 @@
             if (alwaysCheckSignature) {
                 flags |= INSTR_FLAG_ALWAYS_CHECK_SIGNATURE;
             }
+            if (instrumentSdkSandbox) {
+                flags |= INSTR_FLAG_INSTRUMENT_SDK_SANDBOX;
+            }
             if (!mAm.startInstrumentation(cn, profileFile, flags, args, watcher, connection, userId,
                         abi)) {
                 throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
diff --git a/cmds/app_process/Android.bp b/cmds/app_process/Android.bp
index 6a685a7..a157517 100644
--- a/cmds/app_process/Android.bp
+++ b/cmds/app_process/Android.bp
@@ -64,8 +64,6 @@
         "libwilhelm",
     ],
 
-    header_libs: ["bionic_libc_platform_headers"],
-
     compile_multilib: "both",
 
     cflags: [
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 815f945..12083b6 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -15,7 +15,6 @@
 
 #include <android-base/macros.h>
 #include <binder/IPCThreadState.h>
-#include <bionic/pac.h>
 #include <hwbinder/IPCThreadState.h>
 #include <utils/Log.h>
 #include <cutils/memory.h>
@@ -183,10 +182,6 @@
       ALOGV("app_process main with argv: %s", argv_String.string());
     }
 
-    // Because of applications that are using PAC instructions incorrectly, PAC
-    // is disabled in application processes for now.
-    ScopedDisablePAC x;
-
     AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
     // Process command line arguments
     // ignore argv[0]
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index c202f6f..6ef6845 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -52,6 +52,7 @@
         "-readability-braces-around-statements",
         "-readability-const-return-type",
         "-readability-convert-member-functions-to-static",
+        "-readability-duplicate-include",
         "-readability-else-after-return",
         "-readability-identifier-length",
         "-readability-named-parameter",
diff --git a/core/api/current.txt b/core/api/current.txt
index ec87591..d03ab96 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -8,9 +8,6 @@
   public static final class Manifest.permission {
     ctor public Manifest.permission();
     field public static final String ACCEPT_HANDOVER = "android.permission.ACCEPT_HANDOVER";
-    field public static final String ACCESS_ADSERVICES_ATTRIBUTION = "android.permission.ACCESS_ADSERVICES_ATTRIBUTION";
-    field public static final String ACCESS_ADSERVICES_CUSTOM_AUDIENCES = "android.permission.ACCESS_ADSERVICES_CUSTOM_AUDIENCES";
-    field public static final String ACCESS_ADSERVICES_TOPICS = "android.permission.ACCESS_ADSERVICES_TOPICS";
     field public static final String ACCESS_BACKGROUND_LOCATION = "android.permission.ACCESS_BACKGROUND_LOCATION";
     field public static final String ACCESS_BLOBS_ACROSS_USERS = "android.permission.ACCESS_BLOBS_ACROSS_USERS";
     field public static final String ACCESS_CHECKIN_PROPERTIES = "android.permission.ACCESS_CHECKIN_PROPERTIES";
@@ -113,8 +110,9 @@
     field public static final String MANAGE_MEDIA = "android.permission.MANAGE_MEDIA";
     field public static final String MANAGE_ONGOING_CALLS = "android.permission.MANAGE_ONGOING_CALLS";
     field public static final String MANAGE_OWN_CALLS = "android.permission.MANAGE_OWN_CALLS";
-    field public static final String MANAGE_WIFI_AUTO_JOIN = "android.permission.MANAGE_WIFI_AUTO_JOIN";
+    field @Deprecated public static final String MANAGE_WIFI_AUTO_JOIN = "android.permission.MANAGE_WIFI_AUTO_JOIN";
     field public static final String MANAGE_WIFI_INTERFACES = "android.permission.MANAGE_WIFI_INTERFACES";
+    field public static final String MANAGE_WIFI_NETWORK_SELECTION = "android.permission.MANAGE_WIFI_NETWORK_SELECTION";
     field public static final String MASTER_CLEAR = "android.permission.MASTER_CLEAR";
     field public static final String MEDIA_CONTENT_CONTROL = "android.permission.MEDIA_CONTENT_CONTROL";
     field public static final String MODIFY_AUDIO_SETTINGS = "android.permission.MODIFY_AUDIO_SETTINGS";
@@ -141,7 +139,7 @@
     field @Deprecated public static final String READ_INPUT_STATE = "android.permission.READ_INPUT_STATE";
     field public static final String READ_LOGS = "android.permission.READ_LOGS";
     field public static final String READ_MEDIA_AUDIO = "android.permission.READ_MEDIA_AUDIO";
-    field public static final String READ_MEDIA_IMAGE = "android.permission.READ_MEDIA_IMAGE";
+    field public static final String READ_MEDIA_IMAGES = "android.permission.READ_MEDIA_IMAGES";
     field public static final String READ_MEDIA_VIDEO = "android.permission.READ_MEDIA_VIDEO";
     field public static final String READ_NEARBY_STREAMING_POLICY = "android.permission.READ_NEARBY_STREAMING_POLICY";
     field public static final String READ_PHONE_NUMBERS = "android.permission.READ_PHONE_NUMBERS";
@@ -853,7 +851,6 @@
     field public static final int indicatorRight = 16843022; // 0x101010e
     field public static final int indicatorStart = 16843729; // 0x10103d1
     field public static final int inflatedId = 16842995; // 0x10100f3
-    field public static final int inheritKeyStoreKeys;
     field public static final int inheritShowWhenLocked = 16844188; // 0x101059c
     field public static final int initOrder = 16842778; // 0x101001a
     field public static final int initialKeyguardLayout = 16843714; // 0x10103c2
@@ -1755,7 +1752,7 @@
     field public static final int windowShowWallpaper = 16843410; // 0x1010292
     field public static final int windowSoftInputMode = 16843307; // 0x101022b
     field public static final int windowSplashScreenAnimatedIcon = 16844333; // 0x101062d
-    field public static final int windowSplashScreenAnimationDuration = 16844334; // 0x101062e
+    field @Deprecated public static final int windowSplashScreenAnimationDuration = 16844334; // 0x101062e
     field public static final int windowSplashScreenBackground = 16844332; // 0x101062c
     field public static final int windowSplashScreenBehavior;
     field public static final int windowSplashScreenBrandingImage = 16844335; // 0x101062f
@@ -3335,7 +3332,7 @@
   }
 
   public class InputMethod {
-    ctor protected InputMethod(@NonNull android.accessibilityservice.AccessibilityService);
+    ctor public InputMethod(@NonNull android.accessibilityservice.AccessibilityService);
     method @Nullable public final android.accessibilityservice.InputMethod.AccessibilityInputConnection getCurrentInputConnection();
     method @Nullable public final android.view.inputmethod.EditorInfo getCurrentInputEditorInfo();
     method public final boolean getCurrentInputStarted();
@@ -3900,6 +3897,7 @@
     method public Object getAnimatedValue(String);
     method public long getCurrentPlayTime();
     method public long getDuration();
+    method @FloatRange(from=0) public static float getDurationScale();
     method public static long getFrameDelay();
     method public int getRepeatCount();
     method public int getRepeatMode();
@@ -3911,6 +3909,7 @@
     method public static android.animation.ValueAnimator ofInt(int...);
     method public static android.animation.ValueAnimator ofObject(android.animation.TypeEvaluator, java.lang.Object...);
     method public static android.animation.ValueAnimator ofPropertyValuesHolder(android.animation.PropertyValuesHolder...);
+    method public static boolean registerDurationScaleChangeListener(@NonNull android.animation.ValueAnimator.DurationScaleChangeListener);
     method public void removeAllUpdateListeners();
     method public void removeUpdateListener(android.animation.ValueAnimator.AnimatorUpdateListener);
     method public void reverse();
@@ -3927,6 +3926,7 @@
     method public void setRepeatMode(int);
     method public void setStartDelay(long);
     method public void setValues(android.animation.PropertyValuesHolder...);
+    method public static boolean unregisterDurationScaleChangeListener(@NonNull android.animation.ValueAnimator.DurationScaleChangeListener);
     field public static final int INFINITE = -1; // 0xffffffff
     field public static final int RESTART = 1; // 0x1
     field public static final int REVERSE = 2; // 0x2
@@ -3936,6 +3936,10 @@
     method public void onAnimationUpdate(@NonNull android.animation.ValueAnimator);
   }
 
+  public static interface ValueAnimator.DurationScaleChangeListener {
+    method public void onChanged(@FloatRange(from=0) float);
+  }
+
 }
 
 package android.annotation {
@@ -4275,7 +4279,6 @@
     method public void setLocusContext(@Nullable android.content.LocusId, @Nullable android.os.Bundle);
     method public final void setMediaController(android.media.session.MediaController);
     method public void setPictureInPictureParams(@NonNull android.app.PictureInPictureParams);
-    method public void setPreferDockBigOverlays(boolean);
     method @Deprecated public final void setProgress(int);
     method @Deprecated public final void setProgressBarIndeterminate(boolean);
     method @Deprecated public final void setProgressBarIndeterminateVisibility(boolean);
@@ -4285,6 +4288,7 @@
     method public final void setResult(int);
     method public final void setResult(int, android.content.Intent);
     method @Deprecated public final void setSecondaryProgress(int);
+    method public void setShouldDockBigOverlays(boolean);
     method public void setShowWhenLocked(boolean);
     method public void setTaskDescription(android.app.ActivityManager.TaskDescription);
     method public void setTitle(CharSequence);
@@ -4295,6 +4299,7 @@
     method public void setVisible(boolean);
     method public final void setVolumeControlStream(int);
     method public void setVrModeEnabled(boolean, @NonNull android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public boolean shouldDockBigOverlays();
     method public boolean shouldShowRequestPermissionRationale(@NonNull String);
     method public boolean shouldUpRecreateTask(android.content.Intent);
     method public boolean showAssist(android.os.Bundle);
@@ -4523,22 +4528,36 @@
   }
 
   public static class ActivityManager.TaskDescription implements android.os.Parcelable {
-    ctor public ActivityManager.TaskDescription(String, @DrawableRes int, int);
-    ctor public ActivityManager.TaskDescription(String, @DrawableRes int);
-    ctor public ActivityManager.TaskDescription(String);
-    ctor public ActivityManager.TaskDescription();
+    ctor @Deprecated public ActivityManager.TaskDescription(String, @DrawableRes int, int);
+    ctor @Deprecated public ActivityManager.TaskDescription(String, @DrawableRes int);
+    ctor @Deprecated public ActivityManager.TaskDescription(String);
+    ctor @Deprecated public ActivityManager.TaskDescription();
     ctor @Deprecated public ActivityManager.TaskDescription(String, android.graphics.Bitmap, int);
     ctor @Deprecated public ActivityManager.TaskDescription(String, android.graphics.Bitmap);
     ctor public ActivityManager.TaskDescription(android.app.ActivityManager.TaskDescription);
     method public int describeContents();
+    method @ColorInt public int getBackgroundColor();
     method @Deprecated public android.graphics.Bitmap getIcon();
     method public String getLabel();
-    method public int getPrimaryColor();
+    method @ColorInt public int getNavigationBarColor();
+    method @ColorInt public int getPrimaryColor();
+    method @ColorInt public int getStatusBarColor();
     method public void readFromParcel(android.os.Parcel);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.ActivityManager.TaskDescription> CREATOR;
   }
 
+  public static final class ActivityManager.TaskDescription.Builder {
+    ctor public ActivityManager.TaskDescription.Builder();
+    method @NonNull public android.app.ActivityManager.TaskDescription build();
+    method @NonNull public android.app.ActivityManager.TaskDescription.Builder setBackgroundColor(@ColorInt int);
+    method @NonNull public android.app.ActivityManager.TaskDescription.Builder setIcon(@DrawableRes int);
+    method @NonNull public android.app.ActivityManager.TaskDescription.Builder setLabel(@Nullable String);
+    method @NonNull public android.app.ActivityManager.TaskDescription.Builder setNavigationBarColor(@ColorInt int);
+    method @NonNull public android.app.ActivityManager.TaskDescription.Builder setPrimaryColor(@ColorInt int);
+    method @NonNull public android.app.ActivityManager.TaskDescription.Builder setStatusBarColor(@ColorInt int);
+  }
+
   public class ActivityOptions {
     method @Nullable public android.graphics.Rect getLaunchBounds();
     method public int getLaunchDisplayId();
@@ -5621,6 +5640,7 @@
     method public boolean onException(Object, Throwable);
     method public void onStart();
     method public void removeMonitor(android.app.Instrumentation.ActivityMonitor);
+    method public void resetInTouchMode();
     method public void runOnMainSync(Runnable);
     method public void sendCharacterSync(int);
     method public void sendKeyDownUpSync(int);
@@ -5805,6 +5825,7 @@
   public class LocaleManager {
     method @NonNull public android.os.LocaleList getApplicationLocales();
     method @NonNull @RequiresPermission(value="android.permission.READ_APP_SPECIFIC_LOCALES", conditional=true) public android.os.LocaleList getApplicationLocales(@NonNull String);
+    method @NonNull public android.os.LocaleList getSystemLocales();
     method public void setApplicationLocales(@NonNull android.os.LocaleList);
   }
 
@@ -6635,6 +6656,15 @@
 
   public final class PictureInPictureParams implements android.os.Parcelable {
     method public int describeContents();
+    method @NonNull public java.util.List<android.app.RemoteAction> getActions();
+    method @Nullable public android.util.Rational getAspectRatio();
+    method @Nullable public android.app.RemoteAction getCloseAction();
+    method @Nullable public android.util.Rational getExpandedAspectRatio();
+    method @Nullable public android.graphics.Rect getSourceRectHint();
+    method @Nullable public CharSequence getSubtitle();
+    method @Nullable public CharSequence getTitle();
+    method public boolean isAutoEnterEnabled();
+    method public boolean isSeamlessResizeEnabled();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.PictureInPictureParams> CREATOR;
   }
@@ -7388,12 +7418,6 @@
     method @NonNull public java.util.List<java.lang.String> getDelegatedScopes(@Nullable android.content.ComponentName, @NonNull String);
     method public CharSequence getDeviceOwnerLockScreenInfo();
     method @Nullable public String getDevicePolicyManagementRoleHolderPackage();
-    method @Nullable public android.graphics.drawable.Drawable getDrawable(@NonNull String, @NonNull String, @NonNull java.util.function.Supplier<android.graphics.drawable.Drawable>);
-    method @Nullable public android.graphics.drawable.Drawable getDrawable(@NonNull String, @NonNull String, @NonNull String, @NonNull java.util.function.Supplier<android.graphics.drawable.Drawable>);
-    method @Nullable public android.graphics.drawable.Icon getDrawableAsIcon(@NonNull String, @NonNull String, @NonNull String, @Nullable android.graphics.drawable.Icon);
-    method @Nullable public android.graphics.drawable.Icon getDrawableAsIcon(@NonNull String, @NonNull String, @Nullable android.graphics.drawable.Icon);
-    method @Nullable public android.graphics.drawable.Drawable getDrawableForDensity(@NonNull String, @NonNull String, int, @NonNull java.util.function.Supplier<android.graphics.drawable.Drawable>);
-    method @Nullable public android.graphics.drawable.Drawable getDrawableForDensity(@NonNull String, @NonNull String, @NonNull String, int, @NonNull java.util.function.Supplier<android.graphics.drawable.Drawable>);
     method public CharSequence getEndUserSessionMessage(@NonNull android.content.ComponentName);
     method @NonNull public String getEnrollmentSpecificId();
     method @Nullable public android.app.admin.FactoryResetProtectionPolicy getFactoryResetProtectionPolicy(@Nullable android.content.ComponentName);
@@ -7440,6 +7464,7 @@
     method @NonNull public java.util.List<android.app.admin.PreferentialNetworkServiceConfig> getPreferentialNetworkServiceConfigs();
     method public int getRequiredPasswordComplexity();
     method public long getRequiredStrongAuthTimeout(@Nullable android.content.ComponentName);
+    method @NonNull public android.app.admin.DevicePolicyResourcesManager getResources();
     method public boolean getScreenCaptureDisabled(@Nullable android.content.ComponentName);
     method public java.util.List<android.os.UserHandle> getSecondaryUsers(@NonNull android.content.ComponentName);
     method public CharSequence getShortSupportMessage(@NonNull android.content.ComponentName);
@@ -7687,6 +7712,7 @@
     field public static final String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
     field @Deprecated public static final String EXTRA_PROVISIONING_SKIP_USER_CONSENT = "android.app.extra.PROVISIONING_SKIP_USER_CONSENT";
     field public static final String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
+    field public static final String EXTRA_PROVISIONING_USE_MOBILE_DATA = "android.app.extra.PROVISIONING_USE_MOBILE_DATA";
     field public static final String EXTRA_PROVISIONING_WIFI_ANONYMOUS_IDENTITY = "android.app.extra.PROVISIONING_WIFI_ANONYMOUS_IDENTITY";
     field public static final String EXTRA_PROVISIONING_WIFI_CA_CERTIFICATE = "android.app.extra.PROVISIONING_WIFI_CA_CERTIFICATE";
     field public static final String EXTRA_PROVISIONING_WIFI_DOMAIN = "android.app.extra.PROVISIONING_WIFI_DOMAIN";
@@ -7806,31 +7832,18 @@
   }
 
   public final class DevicePolicyResources {
-  }
-
-  public static final class DevicePolicyResources.Drawables {
-    field public static final String UNDEFINED = "UNDEFINED";
-    field public static final String WORK_PROFILE_ICON = "WORK_PROFILE_ICON";
-    field public static final String WORK_PROFILE_ICON_BADGE = "WORK_PROFILE_ICON_BADGE";
-    field public static final String WORK_PROFILE_OFF_ICON = "WORK_PROFILE_OFF_ICON";
-    field public static final String WORK_PROFILE_USER_ICON = "WORK_PROFILE_USER_ICON";
-  }
-
-  public static final class DevicePolicyResources.Drawables.Source {
-    field public static final String HOME_WIDGET = "HOME_WIDGET";
-    field public static final String LAUNCHER_OFF_BUTTON = "LAUNCHER_OFF_BUTTON";
-    field public static final String NOTIFICATION = "NOTIFICATION";
-    field public static final String PROFILE_SWITCH_ANIMATION = "PROFILE_SWITCH_ANIMATION";
-    field public static final String QUICK_SETTINGS = "QUICK_SETTINGS";
-    field public static final String STATUS_BAR = "STATUS_BAR";
     field public static final String UNDEFINED = "UNDEFINED";
   }
 
-  public static final class DevicePolicyResources.Drawables.Style {
-    field public static final String DEFAULT = "DEFAULT";
-    field public static final String OUTLINE = "OUTLINE";
-    field public static final String SOLID_COLORED = "SOLID_COLORED";
-    field public static final String SOLID_NOT_COLORED = "SOLID_NOT_COLORED";
+  public class DevicePolicyResourcesManager {
+    method @Nullable public android.graphics.drawable.Drawable getDrawable(@NonNull String, @NonNull String, @NonNull java.util.function.Supplier<android.graphics.drawable.Drawable>);
+    method @Nullable public android.graphics.drawable.Drawable getDrawable(@NonNull String, @NonNull String, @NonNull String, @NonNull java.util.function.Supplier<android.graphics.drawable.Drawable>);
+    method @Nullable public android.graphics.drawable.Icon getDrawableAsIcon(@NonNull String, @NonNull String, @NonNull String, @Nullable android.graphics.drawable.Icon);
+    method @Nullable public android.graphics.drawable.Icon getDrawableAsIcon(@NonNull String, @NonNull String, @Nullable android.graphics.drawable.Icon);
+    method @Nullable public android.graphics.drawable.Drawable getDrawableForDensity(@NonNull String, @NonNull String, int, @NonNull java.util.function.Supplier<android.graphics.drawable.Drawable>);
+    method @Nullable public android.graphics.drawable.Drawable getDrawableForDensity(@NonNull String, @NonNull String, @NonNull String, int, @NonNull java.util.function.Supplier<android.graphics.drawable.Drawable>);
+    method @Nullable public String getString(@NonNull String, @NonNull java.util.function.Supplier<java.lang.String>);
+    method @Nullable public String getString(@NonNull String, @NonNull java.util.function.Supplier<java.lang.String>, @NonNull java.lang.Object...);
   }
 
   public final class DnsEvent extends android.app.admin.NetworkEvent implements android.os.Parcelable {
@@ -9717,8 +9730,8 @@
     method @Nullable public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler, int);
     method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void removeStickyBroadcast(@RequiresPermission android.content.Intent);
     method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void removeStickyBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
-    method public void revokeOwnPermissionOnKill(@NonNull String);
-    method public void revokeOwnPermissionsOnKill(@NonNull java.util.Collection<java.lang.String>);
+    method public void revokeSelfPermissionOnKill(@NonNull String);
+    method public void revokeSelfPermissionsOnKill(@NonNull java.util.Collection<java.lang.String>);
     method public abstract void revokeUriPermission(android.net.Uri, int);
     method public abstract void revokeUriPermission(String, android.net.Uri, int);
     method public abstract void sendBroadcast(@RequiresPermission android.content.Intent);
@@ -10106,12 +10119,16 @@
     method @Nullable public long[] getLongArrayExtra(String);
     method public long getLongExtra(String, long);
     method @Nullable public String getPackage();
-    method @Nullable public android.os.Parcelable[] getParcelableArrayExtra(String);
-    method @Nullable public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayListExtra(String);
-    method @Nullable public <T extends android.os.Parcelable> T getParcelableExtra(String);
+    method @Deprecated @Nullable public android.os.Parcelable[] getParcelableArrayExtra(String);
+    method @Nullable public <T> T[] getParcelableArrayExtra(@Nullable String, @NonNull Class<T>);
+    method @Deprecated @Nullable public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayListExtra(String);
+    method @Nullable public <T> java.util.ArrayList<T> getParcelableArrayListExtra(@Nullable String, @NonNull Class<? extends T>);
+    method @Deprecated @Nullable public <T extends android.os.Parcelable> T getParcelableExtra(String);
+    method @Nullable public <T> T getParcelableExtra(@Nullable String, @NonNull Class<T>);
     method @Nullable public String getScheme();
     method @Nullable public android.content.Intent getSelector();
-    method @Nullable public java.io.Serializable getSerializableExtra(String);
+    method @Deprecated @Nullable public java.io.Serializable getSerializableExtra(String);
+    method @Nullable public <T extends java.io.Serializable> T getSerializableExtra(@Nullable String, @NonNull Class<T>);
     method @Nullable public short[] getShortArrayExtra(String);
     method public short getShortExtra(String, short);
     method @Nullable public android.graphics.Rect getSourceBounds();
@@ -10420,13 +10437,11 @@
     field public static final String EXTRA_LOCAL_ONLY = "android.intent.extra.LOCAL_ONLY";
     field public static final String EXTRA_LOCUS_ID = "android.intent.extra.LOCUS_ID";
     field public static final String EXTRA_MIME_TYPES = "android.intent.extra.MIME_TYPES";
-    field public static final String EXTRA_NEW_UID = "android.intent.extra.NEW_UID";
     field public static final String EXTRA_NOT_UNKNOWN_SOURCE = "android.intent.extra.NOT_UNKNOWN_SOURCE";
     field public static final String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
     field public static final String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
     field public static final String EXTRA_PERMISSION_GROUP_NAME = "android.intent.extra.PERMISSION_GROUP_NAME";
     field public static final String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
-    field public static final String EXTRA_PREVIOUS_UID = "android.intent.extra.PREVIOUS_UID";
     field public static final String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT";
     field public static final String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY";
     field public static final String EXTRA_QUICK_VIEW_FEATURES = "android.intent.extra.QUICK_VIEW_FEATURES";
@@ -10458,7 +10473,6 @@
     field public static final String EXTRA_TIMEZONE = "time-zone";
     field public static final String EXTRA_TITLE = "android.intent.extra.TITLE";
     field public static final String EXTRA_UID = "android.intent.extra.UID";
-    field public static final String EXTRA_UID_CHANGING = "android.intent.extra.UID_CHANGING";
     field public static final String EXTRA_USER = "android.intent.extra.USER";
     field public static final String EXTRA_USER_INITIATED = "android.intent.extra.USER_INITIATED";
     field public static final int FILL_IN_ACTION = 1; // 0x1
@@ -11221,6 +11235,33 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.Attribution> CREATOR;
   }
 
+  public final class Capability implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public String getName();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.Capability> CREATOR;
+  }
+
+  public static final class Capability.Builder {
+    ctor public Capability.Builder(@NonNull String);
+    method @NonNull public android.content.pm.Capability build();
+  }
+
+  public final class CapabilityParams implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public java.util.List<java.lang.String> getAliases();
+    method @NonNull public String getName();
+    method @NonNull public String getValue();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.CapabilityParams> CREATOR;
+  }
+
+  public static final class CapabilityParams.Builder {
+    ctor public CapabilityParams.Builder(@NonNull String, @NonNull String);
+    method @NonNull public android.content.pm.CapabilityParams.Builder addAlias(@NonNull String);
+    method @NonNull public android.content.pm.CapabilityParams build();
+  }
+
   public final class ChangedPackages implements android.os.Parcelable {
     ctor public ChangedPackages(int, @NonNull java.util.List<java.lang.String>);
     method public int describeContents();
@@ -11291,6 +11332,7 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_PROFILES, "android.permission.INTERACT_ACROSS_USERS"}) public void startActivity(@NonNull android.content.Intent, @NonNull android.os.UserHandle, @Nullable android.app.Activity);
     method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_PROFILES, "android.permission.INTERACT_ACROSS_USERS"}) public void startActivity(@NonNull android.content.Intent, @NonNull android.os.UserHandle, @Nullable android.app.Activity, @Nullable android.os.Bundle);
     method public void startMainActivity(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
+    method public void startMainActivity(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle, @Nullable android.app.Activity, @Nullable android.os.Bundle);
     field public static final String ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED = "android.content.pm.action.CAN_INTERACT_ACROSS_PROFILES_CHANGED";
   }
 
@@ -12281,10 +12323,12 @@
     method @NonNull public static android.content.pm.ShortcutInfo createFromGenericDocument(@NonNull android.content.Context, @NonNull android.app.appsearch.GenericDocument);
     method public int describeContents();
     method @Nullable public android.content.ComponentName getActivity();
-    method @NonNull public java.util.List<java.lang.String> getCapabilityParameterValues(@NonNull String, @NonNull String);
+    method @NonNull public java.util.List<android.content.pm.Capability> getCapabilities();
+    method @NonNull public java.util.List<android.content.pm.CapabilityParams> getCapabilityParams(@NonNull android.content.pm.Capability);
     method @Nullable public java.util.Set<java.lang.String> getCategories();
     method @Nullable public CharSequence getDisabledMessage();
     method public int getDisabledReason();
+    method public int getExcludedFromSurfaces();
     method @Nullable public android.os.PersistableBundle getExtras();
     method @NonNull public String getId();
     method @Nullable public android.content.Intent getIntent();
@@ -12296,14 +12340,13 @@
     method public int getRank();
     method @Nullable public CharSequence getShortLabel();
     method public android.os.UserHandle getUserHandle();
-    method public boolean hasCapability(@NonNull String);
     method public boolean hasKeyFieldsOnly();
     method public boolean isCached();
     method public boolean isDeclaredInManifest();
     method public boolean isDynamic();
     method public boolean isEnabled();
+    method public boolean isExcludedFromSurfaces(int);
     method public boolean isImmutable();
-    method public boolean isIncludedIn(int);
     method public boolean isPinned();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR;
@@ -12321,7 +12364,7 @@
 
   public static class ShortcutInfo.Builder {
     ctor public ShortcutInfo.Builder(android.content.Context, String);
-    method @NonNull public android.content.pm.ShortcutInfo.Builder addCapabilityBinding(@NonNull String, @Nullable String, @Nullable java.util.List<java.lang.String>);
+    method @NonNull public android.content.pm.ShortcutInfo.Builder addCapabilityBinding(@NonNull android.content.pm.Capability, @Nullable android.content.pm.CapabilityParams);
     method @NonNull public android.content.pm.ShortcutInfo build();
     method @NonNull public android.content.pm.ShortcutInfo.Builder setActivity(@NonNull android.content.ComponentName);
     method @NonNull public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>);
@@ -16398,12 +16441,8 @@
 package android.graphics.text {
 
   public final class LineBreakConfig {
-    ctor public LineBreakConfig();
     method public int getLineBreakStyle();
     method public int getLineBreakWordStyle();
-    method public void set(@NonNull android.graphics.text.LineBreakConfig);
-    method public void setLineBreakStyle(int);
-    method public void setLineBreakWordStyle(int);
     field public static final int LINE_BREAK_STYLE_LOOSE = 1; // 0x1
     field public static final int LINE_BREAK_STYLE_NONE = 0; // 0x0
     field public static final int LINE_BREAK_STYLE_NORMAL = 2; // 0x2
@@ -16412,6 +16451,13 @@
     field public static final int LINE_BREAK_WORD_STYLE_PHRASE = 1; // 0x1
   }
 
+  public static final class LineBreakConfig.Builder {
+    ctor public LineBreakConfig.Builder();
+    method @NonNull public android.graphics.text.LineBreakConfig build();
+    method @NonNull public android.graphics.text.LineBreakConfig.Builder setLineBreakStyle(int);
+    method @NonNull public android.graphics.text.LineBreakConfig.Builder setLineBreakWordStyle(int);
+  }
+
   public class LineBreaker {
     method @NonNull public android.graphics.text.LineBreaker.Result computeLineBreaks(@NonNull android.graphics.text.MeasuredText, @NonNull android.graphics.text.LineBreaker.ParagraphConstraints, @IntRange(from=0) int);
     field public static final int BREAK_STRATEGY_BALANCED = 2; // 0x2
@@ -17399,7 +17445,7 @@
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Long> REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Float> SCALER_AVAILABLE_MAX_DIGITAL_ZOOM;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SCALER_AVAILABLE_ROTATE_AND_CROP_MODES;
-    field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SCALER_AVAILABLE_STREAM_USE_CASES;
+    field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<long[]> SCALER_AVAILABLE_STREAM_USE_CASES;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SCALER_CROPPING_TYPE;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Size> SCALER_DEFAULT_SECURE_IMAGE_SIZE;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS;
@@ -18184,7 +18230,7 @@
     method public int get10BitFormat();
     method @NonNull public java.util.List<android.util.Size> getAvailableSizes();
     method public int getFormat();
-    method public int getStreamUseCase();
+    method public long getStreamUseCase();
     method public boolean is10BitCapable();
     method public boolean isInput();
     method public boolean isMaximumSize();
@@ -18242,7 +18288,7 @@
     method public long getDynamicRangeProfile();
     method public int getMaxSharedSurfaceCount();
     method public int getMirrorMode();
-    method public int getStreamUseCase();
+    method public long getStreamUseCase();
     method @Nullable public android.view.Surface getSurface();
     method public int getSurfaceGroupId();
     method @NonNull public java.util.List<android.view.Surface> getSurfaces();
@@ -18252,7 +18298,7 @@
     method public void setDynamicRangeProfile(long);
     method public void setMirrorMode(int);
     method public void setPhysicalCameraId(@Nullable String);
-    method public void setStreamUseCase(int);
+    method public void setStreamUseCase(long);
     method public void setTimestampBase(int);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR;
@@ -18818,6 +18864,7 @@
     method public void onStartInput(android.view.inputmethod.EditorInfo, boolean);
     method public void onStartInputView(android.view.inputmethod.EditorInfo, boolean);
     method public boolean onStartStylusHandwriting();
+    method public void onStylusHandwritingMotionEvent(@NonNull android.view.MotionEvent);
     method public void onUnbindInput();
     method @Deprecated public void onUpdateCursor(android.graphics.Rect);
     method public void onUpdateCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfo);
@@ -19463,26 +19510,26 @@
     method @NonNull public static String convert(@FloatRange double, int);
     method @FloatRange public static double convert(@NonNull String);
     method public int describeContents();
-    method public static void distanceBetween(@FloatRange double, @FloatRange double, @FloatRange double, @FloatRange double, float[]);
-    method @FloatRange public float distanceTo(@NonNull android.location.Location);
-    method public void dump(@NonNull android.util.Printer, @Nullable String);
-    method @FloatRange public float getAccuracy();
+    method public static void distanceBetween(@FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, float[]);
+    method @FloatRange(from=0.0) public float distanceTo(@NonNull android.location.Location);
+    method @Deprecated public void dump(@NonNull android.util.Printer, @Nullable String);
+    method @FloatRange(from=0.0) public float getAccuracy();
     method @FloatRange public double getAltitude();
-    method @FloatRange(from=0.0f, to=360.0f, toInclusive=false) public float getBearing();
-    method @FloatRange public float getBearingAccuracyDegrees();
-    method @IntRange public long getElapsedRealtimeAgeMillis();
-    method @IntRange public long getElapsedRealtimeAgeMillis(@IntRange long);
-    method @IntRange public long getElapsedRealtimeMillis();
-    method @IntRange public long getElapsedRealtimeNanos();
-    method @FloatRange public double getElapsedRealtimeUncertaintyNanos();
+    method @FloatRange(from=0.0, to=360.0, toInclusive=false) public float getBearing();
+    method @FloatRange(from=0.0) public float getBearingAccuracyDegrees();
+    method @IntRange(from=0) public long getElapsedRealtimeAgeMillis();
+    method public long getElapsedRealtimeAgeMillis(@IntRange(from=0) long);
+    method @IntRange(from=0) public long getElapsedRealtimeMillis();
+    method @IntRange(from=0) public long getElapsedRealtimeNanos();
+    method @FloatRange(from=0.0) public double getElapsedRealtimeUncertaintyNanos();
     method @Nullable public android.os.Bundle getExtras();
-    method @FloatRange public double getLatitude();
-    method @FloatRange public double getLongitude();
+    method @FloatRange(from=-90.0, to=90.0) public double getLatitude();
+    method @FloatRange(from=-180.0, to=180.0) public double getLongitude();
     method @Nullable public String getProvider();
-    method @FloatRange public float getSpeed();
-    method @FloatRange public float getSpeedAccuracyMetersPerSecond();
-    method @IntRange public long getTime();
-    method @FloatRange public float getVerticalAccuracyMeters();
+    method @FloatRange(from=0.0) public float getSpeed();
+    method @FloatRange(from=0.0) public float getSpeedAccuracyMetersPerSecond();
+    method @IntRange(from=0) public long getTime();
+    method @FloatRange(from=0.0) public float getVerticalAccuracyMeters();
     method public boolean hasAccuracy();
     method public boolean hasAltitude();
     method public boolean hasBearing();
@@ -19504,21 +19551,21 @@
     method public void removeVerticalAccuracy();
     method public void reset();
     method public void set(@NonNull android.location.Location);
-    method public void setAccuracy(@FloatRange float);
+    method public void setAccuracy(@FloatRange(from=0.0) float);
     method public void setAltitude(@FloatRange double);
     method public void setBearing(@FloatRange(fromInclusive=false, toInclusive=false) float);
-    method public void setBearingAccuracyDegrees(@FloatRange float);
-    method public void setElapsedRealtimeNanos(@IntRange long);
-    method public void setElapsedRealtimeUncertaintyNanos(@FloatRange double);
+    method public void setBearingAccuracyDegrees(@FloatRange(from=0.0) float);
+    method public void setElapsedRealtimeNanos(@IntRange(from=0) long);
+    method public void setElapsedRealtimeUncertaintyNanos(@FloatRange(from=0.0) double);
     method public void setExtras(@Nullable android.os.Bundle);
-    method public void setLatitude(@FloatRange double);
-    method public void setLongitude(@FloatRange double);
+    method public void setLatitude(@FloatRange(from=-90.0, to=90.0) double);
+    method public void setLongitude(@FloatRange(from=-180.0, to=180.0) double);
     method public void setMock(boolean);
     method public void setProvider(@Nullable String);
-    method public void setSpeed(@FloatRange float);
-    method public void setSpeedAccuracyMetersPerSecond(@FloatRange float);
-    method public void setTime(@IntRange long);
-    method public void setVerticalAccuracyMeters(@FloatRange float);
+    method public void setSpeed(@FloatRange(from=0.0) float);
+    method public void setSpeedAccuracyMetersPerSecond(@FloatRange(from=0.0) float);
+    method public void setTime(@IntRange(from=0) long);
+    method public void setVerticalAccuracyMeters(@FloatRange(from=0.0) float);
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.location.Location> CREATOR;
     field public static final int FORMAT_DEGREES = 0; // 0x0
@@ -22162,7 +22209,7 @@
     field public static final String KEY_AAC_DRC_OUTPUT_LOUDNESS = "aac-drc-output-loudness";
     field public static final String KEY_AAC_DRC_TARGET_REFERENCE_LEVEL = "aac-target-ref-level";
     field public static final String KEY_AAC_ENCODED_TARGET_LEVEL = "aac-encoded-target-level";
-    field public static final String KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count";
+    field @Deprecated public static final String KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count";
     field public static final String KEY_AAC_PROFILE = "aac-profile";
     field public static final String KEY_AAC_SBR_MODE = "aac-sbr-mode";
     field public static final String KEY_ALLOW_FRAME_DROP = "allow-frame-drop";
@@ -22181,6 +22228,10 @@
     field public static final String KEY_COLOR_TRANSFER_REQUEST = "color-transfer-request";
     field public static final String KEY_COMPLEXITY = "complexity";
     field public static final String KEY_CREATE_INPUT_SURFACE_SUSPENDED = "create-input-buffers-suspended";
+    field public static final String KEY_CROP_BOTTOM = "crop-bottom";
+    field public static final String KEY_CROP_LEFT = "crop-left";
+    field public static final String KEY_CROP_RIGHT = "crop-right";
+    field public static final String KEY_CROP_TOP = "crop-top";
     field public static final String KEY_DURATION = "durationUs";
     field public static final String KEY_ENCODER_DELAY = "encoder-delay";
     field public static final String KEY_ENCODER_PADDING = "encoder-padding";
@@ -22870,7 +22921,6 @@
     method public int describeContents();
     method @Nullable public String getClientPackageName();
     method public int getConnectionState();
-    method @NonNull public java.util.Set<java.lang.String> getDeduplicationIds();
     method @Nullable public CharSequence getDescription();
     method @Nullable public android.os.Bundle getExtras();
     method @NonNull public java.util.List<java.lang.String> getFeatures();
@@ -22904,7 +22954,6 @@
     method @NonNull public android.media.MediaRoute2Info.Builder clearFeatures();
     method @NonNull public android.media.MediaRoute2Info.Builder setClientPackageName(@Nullable String);
     method @NonNull public android.media.MediaRoute2Info.Builder setConnectionState(int);
-    method @NonNull public android.media.MediaRoute2Info.Builder setDeduplicationIds(@NonNull java.util.Set<java.lang.String>);
     method @NonNull public android.media.MediaRoute2Info.Builder setDescription(@Nullable CharSequence);
     method @NonNull public android.media.MediaRoute2Info.Builder setExtras(@Nullable android.os.Bundle);
     method @NonNull public android.media.MediaRoute2Info.Builder setIconUri(@Nullable android.net.Uri);
@@ -23431,11 +23480,8 @@
 
   public final class RouteDiscoveryPreference implements android.os.Parcelable {
     method public int describeContents();
-    method @NonNull public java.util.List<java.lang.String> getAllowedPackages();
-    method @NonNull public java.util.List<java.lang.String> getDeduplicationPackageOrder();
     method @NonNull public java.util.List<java.lang.String> getPreferredFeatures();
     method public boolean shouldPerformActiveScan();
-    method public boolean shouldRemoveDuplicates();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.media.RouteDiscoveryPreference> CREATOR;
   }
@@ -23444,8 +23490,6 @@
     ctor public RouteDiscoveryPreference.Builder(@NonNull java.util.List<java.lang.String>, boolean);
     ctor public RouteDiscoveryPreference.Builder(@NonNull android.media.RouteDiscoveryPreference);
     method @NonNull public android.media.RouteDiscoveryPreference build();
-    method @NonNull public android.media.RouteDiscoveryPreference.Builder setAllowedPackages(@NonNull java.util.List<java.lang.String>);
-    method @NonNull public android.media.RouteDiscoveryPreference.Builder setDeduplicationPackageOrder(@NonNull java.util.List<java.lang.String>);
     method @NonNull public android.media.RouteDiscoveryPreference.Builder setPreferredFeatures(@NonNull java.util.List<java.lang.String>);
     method @NonNull public android.media.RouteDiscoveryPreference.Builder setShouldPerformActiveScan(boolean);
   }
@@ -23524,17 +23568,24 @@
   }
 
   public class Spatializer {
+    method public void addOnHeadTrackerAvailableListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.Spatializer.OnHeadTrackerAvailableListener);
     method public void addOnSpatializerStateChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.Spatializer.OnSpatializerStateChangedListener);
     method public boolean canBeSpatialized(@NonNull android.media.AudioAttributes, @NonNull android.media.AudioFormat);
     method public int getImmersiveAudioLevel();
     method public boolean isAvailable();
     method public boolean isEnabled();
+    method public boolean isHeadTrackerAvailable();
+    method public void removeOnHeadTrackerAvailableListener(@NonNull android.media.Spatializer.OnHeadTrackerAvailableListener);
     method public void removeOnSpatializerStateChangedListener(@NonNull android.media.Spatializer.OnSpatializerStateChangedListener);
     field public static final int SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL = 1; // 0x1
     field public static final int SPATIALIZER_IMMERSIVE_LEVEL_NONE = 0; // 0x0
     field public static final int SPATIALIZER_IMMERSIVE_LEVEL_OTHER = -1; // 0xffffffff
   }
 
+  public static interface Spatializer.OnHeadTrackerAvailableListener {
+    method public void onHeadTrackerAvailableChanged(@NonNull android.media.Spatializer, boolean);
+  }
+
   public static interface Spatializer.OnSpatializerStateChangedListener {
     method public void onSpatializerAvailableChanged(@NonNull android.media.Spatializer, boolean);
     method public void onSpatializerEnabledChanged(@NonNull android.media.Spatializer, boolean);
@@ -24408,6 +24459,7 @@
     method public void close();
     method @NonNull public android.media.metrics.LogSessionId getSessionId();
     method public void reportBundleMetrics(@NonNull android.os.PersistableBundle);
+    field public static final String KEY_STATSD_ATOM = "bundlesession-statsd-atom";
   }
 
   public final class EditingSession implements java.lang.AutoCloseable {
@@ -24431,6 +24483,7 @@
     method @NonNull public android.media.metrics.PlaybackSession createPlaybackSession();
     method @NonNull public android.media.metrics.RecordingSession createRecordingSession();
     method @NonNull public android.media.metrics.TranscodingSession createTranscodingSession();
+    method @NonNull public void releaseSessionId(@NonNull String);
     field public static final long INVALID_TIMESTAMP = -1L; // 0xffffffffffffffffL
   }
 
@@ -25167,17 +25220,23 @@
   }
 
   public final class CommandRequest extends android.media.tv.BroadcastInfoRequest implements android.os.Parcelable {
-    ctor public CommandRequest(int, int, @NonNull String, @NonNull String, @NonNull String);
+    ctor public CommandRequest(int, int, @NonNull String, @NonNull String, @NonNull String, @NonNull String);
+    method @NonNull public String getArgumentType();
     method @NonNull public String getArguments();
     method @NonNull public String getName();
-    method @NonNull public String getNameSpace();
+    method @NonNull public String getNamespace();
+    field public static final String ARGUMENT_TYPE_JSON = "json";
+    field public static final String ARGUMENT_TYPE_XML = "xml";
     field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.CommandRequest> CREATOR;
   }
 
   public final class CommandResponse extends android.media.tv.BroadcastInfoResponse implements android.os.Parcelable {
-    ctor public CommandResponse(int, int, int, @Nullable String);
+    ctor public CommandResponse(int, int, int, @Nullable String, @NonNull String);
     method @Nullable public String getResponse();
+    method @NonNull public String getResponseType();
     field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.CommandResponse> CREATOR;
+    field public static final String RESPONSE_TYPE_JSON = "json";
+    field public static final String RESPONSE_TYPE_XML = "xml";
   }
 
   public final class DsmccRequest extends android.media.tv.BroadcastInfoRequest implements android.os.Parcelable {
@@ -25242,7 +25301,7 @@
     ctor public StreamEventResponse(int, int, int, int, long, @Nullable byte[]);
     method @Nullable public byte[] getData();
     method public int getEventId();
-    method public long getNpt();
+    method public long getNptMillis();
     field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.StreamEventResponse> CREATOR;
   }
 
@@ -25272,7 +25331,7 @@
 
   public final class TimelineResponse extends android.media.tv.BroadcastInfoResponse implements android.os.Parcelable {
     ctor public TimelineResponse(int, int, int, @Nullable String, int, int, long, long);
-    method @Nullable public String getSelector();
+    method @Nullable public android.net.Uri getSelector();
     method public long getTicks();
     method public int getUnitsPerSecond();
     method public int getUnitsPerTick();
@@ -26035,7 +26094,7 @@
     method public void onContentAllowed(String);
     method public void onContentBlocked(String, android.media.tv.TvContentRating);
     method public void onDisconnected(String);
-    method public void onSignalStrength(@NonNull String, int);
+    method public void onSignalStrengthUpdated(@NonNull String, int);
     method public void onTimeShiftStatusChanged(String, int);
     method public void onTrackSelected(String, int, String);
     method public void onTracksChanged(String, java.util.List<android.media.tv.TvTrackInfo>);
@@ -26050,44 +26109,18 @@
 package android.media.tv.interactive {
 
   public final class AppLinkInfo implements android.os.Parcelable {
+    ctor public AppLinkInfo(@NonNull String, @NonNull String, @NonNull String);
     method public int describeContents();
-    method @NonNull public String getClassName();
-    method @NonNull public String getPackageName();
-    method @Nullable public String getUriHost();
-    method @Nullable public String getUriPrefix();
-    method @Nullable public String getUriScheme();
+    method @NonNull public android.content.ComponentName getComponentName();
+    method @NonNull public android.net.Uri getUri();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.interactive.AppLinkInfo> CREATOR;
   }
 
-  public static final class AppLinkInfo.Builder {
-    ctor public AppLinkInfo.Builder(@NonNull String, @NonNull String);
-    method @NonNull public android.media.tv.interactive.AppLinkInfo build();
-    method @NonNull public android.media.tv.interactive.AppLinkInfo.Builder setClassName(@NonNull String);
-    method @NonNull public android.media.tv.interactive.AppLinkInfo.Builder setPackageName(@NonNull String);
-    method @NonNull public android.media.tv.interactive.AppLinkInfo.Builder setUriHost(@Nullable String);
-    method @NonNull public android.media.tv.interactive.AppLinkInfo.Builder setUriPrefix(@Nullable String);
-    method @NonNull public android.media.tv.interactive.AppLinkInfo.Builder setUriScheme(@Nullable String);
-  }
-
-  public final class TvInteractiveAppInfo implements android.os.Parcelable {
-    ctor public TvInteractiveAppInfo(@NonNull android.content.Context, @NonNull android.content.ComponentName);
-    method public int describeContents();
-    method @NonNull public String getId();
-    method @Nullable public android.content.pm.ServiceInfo getServiceInfo();
-    method @NonNull public int getSupportedTypes();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.interactive.TvInteractiveAppInfo> CREATOR;
-    field public static final int INTERACTIVE_APP_TYPE_ATSC = 2; // 0x2
-    field public static final int INTERACTIVE_APP_TYPE_GINGA = 4; // 0x4
-    field public static final int INTERACTIVE_APP_TYPE_HBBTV = 1; // 0x1
-  }
-
   public final class TvInteractiveAppManager {
-    method @NonNull public java.util.List<android.media.tv.interactive.TvInteractiveAppInfo> getTvInteractiveAppServiceList();
-    method public void prepare(@NonNull String, int);
+    method @NonNull public java.util.List<android.media.tv.interactive.TvInteractiveAppServiceInfo> getTvInteractiveAppServiceList();
     method public void registerAppLinkInfo(@NonNull String, @NonNull android.media.tv.interactive.AppLinkInfo);
-    method public void registerCallback(@NonNull android.media.tv.interactive.TvInteractiveAppManager.TvInteractiveAppCallback, @NonNull java.util.concurrent.Executor);
+    method public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.interactive.TvInteractiveAppManager.TvInteractiveAppCallback);
     method public void sendAppLinkCommand(@NonNull String, @NonNull android.os.Bundle);
     method public void unregisterAppLinkInfo(@NonNull String, @NonNull android.media.tv.interactive.AppLinkInfo);
     method public void unregisterCallback(@NonNull android.media.tv.interactive.TvInteractiveAppManager.TvInteractiveAppCallback);
@@ -26108,6 +26141,7 @@
     field public static final String INTENT_KEY_BI_INTERACTIVE_APP_TYPE = "bi_interactive_app_type";
     field public static final String INTENT_KEY_BI_INTERACTIVE_APP_URI = "bi_interactive_app_uri";
     field public static final String INTENT_KEY_CHANNEL_URI = "channel_uri";
+    field public static final String INTENT_KEY_COMMAND_TYPE = "command_type";
     field public static final String INTENT_KEY_INTERACTIVE_APP_SERVICE_ID = "interactive_app_id";
     field public static final String INTENT_KEY_TV_INPUT_ID = "tv_input_id";
     field public static final int INTERACTIVE_APP_STATE_ERROR = 3; // 0x3
@@ -26136,7 +26170,6 @@
     method public void onAppLinkCommand(@NonNull android.os.Bundle);
     method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
     method @Nullable public abstract android.media.tv.interactive.TvInteractiveAppService.Session onCreateSession(@NonNull String, int);
-    method public abstract void onPrepare(int);
     method public void onRegisterAppLinkInfo(@NonNull android.media.tv.interactive.AppLinkInfo);
     method public void onUnregisterAppLinkInfo(@NonNull android.media.tv.interactive.AppLinkInfo);
     field public static final String COMMAND_PARAMETER_KEY_CHANGE_CHANNEL_QUIETLY = "command_change_channel_quietly";
@@ -26157,31 +26190,33 @@
 
   public abstract static class TvInteractiveAppService.Session implements android.view.KeyEvent.Callback {
     ctor public TvInteractiveAppService.Session(@NonNull android.content.Context);
-    method public void layoutSurface(int, int, int, int);
-    method public final void notifyBiInteractiveAppCreated(@NonNull android.net.Uri, @Nullable String);
-    method public void notifySessionStateChanged(int, int);
-    method public final void notifyTeletextAppStateChanged(int);
+    method public boolean isMediaViewEnabled();
+    method @CallSuper public void layoutSurface(int, int, int, int);
+    method @CallSuper public final void notifyBiInteractiveAppCreated(@NonNull android.net.Uri, @Nullable String);
+    method @CallSuper public void notifySessionStateChanged(int, int);
+    method @CallSuper public final void notifyTeletextAppStateChanged(int);
     method public void onAdResponse(@NonNull android.media.tv.AdResponse);
     method public void onBroadcastInfoResponse(@NonNull android.media.tv.BroadcastInfoResponse);
     method public void onContentAllowed();
     method public void onContentBlocked(@NonNull android.media.tv.TvContentRating);
-    method public void onCreateBiInteractiveApp(@NonNull android.net.Uri, @Nullable android.os.Bundle);
+    method public void onCreateBiInteractiveAppRequest(@NonNull android.net.Uri, @Nullable android.os.Bundle);
     method @Nullable public android.view.View onCreateMediaView();
     method public void onCurrentChannelLcn(int);
     method public void onCurrentChannelUri(@Nullable android.net.Uri);
     method public void onCurrentTvInputId(@Nullable String);
-    method public void onDestroyBiInteractiveApp(@NonNull String);
+    method public void onDestroyBiInteractiveAppRequest(@NonNull String);
     method public boolean onGenericMotionEvent(@NonNull android.view.MotionEvent);
     method public boolean onKeyDown(int, @NonNull android.view.KeyEvent);
     method public boolean onKeyLongPress(int, @NonNull android.view.KeyEvent);
     method public boolean onKeyMultiple(int, int, @NonNull android.view.KeyEvent);
     method public boolean onKeyUp(int, @NonNull android.view.KeyEvent);
-    method public void onMediaViewSizeChanged(int, int);
+    method public void onMediaViewSizeChanged(@Px int, @Px int);
     method public abstract void onRelease();
     method public void onResetInteractiveApp();
     method public abstract boolean onSetSurface(@Nullable android.view.Surface);
     method public void onSetTeletextAppEnabled(boolean);
     method public void onSignalStrength(int);
+    method public void onSigningResult(@NonNull String, @NonNull byte[]);
     method public void onStartInteractiveApp();
     method public void onStopInteractiveApp();
     method public void onStreamVolume(float);
@@ -26194,17 +26229,31 @@
     method public void onTuned(@NonNull android.net.Uri);
     method public void onVideoAvailable();
     method public void onVideoUnavailable(int);
-    method public void removeBroadcastInfo(int);
-    method public void requestAd(@NonNull android.media.tv.AdRequest);
-    method public void requestBroadcastInfo(@NonNull android.media.tv.BroadcastInfoRequest);
-    method public void requestCurrentChannelLcn();
-    method public void requestCurrentChannelUri();
-    method public void requestCurrentTvInputId();
-    method public void requestStreamVolume();
-    method public void requestTrackInfoList();
-    method public void sendPlaybackCommandRequest(@NonNull String, @Nullable android.os.Bundle);
-    method public void setMediaViewEnabled(boolean);
-    method public void setVideoBounds(@NonNull android.graphics.Rect);
+    method @CallSuper public void removeBroadcastInfo(int);
+    method @CallSuper public void requestAd(@NonNull android.media.tv.AdRequest);
+    method @CallSuper public void requestBroadcastInfo(@NonNull android.media.tv.BroadcastInfoRequest);
+    method @CallSuper public void requestCurrentChannelLcn();
+    method @CallSuper public void requestCurrentChannelUri();
+    method @CallSuper public void requestCurrentTvInputId();
+    method @CallSuper public void requestSigning(@NonNull String, @NonNull String, @NonNull String, @NonNull byte[]);
+    method @CallSuper public void requestStreamVolume();
+    method @CallSuper public void requestTrackInfoList();
+    method @CallSuper public void sendPlaybackCommandRequest(@NonNull String, @Nullable android.os.Bundle);
+    method @CallSuper public void setMediaViewEnabled(boolean);
+    method @CallSuper public void setVideoBounds(@NonNull android.graphics.Rect);
+  }
+
+  public final class TvInteractiveAppServiceInfo implements android.os.Parcelable {
+    ctor public TvInteractiveAppServiceInfo(@NonNull android.content.Context, @NonNull android.content.ComponentName);
+    method public int describeContents();
+    method @NonNull public String getId();
+    method @Nullable public android.content.pm.ServiceInfo getServiceInfo();
+    method @NonNull public int getSupportedTypes();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.interactive.TvInteractiveAppServiceInfo> CREATOR;
+    field public static final int INTERACTIVE_APP_TYPE_ATSC = 2; // 0x2
+    field public static final int INTERACTIVE_APP_TYPE_GINGA = 4; // 0x4
+    field public static final int INTERACTIVE_APP_TYPE_HBBTV = 1; // 0x1
   }
 
   public class TvInteractiveAppView extends android.view.ViewGroup {
@@ -26216,6 +26265,7 @@
     method public void createBiInteractiveApp(@NonNull android.net.Uri, @Nullable android.os.Bundle);
     method public void destroyBiInteractiveApp(@NonNull String);
     method public boolean dispatchUnhandledInputEvent(@NonNull android.view.InputEvent);
+    method @Nullable public android.media.tv.interactive.TvInteractiveAppView.OnUnhandledInputEventListener getOnUnhandledInputEventListener();
     method public void onAttachedToWindow();
     method public void onDetachedFromWindow();
     method public void onLayout(boolean, int, int, int, int);
@@ -26228,6 +26278,7 @@
     method public void sendCurrentChannelLcn(int);
     method public void sendCurrentChannelUri(@Nullable android.net.Uri);
     method public void sendCurrentTvInputId(@Nullable String);
+    method public void sendSigningResult(@NonNull String, @NonNull byte[]);
     method public void sendStreamVolume(float);
     method public void sendTrackInfoList(@Nullable java.util.List<android.media.tv.TvTrackInfo>);
     method public void setCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.interactive.TvInteractiveAppView.TvInteractiveAppCallback);
@@ -26236,6 +26287,11 @@
     method public int setTvView(@Nullable android.media.tv.TvView);
     method public void startInteractiveApp();
     method public void stopInteractiveApp();
+    field public static final String BI_INTERACTIVE_APP_KEY_ALIAS = "alias";
+    field public static final String BI_INTERACTIVE_APP_KEY_CERTIFICATE = "certificate";
+    field public static final String BI_INTERACTIVE_APP_KEY_HTTP_ADDITIONAL_HEADERS = "http_additional_headers";
+    field public static final String BI_INTERACTIVE_APP_KEY_HTTP_USER_AGENT = "http_user_agent";
+    field public static final String BI_INTERACTIVE_APP_KEY_PRIVATE_KEY = "private_key";
   }
 
   public static interface TvInteractiveAppView.OnUnhandledInputEventListener {
@@ -26249,6 +26305,7 @@
     method public void onRequestCurrentChannelLcn(@NonNull String);
     method public void onRequestCurrentChannelUri(@NonNull String);
     method public void onRequestCurrentTvInputId(@NonNull String);
+    method public void onRequestSigning(@NonNull String, @NonNull String, @NonNull String, @NonNull String, @NonNull byte[]);
     method public void onRequestStreamVolume(@NonNull String);
     method public void onRequestTrackInfoList(@NonNull String);
     method public void onSetVideoBounds(@NonNull String, @NonNull android.graphics.Rect);
@@ -26507,16 +26564,9 @@
     method public int getUid();
   }
 
-  public final class EthernetNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
-    ctor public EthernetNetworkSpecifier(@NonNull String);
-    method public int describeContents();
-    method @Nullable public String getInterfaceName();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkSpecifier> CREATOR;
-  }
-
   public final class Ikev2VpnProfile extends android.net.PlatformVpnProfile {
     method @NonNull public java.util.List<java.lang.String> getAllowedAlgorithms();
+    method @Nullable public android.net.ipsec.ike.IkeTunnelConnectionParams getIkeTunnelConnectionParams();
     method public int getMaxMtu();
     method @Nullable public String getPassword();
     method @Nullable public byte[] getPresharedKey();
@@ -26811,11 +26861,13 @@
 
   public class VpnManager {
     method public void deleteProvisionedVpnProfile();
+    method @Nullable public android.net.VpnProfileState getProvisionedVpnProfileState();
     method @Nullable public android.content.Intent provisionVpnProfile(@NonNull android.net.PlatformVpnProfile);
     method @Deprecated public void startProvisionedVpnProfile();
     method @NonNull public String startProvisionedVpnProfileSession();
     method public void stopProvisionedVpnProfile();
     field public static final String ACTION_VPN_MANAGER_EVENT = "android.net.action.VPN_MANAGER_EVENT";
+    field public static final String CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED = "android.net.category.EVENT_ALWAYS_ON_STATE_CHANGED";
     field public static final String CATEGORY_EVENT_DEACTIVATED_BY_USER = "android.net.category.EVENT_DEACTIVATED_BY_USER";
     field public static final String CATEGORY_EVENT_IKE_ERROR = "android.net.category.EVENT_IKE_ERROR";
     field public static final String CATEGORY_EVENT_NETWORK_ERROR = "android.net.category.EVENT_NETWORK_ERROR";
@@ -26832,6 +26884,22 @@
     field public static final String EXTRA_UNDERLYING_LINK_PROPERTIES = "android.net.extra.UNDERLYING_LINK_PROPERTIES";
     field public static final String EXTRA_UNDERLYING_NETWORK = "android.net.extra.UNDERLYING_NETWORK";
     field public static final String EXTRA_UNDERLYING_NETWORK_CAPABILITIES = "android.net.extra.UNDERLYING_NETWORK_CAPABILITIES";
+    field public static final String EXTRA_VPN_PROFILE_STATE = "android.net.extra.VPN_PROFILE_STATE";
+  }
+
+  public final class VpnProfileState implements android.os.Parcelable {
+    ctor public VpnProfileState(int, @Nullable String, boolean, boolean);
+    method public int describeContents();
+    method @Nullable public String getSessionId();
+    method public int getState();
+    method public boolean isAlwaysOn();
+    method public boolean isLockdownEnabled();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.VpnProfileState> CREATOR;
+    field public static final int STATE_CONNECTED = 2; // 0x2
+    field public static final int STATE_CONNECTING = 1; // 0x1
+    field public static final int STATE_DISCONNECTED = 0; // 0x0
+    field public static final int STATE_FAILED = 3; // 0x3
   }
 
   public class VpnService extends android.app.Service {
@@ -38133,6 +38201,7 @@
     method public int getNoSaveUiReason();
     method @NonNull public java.util.Set<java.lang.String> getSelectedDatasetIds();
     method public int getType();
+    method public int getUiType();
     field public static final int NO_SAVE_UI_REASON_DATASET_MATCH = 6; // 0x6
     field public static final int NO_SAVE_UI_REASON_FIELD_VALIDATION_FAILED = 5; // 0x5
     field public static final int NO_SAVE_UI_REASON_HAS_EMPTY_REQUIRED = 3; // 0x3
@@ -38146,6 +38215,10 @@
     field public static final int TYPE_DATASET_AUTHENTICATION_SELECTED = 1; // 0x1
     field public static final int TYPE_DATASET_SELECTED = 0; // 0x0
     field public static final int TYPE_SAVE_SHOWN = 3; // 0x3
+    field public static final int UI_TYPE_DIALOG = 3; // 0x3
+    field public static final int UI_TYPE_INLINE = 2; // 0x2
+    field public static final int UI_TYPE_MENU = 1; // 0x1
+    field public static final int UI_TYPE_UNKNOWN = 0; // 0x0
   }
 
   public final class FillRequest implements android.os.Parcelable {
@@ -38160,6 +38233,7 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.service.autofill.FillRequest> CREATOR;
     field public static final int FLAG_COMPATIBILITY_MODE_REQUEST = 2; // 0x2
     field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1
+    field public static final int FLAG_SUPPORTS_FILL_DIALOG = 64; // 0x40
   }
 
   public final class FillResponse implements android.os.Parcelable {
@@ -39557,22 +39631,34 @@
 
   public final class RecognitionSupport implements android.os.Parcelable {
     method public int describeContents();
-    method @NonNull public java.util.List<java.lang.String> getInstalledLanguages();
-    method @NonNull public java.util.List<java.lang.String> getPendingLanguages();
-    method @NonNull public java.util.List<java.lang.String> getSupportedLanguages();
+    method @Deprecated @NonNull public java.util.List<java.lang.String> getInstalledLanguages();
+    method @NonNull public java.util.List<java.lang.String> getInstalledOnDeviceLanguages();
+    method @NonNull public java.util.List<java.lang.String> getOnlineLanguages();
+    method @Deprecated @NonNull public java.util.List<java.lang.String> getPendingLanguages();
+    method @NonNull public java.util.List<java.lang.String> getPendingOnDeviceLanguages();
+    method @Deprecated @NonNull public java.util.List<java.lang.String> getSupportedLanguages();
+    method @NonNull public java.util.List<java.lang.String> getSupportedOnDeviceLanguages();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.speech.RecognitionSupport> CREATOR;
   }
 
   public static final class RecognitionSupport.Builder {
     ctor public RecognitionSupport.Builder();
-    method @NonNull public android.speech.RecognitionSupport.Builder addInstalledLanguage(@NonNull String);
-    method @NonNull public android.speech.RecognitionSupport.Builder addPendingLanguage(@NonNull String);
-    method @NonNull public android.speech.RecognitionSupport.Builder addSupportedLanguage(@NonNull String);
+    method @Deprecated @NonNull public android.speech.RecognitionSupport.Builder addInstalledLanguage(@NonNull String);
+    method @NonNull public android.speech.RecognitionSupport.Builder addInstalledOnDeviceLanguage(@NonNull String);
+    method @NonNull public android.speech.RecognitionSupport.Builder addOnlineLanguage(@NonNull String);
+    method @Deprecated @NonNull public android.speech.RecognitionSupport.Builder addPendingLanguage(@NonNull String);
+    method @NonNull public android.speech.RecognitionSupport.Builder addPendingOnDeviceLanguage(@NonNull String);
+    method @Deprecated @NonNull public android.speech.RecognitionSupport.Builder addSupportedLanguage(@NonNull String);
+    method @NonNull public android.speech.RecognitionSupport.Builder addSupportedOnDeviceLanguage(@NonNull String);
     method @NonNull public android.speech.RecognitionSupport build();
-    method @NonNull public android.speech.RecognitionSupport.Builder setInstalledLanguages(@NonNull java.util.List<java.lang.String>);
-    method @NonNull public android.speech.RecognitionSupport.Builder setPendingLanguages(@NonNull java.util.List<java.lang.String>);
-    method @NonNull public android.speech.RecognitionSupport.Builder setSupportedLanguages(@NonNull java.util.List<java.lang.String>);
+    method @Deprecated @NonNull public android.speech.RecognitionSupport.Builder setInstalledLanguages(@NonNull java.util.List<java.lang.String>);
+    method @NonNull public android.speech.RecognitionSupport.Builder setInstalledOnDeviceLanguages(@NonNull java.util.List<java.lang.String>);
+    method @NonNull public android.speech.RecognitionSupport.Builder setOnlineLanguages(@NonNull java.util.List<java.lang.String>);
+    method @Deprecated @NonNull public android.speech.RecognitionSupport.Builder setPendingLanguages(@NonNull java.util.List<java.lang.String>);
+    method @NonNull public android.speech.RecognitionSupport.Builder setPendingOnDeviceLanguages(@NonNull java.util.List<java.lang.String>);
+    method @Deprecated @NonNull public android.speech.RecognitionSupport.Builder setSupportedLanguages(@NonNull java.util.List<java.lang.String>);
+    method @NonNull public android.speech.RecognitionSupport.Builder setSupportedOnDeviceLanguages(@NonNull java.util.List<java.lang.String>);
   }
 
   public interface RecognitionSupportCallback {
@@ -43782,6 +43868,7 @@
     method public int getNetworkTypeBitmask();
     method public String getOperatorNumeric();
     method public String getPassword();
+    method public int getProfileId();
     method public int getProtocol();
     method @Deprecated public java.net.InetAddress getProxyAddress();
     method public String getProxyAddressAsString();
@@ -43789,6 +43876,7 @@
     method public int getRoamingProtocol();
     method public String getUser();
     method public boolean isEnabled();
+    method public boolean isPersistent();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field public static final int AUTH_TYPE_CHAP = 2; // 0x2
     field public static final int AUTH_TYPE_NONE = 0; // 0x0
@@ -44744,7 +44832,7 @@
   public class BoringLayout extends android.text.Layout implements android.text.TextUtils.EllipsizeCallback {
     ctor public BoringLayout(CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean);
     ctor public BoringLayout(CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean, android.text.TextUtils.TruncateAt, int);
-    ctor public BoringLayout(@NonNull CharSequence, @NonNull android.text.TextPaint, @IntRange(from=0) int, @NonNull android.text.Layout.Alignment, float, float, @NonNull android.text.BoringLayout.Metrics, boolean, @NonNull android.text.TextUtils.TruncateAt, @IntRange(from=0) int, boolean);
+    ctor public BoringLayout(@NonNull CharSequence, @NonNull android.text.TextPaint, @IntRange(from=0) int, @NonNull android.text.Layout.Alignment, float, float, @NonNull android.text.BoringLayout.Metrics, boolean, @Nullable android.text.TextUtils.TruncateAt, @IntRange(from=0) int, boolean);
     method public void ellipsized(int, int);
     method public int getBottomPadding();
     method public int getEllipsisCount(int);
@@ -44762,9 +44850,9 @@
     method @Nullable public static android.text.BoringLayout.Metrics isBoring(@NonNull CharSequence, @NonNull android.text.TextPaint, @NonNull android.text.TextDirectionHeuristic, boolean, @Nullable android.text.BoringLayout.Metrics);
     method public static android.text.BoringLayout make(CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean);
     method public static android.text.BoringLayout make(CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean, android.text.TextUtils.TruncateAt, int);
-    method @NonNull public static android.text.BoringLayout make(@NonNull CharSequence, @NonNull android.text.TextPaint, @IntRange(from=0) int, @NonNull android.text.Layout.Alignment, @NonNull android.text.BoringLayout.Metrics, boolean, @NonNull android.text.TextUtils.TruncateAt, @IntRange(from=0) int, boolean);
+    method @NonNull public static android.text.BoringLayout make(@NonNull CharSequence, @NonNull android.text.TextPaint, @IntRange(from=0) int, @NonNull android.text.Layout.Alignment, @NonNull android.text.BoringLayout.Metrics, boolean, @Nullable android.text.TextUtils.TruncateAt, @IntRange(from=0) int, boolean);
     method public android.text.BoringLayout replaceOrMake(CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean);
-    method @NonNull public android.text.BoringLayout replaceOrMake(@NonNull CharSequence, @NonNull android.text.TextPaint, @IntRange(from=0) int, @NonNull android.text.Layout.Alignment, @NonNull android.text.BoringLayout.Metrics, boolean, @NonNull android.text.TextUtils.TruncateAt, @IntRange(from=0) int, boolean);
+    method @NonNull public android.text.BoringLayout replaceOrMake(@NonNull CharSequence, @NonNull android.text.TextPaint, @IntRange(from=0) int, @NonNull android.text.Layout.Alignment, @NonNull android.text.BoringLayout.Metrics, boolean, @Nullable android.text.TextUtils.TruncateAt, @IntRange(from=0) int, boolean);
     method public android.text.BoringLayout replaceOrMake(CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean, android.text.TextUtils.TruncateAt, int);
   }
 
@@ -45062,7 +45150,7 @@
   public static final class PrecomputedText.Params {
     method public int getBreakStrategy();
     method public int getHyphenationFrequency();
-    method @Nullable public android.graphics.text.LineBreakConfig getLineBreakConfig();
+    method @NonNull public android.graphics.text.LineBreakConfig getLineBreakConfig();
     method @NonNull public android.text.TextDirectionHeuristic getTextDirection();
     method @NonNull public android.text.TextPaint getTextPaint();
   }
@@ -49276,6 +49364,7 @@
     method @NonNull public android.view.SurfaceControl.Transaction setAlpha(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0, to=1.0) float);
     method @NonNull public android.view.SurfaceControl.Transaction setBuffer(@NonNull android.view.SurfaceControl, @Nullable android.hardware.HardwareBuffer);
     method @NonNull public android.view.SurfaceControl.Transaction setBuffer(@NonNull android.view.SurfaceControl, @Nullable android.hardware.HardwareBuffer, @Nullable android.hardware.SyncFence);
+    method @NonNull public android.view.SurfaceControl.Transaction setBuffer(@NonNull android.view.SurfaceControl, @Nullable android.hardware.HardwareBuffer, @Nullable android.hardware.SyncFence, @Nullable java.util.function.Consumer<android.hardware.SyncFence>);
     method @NonNull public android.view.SurfaceControl.Transaction setBufferSize(@NonNull android.view.SurfaceControl, @IntRange(from=0) int, @IntRange(from=0) int);
     method @NonNull public android.view.SurfaceControl.Transaction setBufferTransform(@NonNull android.view.SurfaceControl, int);
     method @NonNull public android.view.SurfaceControl.Transaction setCrop(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect);
@@ -52185,7 +52274,7 @@
     method protected android.view.animation.Animation clone() throws java.lang.CloneNotSupportedException;
     method public long computeDurationHint();
     method protected void ensureInterpolator();
-    method @Deprecated @ColorInt public int getBackgroundColor();
+    method @ColorInt public int getBackgroundColor();
     method @Deprecated public boolean getDetachWallpaper();
     method public long getDuration();
     method public boolean getFillAfter();
@@ -52210,7 +52299,7 @@
     method public void restrictDuration(long);
     method public void scaleCurrentDuration(float);
     method public void setAnimationListener(android.view.animation.Animation.AnimationListener);
-    method @Deprecated public void setBackgroundColor(@ColorInt int);
+    method public void setBackgroundColor(@ColorInt int);
     method @Deprecated public void setDetachWallpaper(boolean);
     method public void setDuration(long);
     method public void setFillAfter(boolean);
@@ -52450,7 +52539,6 @@
 
   public final class AutofillManager {
     method public void cancel();
-    method public void clearAutofillRequestCallback();
     method public void commit();
     method public void disableAutofillServices();
     method @Nullable public android.content.ComponentName getAutofillServiceComponentName();
@@ -52476,7 +52564,6 @@
     method public void registerCallback(@Nullable android.view.autofill.AutofillManager.AutofillCallback);
     method public void requestAutofill(@NonNull android.view.View);
     method public void requestAutofill(@NonNull android.view.View, int, @NonNull android.graphics.Rect);
-    method public void setAutofillRequestCallback(@NonNull java.util.concurrent.Executor, @NonNull android.view.autofill.AutofillRequestCallback);
     method public void setUserData(@Nullable android.service.autofill.UserData);
     method public boolean showAutofillDialog(@NonNull android.view.View);
     method public boolean showAutofillDialog(@NonNull android.view.View, int);
@@ -52497,10 +52584,6 @@
     field public static final int EVENT_INPUT_UNAVAILABLE = 3; // 0x3
   }
 
-  public interface AutofillRequestCallback {
-    method public void onFillRequest(@Nullable android.view.inputmethod.InlineSuggestionsRequest, @NonNull android.os.CancellationSignal, @NonNull android.service.autofill.FillCallback);
-  }
-
   public final class AutofillValue implements android.os.Parcelable {
     method public int describeContents();
     method public static android.view.autofill.AutofillValue forDate(long);
@@ -52888,12 +52971,10 @@
     ctor public InlineSuggestionsRequest.Builder(@NonNull java.util.List<android.widget.inline.InlinePresentationSpec>);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder addInlinePresentationSpecs(@NonNull android.widget.inline.InlinePresentationSpec);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest build();
-    method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setClientSupported(boolean);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setExtras(@NonNull android.os.Bundle);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(@NonNull java.util.List<android.widget.inline.InlinePresentationSpec>);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setInlineTooltipPresentationSpec(@NonNull android.widget.inline.InlinePresentationSpec);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setMaxSuggestionCount(int);
-    method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setServiceSupported(boolean);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setSupportedLocales(@NonNull android.os.LocaleList);
   }
 
@@ -54052,9 +54133,13 @@
 
   public interface UiTranslationStateCallback {
     method public void onFinished();
+    method public default void onFinished(@NonNull String);
     method public void onPaused();
+    method public default void onPaused(@NonNull String);
     method public default void onResumed(@NonNull android.icu.util.ULocale, @NonNull android.icu.util.ULocale);
+    method public default void onResumed(@NonNull android.icu.util.ULocale, @NonNull android.icu.util.ULocale, @NonNull String);
     method public default void onStarted(@NonNull android.icu.util.ULocale, @NonNull android.icu.util.ULocale);
+    method public default void onStarted(@NonNull android.icu.util.ULocale, @NonNull android.icu.util.ULocale, @NonNull String);
   }
 
   @UiThread public interface ViewTranslationCallback {
@@ -57352,7 +57437,8 @@
     method public final android.text.Layout getLayout();
     method public float getLetterSpacing();
     method public int getLineBounds(int, android.graphics.Rect);
-    method @NonNull public android.graphics.text.LineBreakConfig getLineBreakConfig();
+    method public int getLineBreakStyle();
+    method public int getLineBreakWordStyle();
     method public int getLineCount();
     method public int getLineHeight();
     method public float getLineSpacingExtra();
@@ -57480,7 +57566,8 @@
     method public void setKeyListener(android.text.method.KeyListener);
     method public void setLastBaselineToBottomHeight(@IntRange(from=0) @Px int);
     method public void setLetterSpacing(float);
-    method public void setLineBreakConfig(@NonNull android.graphics.text.LineBreakConfig);
+    method public void setLineBreakStyle(int);
+    method public void setLineBreakWordStyle(int);
     method public void setLineHeight(@IntRange(from=0) @Px int);
     method public void setLineSpacing(float, float);
     method public void setLines(int);
@@ -57890,7 +57977,7 @@
   }
 
   public interface OnBackInvokedDispatcher {
-    method public void registerOnBackInvokedCallback(@NonNull android.window.OnBackInvokedCallback, @IntRange(from=0) int);
+    method public void registerOnBackInvokedCallback(@IntRange(from=0) int, @NonNull android.window.OnBackInvokedCallback);
     method public void unregisterOnBackInvokedCallback(@NonNull android.window.OnBackInvokedCallback);
     field public static final int PRIORITY_DEFAULT = 0; // 0x0
     field public static final int PRIORITY_OVERLAY = 1000000; // 0xf4240
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 7aef9a6..44a79c6 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -4,6 +4,7 @@
   public static final class Manifest.permission {
     field public static final String CONTROL_AUTOMOTIVE_GNSS = "android.permission.CONTROL_AUTOMOTIVE_GNSS";
     field public static final String GET_INTENT_SENDER_INTENT = "android.permission.GET_INTENT_SENDER_INTENT";
+    field public static final String MAKE_UID_VISIBLE = "android.permission.MAKE_UID_VISIBLE";
   }
 
 }
@@ -102,6 +103,7 @@
   public abstract class PackageManager {
     method @NonNull public String getPermissionControllerPackageName();
     method @NonNull public String getSdkSandboxPackageName();
+    method @RequiresPermission(android.Manifest.permission.MAKE_UID_VISIBLE) public void makeUidVisible(int, int);
     field public static final String EXTRA_VERIFICATION_ROOT_HASH = "android.content.pm.extra.VERIFICATION_ROOT_HASH";
     field public static final int MATCH_STATIC_SHARED_AND_SDK_LIBRARIES = 67108864; // 0x4000000
   }
@@ -232,22 +234,6 @@
 
 package android.net {
 
-  public class EthernetManager {
-    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void addInterfaceStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.EthernetManager.InterfaceStateListener);
-    method public void removeInterfaceStateListener(@NonNull android.net.EthernetManager.InterfaceStateListener);
-    method public void setIncludeTestInterfaces(boolean);
-    field public static final int ROLE_CLIENT = 1; // 0x1
-    field public static final int ROLE_NONE = 0; // 0x0
-    field public static final int ROLE_SERVER = 2; // 0x2
-    field public static final int STATE_ABSENT = 0; // 0x0
-    field public static final int STATE_LINK_DOWN = 1; // 0x1
-    field public static final int STATE_LINK_UP = 2; // 0x2
-  }
-
-  public static interface EthernetManager.InterfaceStateListener {
-    method public void onInterfaceStateChanged(@NonNull String, int, int, @Nullable android.net.IpConfiguration);
-  }
-
   public class LocalSocket implements java.io.Closeable {
     ctor public LocalSocket(@NonNull java.io.FileDescriptor);
   }
@@ -258,7 +244,8 @@
     method @Nullable @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public android.telephony.SubscriptionPlan getSubscriptionPlan(@NonNull android.net.NetworkTemplate);
     method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidNetworkingBlocked(int, boolean);
     method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidRestrictedOnMeteredNetworks(int);
-    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyStatsProviderWarningOrLimitReached();
+    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyStatsProviderLimitReached();
+    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyStatsProviderWarningReached();
     method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void registerNetworkPolicyCallback(@Nullable java.util.concurrent.Executor, @NonNull android.net.NetworkPolicyManager.NetworkPolicyCallback);
     method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void unregisterNetworkPolicyCallback(@NonNull android.net.NetworkPolicyManager.NetworkPolicyCallback);
   }
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index d28eaae..da0ad2c 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -5,6 +5,7 @@
     field public static final String ACCESS_AMBIENT_CONTEXT_EVENT = "android.permission.ACCESS_AMBIENT_CONTEXT_EVENT";
     field public static final String ACCESS_AMBIENT_LIGHT_STATS = "android.permission.ACCESS_AMBIENT_LIGHT_STATS";
     field public static final String ACCESS_BROADCAST_RADIO = "android.permission.ACCESS_BROADCAST_RADIO";
+    field public static final String ACCESS_BROADCAST_RESPONSE_STATS = "android.permission.ACCESS_BROADCAST_RESPONSE_STATS";
     field public static final String ACCESS_CACHE_FILESYSTEM = "android.permission.ACCESS_CACHE_FILESYSTEM";
     field public static final String ACCESS_CONTEXT_HUB = "android.permission.ACCESS_CONTEXT_HUB";
     field public static final String ACCESS_DRM_CERTIFICATES = "android.permission.ACCESS_DRM_CERTIFICATES";
@@ -34,6 +35,7 @@
     field public static final String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
     field public static final String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK";
     field public static final String ALLOW_PLACE_IN_MULTI_PANE_SETTINGS = "android.permission.ALLOW_PLACE_IN_MULTI_PANE_SETTINGS";
+    field public static final String ALLOW_SLIPPERY_TOUCHES = "android.permission.ALLOW_SLIPPERY_TOUCHES";
     field public static final String AMBIENT_WALLPAPER = "android.permission.AMBIENT_WALLPAPER";
     field public static final String APPROVE_INCIDENT_REPORTS = "android.permission.APPROVE_INCIDENT_REPORTS";
     field public static final String ASSOCIATE_COMPANION_DEVICES = "android.permission.ASSOCIATE_COMPANION_DEVICES";
@@ -243,6 +245,7 @@
     field public static final String READ_APP_SPECIFIC_LOCALES = "android.permission.READ_APP_SPECIFIC_LOCALES";
     field public static final String READ_CARRIER_APP_INFO = "android.permission.READ_CARRIER_APP_INFO";
     field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
+    field public static final String READ_CLIPBOARD_IN_BACKGROUND = "android.permission.READ_CLIPBOARD_IN_BACKGROUND";
     field public static final String READ_CONTENT_RATING_SYSTEMS = "android.permission.READ_CONTENT_RATING_SYSTEMS";
     field public static final String READ_DEVICE_CONFIG = "android.permission.READ_DEVICE_CONFIG";
     field public static final String READ_DREAM_STATE = "android.permission.READ_DREAM_STATE";
@@ -400,6 +403,7 @@
 
   public static final class R.drawable {
     field public static final int ic_info = 17301684; // 0x10800b4
+    field public static final int ic_safety_protection;
   }
 
   public static final class R.raw {
@@ -435,6 +439,7 @@
     field public static final int config_systemContacts = 17039403; // 0x104002b
     field public static final int config_systemGallery = 17039399; // 0x1040027
     field public static final int config_systemNotificationIntelligence = 17039413; // 0x1040035
+    field public static final int config_systemSettingsIntelligence;
     field public static final int config_systemShell = 17039402; // 0x104002a
     field public static final int config_systemSpeechRecognizer = 17039406; // 0x104002e
     field public static final int config_systemSupervision;
@@ -445,6 +450,7 @@
     field public static final int config_systemVisualIntelligence = 17039415; // 0x1040037
     field public static final int config_systemWellbeing = 17039408; // 0x1040030
     field public static final int config_systemWifiCoexManager = 17039407; // 0x104002f
+    field public static final int safety_protection_display_text;
   }
 
   public static final class R.style {
@@ -469,7 +475,6 @@
     method public boolean convertToTranslucent(android.app.Activity.TranslucentConversionListener, android.app.ActivityOptions);
     method @Deprecated public boolean isBackgroundVisibleBehind();
     method @Deprecated public void onBackgroundVisibleBehindChanged(boolean);
-    method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void startActivityAsUser(@NonNull android.content.Intent, @Nullable android.os.Bundle, @NonNull android.os.UserHandle);
     method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void startActivityForResultAsUser(@NonNull android.content.Intent, int, @NonNull android.os.UserHandle);
     method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void startActivityForResultAsUser(@NonNull android.content.Intent, int, @Nullable android.os.Bundle, @NonNull android.os.UserHandle);
     method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void startActivityForResultAsUser(@NonNull android.content.Intent, @NonNull String, int, @Nullable android.os.Bundle, @NonNull android.os.UserHandle);
@@ -1079,6 +1084,7 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public int checkProvisioningPrecondition(@NonNull String, @NonNull String);
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public android.os.UserHandle createAndProvisionManagedProfile(@NonNull android.app.admin.ManagedProfileProvisioningParams) throws android.app.admin.ProvisioningException;
     method @Nullable public android.content.Intent createProvisioningIntentFromNfcIntent(@NonNull android.content.Intent);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void finalizeWorkProfileProvisioning(@NonNull android.os.UserHandle, @Nullable android.accounts.Account);
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public boolean getBluetoothContactSharingDisabled(@NonNull android.os.UserHandle);
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwner();
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public android.content.ComponentName getDeviceOwnerComponentOnAnyUser();
@@ -1087,10 +1093,9 @@
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.UserHandle getDeviceOwnerUser();
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_ADMIN_POLICY}) public java.util.List<java.lang.String> getPermittedAccessibilityServices(int);
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_ADMIN_POLICY}) public java.util.List<java.lang.String> getPermittedInputMethodsForCurrentUser();
+    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public java.util.List<android.os.UserHandle> getPolicyManagedProfiles(@NonNull android.os.UserHandle);
     method @Nullable public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
-    method @Nullable public String getString(@NonNull String, @NonNull java.util.function.Supplier<java.lang.String>);
-    method @Nullable public String getString(@NonNull String, @NonNull java.util.function.Supplier<java.lang.String>, @NonNull java.lang.Object...);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public int getUserProvisioningState();
     method public boolean isDeviceManaged();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioned();
@@ -1103,17 +1108,14 @@
     method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long, boolean);
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public boolean packageHasActiveAdmins(String);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, android.Manifest.permission.PROVISION_DEMO_DEVICE}) public void provisionFullyManagedDevice(@NonNull android.app.admin.FullyManagedDeviceProvisioningParams) throws android.app.admin.ProvisioningException;
-    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void resetDrawables(@NonNull String[]);
-    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void resetStrings(@NonNull String[]);
-    method @RequiresPermission(android.Manifest.permission.SEND_LOST_MODE_LOCATION_UPDATES) public void sendLostModeLocationUpdate(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+    method @RequiresPermission(android.Manifest.permission.TRIGGER_LOST_MODE) public void sendLostModeLocationUpdate(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS) public boolean setActiveProfileOwner(@NonNull android.content.ComponentName, String) throws java.lang.IllegalArgumentException;
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setDeviceProvisioningConfigApplied();
     method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setDpcDownloaded(boolean);
-    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void setDrawables(@NonNull java.util.Set<android.app.admin.DevicePolicyDrawableResource>);
     method @Deprecated @RequiresPermission(value=android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS, conditional=true) public void setProfileOwnerCanAccessDeviceIds(@NonNull android.content.ComponentName);
     method public void setSecondaryLockscreenEnabled(@NonNull android.content.ComponentName, boolean);
-    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void setStrings(@NonNull java.util.Set<android.app.admin.DevicePolicyStringResource>);
     method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setUserProvisioningState(int, @NonNull android.os.UserHandle);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public boolean shouldAllowBypassingDevicePolicyManagementRoleQualification();
     field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED";
     field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
     field public static final String ACTION_BIND_SECONDARY_LOCKSCREEN_SERVICE = "android.app.action.BIND_SECONDARY_LOCKSCREEN_SERVICE";
@@ -1128,7 +1130,7 @@
     field @RequiresPermission(android.Manifest.permission.LAUNCH_DEVICE_MANAGER_SETUP) public static final String ACTION_ROLE_HOLDER_PROVISION_MANAGED_PROFILE = "android.app.action.ROLE_HOLDER_PROVISION_MANAGED_PROFILE";
     field public static final String ACTION_SET_PROFILE_OWNER = "android.app.action.SET_PROFILE_OWNER";
     field @Deprecated public static final String ACTION_STATE_USER_SETUP_COMPLETE = "android.app.action.STATE_USER_SETUP_COMPLETE";
-    field @RequiresPermission(android.Manifest.permission.LAUNCH_DEVICE_MANAGER_SETUP) public static final String ACTION_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER = "android.app.action.UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER";
+    field @RequiresPermission(android.Manifest.permission.LAUNCH_DEVICE_MANAGER_SETUP) public static final String ACTION_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER = "android.app.action.UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER";
     field public static final String EXTRA_FORCE_UPDATE_ROLE_HOLDER = "android.app.extra.FORCE_UPDATE_ROLE_HOLDER";
     field public static final String EXTRA_LOST_MODE_LOCATION = "android.app.extra.LOST_MODE_LOCATION";
     field public static final String EXTRA_PROFILE_OWNER_NAME = "android.app.extra.PROFILE_OWNER_NAME";
@@ -1148,6 +1150,7 @@
     field public static final String EXTRA_RESTRICTION = "android.app.extra.RESTRICTION";
     field public static final String EXTRA_ROLE_HOLDER_PROVISIONING_INITIATOR_PACKAGE = "android.app.extra.ROLE_HOLDER_PROVISIONING_INITIATOR_PACKAGE";
     field public static final String EXTRA_ROLE_HOLDER_STATE = "android.app.extra.ROLE_HOLDER_STATE";
+    field public static final String EXTRA_ROLE_HOLDER_UPDATE_RESULT_CODE = "android.app.extra.ROLE_HOLDER_UPDATE_RESULT_CODE";
     field public static final int FLAG_SUPPORTED_MODES_DEVICE_OWNER = 4; // 0x4
     field public static final int FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED = 1; // 0x1
     field public static final int FLAG_SUPPORTED_MODES_PERSONALLY_OWNED = 2; // 0x2
@@ -1161,8 +1164,9 @@
     field public static final String REQUIRED_APP_MANAGED_PROFILE = "android.app.REQUIRED_APP_MANAGED_PROFILE";
     field public static final String REQUIRED_APP_MANAGED_USER = "android.app.REQUIRED_APP_MANAGED_USER";
     field public static final int RESULT_DEVICE_OWNER_SET = 123; // 0x7b
-    field public static final int RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR = 1; // 0x1
-    field public static final int RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR = 2; // 0x2
+    field public static final int RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_PROVISIONING_DISABLED = 3; // 0x3
+    field public static final int RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR = 1; // 0x1
+    field public static final int RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR = 2; // 0x2
     field public static final int RESULT_UPDATE_ROLE_HOLDER = 2; // 0x2
     field public static final int RESULT_WORK_PROFILE_CREATED = 122; // 0x7a
     field public static final int STATE_USER_PROFILE_COMPLETE = 4; // 0x4
@@ -1189,52 +1193,25 @@
   }
 
   public static final class DevicePolicyResources.Strings {
-    field public static final String UNDEFINED = "UNDEFINED";
   }
 
-  public static final class DevicePolicyResources.Strings.Dialer {
-    field public static final String NOTIFICATION_INCOMING_WORK_CALL_TITLE = "Dialer.NOTIFICATION_INCOMING_WORK_CALL_TITLE";
-    field public static final String NOTIFICATION_MISSED_WORK_CALL_TITLE = "Dialer.NOTIFICATION_MISSED_WORK_CALL_TITLE";
-    field public static final String NOTIFICATION_ONGOING_WORK_CALL_TITLE = "Dialer.NOTIFICATION_ONGOING_WORK_CALL_TITLE";
-    field public static final String NOTIFICATION_WIFI_WORK_CALL_LABEL = "Dialer.NOTIFICATION_WIFI_WORK_CALL_LABEL";
+  public static final class DevicePolicyResources.Strings.DefaultAppSettings {
+    field public static final String HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE = "DefaultAppSettings.HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE";
+    field public static final String WORK_PROFILE_DEFAULT_APPS_TITLE = "DefaultAppSettings.WORK_PROFILE_DEFAULT_APPS_TITLE";
   }
 
-  public static final class DevicePolicyResources.Strings.DocumentsUi {
-    field public static final String CANT_SAVE_TO_PERSONAL_MESSAGE = "DocumentsUi.CANT_SAVE_TO_PERSONAL_MESSAGE";
-    field public static final String CANT_SAVE_TO_PERSONAL_TITLE = "DocumentsUi.CANT_SAVE_TO_PERSONAL_TITLE";
-    field public static final String CANT_SAVE_TO_WORK_MESSAGE = "DocumentsUi.CANT_SAVE_TO_WORK_MESSAGE";
-    field public static final String CANT_SAVE_TO_WORK_TITLE = "DocumentsUi.CANT_SAVE_TO_WORK_TITLE";
-    field public static final String CANT_SELECT_PERSONAL_FILES_MESSAGE = "DocumentsUi.CANT_SELECT_PERSONAL_FILES_MESSAGE";
-    field public static final String CANT_SELECT_PERSONAL_FILES_TITLE = "DocumentsUi.CANT_SELECT_PERSONAL_FILES_TITLE";
-    field public static final String CANT_SELECT_WORK_FILES_MESSAGE = "DocumentsUi.CANT_SELECT_WORK_FILES_MESSAGE";
-    field public static final String CANT_SELECT_WORK_FILES_TITLE = "DocumentsUi.CANT_SELECT_WORK_FILES_TITLE";
-    field public static final String CROSS_PROFILE_NOT_ALLOWED_MESSAGE = "DocumentsUi.CROSS_PROFILE_NOT_ALLOWED_MESSAGE";
-    field public static final String CROSS_PROFILE_NOT_ALLOWED_TITLE = "DocumentsUi.CROSS_PROFILE_NOT_ALLOWED_TITLE";
-    field public static final String PERSONAL_TAB = "DocumentsUi.PERSONAL_TAB";
-    field public static final String PREVIEW_WORK_FILE_ACCESSIBILITY = "DocumentsUi.PREVIEW_WORK_FILE_ACCESSIBILITY";
-    field public static final String WORK_ACCESSIBILITY = "DocumentsUi.WORK_ACCESSIBILITY";
-    field public static final String WORK_PROFILE_OFF_ENABLE_BUTTON = "DocumentsUi.WORK_PROFILE_OFF_ENABLE_BUTTON";
-    field public static final String WORK_PROFILE_OFF_ERROR_TITLE = "DocumentsUi.WORK_PROFILE_OFF_ERROR_TITLE";
-    field public static final String WORK_TAB = "DocumentsUi.WORK_TAB";
+  public static final class DevicePolicyResources.Strings.PermissionSettings {
+    field public static final String BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE = "PermissionSettings.BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE";
+    field public static final String BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE = "PermissionSettings.BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE";
+    field public static final String FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE = "PermissionSettings.FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE";
+    field public static final String LOCATION_AUTO_GRANTED_MESSAGE = "PermissionSettings.LOCATION_AUTO_GRANTED_MESSAGE";
   }
 
-  public static final class DevicePolicyResources.Strings.MediaProvider {
-    field public static final String BLOCKED_BY_ADMIN_TITLE = "MediaProvider.BLOCKED_BY_ADMIN_TITLE";
-    field public static final String BLOCKED_FROM_PERSONAL_MESSAGE = "MediaProvider.BLOCKED_FROM_PERSONAL_MESSAGE";
-    field public static final String BLOCKED_FROM_WORK_MESSAGE = "MediaProvider.BLOCKED_FROM_WORK_MESSAGE";
-    field public static final String SWITCH_TO_PERSONAL_MESSAGE = "MediaProvider.SWITCH_TO_PERSONAL_MESSAGE";
-    field public static final String SWITCH_TO_WORK_MESSAGE = "MediaProvider.SWITCH_TO_WORK_MESSAGE";
-    field public static final String WORK_PROFILE_PAUSED_MESSAGE = "MediaProvider.WORK_PROFILE_PAUSED_MESSAGE";
-    field public static final String WORK_PROFILE_PAUSED_TITLE = "MediaProvider.WORK_PROFILE_PAUSED_TITLE";
-  }
-
-  public static final class DevicePolicyResources.Strings.PermissionController {
-    field public static final String BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE = "PermissionController.BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE";
-    field public static final String BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE = "PermissionController.BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE";
-    field public static final String FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE = "PermissionController.FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE";
-    field public static final String HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE = "PermissionController.HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE";
-    field public static final String LOCATION_AUTO_GRANTED_MESSAGE = "PermissionController.LOCATION_AUTO_GRANTED_MESSAGE";
-    field public static final String WORK_PROFILE_DEFAULT_APPS_TITLE = "PermissionController.WORK_PROFILE_DEFAULT_APPS_TITLE";
+  public class DevicePolicyResourcesManager {
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void resetDrawables(@NonNull java.util.Set<java.lang.String>);
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void resetStrings(@NonNull java.util.Set<java.lang.String>);
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void setDrawables(@NonNull java.util.Set<android.app.admin.DevicePolicyDrawableResource>);
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void setStrings(@NonNull java.util.Set<android.app.admin.DevicePolicyStringResource>);
   }
 
   public final class DevicePolicyStringResource implements android.os.Parcelable {
@@ -1701,8 +1678,10 @@
     method @NonNull public String getTitle();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.cloudsearch.SearchResult> CREATOR;
+    field public static final String EXTRAINFO_ACTION_APP_CARD = "android.app.cloudsearch.ACTION_APP_CARD";
     field public static final String EXTRAINFO_ACTION_BUTTON_IMAGE_PREREGISTERING = "android.app.cloudsearch.ACTION_BUTTON_IMAGE";
     field public static final String EXTRAINFO_ACTION_BUTTON_TEXT_PREREGISTERING = "android.app.cloudsearch.ACTION_BUTTON_TEXT";
+    field public static final String EXTRAINFO_ACTION_INSTALL_BUTTON = "android.app.cloudsearch.ACTION_INSTALL_BUTTON";
     field public static final String EXTRAINFO_APP_BADGES = "android.app.cloudsearch.APP_BADGES";
     field public static final String EXTRAINFO_APP_CONTAINS_ADS_DISCLAIMER = "android.app.cloudsearch.APP_CONTAINS_ADS_DISCLAIMER";
     field public static final String EXTRAINFO_APP_CONTAINS_IAP_DISCLAIMER = "android.app.cloudsearch.APP_CONTAINS_IAP_DISCLAIMER";
@@ -1710,6 +1689,8 @@
     field public static final String EXTRAINFO_APP_DOMAIN_URL = "android.app.cloudsearch.APP_DOMAIN_URL";
     field public static final String EXTRAINFO_APP_IARC = "android.app.cloudsearch.APP_IARC";
     field public static final String EXTRAINFO_APP_ICON = "android.app.cloudsearch.APP_ICON";
+    field public static final String EXTRAINFO_APP_INSTALL_COUNT = "android.app.cloudsearch.APP_INSTALL_COUNT";
+    field public static final String EXTRAINFO_APP_PACKAGE_NAME = "android.app.cloudsearch.APP_PACKAGE_NAME";
     field public static final String EXTRAINFO_APP_REVIEW_COUNT = "android.app.cloudsearch.APP_REVIEW_COUNT";
     field public static final String EXTRAINFO_APP_SIZE_BYTES = "android.app.cloudsearch.APP_SIZE_BYTES";
     field public static final String EXTRAINFO_APP_STAR_RATING = "android.app.cloudsearch.APP_STAR_RATING";
@@ -1921,6 +1902,7 @@
     field public static final int ACTION_DISMISS = 2; // 0x2
     field public static final int ACTION_LAUNCH = 1; // 0x1
     field public static final int ACTION_PIN = 3; // 0x3
+    field public static final int ACTION_UNDISMISS = 5; // 0x5
     field public static final int ACTION_UNPIN = 4; // 0x4
     field @NonNull public static final android.os.Parcelable.Creator<android.app.prediction.AppTargetEvent> CREATOR;
   }
@@ -2616,13 +2598,13 @@
   }
 
   public final class UsageStatsManager {
-    method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void clearBroadcastResponseStats(@Nullable String, @IntRange(from=0) long);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS) public void clearBroadcastResponseStats(@Nullable String, @IntRange(from=0) long);
     method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getAppStandbyBucket(String);
     method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public java.util.Map<java.lang.String,java.lang.Integer> getAppStandbyBuckets();
     method @RequiresPermission(allOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.PACKAGE_USAGE_STATS}) public long getLastTimeAnyComponentUsed(@NonNull String);
     method public int getUsageSource();
     method @RequiresPermission(android.Manifest.permission.BIND_CARRIER_SERVICES) public void onCarrierPrivilegedAppsChanged();
-    method @NonNull @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public java.util.List<android.app.usage.BroadcastResponseStats> queryBroadcastResponseStats(@Nullable String, @IntRange(from=0) long);
+    method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS) public java.util.List<android.app.usage.BroadcastResponseStats> queryBroadcastResponseStats(@Nullable String, @IntRange(from=0) long);
     method @RequiresPermission(allOf={android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void registerAppUsageLimitObserver(int, @NonNull String[], @NonNull java.time.Duration, @NonNull java.time.Duration, @Nullable android.app.PendingIntent);
     method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerAppUsageObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent);
     method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerUsageSessionObserver(int, @NonNull String[], @NonNull java.time.Duration, @NonNull java.time.Duration, @NonNull android.app.PendingIntent, @Nullable android.app.PendingIntent);
@@ -2826,8 +2808,11 @@
   public final class VirtualDeviceParams implements android.os.Parcelable {
     method public int describeContents();
     method @NonNull public java.util.Set<android.content.ComponentName> getAllowedActivities();
+    method @NonNull public java.util.Set<android.content.ComponentName> getAllowedCrossTaskNavigations();
     method @NonNull public java.util.Set<android.content.ComponentName> getBlockedActivities();
+    method @NonNull public java.util.Set<android.content.ComponentName> getBlockedCrossTaskNavigations();
     method public int getDefaultActivityPolicy();
+    method public int getDefaultNavigationPolicy();
     method public int getLockState();
     method @NonNull public java.util.Set<android.os.UserHandle> getUsersWithMatchingAccounts();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -2836,13 +2821,17 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.companion.virtual.VirtualDeviceParams> CREATOR;
     field public static final int LOCK_STATE_ALWAYS_UNLOCKED = 1; // 0x1
     field public static final int LOCK_STATE_DEFAULT = 0; // 0x0
+    field public static final int NAVIGATION_POLICY_DEFAULT_ALLOWED = 0; // 0x0
+    field public static final int NAVIGATION_POLICY_DEFAULT_BLOCKED = 1; // 0x1
   }
 
   public static final class VirtualDeviceParams.Builder {
     ctor public VirtualDeviceParams.Builder();
     method @NonNull public android.companion.virtual.VirtualDeviceParams build();
     method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setAllowedActivities(@NonNull java.util.Set<android.content.ComponentName>);
+    method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setAllowedCrossTaskNavigations(@NonNull java.util.Set<android.content.ComponentName>);
     method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setBlockedActivities(@NonNull java.util.Set<android.content.ComponentName>);
+    method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setBlockedCrossTaskNavigations(@NonNull java.util.Set<android.content.ComponentName>);
     method @NonNull @RequiresPermission(value=android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY, conditional=true) public android.companion.virtual.VirtualDeviceParams.Builder setLockState(int);
     method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setUsersWithMatchingAccounts(@NonNull java.util.Set<android.os.UserHandle>);
   }
@@ -2948,6 +2937,7 @@
     method public void sendBroadcastMultiplePermissions(@NonNull android.content.Intent, @NonNull String[], @Nullable android.app.BroadcastOptions);
     method public abstract void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable android.os.Bundle, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.os.UserHandle);
+    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @Nullable android.os.Bundle, @NonNull android.os.UserHandle);
     field public static final String AMBIENT_CONTEXT_SERVICE = "ambient_context";
     field public static final String APP_HIBERNATION_SERVICE = "app_hibernation";
     field public static final String APP_INTEGRITY_SERVICE = "app_integrity";
@@ -3187,6 +3177,7 @@
   }
 
   public class CrossProfileApps {
+    method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_PROFILES, android.Manifest.permission.START_CROSS_PROFILE_ACTIVITIES}) public void startActivity(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle, @Nullable android.app.Activity, @Nullable android.os.Bundle);
     method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_PROFILES, android.Manifest.permission.START_CROSS_PROFILE_ACTIVITIES}) public void startActivity(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
   }
 
@@ -3406,6 +3397,8 @@
     field public static final String EXTRA_REQUEST_PERMISSIONS_RESULTS = "android.content.pm.extra.REQUEST_PERMISSIONS_RESULTS";
     field public static final String FEATURE_BROADCAST_RADIO = "android.hardware.broadcastradio";
     field public static final String FEATURE_CONTEXT_HUB = "android.hardware.context_hub";
+    field public static final String FEATURE_EROFS = "android.software.erofs";
+    field public static final String FEATURE_EROFS_LEGACY = "android.software.erofs_legacy";
     field public static final String FEATURE_GAME_SERVICE = "android.software.game_service";
     field public static final String FEATURE_INCREMENTAL_DELIVERY = "android.software.incremental_delivery";
     field public static final String FEATURE_REBOOT_ESCROW = "android.hardware.reboot_escrow";
@@ -5265,7 +5258,7 @@
 
   public static final class SoundTrigger.KeyphraseRecognitionExtra implements android.os.Parcelable {
     method public int describeContents();
-    method public int getCoarseConfidenceLevel();
+    method @IntRange(from=0, to=100) public int getCoarseConfidenceLevel();
     method public int getKeyphraseId();
     method public int getRecognitionModes();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -5483,6 +5476,32 @@
     method @NonNull public android.location.GnssCapabilities.Builder setHasSatellitePvt(boolean);
   }
 
+  public final class GnssExcessPathInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method @FloatRange(from=0.0f) public float getAttenuationDb();
+    method @FloatRange(from=0.0f) public float getExcessPathLengthMeters();
+    method @FloatRange(from=0.0f) public float getExcessPathLengthUncertaintyMeters();
+    method @NonNull public android.location.GnssReflectingPlane getReflectingPlane();
+    method public boolean hasAttenuation();
+    method public boolean hasExcessPathLength();
+    method public boolean hasExcessPathLengthUncertainty();
+    method public boolean hasReflectingPlane();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssExcessPathInfo> CREATOR;
+  }
+
+  public static final class GnssExcessPathInfo.Builder {
+    ctor public GnssExcessPathInfo.Builder();
+    method @NonNull public android.location.GnssExcessPathInfo build();
+    method @NonNull public android.location.GnssExcessPathInfo.Builder clearAttenuationDb();
+    method @NonNull public android.location.GnssExcessPathInfo.Builder clearExcessPathLengthMeters();
+    method @NonNull public android.location.GnssExcessPathInfo.Builder clearExcessPathLengthUncertaintyMeters();
+    method @NonNull public android.location.GnssExcessPathInfo.Builder setAttenuationDb(@FloatRange(from=0.0f) float);
+    method @NonNull public android.location.GnssExcessPathInfo.Builder setExcessPathLengthMeters(@FloatRange(from=0.0f) float);
+    method @NonNull public android.location.GnssExcessPathInfo.Builder setExcessPathLengthUncertaintyMeters(@FloatRange(from=0.0f) float);
+    method @NonNull public android.location.GnssExcessPathInfo.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
+  }
+
   public final class GnssMeasurement implements android.os.Parcelable {
     method @Nullable public java.util.Collection<android.location.CorrelationVector> getCorrelationVectors();
     method @Nullable public android.location.SatellitePvt getSatellitePvt();
@@ -5564,15 +5583,18 @@
   public final class GnssSingleSatCorrection implements android.os.Parcelable {
     method public int describeContents();
     method @FloatRange(from=0.0f, fromInclusive=false) public float getCarrierFrequencyHz();
+    method @FloatRange(from=0.0f) public float getCombinedAttenuationDb();
     method public int getConstellationType();
     method @FloatRange(from=0.0f) public float getExcessPathLengthMeters();
     method @FloatRange(from=0.0f) public float getExcessPathLengthUncertaintyMeters();
+    method @NonNull public java.util.List<android.location.GnssExcessPathInfo> getGnssExcessPathInfoList();
     method @FloatRange(from=0.0f, to=1.0f) public float getProbabilityLineOfSight();
-    method @Nullable public android.location.GnssReflectingPlane getReflectingPlane();
+    method @Deprecated @Nullable public android.location.GnssReflectingPlane getReflectingPlane();
     method @IntRange(from=0) public int getSatelliteId();
+    method public boolean hasCombinedAttenuation();
     method public boolean hasExcessPathLength();
     method public boolean hasExcessPathLengthUncertainty();
-    method public boolean hasReflectingPlane();
+    method @Deprecated public boolean hasReflectingPlane();
     method public boolean hasValidSatelliteLineOfSight();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssSingleSatCorrection> CREATOR;
@@ -5581,15 +5603,18 @@
   public static final class GnssSingleSatCorrection.Builder {
     ctor public GnssSingleSatCorrection.Builder();
     method @NonNull public android.location.GnssSingleSatCorrection build();
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder clearCombinedAttenuationDb();
     method @NonNull public android.location.GnssSingleSatCorrection.Builder clearExcessPathLengthMeters();
     method @NonNull public android.location.GnssSingleSatCorrection.Builder clearExcessPathLengthUncertaintyMeters();
     method @NonNull public android.location.GnssSingleSatCorrection.Builder clearProbabilityLineOfSight();
     method @NonNull public android.location.GnssSingleSatCorrection.Builder setCarrierFrequencyHz(@FloatRange(from=0.0f, fromInclusive=false) float);
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder setCombinedAttenuationDb(@FloatRange(from=0.0f) float);
     method @NonNull public android.location.GnssSingleSatCorrection.Builder setConstellationType(int);
     method @NonNull public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthMeters(@FloatRange(from=0.0f) float);
     method @NonNull public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthUncertaintyMeters(@FloatRange(from=0.0f) float);
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder setGnssExcessPathInfoList(@NonNull java.util.List<android.location.GnssExcessPathInfo>);
     method @NonNull public android.location.GnssSingleSatCorrection.Builder setProbabilityLineOfSight(@FloatRange(from=0.0f, to=1.0f) float);
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
+    method @Deprecated @NonNull public android.location.GnssSingleSatCorrection.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
     method @NonNull public android.location.GnssSingleSatCorrection.Builder setSatelliteId(@IntRange(from=0) int);
   }
 
@@ -5831,9 +5856,9 @@
     ctor public LastLocationRequest.Builder();
     ctor public LastLocationRequest.Builder(@NonNull android.location.LastLocationRequest);
     method @NonNull public android.location.LastLocationRequest build();
-    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.WRITE_SECURE_SETTINGS, android.Manifest.permission.LOCATION_BYPASS}) public android.location.LastLocationRequest.Builder setAdasGnssBypass(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LastLocationRequest.Builder setAdasGnssBypass(boolean);
     method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LastLocationRequest.Builder setHiddenFromAppOps(boolean);
-    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.WRITE_SECURE_SETTINGS, android.Manifest.permission.LOCATION_BYPASS}) public android.location.LastLocationRequest.Builder setLocationSettingsIgnored(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LastLocationRequest.Builder setLocationSettingsIgnored(boolean);
   }
 
   public class Location implements android.os.Parcelable {
@@ -5862,7 +5887,7 @@
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
-    method @RequiresPermission(anyOf={android.Manifest.permission.WRITE_SECURE_SETTINGS, android.Manifest.permission.LOCATION_BYPASS}) public void setAdasGnssLocationEnabled(boolean);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public void setAdasGnssLocationEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackage(@Nullable String);
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackageEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
@@ -5895,7 +5920,7 @@
     method @Deprecated @NonNull public android.location.LocationRequest setFastestInterval(long);
     method @Deprecated public void setHideFromAppOps(boolean);
     method @Deprecated @NonNull public android.location.LocationRequest setInterval(long);
-    method @Deprecated @NonNull @RequiresPermission(anyOf={android.Manifest.permission.WRITE_SECURE_SETTINGS, android.Manifest.permission.LOCATION_BYPASS}) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
+    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
     method @Deprecated @NonNull public android.location.LocationRequest setLowPowerMode(boolean);
     method @Deprecated @NonNull public android.location.LocationRequest setNumUpdates(int);
     method @Deprecated @NonNull public android.location.LocationRequest setProvider(@NonNull String);
@@ -5911,9 +5936,9 @@
   }
 
   public static final class LocationRequest.Builder {
-    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.WRITE_SECURE_SETTINGS, android.Manifest.permission.LOCATION_BYPASS}) public android.location.LocationRequest.Builder setAdasGnssBypass(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LocationRequest.Builder setAdasGnssBypass(boolean);
     method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LocationRequest.Builder setHiddenFromAppOps(boolean);
-    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.WRITE_SECURE_SETTINGS, android.Manifest.permission.LOCATION_BYPASS}) public android.location.LocationRequest.Builder setLocationSettingsIgnored(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LocationRequest.Builder setLocationSettingsIgnored(boolean);
     method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.location.LocationRequest.Builder setLowPower(boolean);
     method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.LocationRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
   }
@@ -6946,7 +6971,7 @@
   }
 
   public class Lnb implements java.lang.AutoCloseable {
-    method public void addCallback(@NonNull android.media.tv.tuner.LnbCallback, @NonNull java.util.concurrent.Executor);
+    method public void addCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.LnbCallback);
     method public void close();
     method public boolean removeCallback(@NonNull android.media.tv.tuner.LnbCallback);
     method public int sendDiseqcMessage(@NonNull byte[]);
@@ -8521,45 +8546,6 @@
 
 package android.net {
 
-  public class EthernetManager {
-    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) public void connectNetwork(@NonNull String, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.BiConsumer<android.net.Network,android.net.EthernetNetworkManagementException>);
-    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) public void disconnectNetwork(@NonNull String, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.BiConsumer<android.net.Network,android.net.EthernetNetworkManagementException>);
-    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull java.util.concurrent.Executor, @NonNull android.net.EthernetManager.TetheredInterfaceCallback);
-    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) public void updateConfiguration(@NonNull String, @NonNull android.net.EthernetNetworkUpdateRequest, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.BiConsumer<android.net.Network,android.net.EthernetNetworkManagementException>);
-  }
-
-  public static interface EthernetManager.TetheredInterfaceCallback {
-    method public void onAvailable(@NonNull String);
-    method public void onUnavailable();
-  }
-
-  public static class EthernetManager.TetheredInterfaceRequest {
-    method public void release();
-  }
-
-  public final class EthernetNetworkManagementException extends java.lang.RuntimeException implements android.os.Parcelable {
-    ctor public EthernetNetworkManagementException(@NonNull String);
-    method public int describeContents();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkManagementException> CREATOR;
-  }
-
-  public final class EthernetNetworkUpdateRequest implements android.os.Parcelable {
-    method public int describeContents();
-    method @NonNull public android.net.IpConfiguration getIpConfiguration();
-    method @Nullable public android.net.NetworkCapabilities getNetworkCapabilities();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkUpdateRequest> CREATOR;
-  }
-
-  public static final class EthernetNetworkUpdateRequest.Builder {
-    ctor public EthernetNetworkUpdateRequest.Builder();
-    ctor public EthernetNetworkUpdateRequest.Builder(@NonNull android.net.EthernetNetworkUpdateRequest);
-    method @NonNull public android.net.EthernetNetworkUpdateRequest build();
-    method @NonNull public android.net.EthernetNetworkUpdateRequest.Builder setIpConfiguration(@NonNull android.net.IpConfiguration);
-    method @NonNull public android.net.EthernetNetworkUpdateRequest.Builder setNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
-  }
-
   public final class MatchAllNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
     ctor public MatchAllNetworkSpecifier();
     method public int describeContents();
@@ -9030,7 +9016,7 @@
     method public void enableVerboseLogging(boolean);
     method @NonNull public int[] getChannelsMhzForBand(int);
     method @Nullable public android.net.wifi.nl80211.DeviceWiphyCapabilities getDeviceWiphyCapabilities(@NonNull String);
-    method public int getMaxNumScanSsids(@NonNull String);
+    method public int getMaxSsidsPerScan(@NonNull String);
     method @NonNull public java.util.List<android.net.wifi.nl80211.NativeScanResult> getScanResults(@NonNull String, int);
     method @Nullable public android.net.wifi.nl80211.WifiNl80211Manager.TxPacketCounters getTxPacketCounters(@NonNull String);
     method public void notifyCountryCodeChanged(@Nullable String);
@@ -9820,16 +9806,17 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean hasUserRestrictionForUser(@NonNull String, @NonNull android.os.UserHandle);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isAdminUser();
     method public boolean isCloneProfile();
-    method public boolean isCredentialSharedWithParent();
+    method public boolean isCredentialSharableWithParent();
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isGuestUser();
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isManagedProfile(int);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isMediaSharedWithParent();
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isPrimaryUser();
+    method public static boolean isRemoveResultSuccessful(int);
     method public boolean isRestrictedProfile();
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public boolean isRestrictedProfile(@NonNull android.os.UserHandle);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isSameProfileGroup(@NonNull android.os.UserHandle, @NonNull android.os.UserHandle);
-    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public boolean isUserNameSet();
-    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isUserOfType(@NonNull String);
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS, android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public boolean isUserNameSet();
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isUserOfType(@NonNull String);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isUserUnlockingOrUnlocked(@NonNull android.os.UserHandle);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean removeUser(@NonNull android.os.UserHandle);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public int removeUserWhenPossible(@NonNull android.os.UserHandle, boolean);
@@ -9842,7 +9829,10 @@
     field public static final String DISALLOW_RUN_IN_BACKGROUND = "no_run_in_background";
     field public static final int REMOVE_RESULT_ALREADY_BEING_REMOVED = 2; // 0x2
     field public static final int REMOVE_RESULT_DEFERRED = 1; // 0x1
-    field public static final int REMOVE_RESULT_ERROR = 3; // 0x3
+    field public static final int REMOVE_RESULT_ERROR_SYSTEM_USER = -4; // 0xfffffffc
+    field public static final int REMOVE_RESULT_ERROR_UNKNOWN = -1; // 0xffffffff
+    field public static final int REMOVE_RESULT_ERROR_USER_NOT_FOUND = -3; // 0xfffffffd
+    field public static final int REMOVE_RESULT_ERROR_USER_RESTRICTION = -2; // 0xfffffffe
     field public static final int REMOVE_RESULT_REMOVED = 0; // 0x0
     field public static final int RESTRICTION_NOT_SET = 0; // 0x0
     field public static final int RESTRICTION_SOURCE_DEVICE_OWNER = 2; // 0x2
@@ -10077,9 +10067,9 @@
     method @BinderThread public void onOneTimePermissionSessionTimeout(@NonNull String);
     method @Deprecated @BinderThread public void onRestoreDelayedRuntimePermissionsBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @Deprecated @BinderThread public void onRestoreRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
-    method @BinderThread public void onRevokeOwnPermissionsOnKill(@NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull Runnable);
     method @BinderThread public abstract void onRevokeRuntimePermission(@NonNull String, @NonNull String, @NonNull Runnable);
     method @BinderThread public abstract void onRevokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull String, @NonNull java.util.function.Consumer<java.util.Map<java.lang.String,java.util.List<java.lang.String>>>);
+    method @BinderThread public void onRevokeSelfPermissionsOnKill(@NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull Runnable);
     method @Deprecated @BinderThread public abstract void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull String, @NonNull String, int, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @BinderThread public void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull android.permission.AdminPermissionControlParams, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @BinderThread public void onStageAndApplyRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
@@ -10105,10 +10095,10 @@
 
   public final class PermissionManager {
     method public int checkDeviceIdentifierAccess(@Nullable String, @Nullable String, @Nullable String, int, int);
-    method public int checkPermissionForDataDelivery(@NonNull String, @NonNull android.content.AttributionSource, @Nullable String);
-    method public int checkPermissionForDataDeliveryFromDataSource(@NonNull String, @NonNull android.content.AttributionSource, @Nullable String);
+    method @RequiresPermission(value=android.Manifest.permission.UPDATE_APP_OPS_STATS, conditional=true) public int checkPermissionForDataDelivery(@NonNull String, @NonNull android.content.AttributionSource, @Nullable String);
+    method @RequiresPermission(value=android.Manifest.permission.UPDATE_APP_OPS_STATS, conditional=true) public int checkPermissionForDataDeliveryFromDataSource(@NonNull String, @NonNull android.content.AttributionSource, @Nullable String);
     method public int checkPermissionForPreflight(@NonNull String, @NonNull android.content.AttributionSource);
-    method public int checkPermissionForStartDataDelivery(@NonNull String, @NonNull android.content.AttributionSource, @Nullable String);
+    method @RequiresPermission(value=android.Manifest.permission.UPDATE_APP_OPS_STATS, conditional=true) public int checkPermissionForStartDataDelivery(@NonNull String, @NonNull android.content.AttributionSource, @Nullable String);
     method public void finishDataDelivery(@NonNull String, @NonNull android.content.AttributionSource);
     method @NonNull @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public java.util.Set<java.lang.String> getAutoRevokeExemptionGrantedPackages();
     method @NonNull @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public java.util.Set<java.lang.String> getAutoRevokeExemptionRequestedPackages();
@@ -10332,6 +10322,7 @@
     field public static final String NAMESPACE_MEDIA_NATIVE = "media_native";
     field public static final String NAMESPACE_NETD_NATIVE = "netd_native";
     field public static final String NAMESPACE_NNAPI_NATIVE = "nnapi_native";
+    field public static final String NAMESPACE_ON_DEVICE_PERSONALIZATION = "on_device_personalization";
     field public static final String NAMESPACE_OTA = "ota";
     field public static final String NAMESPACE_PACKAGE_MANAGER_SERVICE = "package_manager_service";
     field public static final String NAMESPACE_PERMISSIONS = "permissions";
@@ -10581,7 +10572,6 @@
     field public static final String AUTO_REVOKE_DISABLED = "auto_revoke_disabled";
     field public static final String COMPLETED_CATEGORY_PREFIX = "suggested.completed_category.";
     field public static final String DOZE_ALWAYS_ON = "doze_always_on";
-    field public static final String FAST_PAIR_SCAN_ENABLED = "fast_pair_scan_enabled";
     field public static final String HUSH_GESTURE_USED = "hush_gesture_used";
     field public static final String INSTANT_APPS_ENABLED = "instant_apps_enabled";
     field public static final String LAST_SETUP_SHOWN = "last_setup_shown";
@@ -10893,10 +10883,11 @@
   }
 
   public static final class AmbientContextDetectionResult.Builder {
-    ctor public AmbientContextDetectionResult.Builder();
+    ctor public AmbientContextDetectionResult.Builder(@NonNull String);
     method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult.Builder addEvent(@NonNull android.app.ambientcontext.AmbientContextEvent);
+    method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult.Builder addEvents(@NonNull java.util.List<android.app.ambientcontext.AmbientContextEvent>);
     method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult build();
-    method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult.Builder setPackageName(@NonNull String);
+    method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult.Builder clearEvents();
   }
 
   public abstract class AmbientContextDetectionService extends android.app.Service {
@@ -10917,9 +10908,8 @@
   }
 
   public static final class AmbientContextDetectionServiceStatus.Builder {
-    ctor public AmbientContextDetectionServiceStatus.Builder();
+    ctor public AmbientContextDetectionServiceStatus.Builder(@NonNull String);
     method @NonNull public android.service.ambientcontext.AmbientContextDetectionServiceStatus build();
-    method @NonNull public android.service.ambientcontext.AmbientContextDetectionServiceStatus.Builder setPackageName(@NonNull String);
     method @NonNull public android.service.ambientcontext.AmbientContextDetectionServiceStatus.Builder setStatusCode(int);
   }
 
@@ -11401,7 +11391,7 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY) public final boolean restartGame();
     method public void setTaskOverlayView(@NonNull android.view.View, @NonNull android.view.ViewGroup.LayoutParams);
     method @RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY) public final void startActivityFromGameSessionForResult(@NonNull android.content.Intent, @Nullable android.os.Bundle, @NonNull java.util.concurrent.Executor, @NonNull android.service.games.GameSessionActivityCallback);
-    method public void takeScreenshot(@NonNull java.util.concurrent.Executor, @NonNull android.service.games.GameSession.ScreenshotCallback);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY) public void takeScreenshot(@NonNull java.util.concurrent.Executor, @NonNull android.service.games.GameSession.ScreenshotCallback);
   }
 
   public static interface GameSession.ScreenshotCallback {
@@ -11825,11 +11815,23 @@
 
 package android.service.trust {
 
+  public final class GrantTrustResult implements android.os.Parcelable {
+    ctor public GrantTrustResult(int);
+    method public int describeContents();
+    method public int getStatus();
+    method @NonNull public static String statusToString(int);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.service.trust.GrantTrustResult> CREATOR;
+    field public static final int STATUS_UNKNOWN = 0; // 0x0
+    field public static final int STATUS_UNLOCKED_BY_GRANT = 1; // 0x1
+  }
+
   public class TrustAgentService extends android.app.Service {
     ctor public TrustAgentService();
     method public final void addEscrowToken(byte[], android.os.UserHandle);
     method @Deprecated public final void grantTrust(CharSequence, long, boolean);
-    method public final void grantTrust(CharSequence, long, int);
+    method @Deprecated public final void grantTrust(CharSequence, long, int);
+    method public final void grantTrust(@NonNull CharSequence, long, int, @Nullable java.util.function.Consumer<android.service.trust.GrantTrustResult>);
     method public final void isEscrowTokenActive(long, android.os.UserHandle);
     method public final void lockUser();
     method public final android.os.IBinder onBind(android.content.Intent);
@@ -11842,7 +11844,8 @@
     method public void onEscrowTokenStateReceived(long, int);
     method public void onTrustTimeout();
     method public void onUnlockAttempt(boolean);
-    method public void onUserRequestedUnlock();
+    method public void onUserMayRequestUnlock();
+    method public void onUserRequestedUnlock(boolean);
     method public final void removeEscrowToken(long, android.os.UserHandle);
     method public final void revokeTrust();
     method public final void setManagingTrust(boolean);
@@ -13375,7 +13378,6 @@
   }
 
   public class TelephonyManager {
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void addCarrierPrivilegesListener(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CarrierPrivilegesListener);
     method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) @WorkerThread public void bootstrapAuthenticationRequest(int, @NonNull android.net.Uri, @NonNull android.telephony.gba.UaSecurityProtocolIdentifier, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.BootstrapAuthenticationCallback);
     method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void call(String, String);
     method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult changeIccLockPin(@NonNull String, @NonNull String);
@@ -13475,7 +13477,7 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled();
     method @RequiresPermission(android.Manifest.permission.REBOOT) public int prepareForUnattendedReboot();
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void removeCarrierPrivilegesListener(@NonNull android.telephony.TelephonyManager.CarrierPrivilegesListener);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerCarrierPrivilegesCallback(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CarrierPrivilegesCallback);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void reportDefaultNetworkStatus(boolean);
     method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestModemActivityInfo(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.ModemActivityInfo,android.telephony.TelephonyManager.ModemActivityInfoException>);
@@ -13525,6 +13527,7 @@
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int[] supplyPukReportResult(String, String);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean switchSlots(int[]);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void toggleRadioOnOff();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterCarrierPrivilegesCallback(@NonNull android.telephony.TelephonyManager.CarrierPrivilegesCallback);
     method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void updateOtaEmergencyNumberDbFilePath(@NonNull android.os.ParcelFileDescriptor);
     method public void updateServiceLocation();
     field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_ANOMALY_REPORTED = "android.telephony.action.ANOMALY_REPORTED";
@@ -13630,8 +13633,9 @@
     field public static final int RESULT_SUCCESS = 0; // 0x0
   }
 
-  public static interface TelephonyManager.CarrierPrivilegesListener {
-    method public void onCarrierPrivilegesChanged(@NonNull java.util.List<java.lang.String>, @NonNull int[]);
+  public static interface TelephonyManager.CarrierPrivilegesCallback {
+    method public void onCarrierPrivilegesChanged(@NonNull java.util.Set<java.lang.String>, @NonNull java.util.Set<java.lang.Integer>);
+    method public default void onCarrierServiceChanged(@Nullable String, int);
   }
 
   public static class TelephonyManager.ModemActivityInfoException extends java.lang.Exception {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 5aec193..a67d002 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -19,6 +19,7 @@
     field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
     field public static final String INSTALL_TEST_ONLY_PACKAGE = "android.permission.INSTALL_TEST_ONLY_PACKAGE";
     field public static final String KEEP_UNINSTALLED_PACKAGES = "android.permission.KEEP_UNINSTALLED_PACKAGES";
+    field public static final String MAKE_UID_VISIBLE = "android.permission.MAKE_UID_VISIBLE";
     field @Deprecated public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
     field public static final String MANAGE_ACTIVITY_TASKS = "android.permission.MANAGE_ACTIVITY_TASKS";
     field public static final String MANAGE_CRATES = "android.permission.MANAGE_CRATES";
@@ -95,8 +96,7 @@
 package android.animation {
 
   public class ValueAnimator extends android.animation.Animator {
-    method public static float getDurationScale();
-    method public static void setDurationScale(float);
+    method @MainThread public static void setDurationScale(@FloatRange(from=0) float);
   }
 
 }
@@ -300,7 +300,6 @@
   }
 
   public class LocaleManager {
-    method @Nullable public android.os.LocaleList getSystemLocales();
     method public void setSystemLocales(@NonNull android.os.LocaleList);
   }
 
@@ -356,14 +355,8 @@
   }
 
   public final class PictureInPictureParams implements android.os.Parcelable {
-    method public java.util.List<android.app.RemoteAction> getActions();
-    method public float getAspectRatio();
-    method @Nullable public android.app.RemoteAction getCloseAction();
-    method public float getExpandedAspectRatio();
-    method public android.graphics.Rect getSourceRectHint();
-    method @Nullable public CharSequence getSubtitle();
-    method @Nullable public CharSequence getTitle();
-    method public boolean isSeamlessResizeEnabled();
+    method public float getAspectRatioFloat();
+    method public float getExpandedAspectRatioFloat();
   }
 
   public final class PictureInPictureUiState implements android.os.Parcelable {
@@ -422,9 +415,9 @@
     method @NonNull public android.content.res.Configuration getConfiguration();
     method public int getParentTaskId();
     method @Nullable public android.app.PictureInPictureParams getPictureInPictureParams();
-    method public boolean getPreferDockBigOverlays();
     method @NonNull public android.window.WindowContainerToken getToken();
     method public boolean hasParentTask();
+    method public boolean shouldDockBigOverlays();
   }
 
   public class TimePickerDialog extends android.app.AlertDialog implements android.content.DialogInterface.OnClickListener android.widget.TimePicker.OnTimeChangedListener {
@@ -508,6 +501,7 @@
     method public void forceUpdateUserSetupComplete(int);
     method @NonNull public java.util.Set<java.lang.String> getDefaultCrossProfilePackages();
     method public int getDeviceOwnerType(@NonNull android.content.ComponentName);
+    method @Nullable public String getDevicePolicyManagementRoleHolderUpdaterPackage();
     method @NonNull public java.util.Set<java.lang.String> getDisallowedSystemApps(@NonNull android.content.ComponentName, int, @NonNull String);
     method public long getLastBugReportRequestTime();
     method public long getLastNetworkLogRetrievalTime();
@@ -518,7 +512,6 @@
     method public boolean isFactoryResetProtectionPolicySupported();
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public boolean isNewUserDisclaimerAcknowledged();
     method public boolean isRemovingAdmin(@NonNull android.content.ComponentName, int);
-    method @RequiresPermission(anyOf={android.Manifest.permission.MARK_DEVICE_ORGANIZATION_OWNED, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}, conditional=true) public void markProfileOwnerOnOrganizationOwnedDevice(@NonNull android.content.ComponentName);
     method @NonNull public static String operationSafetyReasonToString(int);
     method @NonNull public static String operationToString(int);
     method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void resetDefaultCrossProfileIntentFilters(int);
@@ -527,6 +520,7 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public boolean setDeviceOwnerOnly(@NonNull android.content.ComponentName, @Nullable String, int);
     method public void setDeviceOwnerType(@NonNull android.content.ComponentName, int);
     method @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS) public void setNextOperationSafety(int, int);
+    method @RequiresPermission(anyOf={android.Manifest.permission.MARK_DEVICE_ORGANIZATION_OWNED, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}, conditional=true) public void setProfileOwnerOnOrganizationOwnedDevice(@NonNull android.content.ComponentName, boolean);
     field public static final String ACTION_DATA_SHARING_RESTRICTION_APPLIED = "android.app.action.DATA_SHARING_RESTRICTION_APPLIED";
     field public static final String ACTION_DEVICE_POLICY_CONSTANTS_CHANGED = "android.app.action.DEVICE_POLICY_CONSTANTS_CHANGED";
     field public static final int DEVICE_OWNER_TYPE_DEFAULT = 0; // 0x0
@@ -836,6 +830,7 @@
     method @Nullable public String getSystemTextClassifierPackageName();
     method @Nullable public String getWellbeingPackageName();
     method public void holdLock(android.os.IBinder, int);
+    method @RequiresPermission(android.Manifest.permission.MAKE_UID_VISIBLE) public void makeUidVisible(int, int);
     method @RequiresPermission(android.Manifest.permission.KEEP_UNINSTALLED_PACKAGES) public void setKeepUninstalledPackages(@NonNull java.util.List<java.lang.String>);
     field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
     field public static final String FEATURE_COMMUNAL_MODE = "android.software.communal_mode";
@@ -2434,7 +2429,7 @@
 package android.service.voice {
 
   public class AlwaysOnHotwordDetector implements android.service.voice.HotwordDetector {
-    method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public void triggerHardwareRecognitionEventForTest(int, int, boolean, int, int, int, boolean, @NonNull android.media.AudioFormat, @Nullable byte[]);
+    method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public void triggerHardwareRecognitionEventForTest(int, int, boolean, int, int, int, boolean, @NonNull android.media.AudioFormat, @Nullable byte[], @NonNull java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra>);
   }
 
   public static final class AlwaysOnHotwordDetector.EventPayload.Builder {
diff --git a/core/java/Android.bp b/core/java/Android.bp
index a5526bc..f081a43 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -145,16 +145,16 @@
     out: ["com/android/internal/util/FrameworkStatsLog.java"],
 }
 
+// Library that provides functionality to log UiEvents in framework space.
+// If this functionality is needed outside the framework, the interfaces library
+// can be re-used and a local implementation is needed.
 java_library {
     name: "uieventloggerlib",
     srcs: [
-        "com/android/internal/logging/UiEvent.java",
-        "com/android/internal/logging/UiEventLogger.java",
         "com/android/internal/logging/UiEventLoggerImpl.java",
-        "com/android/internal/logging/InstanceId.java",
-        "com/android/internal/logging/InstanceIdSequence.java",
         ":statslog-framework-java-gen",
     ],
+    static_libs: ["modules-utils-uieventlogger-interface"],
 }
 
 filegroup {
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index c82f5f6..3cb04e7 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -825,17 +825,7 @@
             for (int i = 0; i < mMagnificationControllers.size(); i++) {
                 mMagnificationControllers.valueAt(i).onServiceConnectedLocked();
             }
-            AccessibilityServiceInfo info = getServiceInfo();
-            if (info != null) {
-                boolean requestIme = (info.flags
-                        & AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR) != 0;
-                if (requestIme && !mInputMethodInitialized) {
-                    mInputMethod = onCreateInputMethod();
-                    mInputMethodInitialized = true;
-                }
-            } else {
-                Log.e(LOG_TAG, "AccessibilityServiceInfo is null in dispatchServiceConnected");
-            }
+            updateInputMethod(getServiceInfo());
         }
         if (mSoftKeyboardController != null) {
             mSoftKeyboardController.onServiceConnected();
@@ -846,6 +836,20 @@
         onServiceConnected();
     }
 
+    private void updateInputMethod(AccessibilityServiceInfo info) {
+        if (info != null) {
+            boolean requestIme = (info.flags
+                    & AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR) != 0;
+            if (requestIme && !mInputMethodInitialized) {
+                mInputMethod = onCreateInputMethod();
+                mInputMethodInitialized = true;
+            } else if (!requestIme & mInputMethodInitialized) {
+                mInputMethod = null;
+                mInputMethodInitialized = false;
+            }
+        }
+    }
+
     /**
      * This method is a part of the {@link AccessibilityService} lifecycle and is
      * called after the system has successfully bound to the service. If is
@@ -2521,6 +2525,7 @@
      */
     public final void setServiceInfo(AccessibilityServiceInfo info) {
         mInfo = info;
+        updateInputMethod(info);
         sendServiceInfo();
     }
 
diff --git a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
index 4e6cfb35..f53cfe4 100644
--- a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
@@ -169,10 +169,6 @@
             mIntroResId = asAttributes.getResourceId(
                     com.android.internal.R.styleable.AccessibilityShortcutTarget_intro, 0);
             asAttributes.recycle();
-
-            if ((mDescriptionResId == 0 && mHtmlDescriptionRes == 0) || mSummaryResId == 0) {
-                throw new XmlPullParserException("No description or summary in meta-data");
-            }
         } catch (PackageManager.NameNotFoundException e) {
             throw new XmlPullParserException("Unable to create context for: "
                     + mActivityInfo.packageName);
diff --git a/core/java/android/accessibilityservice/InputMethod.java b/core/java/android/accessibilityservice/InputMethod.java
index 001d804..c0e5e84 100644
--- a/core/java/android/accessibilityservice/InputMethod.java
+++ b/core/java/android/accessibilityservice/InputMethod.java
@@ -67,7 +67,11 @@
     private InputConnection mStartedInputConnection;
     private EditorInfo mInputEditorInfo;
 
-    protected InputMethod(@NonNull AccessibilityService service) {
+    /**
+     * Creates a new InputMethod instance for the given <code>service</code>, so that the
+     * accessibility service can control editing.
+     */
+    public InputMethod(@NonNull AccessibilityService service) {
         mService = service;
     }
 
diff --git a/core/java/android/accounts/CantAddAccountActivity.java b/core/java/android/accounts/CantAddAccountActivity.java
index 107efc3..3fac1a0 100644
--- a/core/java/android/accounts/CantAddAccountActivity.java
+++ b/core/java/android/accounts/CantAddAccountActivity.java
@@ -39,7 +39,7 @@
         setContentView(R.layout.app_not_authorized);
 
         TextView view = findViewById(R.id.description);
-        String text = getSystemService(DevicePolicyManager.class).getString(
+        String text = getSystemService(DevicePolicyManager.class).getResources().getString(
                 CANT_ADD_ACCOUNT_MESSAGE,
                 () -> getString(R.string.error_message_change_not_allowed));
         view.setText(text);
diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
index 0d82ac9..f623295d 100644
--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
@@ -205,7 +205,7 @@
 
             setContentView(R.layout.app_not_authorized);
             TextView view = findViewById(R.id.description);
-            String text = getSystemService(DevicePolicyManager.class).getString(
+            String text = getSystemService(DevicePolicyManager.class).getResources().getString(
                     CANT_ADD_ACCOUNT_MESSAGE,
                     () -> getString(R.string.error_message_change_not_allowed));
             view.setText(text);
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 06b424b..6ab7ae6 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -17,7 +17,9 @@
 package android.animation;
 
 import android.annotation.CallSuper;
+import android.annotation.FloatRange;
 import android.annotation.IntDef;
+import android.annotation.MainThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
@@ -35,8 +37,10 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 
 /**
  * This class provides a simple timing engine for running animations
@@ -91,6 +95,9 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private static float sDurationScale = 1.0f;
 
+    private static final ArrayList<WeakReference<DurationScaleChangeListener>>
+            sDurationScaleChangeListeners = new ArrayList<>();
+
     /**
      * Internal variables
      * NOTE: This object implements the clone() method, making a deep copy of any referenced
@@ -308,20 +315,92 @@
      */
     @UnsupportedAppUsage
     @TestApi
-    public static void setDurationScale(float durationScale) {
+    @MainThread
+    public static void setDurationScale(@FloatRange(from = 0) float durationScale) {
         sDurationScale = durationScale;
+        List<WeakReference<DurationScaleChangeListener>> listenerCopy;
+
+        synchronized (sDurationScaleChangeListeners) {
+            listenerCopy = new ArrayList<>(sDurationScaleChangeListeners);
+        }
+
+        for (WeakReference<DurationScaleChangeListener> listenerRef : listenerCopy) {
+            final DurationScaleChangeListener listener = listenerRef.get();
+            if (listener != null) {
+                listener.onChanged(durationScale);
+            }
+        }
     }
 
     /**
-     * @hide
+     * Returns the system-wide scaling factor for Animator-based animations.
+     *
+     * This affects both the start delay and duration of all such animations. Setting to 0 will
+     * cause animations to end immediately. The default value is 1.0f.
+     *
+     * @return the duration scale.
      */
-    @UnsupportedAppUsage
-    @TestApi
+    @FloatRange(from = 0)
     public static float getDurationScale() {
         return sDurationScale;
     }
 
     /**
+     * Registers a {@link DurationScaleChangeListener}
+     *
+     * This listens for changes to the system-wide scaling factor for Animator-based animations.
+     * Listeners will be called on the main thread.
+     *
+     * @param listener the listener to register.
+     * @return true if the listener was registered.
+     */
+    public static boolean registerDurationScaleChangeListener(
+            @NonNull DurationScaleChangeListener listener) {
+        int posToReplace = -1;
+        synchronized (sDurationScaleChangeListeners) {
+            for (int i = 0; i < sDurationScaleChangeListeners.size(); i++) {
+                final WeakReference<DurationScaleChangeListener> ref =
+                        sDurationScaleChangeListeners.get(i);
+                if (ref.get() == null) {
+                    if (posToReplace == -1) {
+                        posToReplace = i;
+                    }
+                } else if (ref.get() == listener) {
+                    return false;
+                }
+            }
+            if (posToReplace != -1) {
+                sDurationScaleChangeListeners.set(posToReplace, new WeakReference<>(listener));
+                return true;
+            } else {
+                return sDurationScaleChangeListeners.add(new WeakReference<>(listener));
+            }
+        }
+    }
+
+    /**
+     * Unregisters a DurationScaleChangeListener.
+     *
+     * @see #registerDurationScaleChangeListener(DurationScaleChangeListener)
+     * @param listener the listener to unregister.
+     * @return true if the listener was unregistered.
+     */
+    public static boolean unregisterDurationScaleChangeListener(
+            @NonNull DurationScaleChangeListener listener) {
+        synchronized (sDurationScaleChangeListeners) {
+            WeakReference<DurationScaleChangeListener> listenerRefToRemove = null;
+            for (WeakReference<DurationScaleChangeListener> listenerRef :
+                    sDurationScaleChangeListeners) {
+                if (listenerRef.get() == listener) {
+                    listenerRefToRemove = listenerRef;
+                    break;
+                }
+            }
+            return sDurationScaleChangeListeners.remove(listenerRefToRemove);
+        }
+    }
+
+    /**
      * Returns whether animators are currently enabled, system-wide. By default, all
      * animators are enabled. This can change if either the user sets a Developer Option
      * to set the animator duration scale to 0 or by Battery Savery mode being enabled
@@ -1709,4 +1788,18 @@
     public void setAnimationHandler(@Nullable AnimationHandler animationHandler) {
         mAnimationHandler = animationHandler;
     }
+
+    /**
+     * Listener interface for the system-wide scaling factor for Animator-based animations.
+     *
+     * @see #registerDurationScaleChangeListener(DurationScaleChangeListener)
+     * @see #unregisterDurationScaleChangeListener(DurationScaleChangeListener)
+     */
+    public interface DurationScaleChangeListener {
+        /**
+         * Called when the duration scale changes.
+         * @param scale the duration scale
+         */
+        void onChanged(@FloatRange(from = 0) float scale);
+    }
 }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 8f348a4..5eda587 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -872,7 +872,7 @@
     @UnsupportedAppUsage
     /*package*/ int mConfigChangeFlags;
     @UnsupportedAppUsage
-    /*package*/ Configuration mCurrentConfig;
+    /*package*/ Configuration mCurrentConfig = Configuration.EMPTY;
     private SearchManager mSearchManager;
     private MenuInflater mMenuInflater;
 
@@ -984,6 +984,8 @@
     private boolean mIsInMultiWindowMode;
     private boolean mIsInPictureInPictureMode;
 
+    private boolean mShouldDockBigOverlays;
+
     private UiTranslationController mUiTranslationController;
 
     private SplashScreen mSplashScreen;
@@ -2977,13 +2979,28 @@
      * <p> If specified, the system will try to respect the preference, but it may be
      * overridden by a user preference.
      *
-     * @param preferDockBigOverlays indicates that the activity prefers big overlays to be
-     *                              docked next to it instead of overlaying its content
+     * @param shouldDockBigOverlays indicates that big overlays should be docked next to the
+     *                              activity instead of overlay its content
      *
      * @see PictureInPictureParams.Builder#setExpandedAspectRatio
+     * @see #shouldDockBigOverlays
      */
-    public void setPreferDockBigOverlays(boolean preferDockBigOverlays) {
-        ActivityClient.getInstance().setPreferDockBigOverlays(mToken, preferDockBigOverlays);
+    public void setShouldDockBigOverlays(boolean shouldDockBigOverlays) {
+        ActivityClient.getInstance().setShouldDockBigOverlays(mToken, shouldDockBigOverlays);
+        mShouldDockBigOverlays = shouldDockBigOverlays;
+    }
+
+    /**
+     * Returns whether big overlays should be docked next to the activity as set by
+     * {@link #setShouldDockBigOverlays}.
+     *
+     * @return {@code true} if big overlays should be docked next to the activity instead
+     *         of overlay its content
+     *
+     * @see #setShouldDockBigOverlays
+     */
+    public boolean shouldDockBigOverlays() {
+        return mShouldDockBigOverlays;
     }
 
     void dispatchMovedToDisplay(int displayId, Configuration config) {
@@ -5663,7 +5680,6 @@
      * @throws ActivityNotFoundException &nbsp;
      * @hide
      */
-    @SystemApi
     @RequiresPermission(anyOf = {INTERACT_ACROSS_USERS, INTERACT_ACROSS_USERS_FULL})
     public void startActivityAsUser(@NonNull Intent intent,
             @Nullable Bundle options, @NonNull UserHandle user) {
@@ -5691,7 +5707,6 @@
      * their launch had come from the original activity.
      * @param intent The Intent to start.
      * @param options ActivityOptions or null.
-     * @param permissionToken Token received from the system that permits this call to be made.
      * @param ignoreTargetSecurity If true, the activity manager will not check whether the
      * caller it is doing the start is, is actually allowed to start the target activity.
      * If you set this to true, you must set an explicit component in the Intent and do any
@@ -5700,18 +5715,18 @@
      * @hide
      */
     public void startActivityAsCaller(Intent intent, @Nullable Bundle options,
-            IBinder permissionToken, boolean ignoreTargetSecurity, int userId) {
-        startActivityAsCaller(intent, options, permissionToken, ignoreTargetSecurity, userId, -1);
+            boolean ignoreTargetSecurity, int userId) {
+        startActivityAsCaller(intent, options, ignoreTargetSecurity, userId, -1);
     }
 
     /**
-     * @see #startActivityAsCaller(Intent, Bundle, IBinder, boolean, int)
+     * @see #startActivityAsCaller(Intent, Bundle, boolean, int)
      * @param requestCode The request code used for returning a result or -1 if no result should be
      *                    returned.
      * @hide
      */
     public void startActivityAsCaller(Intent intent, @Nullable Bundle options,
-            IBinder permissionToken, boolean ignoreTargetSecurity, int userId, int requestCode) {
+            boolean ignoreTargetSecurity, int userId, int requestCode) {
         if (mParent != null) {
             throw new RuntimeException("Can't be called from a child");
         }
@@ -5719,8 +5734,7 @@
         Instrumentation.ActivityResult ar =
                 mInstrumentation.execStartActivityAsCaller(
                         this, mMainThread.getApplicationThread(), mToken, this,
-                        intent, requestCode, options, permissionToken, ignoreTargetSecurity,
-                        userId);
+                        intent, requestCode, options, ignoreTargetSecurity, userId);
         if (ar != null) {
             mMainThread.sendActivityResult(
                     mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData());
@@ -8249,6 +8263,7 @@
                 .getWindowingMode();
         mIsInMultiWindowMode = inMultiWindowMode(windowingMode);
         mIsInPictureInPictureMode = windowingMode == WINDOWING_MODE_PINNED;
+        mShouldDockBigOverlays = getResources().getBoolean(R.bool.config_dockBigOverlayWindows);
         restoreHasCurrentPermissionRequest(icicle);
         if (persistentState != null) {
             onCreate(icicle, persistentState);
diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java
index cf8480c..7b7b1ef 100644
--- a/core/java/android/app/ActivityClient.java
+++ b/core/java/android/app/ActivityClient.java
@@ -324,9 +324,9 @@
         }
     }
 
-    void setPreferDockBigOverlays(IBinder token, boolean preferDockBigOverlays) {
+    void setShouldDockBigOverlays(IBinder token, boolean shouldDockBigOverlays) {
         try {
-            getActivityClientController().setPreferDockBigOverlays(token, preferDockBigOverlays);
+            getActivityClientController().setShouldDockBigOverlays(token, shouldDockBigOverlays);
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 9f15105..88844b5 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -22,6 +22,7 @@
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
 
 import android.Manifest;
+import android.annotation.ColorInt;
 import android.annotation.DrawableRes;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
@@ -185,6 +186,11 @@
      * @hide
      */
     public static final int INSTR_FLAG_ALWAYS_CHECK_SIGNATURE = 1 << 4;
+    /**
+     * Instrument Sdk Sandbox process that corresponds to the target package.
+     * @hide
+     */
+    public static final int INSTR_FLAG_INSTRUMENT_SDK_SANDBOX = 1 << 5;
 
     static final class UidObserver extends IUidObserver.Stub {
         final OnUidImportanceListener mListener;
@@ -1264,6 +1270,104 @@
         private int mMinWidth;
         private int mMinHeight;
 
+        /**
+         * Provides a convenient way to set the fields of a {@link TaskDescription} when creating a
+         * new instance.
+         */
+        public static final class Builder {
+            /**
+             * Default values for the TaskDescription
+             */
+            @Nullable
+            private String mLabel = null;
+            @DrawableRes
+            private int mIconRes = Resources.ID_NULL;
+            private int mPrimaryColor = 0;
+            private int mBackgroundColor = 0;
+            private int mStatusBarColor = 0;
+            private int mNavigationBarColor = 0;
+
+            /**
+             * Set the label to use in the TaskDescription.
+             * @param label A label and description of the current state of this activity.
+             * @return The same instance of the builder.
+             */
+            @NonNull
+            public Builder setLabel(@Nullable String label) {
+                this.mLabel = label;
+                return this;
+            }
+
+            /**
+             * Set the drawable resource of the icon to use in the TaskDescription.
+             * @param iconRes A drawable resource of an icon that represents the current state of
+             *                this activity.
+             * @return The same instance of the builder.
+             */
+            @NonNull
+            public Builder setIcon(@DrawableRes int iconRes) {
+                this.mIconRes = iconRes;
+                return this;
+            }
+
+            /**
+             * Set the primary color to use in the TaskDescription.
+             * @param color A color to override the theme's primary color. The color must be opaque.
+             * @return The same instance of the builder.
+             */
+            @NonNull
+            public Builder setPrimaryColor(@ColorInt int color) {
+                this.mPrimaryColor = color;
+                return this;
+            }
+
+            /**
+             * Set the background color to use in the TaskDescription.
+             * @param color A color to override the theme's background color. The color must be
+             *              opaque.
+             * @return The same instance of the builder.
+             */
+            @NonNull
+            public Builder setBackgroundColor(@ColorInt int color) {
+                this.mBackgroundColor = color;
+                return this;
+            }
+
+            /**
+             * Set the status bar color to use in the TaskDescription.
+             * @param color A color to override the theme's status bar color.
+             * @return The same instance of the builder.
+             */
+            @NonNull
+            public Builder setStatusBarColor(@ColorInt int color) {
+                this.mStatusBarColor = color;
+                return this;
+            }
+
+            /**
+             * Set the navigation bar color to use in the TaskDescription.
+             * @param color A color to override the theme's navigation bar color.
+             * @return The same instance of the builder.
+             */
+            @NonNull
+            public Builder setNavigationBarColor(@ColorInt int color) {
+                this.mNavigationBarColor = color;
+                return this;
+            }
+
+            /**
+             * Build the TaskDescription.
+             * @return the TaskDescription object.
+             */
+            @NonNull
+            public TaskDescription build() {
+                final Icon icon = mIconRes == Resources.ID_NULL ? null :
+                        Icon.createWithResource(ActivityThread.currentPackageName(), mIconRes);
+                return new TaskDescription(mLabel, icon, mPrimaryColor, mBackgroundColor,
+                        mStatusBarColor, mNavigationBarColor, false, false, RESIZE_MODE_RESIZEABLE,
+                        -1, -1, 0);
+            }
+        }
 
         /**
          * Creates the TaskDescription to the specified values.
@@ -1273,7 +1377,10 @@
          *                activity.
          * @param colorPrimary A color to override the theme's primary color.  This color must be
          *                     opaque.
+         *
+         * @deprecated Use {@link Builder} instead.
          */
+        @Deprecated
         public TaskDescription(String label, @DrawableRes int iconRes, int colorPrimary) {
             this(label, Icon.createWithResource(ActivityThread.currentPackageName(), iconRes),
                     colorPrimary, 0, 0, 0, false, false, RESIZE_MODE_RESIZEABLE, -1, -1, 0);
@@ -1288,7 +1395,10 @@
          * @param label A label and description of the current state of this activity.
          * @param iconRes A drawable resource of an icon that represents the current state of this
          *                activity.
+         *
+         * @deprecated Use {@link Builder} instead.
          */
+        @Deprecated
         public TaskDescription(String label, @DrawableRes int iconRes) {
             this(label, Icon.createWithResource(ActivityThread.currentPackageName(), iconRes),
                     0, 0, 0, 0, false, false, RESIZE_MODE_RESIZEABLE, -1, -1, 0);
@@ -1298,14 +1408,20 @@
          * Creates the TaskDescription to the specified values.
          *
          * @param label A label and description of the current state of this activity.
+         *
+         * @deprecated Use {@link Builder} instead.
          */
+        @Deprecated
         public TaskDescription(String label) {
             this(label, null, 0, 0, 0, 0, false, false, RESIZE_MODE_RESIZEABLE, -1, -1, 0);
         }
 
         /**
          * Creates an empty TaskDescription.
+         *
+         * @deprecated Use {@link Builder} instead.
          */
+        @Deprecated
         public TaskDescription() {
             this(null, null, 0, 0, 0, 0, false, false, RESIZE_MODE_RESIZEABLE, -1, -1, 0);
         }
@@ -1317,7 +1433,8 @@
          * @param icon An icon that represents the current state of this task.
          * @param colorPrimary A color to override the theme's primary color.  This color must be
          *                     opaque.
-         * @deprecated use TaskDescription constructor with icon resource instead
+         *
+         * @deprecated Use {@link Builder} instead.
          */
         @Deprecated
         public TaskDescription(String label, Bitmap icon, int colorPrimary) {
@@ -1333,7 +1450,8 @@
          *
          * @param label A label and description of the current state of this activity.
          * @param icon An icon that represents the current state of this activity.
-         * @deprecated use TaskDescription constructor with icon resource instead
+         *
+         * @deprecated Use {@link Builder} instead.
          */
         @Deprecated
         public TaskDescription(String label, Bitmap icon) {
@@ -1635,15 +1753,15 @@
         /**
          * @return The color override on the theme's primary color.
          */
+        @ColorInt
         public int getPrimaryColor() {
             return mColorPrimary;
         }
 
         /**
-         * @return The background color.
-         * @hide
+         * @return The color override on the theme's background color.
          */
-        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+        @ColorInt
         public int getBackgroundColor() {
             return mColorBackground;
         }
@@ -1657,15 +1775,17 @@
         }
 
         /**
-         * @hide
+         * @return The color override on the theme's status bar color.
          */
+        @ColorInt
         public int getStatusBarColor() {
             return mStatusBarColor;
         }
 
         /**
-         * @hide
+         * @return The color override on the theme's navigation bar color.
          */
+        @ColorInt
         public int getNavigationBarColor() {
             return mNavigationBarColor;
         }
@@ -4355,23 +4475,6 @@
     }
 
     /**
-     * Logs out current current foreground user by switching to the system user and stopping the
-     * user being switched from.
-     * @hide
-     */
-    public static void logoutCurrentUser() {
-        int currentUser = ActivityManager.getCurrentUser();
-        if (currentUser != UserHandle.USER_SYSTEM) {
-            try {
-                getService().switchUser(UserHandle.USER_SYSTEM);
-                getService().stopUser(currentUser, /* force= */ false, null);
-            } catch (RemoteException e) {
-                e.rethrowFromSystemServer();
-            }
-        }
-    }
-
-    /**
      * Stops the given {@code userId}.
      *
      * @hide
@@ -4787,6 +4890,11 @@
     }
 
     /** @hide */
+    public static boolean isProcStateConsideredInteraction(@ProcessState int procState) {
+        return (procState <= PROCESS_STATE_TOP || procState == PROCESS_STATE_BOUND_TOP);
+    }
+
+    /** @hide */
     public static String procStateToString(int procState) {
         final String procStateStr;
         switch (procState) {
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 9fe8e79..95ac799 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -630,8 +630,9 @@
     /**
      * Delete uid from the ActivityManagerService PendingStartActivityUids list.
      * @param uid uid
+     * @param nowElapsed starting time of updateOomAdj
      */
-    public abstract void deletePendingTopUid(int uid);
+    public abstract void deletePendingTopUid(int uid, long nowElapsed);
 
     /**
      * Is the uid in ActivityManagerService PendingStartActivityUids list?
@@ -684,6 +685,11 @@
     public abstract @TempAllowListType int getPushMessagingOverQuotaBehavior();
 
     /**
+     * Return the startForeground() grace period after calling startForegroundService().
+     */
+    public abstract int getServiceStartForegroundTimeout();
+
+    /**
      * Returns the capability of the given uid
      */
     public abstract @ProcessCapability int getUidCapability(int uid);
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 0178fa1..0f54ce5 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -361,6 +361,10 @@
     private static final String KEY_LAUNCH_INTO_PIP_PARAMS =
             "android.activity.launchIntoPipParams";
 
+    /** See {@link #setDismissKeyguardIfInsecure()}. */
+    private static final String KEY_DISMISS_KEYGUARD_IF_INSECURE =
+            "android.activity.dismissKeyguardIfInsecure";
+
     /**
      * @see #setLaunchCookie
      * @hide
@@ -457,6 +461,7 @@
     private boolean mLaunchedFromBubble;
     private boolean mTransientLaunch;
     private PictureInPictureParams mLaunchIntoPipParams;
+    private boolean mDismissKeyguardIfInsecure;
 
     /**
      * Create an ActivityOptions specifying a custom animation to run when
@@ -1162,6 +1167,7 @@
             case ANIM_CUSTOM:
                 mCustomEnterResId = opts.getInt(KEY_ANIM_ENTER_RES_ID, 0);
                 mCustomExitResId = opts.getInt(KEY_ANIM_EXIT_RES_ID, 0);
+                mCustomBackgroundColor = opts.getInt(KEY_ANIM_BACKGROUND_COLOR, 0);
                 mAnimationStartedListener = IRemoteCallback.Stub.asInterface(
                         opts.getBinder(KEY_ANIM_START_LISTENER));
                 break;
@@ -1253,6 +1259,7 @@
         mLaunchIntoPipParams = opts.getParcelable(KEY_LAUNCH_INTO_PIP_PARAMS);
         mIsEligibleForLegacyPermissionPrompt =
                 opts.getBoolean(KEY_LEGACY_PERMISSION_PROMPT_ELIGIBLE);
+        mDismissKeyguardIfInsecure = opts.getBoolean(KEY_DISMISS_KEYGUARD_IF_INSECURE);
     }
 
     /**
@@ -1849,6 +1856,27 @@
     }
 
     /**
+     * Sets whether the insecure keyguard should go away when this activity launches. In case the
+     * keyguard is secure, this option will be ignored.
+     *
+     * @see Activity#setShowWhenLocked(boolean)
+     * @see android.R.attr#showWhenLocked
+     * @hide
+     */
+    public void setDismissKeyguardIfInsecure() {
+        mDismissKeyguardIfInsecure = true;
+    }
+
+    /**
+     * @see #setDismissKeyguardIfInsecure()
+     * @return whether the insecure keyguard should go away when the activity launches.
+     * @hide
+     */
+    public boolean getDismissKeyguardIfInsecure() {
+        return mDismissKeyguardIfInsecure;
+    }
+
+    /**
      * Update the current values in this ActivityOptions from those supplied
      * in <var>otherOptions</var>.  Any values
      * defined in <var>otherOptions</var> replace those in the base options.
@@ -2109,6 +2137,9 @@
             b.putBoolean(KEY_LEGACY_PERMISSION_PROMPT_ELIGIBLE,
                     mIsEligibleForLegacyPermissionPrompt);
         }
+        if (mDismissKeyguardIfInsecure) {
+            b.putBoolean(KEY_DISMISS_KEYGUARD_IF_INSECURE, mDismissKeyguardIfInsecure);
+        }
         return b;
     }
 
diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java
index a836625..6fc0c26 100644
--- a/core/java/android/app/ActivityTaskManager.java
+++ b/core/java/android/app/ActivityTaskManager.java
@@ -106,14 +106,6 @@
             RESIZE_MODE_PRESERVE_WINDOW | RESIZE_MODE_FORCED;
 
     /**
-     * Extra included on intents that are delegating the call to
-     * ActivityManager#startActivityAsCaller to another app.  This token is necessary for that call
-     * to succeed.  Type is IBinder.
-     * @hide
-     */
-    public static final String EXTRA_PERMISSION_TOKEN = "android.app.extra.PERMISSION_TOKEN";
-
-    /**
      * Extra included on intents that contain an EXTRA_INTENT, with options that the contained
      * intent may want to be started with.  Type is Bundle.
      * TODO: remove once the ChooserActivity moves to systemui
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 64f0301..3b843a9 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -868,6 +868,7 @@
         String processName;
         @UnsupportedAppUsage
         ApplicationInfo appInfo;
+        String sdkSandboxClientAppPackage;
         @UnsupportedAppUsage
         List<ProviderInfo> providers;
         ComponentName instrumentationName;
@@ -1113,9 +1114,9 @@
 
         @Override
         public final void bindApplication(String processName, ApplicationInfo appInfo,
-                ProviderInfoList providerList, ComponentName instrumentationName,
-                ProfilerInfo profilerInfo, Bundle instrumentationArgs,
-                IInstrumentationWatcher instrumentationWatcher,
+                String sdkSandboxClientAppPackage, ProviderInfoList providerList,
+                ComponentName instrumentationName, ProfilerInfo profilerInfo,
+                Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,
                 IUiAutomationConnection instrumentationUiConnection, int debugMode,
                 boolean enableBinderTracking, boolean trackAllocation,
                 boolean isRestrictedBackupMode, boolean persistent, Configuration config,
@@ -1155,6 +1156,7 @@
             AppBindData data = new AppBindData();
             data.processName = processName;
             data.appInfo = appInfo;
+            data.sdkSandboxClientAppPackage = sdkSandboxClientAppPackage;
             data.providers = providerList.getList();
             data.instrumentationName = instrumentationName;
             data.instrumentationArgs = instrumentationArgs;
@@ -3587,7 +3589,7 @@
         }
 
         try {
-            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
+            Application app = r.packageInfo.makeApplicationInner(false, mInstrumentation);
 
             if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
             if (localLOGV) Slog.v(
@@ -4286,7 +4288,7 @@
         BroadcastReceiver receiver;
         ContextImpl context;
         try {
-            app = packageInfo.makeApplication(false, mInstrumentation);
+            app = packageInfo.makeApplicationInner(false, mInstrumentation);
             context = (ContextImpl) app.getBaseContext();
             if (data.info.splitName != null) {
                 context = (ContextImpl) context.createContextForSplit(data.info.splitName);
@@ -4475,7 +4477,7 @@
         try {
             if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
 
-            Application app = packageInfo.makeApplication(false, mInstrumentation);
+            Application app = packageInfo.makeApplicationInner(false, mInstrumentation);
 
             final java.lang.ClassLoader cl;
             if (data.info.splitName != null) {
@@ -5883,19 +5885,17 @@
         final boolean movedToDifferentDisplay = isDifferentDisplay(activity.getDisplayId(),
                 displayId);
         final Configuration currentConfig = activity.mCurrentConfig;
-        final int diff = (currentConfig == null) ? 0xffffffff
-                : currentConfig.diffPublicOnly(newConfig);
+        final int diff = currentConfig.diffPublicOnly(newConfig);
         final boolean hasPublicConfigChange = diff != 0;
+        final ActivityClientRecord r = getActivityClient(activityToken);
         // TODO(b/173090263): Use diff instead after the improvement of AssetManager and
         // ResourcesImpl constructions.
         final boolean shouldUpdateResources = hasPublicConfigChange
                 || shouldUpdateResources(activityToken, currentConfig, newConfig, amOverrideConfig,
                 movedToDifferentDisplay, hasPublicConfigChange);
-        final boolean shouldReportChange = hasPublicConfigChange
-                // If this activity doesn't handle any of the config changes, then don't bother
-                // calling onConfigurationChanged. Otherwise, report to the activity for the
-                // changes.
-                && (~activity.mActivityInfo.getRealConfigChanged() & diff) == 0;
+        final boolean shouldReportChange = shouldReportChange(diff, currentConfig, newConfig,
+                r != null ? r.mSizeConfigurations : null,
+                activity.mActivityInfo.getRealConfigChanged());
         // Nothing significant, don't proceed with updating and reporting.
         if (!shouldUpdateResources) {
             return null;
@@ -5942,6 +5942,40 @@
         return configToReport;
     }
 
+    /**
+     * Returns {@code true} if {@link Activity#onConfigurationChanged(Configuration)} should be
+     * dispatched.
+     *
+     * @param publicDiff Usually computed by {@link Configuration#diffPublicOnly(Configuration)}.
+     *                   This parameter is to prevent we compute it again.
+     * @param currentConfig The current configuration cached in {@link Activity#mCurrentConfig}.
+     *                      It is {@code null} before the first config update from the server side.
+     * @param newConfig The updated {@link Configuration}
+     * @param sizeBuckets The Activity's {@link SizeConfigurationBuckets} if not {@code null}
+     * @param handledConfigChanges Bit mask of configuration changes that the activity can handle
+     * @return {@code true} if the config change should be reported to the Activity
+     */
+    @VisibleForTesting
+    public static boolean shouldReportChange(int publicDiff, @Nullable Configuration currentConfig,
+            @NonNull Configuration newConfig, @Nullable SizeConfigurationBuckets sizeBuckets,
+            int handledConfigChanges) {
+        // Don't report the change if there's no public diff between current and new config.
+        if (publicDiff == 0) {
+            return false;
+        }
+        final int diffWithBucket = SizeConfigurationBuckets.filterDiff(publicDiff, currentConfig,
+                newConfig, sizeBuckets);
+        // Compare to the diff which filter the change without crossing size buckets with
+        // {@code handledConfigChanges}. The small changes should not block Activity to receive
+        // its handled config updates. Also, if Activity handles all small changes, we should
+        // dispatch the updated config to it.
+        final int diff = diffWithBucket != 0 ? diffWithBucket : publicDiff;
+        // If this activity doesn't handle any of the config changes, then don't bother
+        // calling onConfigurationChanged. Otherwise, report to the activity for the
+        // changes.
+        return (~handledConfigChanges & diff) == 0;
+    }
+
     public final void applyConfigurationToResources(Configuration config) {
         synchronized (mResourcesManager) {
             mResourcesManager.applyConfigurationToResources(config, null);
@@ -6536,6 +6570,9 @@
         }
 
         data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
+        if (data.sdkSandboxClientAppPackage != null) {
+            data.info.setSdkSandboxStorage(data.sdkSandboxClientAppPackage);
+        }
 
         if (agent != null) {
             handleAttachAgent(agent, data.info);
@@ -6695,7 +6732,7 @@
         try {
             // If the app is being launched for full backup or restore, bring it up in
             // a restricted environment with the base application class.
-            app = data.info.makeApplication(data.restrictedBackupMode, null);
+            app = data.info.makeApplicationInner(data.restrictedBackupMode, null);
 
             // Propagate autofill compat state
             app.setAutofillOptions(data.autofillOptions);
@@ -7565,7 +7602,7 @@
                 mInstrumentation.basicInit(this);
                 ContextImpl context = ContextImpl.createAppContext(
                         this, getSystemContext().mPackageInfo);
-                mInitialApplication = context.mPackageInfo.makeApplication(true, null);
+                mInitialApplication = context.mPackageInfo.makeApplicationInner(true, null);
                 mInitialApplication.onCreate();
             } catch (Exception e) {
                 throw new RuntimeException(
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 7c7c7ef..4829dc0 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -2367,7 +2367,7 @@
             null, // no permission for OP_WRITE_MEDIA_AUDIO
             Manifest.permission.READ_MEDIA_VIDEO,
             null, // no permission for OP_WRITE_MEDIA_VIDEO
-            Manifest.permission.READ_MEDIA_IMAGE,
+            Manifest.permission.READ_MEDIA_IMAGES,
             null, // no permission for OP_WRITE_MEDIA_IMAGES
             null, // no permission for OP_LEGACY_STORAGE
             null, // no permission for OP_ACCESS_ACCESSIBILITY
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index dca5c54..d641a3b 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -18,9 +18,9 @@
 
 import static android.app.admin.DevicePolicyResources.Drawables.Style.SOLID_COLORED;
 import static android.app.admin.DevicePolicyResources.Drawables.Style.SOLID_NOT_COLORED;
-import static android.app.admin.DevicePolicyResources.Drawables.UNDEFINED;
 import static android.app.admin.DevicePolicyResources.Drawables.WORK_PROFILE_ICON;
 import static android.app.admin.DevicePolicyResources.Drawables.WORK_PROFILE_ICON_BADGE;
+import static android.app.admin.DevicePolicyResources.UNDEFINED;
 import static android.content.pm.Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256;
 import static android.content.pm.Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA512;
 import static android.content.pm.Checksum.TYPE_WHOLE_MD5;
@@ -1886,7 +1886,7 @@
             return icon;
         }
 
-        final Drawable badgeForeground = getDevicePolicyManager().getDrawable(
+        final Drawable badgeForeground = getDevicePolicyManager().getResources().getDrawable(
                 getUpdatableUserIconBadgeId(user),
                 SOLID_COLORED,
                 () -> getDefaultUserIconBadge(user));
@@ -1938,11 +1938,12 @@
             return null;
         }
 
-        final Drawable badgeForeground = getDevicePolicyManager().getDrawableForDensity(
-                getUpdatableUserBadgeId(user),
-                SOLID_COLORED,
-                density,
-                () -> getDefaultUserBadgeForDensity(user, density));
+        final Drawable badgeForeground = getDevicePolicyManager().getResources()
+                .getDrawableForDensity(
+                        getUpdatableUserBadgeId(user),
+                        SOLID_COLORED,
+                        density,
+                        () -> getDefaultUserBadgeForDensity(user, density));
 
         badgeForeground.setTint(getUserBadgeColor(user, false));
         Drawable badge = new LayerDrawable(new Drawable[] {badgeColor, badgeForeground });
@@ -1968,7 +1969,7 @@
             return null;
         }
 
-        final Drawable badge = getDevicePolicyManager().getDrawableForDensity(
+        final Drawable badge = getDevicePolicyManager().getResources().getDrawableForDensity(
                 getUpdatableUserBadgeId(user),
                 SOLID_NOT_COLORED,
                 density,
@@ -3832,4 +3833,13 @@
             throw re.rethrowAsRuntimeException();
         }
     }
+
+    @Override
+    public void makeUidVisible(int recipientUid, int visibleUid) {
+        try {
+            mPM.makeUidVisible(recipientUid, visibleUid);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
 }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index a3dd705a..ac46066 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -77,6 +77,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.storage.StorageManager;
+import android.permission.PermissionControllerManager;
 import android.permission.PermissionManager;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -216,6 +217,12 @@
     @UnsupportedAppUsage
     private @Nullable ClassLoader mClassLoader;
 
+    /**
+     * The {@link com.android.server.wm.WindowToken} representing this instance if it is
+     * {@link #CONTEXT_TYPE_WINDOW_CONTEXT} or {@link #CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI}.
+     * If the type is {@link #CONTEXT_TYPE_ACTIVITY}, then represents the
+     * {@link android.window.WindowContainerToken} of the activity.
+     */
     private final @Nullable IBinder mToken;
 
     private final @NonNull UserHandle mUser;
@@ -1998,7 +2005,7 @@
     private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
             String instanceName, Handler handler, Executor executor, UserHandle user) {
         // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser and
-        // ActivityManagerLocal.bindSupplementalProcessService
+        // ActivityManagerLocal.bindSdkSandboxService
         IServiceConnection sd;
         if (conn == null) {
             throw new IllegalArgumentException("connection is null");
@@ -2180,8 +2187,9 @@
     }
 
     @Override
-    public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
-        getSystemService(PermissionManager.class).revokeOwnPermissionsOnKill(permissions);
+    public void revokeSelfPermissionsOnKill(@NonNull Collection<String> permissions) {
+        getSystemService(PermissionControllerManager.class).revokeSelfPermissionsOnKill(
+                getPackageName(), new ArrayList<String>(permissions));
     }
 
     @Override
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 82ff42b..a763b14 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -465,7 +465,8 @@
                     onBackPressed();
                 }
             };
-            getOnBackInvokedDispatcher().registerSystemOnBackInvokedCallback(mDefaultBackCallback);
+            getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
+                    OnBackInvokedDispatcher.PRIORITY_DEFAULT, mDefaultBackCallback);
             mDefaultBackCallback = null;
         }
     }
diff --git a/core/java/android/app/GameManager.java b/core/java/android/app/GameManager.java
index 6f49c9e..a138fa1 100644
--- a/core/java/android/app/GameManager.java
+++ b/core/java/android/app/GameManager.java
@@ -191,7 +191,7 @@
      */
     @TestApi
     @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
-    public @GameMode boolean isAngleEnabled(@NonNull String packageName) {
+    public boolean isAngleEnabled(@NonNull String packageName) {
         try {
             return mService.isAngleEnabled(packageName, mContext.getUserId());
         } catch (RemoteException e) {
diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl
index caf1c41b7..1307161 100644
--- a/core/java/android/app/IActivityClientController.aidl
+++ b/core/java/android/app/IActivityClientController.aidl
@@ -88,7 +88,7 @@
 
     boolean enterPictureInPictureMode(in IBinder token, in PictureInPictureParams params);
     void setPictureInPictureParams(in IBinder token, in PictureInPictureParams params);
-    oneway void setPreferDockBigOverlays(in IBinder token, in boolean preferDockBigOverlays);
+    oneway void setShouldDockBigOverlays(in IBinder token, in boolean shouldDockBigOverlays);
     void toggleFreeformWindowingMode(in IBinder token);
 
     oneway void startLockTaskModeByToken(in IBinder token);
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index fe0edfe..49a6158 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -449,7 +449,7 @@
 
     void requestInteractiveBugReport();
     void requestFullBugReport();
-    void requestRemoteBugReport();
+    void requestRemoteBugReport(long nonce);
     boolean launchBugReportHandlerApp();
     List<String> getBugreportWhitelistedPackages();
 
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index ef9a2f2..87b2417 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -141,7 +141,7 @@
     int startActivityAsCaller(in IApplicationThread caller, in String callingPackage,
             in Intent intent, in String resolvedType, in IBinder resultTo, in String resultWho,
             int requestCode, int flags, in ProfilerInfo profilerInfo, in Bundle options,
-            IBinder permissionToken, boolean ignoreTargetSecurity, int userId);
+            boolean ignoreTargetSecurity, int userId);
 
     boolean isActivityStartAllowedOnDisplay(int displayId, in Intent intent, in String resolvedType,
             int userId);
@@ -182,18 +182,6 @@
     int addAppTask(in IBinder activityToken, in Intent intent,
             in ActivityManager.TaskDescription description, in Bitmap thumbnail);
     Point getAppTaskThumbnailSize();
-    /**
-     * Only callable from the system. This token grants a temporary permission to call
-     * #startActivityAsCaller. The token will time out after START_AS_CALLER_TOKEN_TIMEOUT
-     * if it is not used.
-     *
-     * @param componentName The component name of the delegated component that is allowed to
-     *                      call #startActivityAsCaller with the returned token.
-     *
-     * @return Returns a token that can be given to a "delegate" app that may call
-     *         #startActivityAsCaller
-     */
-    IBinder requestStartActivityPermissionToken(in ComponentName componentName);
 
     oneway void releaseSomeActivities(in IApplicationThread app);
     Bitmap getTaskDescriptionIcon(in String filename, int userId);
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index 77657d5..f4fbcce 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -72,6 +72,7 @@
     @UnsupportedAppUsage
     void scheduleStopService(IBinder token);
     void bindApplication(in String packageName, in ApplicationInfo info,
+            in String sdkSandboxClientAppPackage,
             in ProviderInfoList providerList, in ComponentName testName,
             in ProfilerInfo profilerInfo, in Bundle testArguments,
             IInstrumentationWatcher testWatcher, IUiAutomationConnection uiAutomationConnection,
diff --git a/core/java/android/app/ILocaleManager.aidl b/core/java/android/app/ILocaleManager.aidl
index 348cb2d..3002c8b 100644
--- a/core/java/android/app/ILocaleManager.aidl
+++ b/core/java/android/app/ILocaleManager.aidl
@@ -40,4 +40,9 @@
       */
      LocaleList getApplicationLocales(String packageName, int userId);
 
+     /**
+       * Returns the current system locales.
+       */
+     LocaleList getSystemLocales();
+
  }
\ No newline at end of file
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index e0c69df..995a9f3 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -381,6 +381,10 @@
      * Force the global system in or out of touch mode. This can be used if your
      * instrumentation relies on the UI being in one more or the other when it starts.
      *
+     * <p><b>Note:</b> Starting from Android {@link Build.VERSION_CODES#TIRAMISU}, this method
+     * will only take effect if the instrumentation was sourced from a process with
+     * {@code MODIFY_TOUCH_MODE_STATE} internal permission granted (shell already have it).
+     *
      * @param inTouch Set to true to be in touch mode, false to be in focus mode.
      */
     public void setInTouchMode(boolean inTouch) {
@@ -393,6 +397,15 @@
     }
 
     /**
+     * Resets the {@link #setInTouchMode touch mode} to the device default.
+     */
+    public void resetInTouchMode() {
+        final boolean defaultInTouchMode = getContext().getResources().getBoolean(
+                com.android.internal.R.bool.config_defaultInTouchMode);
+        setInTouchMode(defaultInTouchMode);
+    }
+
+    /**
      * Schedule a callback for when the application's main thread goes idle
      * (has no more events to process).
      *
@@ -1986,7 +1999,7 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public ActivityResult execStartActivityAsCaller(
             Context who, IBinder contextThread, IBinder token, Activity target,
-            Intent intent, int requestCode, Bundle options, IBinder permissionToken,
+            Intent intent, int requestCode, Bundle options,
             boolean ignoreTargetSecurity, int userId) {
         IApplicationThread whoThread = (IApplicationThread) contextThread;
         if (mActivityMonitors != null) {
@@ -2021,7 +2034,7 @@
                     .startActivityAsCaller(whoThread, who.getOpPackageName(), intent,
                             intent.resolveTypeIfNeeded(who.getContentResolver()),
                             token, target != null ? target.mEmbeddedID : null,
-                            requestCode, 0, null, options, permissionToken,
+                            requestCode, 0, null, options,
                             ignoreTargetSecurity, userId);
             checkStartActivityResult(result, intent);
         } catch (RemoteException e) {
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index cedf483e..e9c29b8 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -1103,9 +1103,12 @@
     }
 
     /**
-     * Registers a listener to execute when the keyguard visibility changes.
+     * Registers a listener to execute when the keyguard locked state changes.
      *
-     * @param listener The listener to add to receive keyguard visibility changes.
+     * @param listener The listener to add to receive keyguard locked state changes.
+     *
+     * @see #isKeyguardLocked()
+     * @see #removeKeyguardLockedStateListener(KeyguardLockedStateListener)
      */
     @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
     public void addKeyguardLockedStateListener(@NonNull @CallbackExecutor Executor executor,
@@ -1124,7 +1127,12 @@
     }
 
     /**
-     * Unregisters a listener that executes when the keyguard visibility changes.
+     * Unregisters a listener that executes when the keyguard locked state changes.
+     *
+     * @param listener The listener to remove.
+     *
+     * @see #isKeyguardLocked()
+     * @see #addKeyguardLockedStateListener(Executor, KeyguardLockedStateListener)
      */
     @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
     public void removeKeyguardLockedStateListener(@NonNull KeyguardLockedStateListener listener) {
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index cf259e57..deefea8 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -37,6 +37,7 @@
 import android.content.res.Resources;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.Environment;
 import android.os.FileUtils;
 import android.os.GraphicsEnvironment;
 import android.os.Handler;
@@ -411,6 +412,26 @@
         }
     }
 
+    /** @hide */
+    void setSdkSandboxStorage(String sdkSandboxClientAppPackage) {
+        int userId = UserHandle.myUserId();
+        mDeviceProtectedDataDirFile = Environment
+                .getDataMiscDeSharedSdkSandboxDirectory(userId, sdkSandboxClientAppPackage)
+                .getAbsoluteFile();
+        mCredentialProtectedDataDirFile = Environment
+                .getDataMiscCeSharedSdkSandboxDirectory(userId, sdkSandboxClientAppPackage)
+                .getAbsoluteFile();
+
+        if ((mApplicationInfo.privateFlags
+                & ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) != 0
+                && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
+            mDataDirFile = mDeviceProtectedDataDirFile;
+        } else {
+            mDataDirFile = mCredentialProtectedDataDirFile;
+        }
+        mDataDir = mDataDirFile.getAbsolutePath();
+    }
+
     public static void makePaths(ActivityThread activityThread,
                                  ApplicationInfo aInfo,
                                  List<String> outZipPaths) {
@@ -1352,9 +1373,28 @@
         return mResources;
     }
 
+    /**
+     * This is for 3p apps accessing this hidden API directly... in which case, we don't return
+     * the cached Application instance.
+     */
     @UnsupportedAppUsage
     public Application makeApplication(boolean forceDefaultAppClass,
             Instrumentation instrumentation) {
+        return makeApplicationInner(forceDefaultAppClass, instrumentation,
+                /* allowDuplicateInstances= */ true);
+    }
+
+    /**
+     * This is for all the (internal) callers, for which we do return the cached instance.
+     */
+    public Application makeApplicationInner(boolean forceDefaultAppClass,
+            Instrumentation instrumentation) {
+        return makeApplicationInner(forceDefaultAppClass, instrumentation,
+                /* allowDuplicateInstances= */ false);
+    }
+
+    private Application makeApplicationInner(boolean forceDefaultAppClass,
+            Instrumentation instrumentation, boolean allowDuplicateInstances) {
         if (mApplication != null) {
             return mApplication;
         }
@@ -1366,11 +1406,15 @@
                 // Looks like this is always happening for the system server, because
                 // the LoadedApk created in systemMain() -> attach() isn't cached properly?
                 if (!"android".equals(mPackageName)) {
-                    Slog.wtf(TAG, "App instance already created for package=" + mPackageName
+                    Slog.wtfStack(TAG, "App instance already created for package=" + mPackageName
                             + " instance=" + cached);
                 }
-                mApplication = cached;
-                return cached;
+                if (!allowDuplicateInstances) {
+                    mApplication = cached;
+                    return cached;
+                }
+                // Some apps intentionally call makeApplication() to create a new Application
+                // instance... Sigh...
             }
         }
 
@@ -1421,8 +1465,10 @@
         }
         mActivityThread.mAllApplications.add(app);
         mApplication = app;
-        synchronized (sApplications) {
-            sApplications.put(mPackageName, app);
+        if (!allowDuplicateInstances) {
+            synchronized (sApplications) {
+                sApplications.put(mPackageName, app);
+            }
         }
 
         if (instrumentation != null) {
diff --git a/core/java/android/app/LocaleManager.java b/core/java/android/app/LocaleManager.java
index 522dc84..efe9e35 100644
--- a/core/java/android/app/LocaleManager.java
+++ b/core/java/android/app/LocaleManager.java
@@ -18,7 +18,6 @@
 
 import android.Manifest;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
@@ -127,6 +126,26 @@
     }
 
     /**
+     * Returns the current system locales, ignoring app-specific overrides.
+     *
+     * <p><b>Note:</b> Apps should generally access the user's locale preferences as indicated in
+     * their in-process {@link LocaleList}s. However, in case an app-specific locale is set, this
+     * method helps cater to rare use-cases which might require specifically knowing the system
+     * locale.
+     *
+     * <p><b>Note:</b> This API is not user-aware. It returns the system locales for the foreground
+     * user.
+     */
+    @NonNull
+    public LocaleList getSystemLocales() {
+        try {
+            return mService.getSystemLocales();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Sets the current system locales to the provided value.
      *
      * @hide
@@ -142,19 +161,4 @@
         }
     }
 
-    /**
-     * Returns the current system locales for the device.
-     *
-     * @hide
-     */
-    @TestApi
-    @Nullable
-    public LocaleList getSystemLocales() {
-        try {
-            return ActivityManager.getService().getConfiguration().getLocales();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
 }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 7e0cea89..6e1d1cd 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -19,8 +19,8 @@
 import static android.annotation.Dimension.DP;
 import static android.app.admin.DevicePolicyResources.Drawables.Source.NOTIFICATION;
 import static android.app.admin.DevicePolicyResources.Drawables.Style.SOLID_COLORED;
-import static android.app.admin.DevicePolicyResources.Drawables.UNDEFINED;
 import static android.app.admin.DevicePolicyResources.Drawables.WORK_PROFILE_ICON;
+import static android.app.admin.DevicePolicyResources.UNDEFINED;
 import static android.graphics.drawable.Icon.TYPE_URI;
 import static android.graphics.drawable.Icon.TYPE_URI_ADAPTIVE_BITMAP;
 
@@ -5079,7 +5079,7 @@
             // Note: This assumes that the current user can read the profile badge of the
             // originating user.
             DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
-            return dpm.getDrawable(
+            return dpm.getResources().getDrawable(
                     getUpdatableProfileBadgeId(), SOLID_COLORED, NOTIFICATION,
                     this::getDefaultProfileBadgeDrawable);
         }
diff --git a/core/java/android/app/PictureInPictureParams.java b/core/java/android/app/PictureInPictureParams.java
index 2d2788c..3f1844e 100644
--- a/core/java/android/app/PictureInPictureParams.java
+++ b/core/java/android/app/PictureInPictureParams.java
@@ -280,7 +280,7 @@
     private Rational mAspectRatio;
 
     /**
-     * The expected aspect ratio of the vertically expanded picture-in-picture window.
+     * The expected aspect ratio of the expanded picture-in-picture window.
      */
     @Nullable
     private Rational mExpandedAspectRatio;
@@ -441,15 +441,21 @@
      * @hide
      */
     @TestApi
-    public float getAspectRatio() {
+    public float getAspectRatioFloat() {
         if (mAspectRatio != null) {
             return mAspectRatio.floatValue();
         }
         return 0f;
     }
 
-    /** @hide */
-    public Rational getAspectRatioRational() {
+    /**
+     * Returns the expected aspect ratio of the picture-in-picture window.
+     *
+     * @return aspect ratio as the desired width / height or {@code null} if not set.
+     * @see PictureInPictureParams.Builder#setAspectRatio(Rational)
+     */
+    @Nullable
+    public Rational getAspectRatio() {
         return mAspectRatio;
     }
 
@@ -466,7 +472,7 @@
      * @hide
      */
     @TestApi
-    public float getExpandedAspectRatio() {
+    public float getExpandedAspectRatioFloat() {
         if (mExpandedAspectRatio != null) {
             return mExpandedAspectRatio.floatValue();
         }
@@ -474,6 +480,17 @@
     }
 
     /**
+     * Returns the desired aspect ratio of the expanded picture-in-picture window.
+     *
+     * @return aspect ratio as the desired width / height or {@code null} if not set.
+     * @see PictureInPictureParams.Builder#setExpandedAspectRatio(Rational)
+     */
+    @Nullable
+    public Rational getExpandedAspectRatio() {
+        return mExpandedAspectRatio;
+    }
+
+    /**
      * @return whether the expanded aspect ratio is set
      * @hide
      */
@@ -482,11 +499,17 @@
     }
 
     /**
-     * @return the set of user actions.
-     * @hide
+     * Returns the list of user actions that are associated with the activity when in
+     * picture-in-picture mode.
+     *
+     * @return the user actions in a new list.
+     * @see PictureInPictureParams.Builder#setActions(List)
      */
-    @TestApi
+    @NonNull
     public List<RemoteAction> getActions() {
+        if (mUserActions == null) {
+            return new ArrayList<>();
+        }
         return mUserActions;
     }
 
@@ -499,10 +522,11 @@
     }
 
     /**
-     * @return the close action.
-     * @hide
+     * Returns the action that is to replace the system close action.
+     *
+     * @return the close action or {@code null} if not set.
+     * @see PictureInPictureParams.Builder#setCloseAction(RemoteAction)
      */
-    @TestApi
     @Nullable
     public RemoteAction getCloseAction() {
         return mCloseAction;
@@ -528,10 +552,12 @@
     }
 
     /**
-     * @return the source rect hint
-     * @hide
+     * Returns the source rect hint.
+     *
+     * @return the source rect hint also known as launch bounds or {@code null} if not set.
+     * @see PictureInPictureParams.Builder#setSourceRectHint(Rect)
      */
-    @TestApi
+    @Nullable
     public Rect getSourceRectHint() {
         return mSourceRectHint;
     }
@@ -545,18 +571,23 @@
     }
 
     /**
-     * @return whether auto pip is enabled.
-     * @hide
+     * Returns whether auto enter picture-in-picture is enabled.
+     *
+     * @return {@code true} if the system will automatically put the activity in
+     * picture-in-picture mode.
+     * @see PictureInPictureParams.Builder#setAutoEnterEnabled(boolean)
      */
     public boolean isAutoEnterEnabled() {
         return mAutoEnterEnabled == null ? false : mAutoEnterEnabled;
     }
 
     /**
-     * @return whether seamless resize is enabled.
-     * @hide
+     * Returns whether seamless resize is enabled.
+     *
+     * @return true if the system can seamlessly resize the window while activity is in
+     * picture-in-picture mode.
+     * @see PictureInPictureParams.Builder#setSeamlessResizeEnabled(boolean)
      */
-    @TestApi
     public boolean isSeamlessResizeEnabled() {
         return mSeamlessResizeEnabled == null ? true : mSeamlessResizeEnabled;
     }
@@ -570,10 +601,11 @@
     }
 
     /**
-     * @return title of the pip.
-     * @hide
+     * Returns the title of the picture-in-picture window that may be displayed to the user.
+     *
+     * @return title of the picture-in-picture window.
+     * @see PictureInPictureParams.Builder#setTitle(CharSequence)
      */
-    @TestApi
     @Nullable
     public CharSequence getTitle() {
         return mTitle;
@@ -588,10 +620,11 @@
     }
 
     /**
-     * @return subtitle of the pip.
-     * @hide
+     * Returns the subtitle of the picture-in-picture window that may be displayed to the user.
+     *
+     * @return subtitle of the picture-in-picture window.
+     * @see PictureInPictureParams.Builder#setSubtitle(CharSequence)
      */
-    @TestApi
     @Nullable
     public CharSequence getSubtitle() {
         return mSubtitle;
@@ -716,7 +749,7 @@
     @Override
     public String toString() {
         return "PictureInPictureParams("
-                + " aspectRatio=" + getAspectRatioRational()
+                + " aspectRatio=" + getAspectRatio()
                 + " expandedAspectRatio=" + mExpandedAspectRatio
                 + " sourceRectHint=" + getSourceRectHint()
                 + " hasSetActions=" + hasSetActions()
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index c6e36a3..ae0fc09 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -24,6 +24,9 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
@@ -39,6 +42,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.util.Pair;
 import android.util.Slog;
 import android.view.View;
@@ -520,6 +524,27 @@
     private final Map<NearbyMediaDevicesProvider, NearbyMediaDevicesProviderWrapper>
             nearbyMediaDevicesProviderMap = new HashMap<>();
 
+    /**
+     * Media controls based on {@link android.app.Notification.MediaStyle} notifications will have
+     * actions based on the media session's {@link android.media.session.PlaybackState}, rather than
+     * the notification's actions.
+     *
+     * These actions will be:
+     * - Play/Pause (depending on whether the current state is a playing state)
+     * - Previous (if declared), or a custom action if the slot is not reserved with
+     *   {@code SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV}
+     * - Next (if declared), or a custom action if the slot is not reserved with
+     *   {@code SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT}
+     * - Custom action
+     * - Custom action
+     *
+     * @see androidx.media.utils.MediaConstants#SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV
+     * @see androidx.media.utils.MediaConstants#SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
+    private static final long MEDIA_CONTROL_SESSION_ACTIONS = 203800354L;
+
     @UnsupportedAppUsage
     private Context mContext;
     private IStatusBarService mService;
@@ -844,6 +869,24 @@
     }
 
     /**
+     * Sets an active {@link android.service.quicksettings.TileService} to listening state
+     *
+     * The {@code componentName}'s package must match the calling package.
+     *
+     * @param componentName the tile to set into listening state
+     * @see android.service.quicksettings.TileService#requestListeningState
+     * @hide
+     */
+    public void requestTileServiceListeningState(@NonNull ComponentName componentName) {
+        Objects.requireNonNull(componentName);
+        try {
+            getService().requestTileServiceListeningState(componentName, mContext.getUserId());
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Request to the user to add a {@link android.service.quicksettings.TileService}
      * to the set of current QS tiles.
      * <p>
@@ -1109,6 +1152,21 @@
         }
     }
 
+    /**
+     * Checks whether the given package should use session-based actions for its media controls.
+     *
+     * @param packageName App posting media controls
+     * @param user Current user handle
+     * @return true if the app supports session actions
+     *
+     * @hide
+     */
+    @RequiresPermission(allOf = {android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG,
+            android.Manifest.permission.LOG_COMPAT_CHANGE})
+    public static boolean useMediaSessionActionsForApp(String packageName, UserHandle user) {
+        return CompatChanges.isChangeEnabled(MEDIA_CONTROL_SESSION_ACTIONS, packageName, user);
+    }
+
     /** @hide */
     public static String windowStateToString(int state) {
         if (state == WINDOW_STATE_HIDING) return "WINDOW_STATE_HIDING";
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 58db93c..6615374 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -138,8 +138,6 @@
 import android.nearby.NearbyFrameworkInitializer;
 import android.net.ConnectivityFrameworkInitializer;
 import android.net.ConnectivityFrameworkInitializerTiramisu;
-import android.net.EthernetManager;
-import android.net.IEthernetManager;
 import android.net.INetworkPolicyManager;
 import android.net.IPacProxyManager;
 import android.net.IVpnManager;
@@ -156,6 +154,7 @@
 import android.net.wifi.WifiFrameworkInitializer;
 import android.net.wifi.nl80211.WifiNl80211Manager;
 import android.nfc.NfcManager;
+import android.ondevicepersonalization.OnDevicePersonalizationFrameworkInitializer;
 import android.os.BatteryManager;
 import android.os.BatteryStats;
 import android.os.BatteryStatsManager;
@@ -789,15 +788,6 @@
                 return new LowpanManager(ctx.getOuterContext(), service);
             }});
 
-        registerService(Context.ETHERNET_SERVICE, EthernetManager.class,
-                new CachedServiceFetcher<EthernetManager>() {
-            @Override
-            public EthernetManager createService(ContextImpl ctx) throws ServiceNotFoundException {
-                IBinder b = ServiceManager.getServiceOrThrow(Context.ETHERNET_SERVICE);
-                IEthernetManager service = IEthernetManager.Stub.asInterface(b);
-                return new EthernetManager(ctx.getOuterContext(), service);
-            }});
-
         registerService(Context.WIFI_NL80211_SERVICE, WifiNl80211Manager.class,
                 new CachedServiceFetcher<WifiNl80211Manager>() {
                     @Override
@@ -1571,6 +1561,7 @@
             SafetyCenterFrameworkInitializer.registerServiceWrappers();
             ConnectivityFrameworkInitializerTiramisu.registerServiceWrappers();
             NearbyFrameworkInitializer.registerServiceWrappers();
+            OnDevicePersonalizationFrameworkInitializer.registerServiceWrappers();
         } finally {
             // If any of the above code throws, we're in a pretty bad shape and the process
             // will likely crash, but we'll reset it just in case there's an exception handler...
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index 32207af..649f904 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -146,15 +146,6 @@
                 }
             ],
             "file_patterns": ["(/|^)ContextImpl.java"]
-        },
-        {
-            "file_patterns": ["(/|^)LocaleManager.java"],
-            "name": "CtsLocaleManagerTestCases",
-            "options": [
-                {
-                    "exclude-annotation": "androidx.test.filters.FlakyTest"
-                }
-            ]
         }
     ],
     "presubmit-large": [
@@ -182,6 +173,16 @@
         {
             "file_patterns": ["(/|^)ActivityThreadTest.java"],
             "name": "FrameworksCoreTests"
+        },
+        // TODO(b/225192026): Move back to presubmit after b/225192026 is fixed
+        {
+            "file_patterns": ["(/|^)LocaleManager.java"],
+            "name": "CtsLocaleManagerTestCases",
+            "options": [
+                {
+                    "exclude-annotation": "androidx.test.filters.FlakyTest"
+                }
+            ]
         }
     ]
 }
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 5c7c73c..1a38fcf 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -188,7 +188,7 @@
     /**
      * @hide
      */
-    public boolean preferDockBigOverlays;
+    public boolean shouldDockBigOverlays;
 
     /**
      * The task id of the host Task of the launch-into-pip Activity, i.e., it points to the Task
@@ -392,8 +392,8 @@
 
     /** @hide */
     @TestApi
-    public boolean getPreferDockBigOverlays() {
-        return preferDockBigOverlays;
+    public boolean shouldDockBigOverlays() {
+        return shouldDockBigOverlays;
     }
 
     /** @hide */
@@ -465,7 +465,7 @@
                 && displayAreaFeatureId == that.displayAreaFeatureId
                 && Objects.equals(positionInParent, that.positionInParent)
                 && Objects.equals(pictureInPictureParams, that.pictureInPictureParams)
-                && Objects.equals(preferDockBigOverlays, that.preferDockBigOverlays)
+                && Objects.equals(shouldDockBigOverlays, that.shouldDockBigOverlays)
                 && Objects.equals(displayCutoutInsets, that.displayCutoutInsets)
                 && getWindowingMode() == that.getWindowingMode()
                 && Objects.equals(taskDescription, that.taskDescription)
@@ -522,7 +522,7 @@
         token = WindowContainerToken.CREATOR.createFromParcel(source);
         topActivityType = source.readInt();
         pictureInPictureParams = source.readTypedObject(PictureInPictureParams.CREATOR);
-        preferDockBigOverlays = source.readBoolean();
+        shouldDockBigOverlays = source.readBoolean();
         launchIntoPipHostTaskId = source.readInt();
         displayCutoutInsets = source.readTypedObject(Rect.CREATOR);
         topActivityInfo = source.readTypedObject(ActivityInfo.CREATOR);
@@ -569,7 +569,7 @@
         token.writeToParcel(dest, flags);
         dest.writeInt(topActivityType);
         dest.writeTypedObject(pictureInPictureParams, flags);
-        dest.writeBoolean(preferDockBigOverlays);
+        dest.writeBoolean(shouldDockBigOverlays);
         dest.writeInt(launchIntoPipHostTaskId);
         dest.writeTypedObject(displayCutoutInsets, flags);
         dest.writeTypedObject(topActivityInfo, flags);
@@ -610,7 +610,7 @@
                 + " token=" + token
                 + " topActivityType=" + topActivityType
                 + " pictureInPictureParams=" + pictureInPictureParams
-                + " preferDockBigOverlays=" + preferDockBigOverlays
+                + " shouldDockBigOverlays=" + shouldDockBigOverlays
                 + " launchIntoPipHostTaskId=" + launchIntoPipHostTaskId
                 + " displayCutoutSafeInsets=" + displayCutoutInsets
                 + " topActivityInfo=" + topActivityInfo
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index f523a7d..83fe29f 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -19,7 +19,6 @@
 import android.app.ActivityManager.RunningTaskInfo;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
-import android.os.Binder;
 import android.os.Build;
 import android.os.RemoteException;
 import android.window.TaskSnapshot;
@@ -32,10 +31,18 @@
  */
 public abstract class TaskStackListener extends ITaskStackListener.Stub {
 
+    /** Whether this listener and the callback dispatcher are in different processes. */
+    private boolean mIsRemote = true;
+
     @UnsupportedAppUsage
     public TaskStackListener() {
     }
 
+    /** Indicates that this listener lives in system server. */
+    public void setIsLocal() {
+        mIsRemote = false;
+    }
+
     @Override
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void onTaskStackChanged() throws RemoteException {
@@ -154,8 +161,7 @@
     @Override
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) throws RemoteException {
-        if (Binder.getCallingPid() != android.os.Process.myPid()
-                && snapshot != null && snapshot.getHardwareBuffer() != null) {
+        if (mIsRemote && snapshot != null && snapshot.getHardwareBuffer() != null) {
             // Preemptively clear any reference to the buffer
             snapshot.getHardwareBuffer().close();
         }
diff --git a/core/java/android/app/admin/DevicePolicyDrawableResource.java b/core/java/android/app/admin/DevicePolicyDrawableResource.java
index 7fd8e89..dab9888 100644
--- a/core/java/android/app/admin/DevicePolicyDrawableResource.java
+++ b/core/java/android/app/admin/DevicePolicyDrawableResource.java
@@ -20,7 +20,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.app.admin.DevicePolicyResources.Drawables;
 import android.content.Context;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -29,21 +28,21 @@
 
 /**
  * Used to pass in the required information for updating an enterprise drawable resource using
- * {@link DevicePolicyManager#setDrawables}.
+ * {@link DevicePolicyResourcesManager#setDrawables}.
  *
  * @hide
  */
 @SystemApi
 public final class DevicePolicyDrawableResource implements Parcelable {
-    @NonNull private final @DevicePolicyResources.UpdatableDrawableId String mDrawableId;
-    @NonNull private final @DevicePolicyResources.UpdatableDrawableStyle String mDrawableStyle;
-    @NonNull private final @DevicePolicyResources.UpdatableDrawableSource String mDrawableSource;
+    @NonNull private final String mDrawableId;
+    @NonNull private final String mDrawableStyle;
+    @NonNull private final String mDrawableSource;
     private final @DrawableRes int mResourceIdInCallingPackage;
     @NonNull private ParcelableResource mResource;
 
     /**
      * Creates an object containing the required information for updating an enterprise drawable
-     * resource using {@link DevicePolicyManager#setDrawables}.
+     * resource using {@link DevicePolicyResourcesManager#setDrawables}.
      *
      * <p>It will be used to update the drawable defined by {@code drawableId} with style
      * {@code drawableStyle} located in source {@code drawableSource} to the drawable with ID
@@ -60,9 +59,9 @@
      */
     public DevicePolicyDrawableResource(
             @NonNull Context context,
-            @NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
-            @NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
-            @NonNull @DevicePolicyResources.UpdatableDrawableSource String drawableSource,
+            @NonNull String drawableId,
+            @NonNull String drawableStyle,
+            @NonNull String drawableSource,
             @DrawableRes int resourceIdInCallingPackage) {
         this(drawableId, drawableStyle, drawableSource, resourceIdInCallingPackage,
                 new ParcelableResource(context, resourceIdInCallingPackage,
@@ -70,9 +69,9 @@
     }
 
     private DevicePolicyDrawableResource(
-            @NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
-            @NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
-            @NonNull @DevicePolicyResources.UpdatableDrawableSource String drawableSource,
+            @NonNull String drawableId,
+            @NonNull String drawableStyle,
+            @NonNull String drawableSource,
             @DrawableRes int resourceIdInCallingPackage,
             @NonNull ParcelableResource resource) {
 
@@ -90,7 +89,7 @@
 
     /**
      * Creates an object containing the required information for updating an enterprise drawable
-     * resource using {@link DevicePolicyManager#setDrawables}.
+     * resource using {@link DevicePolicyResourcesManager#setDrawables}.
      * <p>It will be used to update the drawable defined by {@code drawableId} with style
      * {@code drawableStyle} to the drawable with ID {@code resourceIdInCallingPackage} in the
      * calling package</p>
@@ -105,10 +104,10 @@
      */
     public DevicePolicyDrawableResource(
             @NonNull Context context,
-            @NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
-            @NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
+            @NonNull String drawableId,
+            @NonNull String drawableStyle,
             @DrawableRes int resourceIdInCallingPackage) {
-       this(context, drawableId, drawableStyle, Drawables.Source.UNDEFINED,
+       this(context, drawableId, drawableStyle, DevicePolicyResources.UNDEFINED,
                resourceIdInCallingPackage);
     }
 
@@ -116,7 +115,6 @@
      * Returns the ID of the drawable to update.
      */
     @NonNull
-    @DevicePolicyResources.UpdatableDrawableId
     public String getDrawableId() {
         return mDrawableId;
     }
@@ -125,7 +123,6 @@
      * Returns the style of the drawable to update
      */
     @NonNull
-    @DevicePolicyResources.UpdatableDrawableStyle
     public String getDrawableStyle() {
         return mDrawableStyle;
     }
@@ -134,7 +131,6 @@
      * Returns the source of the drawable to update.
      */
     @NonNull
-    @DevicePolicyResources.UpdatableDrawableSource
     public String getDrawableSource() {
         return mDrawableSource;
     }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 4c7b910..df6627c 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -21,6 +21,7 @@
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 
 import android.Manifest.permission;
+import android.accounts.Account;
 import android.annotation.CallbackExecutor;
 import android.annotation.ColorInt;
 import android.annotation.IntDef;
@@ -41,7 +42,6 @@
 import android.app.Activity;
 import android.app.IServiceConnection;
 import android.app.KeyguardManager;
-import android.app.admin.DevicePolicyResources.Drawables;
 import android.app.admin.SecurityLog.SecurityEvent;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
@@ -55,10 +55,8 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.UserInfo;
-import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
 import android.net.PrivateDnsConnectivityChecker;
 import android.net.ProxyInfo;
 import android.net.Uri;
@@ -97,7 +95,6 @@
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.DebugUtils;
-import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Pair;
 
@@ -138,7 +135,6 @@
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
-import java.util.function.Supplier;
 
 // TODO(b/172376923) - add CarDevicePolicyManager examples below (or remove reference to it).
 /**
@@ -173,6 +169,7 @@
     private final Context mContext;
     private final IDevicePolicyManager mService;
     private final boolean mParentInstance;
+    private final DevicePolicyResourcesManager mResourcesManager;
 
     /** @hide */
     public DevicePolicyManager(Context context, IDevicePolicyManager service) {
@@ -186,6 +183,7 @@
         mContext = context;
         mService = service;
         mParentInstance = parentInstance;
+        mResourcesManager = new DevicePolicyResourcesManager(context, service);
     }
 
     /** @hide test will override it. */
@@ -719,10 +717,11 @@
 
     /**
      * A {@code boolean} extra which determines whether to force a role holder update, regardless
-     * of any internal conditions {@link #ACTION_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER} might have.
+     * of any internal conditions {@link #ACTION_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER} might
+     * have.
      *
      * <p>This extra can be provided to intents with action {@link
-     * #ACTION_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER}.
+     * #ACTION_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER}.
      *
      * @hide
      */
@@ -909,6 +908,14 @@
             "android.intent.extra.REMOTE_BUGREPORT_HASH";
 
     /**
+     * Extra for shared bugreport's nonce in long integer type.
+     *
+     * @hide
+     */
+    public static final String EXTRA_REMOTE_BUGREPORT_NONCE =
+            "android.intent.extra.REMOTE_BUGREPORT_NONCE";
+
+    /**
      * Extra for remote bugreport notification shown type.
      *
      * @hide
@@ -1622,14 +1629,26 @@
             "android.app.extra.PROVISIONING_SKIP_EDUCATION_SCREENS";
 
     /**
-     * A boolean extra indicating if mobile data should be used during NFC device owner provisioning
-     * for downloading the mobile device management application. If {@link
-     * #EXTRA_PROVISIONING_WIFI_SSID} is also specified, wifi network will be used instead.
+     * A boolean extra indicating if mobile data should be used during the provisioning flow
+     * for downloading the admin app. If {@link #EXTRA_PROVISIONING_WIFI_SSID} is also specified,
+     * wifi network will be used instead.
      *
-     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
-     * provisioning via an NFC bump.
+     * <p>Default value is {@code false}.
      *
-     * @hide
+     * <p>If this extra is set to {@code true} and {@link #EXTRA_PROVISIONING_WIFI_SSID} is not
+     * specified, this extra has different behaviour depending on the way provisioning is triggered:
+     * <ul>
+     * <li>
+     *     For provisioning started via a QR code or an NFC tag, mobile data is always used for
+     *     downloading the admin app.
+     * </li>
+     * <li>
+     *     For all other provisioning methods, a mobile data connection check is made at the start
+     *     of provisioning. If mobile data is connected at that point, the admin app download will
+     *     happen using mobile data. If mobile data is not connected at that point, the end-user
+     *     will be asked to pick a wifi network and the admin app download will proceed over wifi.
+     * </li>
+     * </ul>
      */
     public static final String EXTRA_PROVISIONING_USE_MOBILE_DATA =
             "android.app.extra.PROVISIONING_USE_MOBILE_DATA";
@@ -3281,39 +3300,84 @@
      *
      * <p>The activity must handle the device policy management role holder update and set the
      * intent result to either {@link Activity#RESULT_OK} if the update was successful, {@link
-     * #RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR} if it encounters a problem
-     * that may be solved by relaunching it again, or {@link
-     * #RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR} if it encounters a problem
-     * that will not be solved by relaunching it again.
+     * #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR} if it encounters a
+     * problem that may be solved by relaunching it again, {@link
+     * #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_PROVISIONING_DISABLED} if role holder
+     * provisioning is disabled, or {@link
+     * #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR} if it encounters
+     * any other problem that will not be solved by relaunching it again.
      *
      * <p>If this activity has additional internal conditions which are not met, it should return
-     * {@link #RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR}.
+     * {@link #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR}.
      *
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.LAUNCH_DEVICE_MANAGER_SETUP)
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     @SystemApi
-    public static final String ACTION_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER =
-            "android.app.action.UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER";
+    public static final String ACTION_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER =
+            "android.app.action.UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER";
 
     /**
-     * Result code that can be returned by the {@link #ACTION_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER}
-     * handler if it encounters a problem that may be solved by relaunching it again.
+     * Result code that can be returned by the {@link
+     * #ACTION_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER} handler if it encounters a problem
+     * that may be solved by relaunching it again.
      *
      * @hide
      */
     @SystemApi
-    public static final int RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR = 1;
+    public static final int RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR =
+            1;
 
     /**
-     * Result code that can be returned by the {@link #ACTION_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER}
-     * handler if it encounters a problem that will not be solved by relaunching it again.
+     * Result code that can be returned by the {@link
+     * #ACTION_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER} handler if it encounters a problem that
+     * will not be solved by relaunching it again.
      *
      * @hide
      */
     @SystemApi
-    public static final int RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR = 2;
+    public static final int RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR =
+            2;
+
+    /**
+     * Result code that can be returned by the {@link
+     * #ACTION_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER} handler if role holder provisioning
+     * is disabled.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int
+            RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_PROVISIONING_DISABLED = 3;
+
+    /**
+     * An {@code int} extra which contains the result code of the last attempt to update
+     * the device policy management role holder.
+     *
+     * <p>This extra is provided to the device policy management role holder via either {@link
+     * #ACTION_ROLE_HOLDER_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE} or {@link
+     * #ACTION_ROLE_HOLDER_PROVISION_MANAGED_PROFILE} when started after the role holder
+     * had previously returned {@link #RESULT_UPDATE_ROLE_HOLDER}.
+     *
+     * <p>If the role holder update had failed, the role holder can use the value of this extra to
+     * make a decision whether to fail the provisioning flow or to carry on with the older version
+     * of the role holder.
+     *
+     * <p>Possible values can be:
+     * <ul>
+     *    <li>{@link Activity#RESULT_OK} if the update was successful
+     *    <li>{@link #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR} if it
+     *    encounters a problem that may be solved by relaunching it again.
+     *    <li>{@link #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR} if
+     *    it encounters a problem that will not be solved by relaunching it again.
+     * </ul>
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_ROLE_HOLDER_UPDATE_RESULT_CODE =
+            "android.app.extra.ROLE_HOLDER_UPDATE_RESULT_CODE";
 
     /**
      * An {@link Intent} extra which resolves to a custom user consent screen.
@@ -3335,6 +3399,16 @@
      *     <li>General disclaimer relevant to the provisioning mode</li>
      * </ul>
      *
+     * <p>When this {@link Intent} is started, the following intent extras will be supplied:
+     * <ul>
+     *     <li>{@link #EXTRA_PROVISIONING_DISCLAIMERS}</li>
+     *     <li>{@link #EXTRA_PROVISIONING_MODE}</li>
+     *     <li>{@link #EXTRA_PROVISIONING_LOCALE}</li>
+     *     <li>{@link #EXTRA_PROVISIONING_LOCAL_TIME}</li>
+     *     <li>{@link #EXTRA_PROVISIONING_TIME_ZONE}</li>
+     *     <li>{@link #EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS}</li>
+     * </ul>
+     *
      * <p>If the custom consent screens are granted by the user {@link Activity#RESULT_OK} is
      * returned, otherwise {@link Activity#RESULT_CANCELED} is returned. The device policy
      * management role holder should ensure that the provisioning flow terminates immediately if
@@ -3669,7 +3743,8 @@
     /**
      * Broadcast action: notify system apps (e.g. settings, SysUI, etc) that the device management
      * resources with IDs {@link #EXTRA_RESOURCE_IDS} has been updated, the updated resources can be
-     * retrieved using {@link #getDrawable} and {@code #getString}.
+     * retrieved using {@link DevicePolicyResourcesManager#getDrawable} and
+     * {@link DevicePolicyResourcesManager#getString}.
      *
      * <p>This broadcast is sent to registered receivers only.
      *
@@ -6122,7 +6197,7 @@
      * organization-owned managed profile.
      *
      * <p>The caller must hold the
-     * {@link android.Manifest.permission#SEND_LOST_MODE_LOCATION_UPDATES} permission.
+     * {@link android.Manifest.permission#TRIGGER_LOST_MODE} permission.
      *
      * <p> Not for use by third-party applications.
      *
@@ -6132,7 +6207,7 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.SEND_LOST_MODE_LOCATION_UPDATES)
+    @RequiresPermission(android.Manifest.permission.TRIGGER_LOST_MODE)
     public void sendLostModeLocationUpdate(@NonNull @CallbackExecutor Executor executor,
             @NonNull Consumer<Boolean> callback) {
         throwIfParentInstance("sendLostModeLocationUpdate");
@@ -14004,12 +14079,12 @@
     /**
      * Deprecated. Use {@code markProfileOwnerOnOrganizationOwnedDevice} instead.
      * When called by an app targeting SDK level {@link android.os.Build.VERSION_CODES#Q} or
-     * below, will behave the same as {@link #markProfileOwnerOnOrganizationOwnedDevice}.
+     * below, will behave the same as {@link #setProfileOwnerOnOrganizationOwnedDevice}.
      *
      * When called by an app targeting SDK level {@link android.os.Build.VERSION_CODES#R}
      * or above, will throw an UnsupportedOperationException when called.
      *
-     * @deprecated Use {@link #markProfileOwnerOnOrganizationOwnedDevice} instead.
+     * @deprecated Use {@link #setProfileOwnerOnOrganizationOwnedDevice} instead.
      *
      * @hide
      */
@@ -14024,14 +14099,14 @@
                     "This method is deprecated. use markProfileOwnerOnOrganizationOwnedDevice"
                     + " instead.");
         } else {
-            markProfileOwnerOnOrganizationOwnedDevice(who);
+            setProfileOwnerOnOrganizationOwnedDevice(who, true);
         }
     }
 
     /**
-     * Marks the profile owner of the given user as managing an organization-owned device.
-     * That will give it access to device identifiers (such as serial number, IMEI and MEID)
-     * as well as other privileges.
+     * Sets whether the profile owner of the given user as managing an organization-owned device.
+     * Managing an organization-owned device will give it access to device identifiers (such as
+     * serial number, IMEI and MEID) as well as other privileges.
      *
      * @hide
      */
@@ -14039,13 +14114,15 @@
     @RequiresPermission(anyOf = {
             android.Manifest.permission.MARK_DEVICE_ORGANIZATION_OWNED,
             android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS
-    }, conditional = true)
-    public void markProfileOwnerOnOrganizationOwnedDevice(@NonNull ComponentName who) {
+            }, conditional = true)
+    public void setProfileOwnerOnOrganizationOwnedDevice(@NonNull ComponentName who,
+            boolean isProfileOwnerOnOrganizationOwnedDevice) {
         if (mService == null) {
             return;
         }
         try {
-            mService.markProfileOwnerOnOrganizationOwnedDevice(who, myUserId());
+            mService.setProfileOwnerOnOrganizationOwnedDevice(who, myUserId(),
+                    isProfileOwnerOnOrganizationOwnedDevice);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
@@ -14795,6 +14872,28 @@
     }
 
     /**
+     * Called when a managed profile has been provisioned.
+     *
+     * @throws SecurityException if the caller does not hold
+     * {@link android.Manifest.permission#MANAGE_PROFILE_AND_DEVICE_OWNERS}.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+    public void finalizeWorkProfileProvisioning(
+            @NonNull UserHandle managedProfileUser, @Nullable Account migratedAccount) {
+        Objects.requireNonNull(managedProfileUser, "managedProfileUser can't be null");
+        if (mService == null) {
+            throw new IllegalStateException("Could not find DevicePolicyManagerService");
+        }
+        try {
+            mService.finalizeWorkProfileProvisioning(managedProfileUser, migratedAccount);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * The localized error message to show to the end-user. If {@code null}, a generic error
      * message will be shown.
      */
@@ -15202,481 +15301,12 @@
     }
 
     /**
-     * For each {@link DevicePolicyDrawableResource} item in {@code drawables}, if
-     * {@link DevicePolicyDrawableResource#getDrawableSource()} is not set or is set to
-     * {@link DevicePolicyResources.Drawables.Source#UNDEFINED}, it updates the drawable resource for
-     * the combination of {@link DevicePolicyDrawableResource#getDrawableId()} and
-     * {@link DevicePolicyDrawableResource#getDrawableStyle()}, (see
-     * {@link DevicePolicyResources.Drawables} and {@link DevicePolicyResources.Drawables.Style}) to
-     * the drawable with ID {@link DevicePolicyDrawableResource#getResourceIdInCallingPackage()},
-     * meaning any system UI surface calling {@link #getDrawable}
-     * with {@code drawableId} and {@code drawableStyle} will get the new resource after this API
-     * is called.
-     *
-     * <p>Otherwise, if {@link DevicePolicyDrawableResource#getDrawableSource()} is set (see
-     * {@link DevicePolicyResources.Drawables.Source}, it overrides any drawables that was set for
-     * the same {@code drawableId} and {@code drawableStyle} for the provided source.
-     *
-     * <p>Sends a broadcast with action {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to
-     * registered receivers when a resource has been updated successfully.
-     *
-     * <p>Important notes to consider when using this API:
-     * <ul>
-     * <li>{@link #getDrawable} references the resource
-     * {@link DevicePolicyDrawableResource#getResourceIdInCallingPackage()} in the
-     * calling package each time it gets called. You have to ensure that the resource is always
-     * available in the calling package as long as it is used as an updated resource.
-     * <li>You still have to re-call {@code setDrawables} even if you only make changes to the
-     * content of the resource with ID
-     * {@link DevicePolicyDrawableResource#getResourceIdInCallingPackage()} as the content might be
-     * cached and would need updating.
-     * </ul>
-     *
-     * @param drawables The list of {@link DevicePolicyDrawableResource} to update.
-     *
-     * @hide
+     * Returns a {@link DevicePolicyResourcesManager} containing the required APIs to set, reset,
+     * and get device policy related resources.
      */
-    @SystemApi
-    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
-    public void setDrawables(@NonNull Set<DevicePolicyDrawableResource> drawables) {
-        if (mService != null) {
-            try {
-                mService.setDrawables(new ArrayList<>(drawables));
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-        }
-    }
-
-    /**
-     * Removes all updated drawables for the list of {@code drawableIds} (see
-     * {@link DevicePolicyResources.Drawables} that was previously set by calling
-     * {@link #setDrawables}, meaning any subsequent calls to {@link #getDrawable} for the provided
-     * IDs with any {@link DevicePolicyResources.Drawables.Style} and any
-     * {@link DevicePolicyResources.Drawables.Source} will return the default drawable from
-     * {@code defaultDrawableLoader}.
-     *
-     * <p>Sends a broadcast with action {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to
-     * registered receivers when a resource has been reset successfully.
-     *
-     * @param drawableIds The list of IDs  to remove.
-     *
-     * @hide
-     */
-    @SystemApi
-    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
-    public void resetDrawables(@NonNull String[] drawableIds) {
-        if (mService != null) {
-            try {
-                mService.resetDrawables(drawableIds);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-        }
-    }
-
-    /**
-     * Returns the appropriate updated drawable for the {@code drawableId}
-     * (see {@link DevicePolicyResources.Drawables}), with style {@code drawableStyle}
-     * (see {@link DevicePolicyResources.Drawables.Style}) if one was set using
-     * {@code setDrawables}, otherwise returns the drawable from {@code defaultDrawableLoader}.
-     *
-     * <p>Also returns the drawable from {@code defaultDrawableLoader} if
-     * {@link DevicePolicyResources.Drawables#UNDEFINED} was passed.
-     *
-     * <p>Calls to this API will not return {@code null} unless no updated drawable was found
-     * and the call to {@code defaultDrawableLoader} returned {@code null}.
-     *
-     * <p>This API uses the screen density returned from {@link Resources#getConfiguration()}, to
-     * set a different value use
-     * {@link #getDrawableForDensity(String, String, int, Supplier)}.
-     *
-     * <p>Callers should register for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get
-     * notified when a resource has been updated.
-     *
-     * <p>Note that each call to this API loads the resource from the package that called
-     * {@code setDrawables} to set the updated resource.
-     *
-     * @param drawableId The drawable ID to get the updated resource for.
-     * @param drawableStyle The drawable style to use.
-     * @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
-     *                              the provided params.
-     */
-    @Nullable
-    public Drawable getDrawable(
-            @NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
-            @NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
-            @NonNull Supplier<Drawable> defaultDrawableLoader) {
-        return getDrawable(
-                drawableId, drawableStyle, Drawables.Source.UNDEFINED, defaultDrawableLoader);
-    }
-
-    /**
-     * Similar to {@link #getDrawable(String, String, Supplier)}, but also accepts
-     * a {@code drawableSource} (see {@link DevicePolicyResources.Drawables.Source}) which
-     * could result in returning a different drawable than
-     * {@link #getDrawable(String, String, Supplier)}
-     * if an override was set for that specific source.
-     *
-     * <p>Calls to this API will not return {@code null} unless no updated drawable was found
-     * and the call to {@code defaultDrawableLoader} returned {@code null}.
-     *
-     * <p>Callers should register for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get
-     * notified when a resource has been updated.
-     *
-     * @param drawableId The drawable ID to get the updated resource for.
-     * @param drawableStyle The drawable style to use.
-     * @param drawableSource The source for the caller.
-     * @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
-     *                              the provided params.
-     */
-    @Nullable
-    public Drawable getDrawable(
-            @NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
-            @NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
-            @NonNull @DevicePolicyResources.UpdatableDrawableSource String drawableSource,
-            @NonNull Supplier<Drawable> defaultDrawableLoader) {
-
-        Objects.requireNonNull(drawableId, "drawableId can't be null");
-        Objects.requireNonNull(drawableStyle, "drawableStyle can't be null");
-        Objects.requireNonNull(drawableSource, "drawableSource can't be null");
-        Objects.requireNonNull(defaultDrawableLoader, "defaultDrawableLoader can't be null");
-
-        if (Drawables.UNDEFINED.equals(drawableId)) {
-            return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
-        }
-        if (mService != null) {
-            try {
-                ParcelableResource resource = mService.getDrawable(
-                        drawableId, drawableStyle, drawableSource);
-                if (resource == null) {
-                    return ParcelableResource.loadDefaultDrawable(
-                            defaultDrawableLoader);
-                }
-                return resource.getDrawable(
-                        mContext,
-                        /* density= */ 0,
-                        defaultDrawableLoader);
-
-            } catch (RemoteException e) {
-                Log.e(
-                        TAG,
-                        "Error getting the updated drawable from DevicePolicyManagerService.",
-                        e);
-                return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
-            }
-        }
-        return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
-    }
-
-    /**
-     * Similar to {@link #getDrawable(String, String, Supplier)}, but also accepts
-     * {@code density}. See {@link Resources#getDrawableForDensity(int, int, Resources.Theme)}.
-     *
-     * <p>Calls to this API will not return {@code null} unless no updated drawable was found
-     * and the call to {@code defaultDrawableLoader} returned {@code null}.
-     *
-     * <p>Callers should register for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get
-     * notified when a resource has been updated.
-     *
-     * @param drawableId The drawable ID to get the updated resource for.
-     * @param drawableStyle The drawable style to use.
-     * @param density The desired screen density indicated by the resource as
-     *            found in {@link DisplayMetrics}. A value of 0 means to use the
-     *            density returned from {@link Resources#getConfiguration()}.
-     * @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
-     *                              the provided params.
-     */
-    @Nullable
-    public Drawable getDrawableForDensity(
-            @NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
-            @NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
-            int density,
-            @NonNull Supplier<Drawable> defaultDrawableLoader) {
-        return getDrawableForDensity(
-                drawableId,
-                drawableStyle,
-                Drawables.Source.UNDEFINED,
-                density,
-                defaultDrawableLoader);
-    }
-
-     /**
-     * Similar to {@link #getDrawable(String, String, String, Supplier)}, but also accepts
-     * {@code density}. See {@link Resources#getDrawableForDensity(int, int, Resources.Theme)}.
-     *
-      * <p>Calls to this API will not return {@code null} unless no updated drawable was found
-      * and the call to {@code defaultDrawableLoader} returned {@code null}.
-     *
-     * <p>Callers should register for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get
-     * notified when a resource has been updated.
-     *
-     * @param drawableId The drawable ID to get the updated resource for.
-     * @param drawableStyle The drawable style to use.
-     * @param drawableSource The source for the caller.
-     * @param density The desired screen density indicated by the resource as
-     *            found in {@link DisplayMetrics}. A value of 0 means to use the
-     *            density returned from {@link Resources#getConfiguration()}.
-     * @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
-     *                              the provided params.
-     */
-    @Nullable
-    public Drawable getDrawableForDensity(
-            @NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
-            @NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
-            @NonNull @DevicePolicyResources.UpdatableDrawableSource String drawableSource,
-            int density,
-            @NonNull Supplier<Drawable> defaultDrawableLoader) {
-
-        Objects.requireNonNull(drawableId, "drawableId can't be null");
-        Objects.requireNonNull(drawableStyle, "drawableStyle can't be null");
-        Objects.requireNonNull(drawableSource, "drawableSource can't be null");
-        Objects.requireNonNull(defaultDrawableLoader, "defaultDrawableLoader can't be null");
-
-        if (Drawables.UNDEFINED.equals(drawableId)) {
-            return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
-        }
-        if (mService != null) {
-            try {
-                ParcelableResource resource = mService.getDrawable(
-                        drawableId, drawableStyle, drawableSource);
-                if (resource == null) {
-                    return ParcelableResource.loadDefaultDrawable(
-                            defaultDrawableLoader);
-                }
-                return resource.getDrawable(mContext, density, defaultDrawableLoader);
-            } catch (RemoteException e) {
-                Log.e(
-                        TAG,
-                        "Error getting the updated drawable from DevicePolicyManagerService.",
-                        e);
-                return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
-            }
-        }
-        return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
-    }
-
-    /**
-     * Similar to {@link #getDrawable(String, String, String, Supplier)} but returns an
-     * {@link Icon} instead of a {@link Drawable}.
-     *
-     * @param drawableId The drawable ID to get the updated resource for.
-     * @param drawableStyle The drawable style to use.
-     * @param drawableSource The source for the caller.
-     * @param defaultIcon Returned if no updated drawable was set for the provided params.
-     */
-    @Nullable
-    public Icon getDrawableAsIcon(
-            @NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
-            @NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
-            @NonNull @DevicePolicyResources.UpdatableDrawableSource String drawableSource,
-            @Nullable Icon defaultIcon) {
-        Objects.requireNonNull(drawableId, "drawableId can't be null");
-        Objects.requireNonNull(drawableStyle, "drawableStyle can't be null");
-        Objects.requireNonNull(drawableSource, "drawableSource can't be null");
-        Objects.requireNonNull(defaultIcon, "defaultIcon can't be null");
-
-        if (Drawables.UNDEFINED.equals(drawableId)) {
-            return defaultIcon;
-        }
-        if (mService != null) {
-            try {
-                ParcelableResource resource = mService.getDrawable(
-                        drawableId, drawableStyle, drawableSource);
-                if (resource == null) {
-                    return defaultIcon;
-                }
-                return Icon.createWithResource(resource.getPackageName(), resource.getResourceId());
-            } catch (RemoteException e) {
-                Log.e(
-                        TAG,
-                        "Error getting the updated drawable from DevicePolicyManagerService.",
-                        e);
-                return defaultIcon;
-            }
-        }
-        return defaultIcon;
-    }
-
-    /**
-     * Similar to {@link #getDrawable(String, String, Supplier)} but returns an {@link Icon}
-     * instead of a {@link Drawable}.
-     *
-     * @param drawableId The drawable ID to get the updated resource for.
-     * @param drawableStyle The drawable style to use.
-     * @param defaultIcon Returned if no updated drawable was set for the provided params.
-     */
-    @Nullable
-    public Icon getDrawableAsIcon(
-            @NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
-            @NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
-            @Nullable Icon defaultIcon) {
-        return getDrawableAsIcon(
-                drawableId, drawableStyle, Drawables.Source.UNDEFINED, defaultIcon);
-    }
-
-
-    /**
-     * For each {@link DevicePolicyStringResource} item in {@code strings}, it updates the string
-     * resource for {@link DevicePolicyStringResource#getStringId()} to the string with ID
-     * {@code callingPackageResourceId} (see {@link DevicePolicyResources.Strings}), meaning any
-     * system UI surface calling {@link #getString} with {@code stringId} will get
-     * the new resource after this API is called.
-     *
-     * <p>Sends a broadcast with action {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to
-     * registered receivers when a resource has been updated successfully.
-     *
-     * <p>Important notes to consider when using this API:
-     * <ul>
-     * <li> {@link #getString} references the resource
-     * {@code callingPackageResourceId} in the calling package each time it gets called. You have to
-     * ensure that the resource is always available in the calling package as long as it is used as
-     * an updated resource.
-     * <li> You still have to re-call {@code setStrings} even if you only make changes to the
-     * content of the resource with ID {@code callingPackageResourceId} as the content might be
-     * cached and would need updating.
-     * </ul>
-     *
-     * @param strings The list of {@link DevicePolicyStringResource} to update.
-     *
-     * @hide
-     */
-    @SystemApi
-    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
-    public void setStrings(@NonNull Set<DevicePolicyStringResource> strings) {
-        if (mService != null) {
-            try {
-                mService.setStrings(new ArrayList<>(strings));
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-        }
-    }
-
-    /**
-     * Removes the updated strings for the list of {@code stringIds} (see
-     * {@link DevicePolicyResources.Strings}) that was previously set by calling {@link #setStrings},
-     * meaning any subsequent calls to {@link #getString} for the provided IDs will
-     * return the default string from {@code defaultStringLoader}.
-     *
-     * <p>Sends a broadcast with action {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to
-     * registered receivers when a resource has been reset successfully.
-     *
-     * @param stringIds The list of IDs to remove the updated resources for.
-     *
-     * @hide
-     */
-    @SystemApi
-    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
-    public void resetStrings(@NonNull String[] stringIds) {
-        if (mService != null) {
-            try {
-                mService.resetStrings(stringIds);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-        }
-    }
-
-    /**
-     * Returns the appropriate updated string for the {@code stringId} (see
-     * {@link DevicePolicyResources.Strings}) if one was set using
-     * {@link #setStrings}, otherwise returns the string from {@code defaultStringLoader}.
-     *
-     * <p>Also returns the string from {@code defaultStringLoader} if
-     * {@link DevicePolicyResources.Strings#UNDEFINED} was passed.
-     *
-     * <p>Calls to this API will not return {@code null} unless no updated drawable was found
-     * and the call to {@code defaultStringLoader} returned {@code null}.
-     *
-     * <p>Callers should register for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get
-     * notified when a resource has been updated.
-     *
-     * <p>Note that each call to this API loads the resource from the package that called
-     * {@link #setStrings} to set the updated resource.
-     *
-     * @param stringId The IDs to get the updated resource for.
-     * @param defaultStringLoader To get the default string if no updated string was set for
-     *         {@code stringId}.
-     *
-     * @hide
-     */
-    @SystemApi
-    @Nullable
-    public String getString(
-            @NonNull @DevicePolicyResources.UpdatableStringId String stringId,
-            @NonNull Supplier<String> defaultStringLoader) {
-
-        Objects.requireNonNull(stringId, "stringId can't be null");
-        Objects.requireNonNull(defaultStringLoader, "defaultStringLoader can't be null");
-
-        if (stringId.equals(DevicePolicyResources.Strings.UNDEFINED)) {
-            return ParcelableResource.loadDefaultString(defaultStringLoader);
-        }
-        if (mService != null) {
-            try {
-                ParcelableResource resource = mService.getString(stringId);
-                if (resource == null) {
-                    return ParcelableResource.loadDefaultString(defaultStringLoader);
-                }
-                return resource.getString(mContext, defaultStringLoader);
-            } catch (RemoteException e) {
-                Log.e(
-                        TAG,
-                        "Error getting the updated string from DevicePolicyManagerService.",
-                        e);
-                return ParcelableResource.loadDefaultString(defaultStringLoader);
-            }
-        }
-        return ParcelableResource.loadDefaultString(defaultStringLoader);
-    }
-
-    /**
-     * Similar to {@link #getString(String, Supplier)} but accepts {@code formatArgs} and returns a
-     * localized formatted string, substituting the format arguments as defined in
-     * {@link java.util.Formatter} and {@link java.lang.String#format}, (see
-     * {@link Resources#getString(int, Object...)}).
-     *
-     * <p>Calls to this API will not return {@code null} unless no updated drawable was found
-     * and the call to {@code defaultStringLoader} returned {@code null}.
-     *
-     * @param stringId The IDs to get the updated resource for.
-     * @param defaultStringLoader To get the default string if no updated string was set for
-     *         {@code stringId}.
-     * @param formatArgs The format arguments that will be used for substitution.
-     *
-     * @hide
-     */
-    @SystemApi
-    @Nullable
-    @SuppressLint("SamShouldBeLast")
-    public String getString(
-            @NonNull @DevicePolicyResources.UpdatableStringId String stringId,
-            @NonNull Supplier<String> defaultStringLoader,
-            @NonNull Object... formatArgs) {
-
-        Objects.requireNonNull(stringId, "stringId can't be null");
-        Objects.requireNonNull(defaultStringLoader, "defaultStringLoader can't be null");
-
-        if (stringId.equals(DevicePolicyResources.Strings.UNDEFINED)) {
-            return ParcelableResource.loadDefaultString(defaultStringLoader);
-        }
-        if (mService != null) {
-            try {
-                ParcelableResource resource = mService.getString(stringId);
-                if (resource == null) {
-                    return ParcelableResource.loadDefaultString(defaultStringLoader);
-                }
-                return resource.getString(mContext, defaultStringLoader, formatArgs);
-            } catch (RemoteException e) {
-                Log.e(
-                        TAG,
-                        "Error getting the updated string from DevicePolicyManagerService.",
-                        e);
-                return ParcelableResource.loadDefaultString(defaultStringLoader);
-            }
-        }
-        return ParcelableResource.loadDefaultString(defaultStringLoader);
+    @NonNull
+    public DevicePolicyResourcesManager getResources() {
+        return mResourcesManager;
     }
 
     /**
@@ -15732,9 +15362,51 @@
      */
     @Nullable
     public String getDevicePolicyManagementRoleHolderPackage() {
-        String deviceManagerConfig = mContext.getString(
+        String devicePolicyManagementConfig = mContext.getString(
                 com.android.internal.R.string.config_devicePolicyManagement);
-        return extractPackageNameFromDeviceManagerConfig(deviceManagerConfig);
+        return extractPackageNameFromDeviceManagerConfig(devicePolicyManagementConfig);
+    }
+
+    /**
+     * Returns the package name of the device policy management role holder updater.
+     *
+     * <p>If the device policy management role holder updater is not configured for this device,
+     * returns {@code null}.
+     *
+     * @hide
+     */
+    @Nullable
+    @TestApi
+    public String getDevicePolicyManagementRoleHolderUpdaterPackage() {
+        String devicePolicyManagementUpdaterConfig = mContext.getString(
+                com.android.internal.R.string.config_devicePolicyManagementUpdater);
+        if (TextUtils.isEmpty(devicePolicyManagementUpdaterConfig)) {
+            return null;
+        }
+        return devicePolicyManagementUpdaterConfig;
+    }
+
+    /**
+     * Returns a {@link List} of managed profiles managed by some profile owner within the profile
+     * group of the given user, or an empty {@link List} if there is not one.
+     *
+     * @param user the user whose profile group to look within to return managed profiles
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+    @NonNull
+    public List<UserHandle> getPolicyManagedProfiles(@NonNull UserHandle user) {
+        Objects.requireNonNull(user);
+        if (mService != null) {
+            try {
+                return mService.getPolicyManagedProfiles(user);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return Collections.emptyList();
     }
 
     /**
@@ -15760,4 +15432,23 @@
         }
         return deviceManagerConfig;
     }
+
+    /**
+     * @return {@code true} if bypassing the device policy management role qualification is allowed
+     * with the current state of the device.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS)
+    public boolean shouldAllowBypassingDevicePolicyManagementRoleQualification() {
+        if (mService != null) {
+            try {
+                return mService.shouldAllowBypassingDevicePolicyManagementRoleQualification();
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return false;
+    }
 }
diff --git a/core/java/android/app/admin/DevicePolicyResources.java b/core/java/android/app/admin/DevicePolicyResources.java
index 042e407..ea30ef7 100644
--- a/core/java/android/app/admin/DevicePolicyResources.java
+++ b/core/java/android/app/admin/DevicePolicyResources.java
@@ -16,519 +16,32 @@
 
 package android.app.admin;
 
-import static android.app.admin.DevicePolicyResources.Strings.Core.CANT_ADD_ACCOUNT_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.FORWARD_INTENT_TO_PERSONAL;
-import static android.app.admin.DevicePolicyResources.Strings.Core.FORWARD_INTENT_TO_WORK;
-import static android.app.admin.DevicePolicyResources.Strings.Core.LOCATION_CHANGED_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.LOCATION_CHANGED_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.NETWORK_LOGGING_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.NETWORK_LOGGING_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.NOTIFICATION_CHANNEL_DEVICE_ADMIN;
-import static android.app.admin.DevicePolicyResources.Strings.Core.NOTIFICATION_WORK_PROFILE_CONTENT_DESCRIPTION;
-import static android.app.admin.DevicePolicyResources.Strings.Core.PACKAGE_DELETED_BY_DO;
-import static android.app.admin.DevicePolicyResources.Strings.Core.PACKAGE_INSTALLED_BY_DO;
-import static android.app.admin.DevicePolicyResources.Strings.Core.PACKAGE_UPDATED_BY_DO;
-import static android.app.admin.DevicePolicyResources.Strings.Core.PERSONAL_APP_SUSPENSION_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.PERSONAL_APP_SUSPENSION_SOON_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.PERSONAL_APP_SUSPENSION_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.PERSONAL_APP_SUSPENSION_TURN_ON_PROFILE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.PRINTING_DISABLED_NAMED_ADMIN;
-import static android.app.admin.DevicePolicyResources.Strings.Core.PROFILE_ENCRYPTED_DETAIL;
-import static android.app.admin.DevicePolicyResources.Strings.Core.PROFILE_ENCRYPTED_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.PROFILE_ENCRYPTED_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_ACCESS_PERSONAL;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_ACCESS_WORK;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_SHARE_WITH_PERSONAL;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_SHARE_WITH_WORK;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CROSS_PROFILE_BLOCKED_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_NO_PERSONAL_APPS;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_NO_WORK_APPS;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_PERSONAL_TAB;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_PERSONAL_TAB_ACCESSIBILITY;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_WORK_PAUSED_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_WORK_PROFILE_NOT_SUPPORTED;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_WORK_TAB;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_WORK_TAB_ACCESSIBILITY;
-import static android.app.admin.DevicePolicyResources.Strings.Core.SWITCH_TO_PERSONAL_LABEL;
-import static android.app.admin.DevicePolicyResources.Strings.Core.SWITCH_TO_WORK_LABEL;
-import static android.app.admin.DevicePolicyResources.Strings.Core.UNLAUNCHABLE_APP_WORK_PAUSED_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.UNLAUNCHABLE_APP_WORK_PAUSED_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_BADGED_LABEL;
-import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_FAILED_PASSWORD_ATTEMPTS_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_GENERIC_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_ORG_OWNED_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Dialer.NOTIFICATION_INCOMING_WORK_CALL_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Dialer.NOTIFICATION_MISSED_WORK_CALL_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Dialer.NOTIFICATION_ONGOING_WORK_CALL_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Dialer.NOTIFICATION_WIFI_WORK_CALL_LABEL;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SAVE_TO_PERSONAL_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SAVE_TO_PERSONAL_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SAVE_TO_WORK_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SAVE_TO_WORK_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SELECT_PERSONAL_FILES_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SELECT_PERSONAL_FILES_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SELECT_WORK_FILES_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SELECT_WORK_FILES_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CROSS_PROFILE_NOT_ALLOWED_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CROSS_PROFILE_NOT_ALLOWED_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.PERSONAL_TAB;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.PREVIEW_WORK_FILE_ACCESSIBILITY;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.WORK_ACCESSIBILITY;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.WORK_PROFILE_OFF_ENABLE_BUTTON;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.WORK_PROFILE_OFF_ERROR_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.WORK_TAB;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.ALL_APPS_PERSONAL_TAB;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.ALL_APPS_PERSONAL_TAB_ACCESSIBILITY;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.ALL_APPS_WORK_TAB;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.ALL_APPS_WORK_TAB_ACCESSIBILITY;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.DISABLED_BY_ADMIN_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.WIDGETS_PERSONAL_TAB;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.WIDGETS_WORK_TAB;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.WORK_FOLDER_NAME;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.WORK_PROFILE_EDU;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.WORK_PROFILE_EDU_ACCEPT;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.WORK_PROFILE_ENABLE_BUTTON;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.WORK_PROFILE_PAUSED_DESCRIPTION;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.WORK_PROFILE_PAUSE_BUTTON;
-import static android.app.admin.DevicePolicyResources.Strings.MediaProvider.BLOCKED_BY_ADMIN_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.MediaProvider.BLOCKED_FROM_PERSONAL_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.MediaProvider.BLOCKED_FROM_WORK_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.MediaProvider.SWITCH_TO_PERSONAL_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.MediaProvider.SWITCH_TO_WORK_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.MediaProvider.WORK_PROFILE_PAUSED_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.PermissionController.BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.PermissionController.BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.PermissionController.FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.PermissionController.HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.PermissionController.LOCATION_AUTO_GRANTED_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.PermissionController.WORK_PROFILE_DEFAULT_APPS_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ACCESSIBILITY_CATEGORY_PERSONAL;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ACCESSIBILITY_CATEGORY_WORK;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ACCESSIBILITY_PERSONAL_ACCOUNT_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ACCESSIBILITY_WORK_ACCOUNT_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ACCOUNTS_SEARCH_KEYWORDS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ACTIVATE_DEVICE_ADMIN_APP;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ACTIVATE_DEVICE_ADMIN_APP_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ACTIVATE_THIS_DEVICE_ADMIN_APP;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ACTIVE_DEVICE_ADMIN_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_ACTIONS_APPS_COUNT;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_ACTIONS_APPS_COUNT_MINIMUM;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_ACTION_ACCESS_CAMERA;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_ACTION_ACCESS_LOCATION;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_ACTION_ACCESS_MICROPHONE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_ACTION_APPS_COUNT_ESTIMATED;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_ACTION_APPS_INSTALLED;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_ACTION_NONE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_ACTION_SET_CURRENT_INPUT_METHOD;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_ACTION_SET_DEFAULT_APPS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_ACTION_SET_HTTP_PROXY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_ACTION_SET_INPUT_METHOD_NAME;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_LOCK_DEVICE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_SEE_APPS_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_SEE_BUG_REPORT_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_SEE_NETWORK_LOGS_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_SEE_SECURITY_LOGS_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_SEE_USAGE_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_SEE_WORK_DATA_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_WIPE_DEVICE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CONFIGURED_FAILED_PASSWORD_WIPE_DEVICE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CONFIGURED_FAILED_PASSWORD_WIPE_WORK_PROFILE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ALWAYS_ON_VPN_DEVICE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ALWAYS_ON_VPN_PERSONAL_PROFILE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ALWAYS_ON_VPN_WORK_PROFILE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.APP_CAN_ACCESS_PERSONAL_DATA;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.APP_CAN_ACCESS_PERSONAL_PERMISSIONS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CA_CERTS_DEVICE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CA_CERTS_PERSONAL_PROFILE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CA_CERTS_WORK_PROFILE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CHANGES_MADE_BY_YOUR_ORGANIZATION_ADMIN_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CONFIRM_WORK_PROFILE_PASSWORD_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CONFIRM_WORK_PROFILE_PATTERN_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CONFIRM_WORK_PROFILE_PIN_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CONNECTED_APPS_SEARCH_KEYWORDS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CONNECTED_APPS_SHARE_PERMISSIONS_AND_DATA;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CONNECTED_WORK_AND_PERSONAL_APPS_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CONNECT_APPS_DIALOG_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CONNECT_APPS_DIALOG_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CONTACT_YOUR_IT_ADMIN;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CONTROLLED_BY_ADMIN_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CROSS_PROFILE_CALENDAR_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CROSS_PROFILE_CALENDAR_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.DEVICE_ADMIN_POLICIES_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.DEVICE_ADMIN_SETTINGS_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.DEVICE_MANAGED_WITHOUT_NAME;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.DEVICE_MANAGED_WITH_NAME;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.DEVICE_OWNER_INSTALLED_CERTIFICATE_AUTHORITY_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.DISABLED_BY_IT_ADMIN_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ENABLE_WORK_PROFILE_SYNC_WITH_PERSONAL_SOUNDS_DIALOG_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ENABLE_WORK_PROFILE_SYNC_WITH_PERSONAL_SOUNDS_DIALOG_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ENTERPRISE_PRIVACY_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ERROR_MOVE_DEVICE_ADMIN;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.FACE_SETTINGS_FOR_WORK_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.FACE_UNLOCK_DISABLED;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.FINGERPRINT_FOR_WORK;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.FINGERPRINT_UNLOCK_DISABLED;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.FINGERPRINT_UNLOCK_DISABLED_EXPLANATION;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.FORGOT_PASSWORD_TEXT;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.FORGOT_PASSWORD_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.HOW_TO_DISCONNECT_APPS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.INFORMATION_YOUR_ORGANIZATION_CAN_SEE_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.INSTALL_IN_PERSONAL_PROFILE_TO_CONNECT_PROMPT;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.INSTALL_IN_WORK_PROFILE_TO_CONNECT_PROMPT;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.IT_ADMIN_POLICY_DISABLING_INFO_URL;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGED_BY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGED_DEVICE_INFO;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGED_DEVICE_INFO_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGED_DEVICE_INFO_SUMMARY_WITH_NAME;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGED_PROFILE_SETTINGS_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGE_DEVICE_ADMIN_APPS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.NEW_DEVICE_ADMIN_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.NEW_DEVICE_ADMIN_WARNING_SIMPLIFIED;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.NO_DEVICE_ADMINS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.NUMBER_OF_DEVICE_ADMINS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.NUMBER_OF_DEVICE_ADMINS_NONE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ONLY_CONNECT_TRUSTED_APPS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.OTHER_OPTIONS_DISABLED_BY_ADMIN;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.PASSWORD_RECENTLY_USED;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.PERSONAL_CATEGORY_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.PERSONAL_PROFILE_APP_SUBTEXT;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.PIN_RECENTLY_USED;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.REENTER_WORK_PROFILE_PASSWORD_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.REENTER_WORK_PROFILE_PIN_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.REMOVE_ACCOUNT_FAILED_ADMIN_RESTRICTION;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.REMOVE_AND_UNINSTALL_DEVICE_ADMIN;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.REMOVE_DEVICE_ADMIN;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.REMOVE_WORK_PROFILE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.SELECT_DEVICE_ADMIN_APPS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.SET_PROFILE_OWNER_DIALOG_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.SET_PROFILE_OWNER_POSTSETUP_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.SET_PROFILE_OWNER_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.SET_WORK_PROFILE_PASSWORD_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.SET_WORK_PROFILE_PATTERN_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.SET_WORK_PROFILE_PIN_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.SHARE_REMOTE_BUGREPORT_DIALOG_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.SHARE_REMOTE_BUGREPORT_FINISHED_REQUEST_CONSENT;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.SHARE_REMOTE_BUGREPORT_NOT_FINISHED_REQUEST_CONSENT;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.SHARING_REMOTE_BUGREPORT_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.UNINSTALL_DEVICE_ADMIN;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.USER_ADMIN_POLICIES_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_APPS_CANNOT_ACCESS_NOTIFICATION_SETTINGS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_CATEGORY_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_ADMIN_POLICIES_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_ALARM_RINGTONE_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_APP_SUBTEXT;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_CONFIRM_PATTERN;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_CONFIRM_PIN;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_CONFIRM_REMOVE_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_CONFIRM_REMOVE_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_CONTACT_SEARCH_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_CONTACT_SEARCH_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_DISABLE_USAGE_ACCESS_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_FINGERPRINT_LAST_DELETE_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_INSTALLED_CERTIFICATE_AUTHORITY_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_IT_ADMIN_CANT_RESET_SCREEN_LOCK;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_KEYBOARDS_AND_TOOLS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_LAST_PASSWORD_ATTEMPT_BEFORE_WIPE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_LAST_PATTERN_ATTEMPT_BEFORE_WIPE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_LAST_PIN_ATTEMPT_BEFORE_WIPE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_LOCATION_SWITCH_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_LOCKED_NOTIFICATION_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_LOCK_ATTEMPTS_FAILED;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_LOCK_SCREEN_REDACT_NOTIFICATION_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_LOCK_SCREEN_REDACT_NOTIFICATION_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_MANAGED_BY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_NOTIFICATIONS_SECTION_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_NOTIFICATION_LISTENER_BLOCKED;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_NOTIFICATION_RINGTONE_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_NOT_AVAILABLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_OFF_CONDITION_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_PASSWORD_REQUIRED;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_PRIVACY_POLICY_INFO;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_PRIVACY_POLICY_INFO_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_RINGTONE_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SCREEN_LOCK_SETUP_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SECURITY_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SETTING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SETTING_OFF_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SETTING_ON_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SET_UNLOCK_LAUNCH_PICKER_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SOUND_SETTINGS_SECTION_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SYNC_WITH_PERSONAL_SOUNDS_ACTIVE_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_UNIFICATION_SEARCH_KEYWORDS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_UNIFY_LOCKS_DETAIL;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_UNIFY_LOCKS_NONCOMPLIANT;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_UNIFY_LOCKS_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_UNIFY_LOCKS_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_USER_LABEL;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_USE_PERSONAL_SOUNDS_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_USE_PERSONAL_SOUNDS_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.YOUR_ACCESS_TO_THIS_DEVICE_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.BIOMETRIC_DIALOG_WORK_LOCK_FAILED_ATTEMPTS;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.BIOMETRIC_DIALOG_WORK_PASSWORD_LAST_ATTEMPT;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.BIOMETRIC_DIALOG_WORK_PATTERN_LAST_ATTEMPT;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.BIOMETRIC_DIALOG_WORK_PIN_LAST_ATTEMPT;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.KEYGUARD_MANAGEMENT_DISCLOSURE;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.KEYGUARD_NAMED_MANAGEMENT_DISCLOSURE;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.ONGOING_PRIVACY_DIALOG_WORK;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MANAGEMENT;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MANAGEMENT_CA_CERT;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MANAGEMENT_NAMED_VPN;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MANAGEMENT_NETWORK;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MANAGEMENT_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MANAGEMENT_TWO_NAMED_VPN;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_NAMED_MANAGEMENT;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_PERSONAL_PROFILE_NAMED_VPN;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_VIEW_POLICIES;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_WORK_PROFILE_CA_CERT;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_WORK_PROFILE_NAMED_VPN;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_WORK_PROFILE_NETWORK;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_MANAGEMENT;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_MANAGEMENT_MONITORING;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_MANAGEMENT_MULTIPLE_VPNS;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_MANAGEMENT_NAMED_VPN;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_NAMED_MANAGEMENT;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_NAMED_MANAGEMENT_MONITORING;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_NAMED_MANAGEMENT_MULTIPLE_VPNS;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_NAMED_MANAGEMENT_NAMED_VPN;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_NAMED_WORK_PROFILE_MONITORING;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_PERSONAL_PROFILE_NAMED_VPN;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_WORK_PROFILE_MONITORING;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_WORK_PROFILE_NAMED_VPN;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_WORK_PROFILE_NETWORK;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.STATUS_BAR_WORK_ICON_ACCESSIBILITY;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.WORK_LOCK_ACCESSIBILITY;
-
-import android.annotation.StringDef;
-import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.os.UserHandle;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.HashSet;
-import java.util.Set;
-
 /**
  * Class containing the required identifiers to update device management resources.
  *
- * <p>See {@link DevicePolicyManager#getDrawable} and
- * {@code DevicePolicyManager#getString}.
+ * <p>See {@link DevicePolicyResourcesManager#getDrawable} and
+ * {@link DevicePolicyResourcesManager#getString}.
  */
 public final class DevicePolicyResources {
 
     private DevicePolicyResources() {}
 
     /**
-     * Resource identifiers used to update device management-related system drawable resources.
-     *
-     * @hide
+     * An identifier used for:
+     * <ul>
+     *     <li>un-updatable resource IDs</li>
+     *     <li>undefined sources</li>
+     * </ul>
      */
-    @Retention(RetentionPolicy.SOURCE)
-    @StringDef(value = {
-            Drawables.UNDEFINED,
-            Drawables.WORK_PROFILE_ICON_BADGE,
-            Drawables.WORK_PROFILE_ICON,
-            Drawables.WORK_PROFILE_OFF_ICON,
-            Drawables.WORK_PROFILE_USER_ICON
-    })
-    public @interface UpdatableDrawableId {
-    }
-
-    /**
-     * Identifiers to specify the desired style for the updatable device management system
-     * resource.
-     *
-     * @hide
-     */
-    @Retention(RetentionPolicy.SOURCE)
-    @StringDef(value = {
-            Drawables.Style.SOLID_COLORED,
-            Drawables.Style.SOLID_NOT_COLORED,
-            Drawables.Style.OUTLINE,
-            Drawables.Style.DEFAULT
-    })
-    public @interface UpdatableDrawableStyle {
-    }
-
-    /**
-     * Identifiers to specify the location if the updatable device management system resource.
-     *
-     * @hide
-     */
-    @Retention(RetentionPolicy.SOURCE)
-    @StringDef(value = {
-            Drawables.Source.UNDEFINED,
-            Drawables.Source.NOTIFICATION,
-            Drawables.Source.PROFILE_SWITCH_ANIMATION,
-            Drawables.Source.HOME_WIDGET,
-            Drawables.Source.LAUNCHER_OFF_BUTTON,
-            Drawables.Source.QUICK_SETTINGS,
-            Drawables.Source.STATUS_BAR
-    })
-    public @interface UpdatableDrawableSource {
-    }
-
-    /**
-     * Resource identifiers used to update device management-related string resources.
-     *
-     * @hide
-     */
-    @Retention(RetentionPolicy.SOURCE)
-    @StringDef({
-            // Launcher Strings
-            WORK_PROFILE_EDU, WORK_PROFILE_EDU_ACCEPT, Strings.Launcher.WORK_PROFILE_PAUSED_TITLE,
-            WORK_PROFILE_PAUSED_DESCRIPTION, WORK_PROFILE_PAUSE_BUTTON, WORK_PROFILE_ENABLE_BUTTON,
-            ALL_APPS_WORK_TAB, ALL_APPS_PERSONAL_TAB, ALL_APPS_WORK_TAB_ACCESSIBILITY,
-            ALL_APPS_PERSONAL_TAB_ACCESSIBILITY, WORK_FOLDER_NAME, WIDGETS_WORK_TAB,
-            WIDGETS_PERSONAL_TAB, DISABLED_BY_ADMIN_MESSAGE,
-
-            // SysUI Strings
-            QS_MSG_MANAGEMENT, QS_MSG_NAMED_MANAGEMENT, QS_MSG_MANAGEMENT_MONITORING,
-            QS_MSG_NAMED_MANAGEMENT_MONITORING, QS_MSG_MANAGEMENT_NAMED_VPN,
-            QS_MSG_NAMED_MANAGEMENT_NAMED_VPN, QS_MSG_MANAGEMENT_MULTIPLE_VPNS,
-            QS_MSG_NAMED_MANAGEMENT_MULTIPLE_VPNS, QS_MSG_WORK_PROFILE_MONITORING,
-            QS_MSG_NAMED_WORK_PROFILE_MONITORING, QS_MSG_WORK_PROFILE_NETWORK,
-            QS_MSG_WORK_PROFILE_NAMED_VPN, QS_MSG_PERSONAL_PROFILE_NAMED_VPN,
-            QS_DIALOG_MANAGEMENT_TITLE, QS_DIALOG_VIEW_POLICIES, QS_DIALOG_MANAGEMENT,
-            QS_DIALOG_NAMED_MANAGEMENT, QS_DIALOG_MANAGEMENT_CA_CERT,
-            QS_DIALOG_WORK_PROFILE_CA_CERT, QS_DIALOG_MANAGEMENT_NETWORK,
-            QS_DIALOG_WORK_PROFILE_NETWORK, QS_DIALOG_MANAGEMENT_NAMED_VPN,
-            QS_DIALOG_MANAGEMENT_TWO_NAMED_VPN, QS_DIALOG_WORK_PROFILE_NAMED_VPN,
-            QS_DIALOG_PERSONAL_PROFILE_NAMED_VPN, BIOMETRIC_DIALOG_WORK_PIN_LAST_ATTEMPT,
-            BIOMETRIC_DIALOG_WORK_PATTERN_LAST_ATTEMPT, BIOMETRIC_DIALOG_WORK_PASSWORD_LAST_ATTEMPT,
-            BIOMETRIC_DIALOG_WORK_LOCK_FAILED_ATTEMPTS, STATUS_BAR_WORK_ICON_ACCESSIBILITY,
-            ONGOING_PRIVACY_DIALOG_WORK, KEYGUARD_MANAGEMENT_DISCLOSURE,
-            KEYGUARD_NAMED_MANAGEMENT_DISCLOSURE, WORK_LOCK_ACCESSIBILITY,
-
-            // Core Strings
-            WORK_PROFILE_DELETED_TITLE, WORK_PROFILE_DELETED_FAILED_PASSWORD_ATTEMPTS_MESSAGE,
-            WORK_PROFILE_DELETED_GENERIC_MESSAGE, WORK_PROFILE_DELETED_ORG_OWNED_MESSAGE,
-            PERSONAL_APP_SUSPENSION_TITLE, PERSONAL_APP_SUSPENSION_MESSAGE,
-            PERSONAL_APP_SUSPENSION_SOON_MESSAGE, PERSONAL_APP_SUSPENSION_TURN_ON_PROFILE,
-            PRINTING_DISABLED_NAMED_ADMIN, LOCATION_CHANGED_TITLE, LOCATION_CHANGED_MESSAGE,
-            NETWORK_LOGGING_TITLE, NETWORK_LOGGING_MESSAGE,
-            NOTIFICATION_WORK_PROFILE_CONTENT_DESCRIPTION, NOTIFICATION_CHANNEL_DEVICE_ADMIN,
-            SWITCH_TO_WORK_LABEL, SWITCH_TO_PERSONAL_LABEL, FORWARD_INTENT_TO_WORK,
-            FORWARD_INTENT_TO_PERSONAL, RESOLVER_WORK_PROFILE_NOT_SUPPORTED, RESOLVER_PERSONAL_TAB,
-            RESOLVER_WORK_TAB, RESOLVER_PERSONAL_TAB_ACCESSIBILITY, RESOLVER_WORK_TAB_ACCESSIBILITY,
-            RESOLVER_CROSS_PROFILE_BLOCKED_TITLE, RESOLVER_CANT_SHARE_WITH_PERSONAL,
-            RESOLVER_CANT_SHARE_WITH_WORK, RESOLVER_CANT_ACCESS_PERSONAL, RESOLVER_CANT_ACCESS_WORK,
-            RESOLVER_WORK_PAUSED_TITLE, RESOLVER_NO_WORK_APPS, RESOLVER_NO_PERSONAL_APPS,
-            CANT_ADD_ACCOUNT_MESSAGE, PACKAGE_INSTALLED_BY_DO, PACKAGE_UPDATED_BY_DO,
-            PACKAGE_DELETED_BY_DO, UNLAUNCHABLE_APP_WORK_PAUSED_TITLE,
-            UNLAUNCHABLE_APP_WORK_PAUSED_MESSAGE, PROFILE_ENCRYPTED_TITLE, PROFILE_ENCRYPTED_DETAIL,
-            PROFILE_ENCRYPTED_MESSAGE, WORK_PROFILE_BADGED_LABEL,
-
-            // DocsUi Strings
-            WORK_PROFILE_OFF_ERROR_TITLE, WORK_PROFILE_OFF_ENABLE_BUTTON,
-            CANT_SELECT_WORK_FILES_TITLE, CANT_SELECT_WORK_FILES_MESSAGE,
-            CANT_SELECT_PERSONAL_FILES_TITLE, CANT_SELECT_PERSONAL_FILES_MESSAGE,
-            CANT_SAVE_TO_WORK_TITLE, CANT_SAVE_TO_WORK_MESSAGE, CANT_SAVE_TO_PERSONAL_TITLE,
-            CANT_SAVE_TO_PERSONAL_MESSAGE, CROSS_PROFILE_NOT_ALLOWED_TITLE,
-            CROSS_PROFILE_NOT_ALLOWED_MESSAGE, PREVIEW_WORK_FILE_ACCESSIBILITY, PERSONAL_TAB,
-            WORK_TAB, WORK_ACCESSIBILITY,
-
-            // MediaProvider Strings
-            SWITCH_TO_WORK_MESSAGE, SWITCH_TO_PERSONAL_MESSAGE, BLOCKED_BY_ADMIN_TITLE,
-            BLOCKED_FROM_PERSONAL_MESSAGE, BLOCKED_FROM_PERSONAL_MESSAGE,
-            BLOCKED_FROM_WORK_MESSAGE, Strings.MediaProvider.WORK_PROFILE_PAUSED_TITLE,
-            WORK_PROFILE_PAUSED_MESSAGE,
-
-            // Settings Strings
-            FACE_SETTINGS_FOR_WORK_TITLE, WORK_PROFILE_FINGERPRINT_LAST_DELETE_MESSAGE,
-            WORK_PROFILE_IT_ADMIN_CANT_RESET_SCREEN_LOCK, WORK_PROFILE_SCREEN_LOCK_SETUP_MESSAGE,
-            WORK_PROFILE_SET_UNLOCK_LAUNCH_PICKER_TITLE,
-            WORK_PROFILE_LAST_PATTERN_ATTEMPT_BEFORE_WIPE,
-            WORK_PROFILE_LAST_PIN_ATTEMPT_BEFORE_WIPE,
-            WORK_PROFILE_LAST_PASSWORD_ATTEMPT_BEFORE_WIPE, WORK_PROFILE_LOCK_ATTEMPTS_FAILED,
-            ACCESSIBILITY_CATEGORY_WORK, ACCESSIBILITY_CATEGORY_PERSONAL,
-            ACCESSIBILITY_WORK_ACCOUNT_TITLE, ACCESSIBILITY_PERSONAL_ACCOUNT_TITLE,
-            WORK_PROFILE_LOCATION_SWITCH_TITLE, SET_WORK_PROFILE_PASSWORD_HEADER,
-            SET_WORK_PROFILE_PIN_HEADER, SET_WORK_PROFILE_PATTERN_HEADER,
-            CONFIRM_WORK_PROFILE_PASSWORD_HEADER, CONFIRM_WORK_PROFILE_PIN_HEADER,
-            CONFIRM_WORK_PROFILE_PATTERN_HEADER, REENTER_WORK_PROFILE_PASSWORD_HEADER,
-            REENTER_WORK_PROFILE_PIN_HEADER, WORK_PROFILE_CONFIRM_PATTERN, WORK_PROFILE_CONFIRM_PIN,
-            WORK_PROFILE_PASSWORD_REQUIRED, WORK_PROFILE_SECURITY_TITLE,
-            WORK_PROFILE_UNIFY_LOCKS_TITLE, WORK_PROFILE_UNIFY_LOCKS_SUMMARY,
-            WORK_PROFILE_UNIFY_LOCKS_DETAIL, WORK_PROFILE_UNIFY_LOCKS_NONCOMPLIANT,
-            WORK_PROFILE_KEYBOARDS_AND_TOOLS, WORK_PROFILE_NOT_AVAILABLE, WORK_PROFILE_SETTING,
-            WORK_PROFILE_SETTING_ON_SUMMARY, WORK_PROFILE_SETTING_OFF_SUMMARY, REMOVE_WORK_PROFILE,
-            DEVICE_OWNER_INSTALLED_CERTIFICATE_AUTHORITY_WARNING,
-            WORK_PROFILE_INSTALLED_CERTIFICATE_AUTHORITY_WARNING, WORK_PROFILE_CONFIRM_REMOVE_TITLE,
-            WORK_PROFILE_CONFIRM_REMOVE_MESSAGE, WORK_APPS_CANNOT_ACCESS_NOTIFICATION_SETTINGS,
-            WORK_PROFILE_SOUND_SETTINGS_SECTION_HEADER, WORK_PROFILE_USE_PERSONAL_SOUNDS_TITLE,
-            WORK_PROFILE_USE_PERSONAL_SOUNDS_SUMMARY, WORK_PROFILE_RINGTONE_TITLE,
-            WORK_PROFILE_NOTIFICATION_RINGTONE_TITLE, WORK_PROFILE_ALARM_RINGTONE_TITLE,
-            WORK_PROFILE_SYNC_WITH_PERSONAL_SOUNDS_ACTIVE_SUMMARY,
-            ENABLE_WORK_PROFILE_SYNC_WITH_PERSONAL_SOUNDS_DIALOG_TITLE,
-            ENABLE_WORK_PROFILE_SYNC_WITH_PERSONAL_SOUNDS_DIALOG_MESSAGE,
-            WORK_PROFILE_NOTIFICATIONS_SECTION_HEADER, WORK_PROFILE_LOCKED_NOTIFICATION_TITLE,
-            WORK_PROFILE_LOCK_SCREEN_REDACT_NOTIFICATION_TITLE,
-            WORK_PROFILE_LOCK_SCREEN_REDACT_NOTIFICATION_SUMMARY,
-            WORK_PROFILE_NOTIFICATION_LISTENER_BLOCKED, CONNECTED_WORK_AND_PERSONAL_APPS_TITLE,
-            CONNECTED_APPS_SHARE_PERMISSIONS_AND_DATA, ONLY_CONNECT_TRUSTED_APPS,
-            HOW_TO_DISCONNECT_APPS, CONNECT_APPS_DIALOG_TITLE, CONNECT_APPS_DIALOG_SUMMARY,
-            APP_CAN_ACCESS_PERSONAL_DATA, APP_CAN_ACCESS_PERSONAL_PERMISSIONS,
-            INSTALL_IN_WORK_PROFILE_TO_CONNECT_PROMPT,
-            INSTALL_IN_PERSONAL_PROFILE_TO_CONNECT_PROMPT, WORK_PROFILE_MANAGED_BY, MANAGED_BY,
-            WORK_PROFILE_DISABLE_USAGE_ACCESS_WARNING, DISABLED_BY_IT_ADMIN_TITLE,
-            CONTACT_YOUR_IT_ADMIN, WORK_PROFILE_ADMIN_POLICIES_WARNING, USER_ADMIN_POLICIES_WARNING,
-            DEVICE_ADMIN_POLICIES_WARNING, WORK_PROFILE_OFF_CONDITION_TITLE,
-            MANAGED_PROFILE_SETTINGS_TITLE, WORK_PROFILE_CONTACT_SEARCH_TITLE,
-            WORK_PROFILE_CONTACT_SEARCH_SUMMARY, CROSS_PROFILE_CALENDAR_TITLE,
-            CROSS_PROFILE_CALENDAR_SUMMARY, ALWAYS_ON_VPN_PERSONAL_PROFILE, ALWAYS_ON_VPN_DEVICE,
-            ALWAYS_ON_VPN_WORK_PROFILE, CA_CERTS_PERSONAL_PROFILE, CA_CERTS_WORK_PROFILE,
-            CA_CERTS_DEVICE, ADMIN_CAN_LOCK_DEVICE, ADMIN_CAN_WIPE_DEVICE,
-            ADMIN_CONFIGURED_FAILED_PASSWORD_WIPE_DEVICE,
-            ADMIN_CONFIGURED_FAILED_PASSWORD_WIPE_WORK_PROFILE, DEVICE_MANAGED_WITHOUT_NAME,
-            DEVICE_MANAGED_WITH_NAME, WORK_PROFILE_APP_SUBTEXT, PERSONAL_PROFILE_APP_SUBTEXT,
-            FINGERPRINT_FOR_WORK, FACE_UNLOCK_DISABLED, FINGERPRINT_UNLOCK_DISABLED,
-            FINGERPRINT_UNLOCK_DISABLED_EXPLANATION, PIN_RECENTLY_USED, PASSWORD_RECENTLY_USED,
-            MANAGE_DEVICE_ADMIN_APPS, NUMBER_OF_DEVICE_ADMINS_NONE, NUMBER_OF_DEVICE_ADMINS,
-            FORGOT_PASSWORD_TITLE, FORGOT_PASSWORD_TEXT, ERROR_MOVE_DEVICE_ADMIN,
-            DEVICE_ADMIN_SETTINGS_TITLE, REMOVE_DEVICE_ADMIN, UNINSTALL_DEVICE_ADMIN,
-            REMOVE_AND_UNINSTALL_DEVICE_ADMIN, SELECT_DEVICE_ADMIN_APPS, NO_DEVICE_ADMINS,
-            ACTIVATE_DEVICE_ADMIN_APP, ACTIVATE_THIS_DEVICE_ADMIN_APP,
-            ACTIVATE_DEVICE_ADMIN_APP_TITLE, NEW_DEVICE_ADMIN_WARNING,
-            NEW_DEVICE_ADMIN_WARNING_SIMPLIFIED, ACTIVE_DEVICE_ADMIN_WARNING,
-            SET_PROFILE_OWNER_TITLE, SET_PROFILE_OWNER_DIALOG_TITLE,
-            SET_PROFILE_OWNER_POSTSETUP_WARNING, OTHER_OPTIONS_DISABLED_BY_ADMIN,
-            REMOVE_ACCOUNT_FAILED_ADMIN_RESTRICTION, IT_ADMIN_POLICY_DISABLING_INFO_URL,
-            SHARE_REMOTE_BUGREPORT_DIALOG_TITLE, SHARE_REMOTE_BUGREPORT_FINISHED_REQUEST_CONSENT,
-            SHARE_REMOTE_BUGREPORT_NOT_FINISHED_REQUEST_CONSENT, SHARING_REMOTE_BUGREPORT_MESSAGE,
-            MANAGED_DEVICE_INFO, MANAGED_DEVICE_INFO_SUMMARY, MANAGED_DEVICE_INFO_SUMMARY_WITH_NAME,
-            ENTERPRISE_PRIVACY_HEADER, INFORMATION_YOUR_ORGANIZATION_CAN_SEE_TITLE,
-            CHANGES_MADE_BY_YOUR_ORGANIZATION_ADMIN_TITLE, YOUR_ACCESS_TO_THIS_DEVICE_TITLE,
-            ADMIN_CAN_SEE_WORK_DATA_WARNING, ADMIN_CAN_SEE_APPS_WARNING,
-            ADMIN_CAN_SEE_USAGE_WARNING, ADMIN_CAN_SEE_NETWORK_LOGS_WARNING,
-            ADMIN_CAN_SEE_BUG_REPORT_WARNING, ADMIN_CAN_SEE_SECURITY_LOGS_WARNING,
-            ADMIN_ACTION_NONE, ADMIN_ACTION_APPS_INSTALLED, ADMIN_ACTION_APPS_COUNT_ESTIMATED,
-            ADMIN_ACTIONS_APPS_COUNT_MINIMUM, ADMIN_ACTION_ACCESS_LOCATION,
-            ADMIN_ACTION_ACCESS_MICROPHONE, ADMIN_ACTION_ACCESS_CAMERA,
-            ADMIN_ACTION_SET_DEFAULT_APPS, ADMIN_ACTIONS_APPS_COUNT,
-            ADMIN_ACTION_SET_CURRENT_INPUT_METHOD, ADMIN_ACTION_SET_INPUT_METHOD_NAME,
-            ADMIN_ACTION_SET_HTTP_PROXY, WORK_PROFILE_PRIVACY_POLICY_INFO_SUMMARY,
-            WORK_PROFILE_PRIVACY_POLICY_INFO, CONNECTED_APPS_SEARCH_KEYWORDS,
-            WORK_PROFILE_UNIFICATION_SEARCH_KEYWORDS, ACCOUNTS_SEARCH_KEYWORDS,
-            CONTROLLED_BY_ADMIN_SUMMARY, WORK_PROFILE_USER_LABEL, WORK_CATEGORY_HEADER,
-            PERSONAL_CATEGORY_HEADER,
-
-            // PermissionController Strings
-            WORK_PROFILE_DEFAULT_APPS_TITLE, HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE,
-            BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE, BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE,
-            BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE, FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE,
-            LOCATION_AUTO_GRANTED_MESSAGE,
-
-            // Dialer Strings
-            NOTIFICATION_INCOMING_WORK_CALL_TITLE, NOTIFICATION_ONGOING_WORK_CALL_TITLE,
-            NOTIFICATION_MISSED_WORK_CALL_TITLE, NOTIFICATION_WIFI_WORK_CALL_LABEL,
-    })
-    public @interface UpdatableStringId {
-    }
+    public static final String UNDEFINED = "UNDEFINED";
 
     /**
      * Class containing the identifiers used to update device management-related system drawable.
+     *
+     * @hide
      */
     public static final class Drawables {
 
@@ -536,11 +49,6 @@
         }
 
         /**
-         * An ID for any drawable that can't be updated.
-         */
-        public static final String UNDEFINED = "UNDEFINED";
-
-        /**
          * Specifically used to badge work profile app icons.
          */
         public static final String WORK_PROFILE_ICON_BADGE = "WORK_PROFILE_ICON_BADGE";
@@ -562,20 +70,6 @@
         public static final String WORK_PROFILE_USER_ICON = "WORK_PROFILE_USER_ICON";
 
         /**
-         * @hide
-         */
-        public static final Set<String> UPDATABLE_DRAWABLE_IDS = buildDrawablesSet();
-
-        private static Set<String> buildDrawablesSet() {
-            Set<String> drawables = new HashSet<>();
-            drawables.add(WORK_PROFILE_ICON_BADGE);
-            drawables.add(WORK_PROFILE_ICON);
-            drawables.add(WORK_PROFILE_OFF_ICON);
-            drawables.add(WORK_PROFILE_USER_ICON);
-            return drawables;
-        }
-
-        /**
          * Class containing the source identifiers used to update device management-related system
          * drawable.
          */
@@ -585,12 +79,6 @@
             }
 
             /**
-             * A source identifier indicating that the updatable resource is used in a generic
-             * undefined location.
-             */
-            public static final String UNDEFINED = "UNDEFINED";
-
-            /**
              * A source identifier indicating that the updatable drawable is used in notifications.
              */
             public static final String NOTIFICATION = "NOTIFICATION";
@@ -622,42 +110,18 @@
              * A source identifier indicating that the updatable drawable is used in the status bar.
              */
             public static final String STATUS_BAR = "STATUS_BAR";
-
-            /**
-             * @hide
-             */
-            public static final Set<String> UPDATABLE_DRAWABLE_SOURCES = buildSourcesSet();
-
-            private static Set<String> buildSourcesSet() {
-                Set<String> sources = new HashSet<>();
-                sources.add(UNDEFINED);
-                sources.add(NOTIFICATION);
-                sources.add(PROFILE_SWITCH_ANIMATION);
-                sources.add(HOME_WIDGET);
-                sources.add(LAUNCHER_OFF_BUTTON);
-                sources.add(QUICK_SETTINGS);
-                sources.add(STATUS_BAR);
-                return sources;
-            }
         }
 
         /**
          * Class containing the style identifiers used to update device management-related system
          * drawable.
          */
-        @SuppressLint("StaticUtils")
         public static final class Style {
 
             private Style() {
             }
 
             /**
-             * A style identifier indicating that the updatable drawable should use the default
-             * style.
-             */
-            public static final String DEFAULT = "DEFAULT";
-
-            /**
              * A style identifier indicating that the updatable drawable has a solid color fill.
              */
             public static final String SOLID_COLORED = "SOLID_COLORED";
@@ -672,20 +136,6 @@
              * A style identifier indicating that the updatable drawable is an outline.
              */
             public static final String OUTLINE = "OUTLINE";
-
-            /**
-             * @hide
-             */
-            public static final Set<String> UPDATABLE_DRAWABLE_STYLES = buildStylesSet();
-
-            private static Set<String> buildStylesSet() {
-                Set<String> styles = new HashSet<>();
-                styles.add(DEFAULT);
-                styles.add(SOLID_COLORED);
-                styles.add(SOLID_NOT_COLORED);
-                styles.add(OUTLINE);
-                return styles;
-            }
         }
     }
 
@@ -701,29 +151,6 @@
         }
 
         /**
-         * An ID for any string that can't be updated.
-         */
-        public static final String UNDEFINED = "UNDEFINED";
-
-        /**
-         * @hide
-         */
-        public static final Set<String> UPDATABLE_STRING_IDS = buildStringsSet();
-
-        private static Set<String> buildStringsSet() {
-            Set<String> strings = new HashSet<>();
-            strings.addAll(Settings.buildStringsSet());
-            strings.addAll(Launcher.buildStringsSet());
-            strings.addAll(SystemUi.buildStringsSet());
-            strings.addAll(Core.buildStringsSet());
-            strings.addAll(DocumentsUi.buildStringsSet());
-            strings.addAll(MediaProvider.buildStringsSet());
-            strings.addAll(PermissionController.buildStringsSet());
-            strings.addAll(Dialer.buildStringsSet());
-            return strings;
-        }
-
-        /**
          * Class containing the identifiers used to update device management-related system strings
          * in the Settings package
          *
@@ -1747,288 +1174,6 @@
              * Header for items under the personal user
              */
             public static final String PERSONAL_CATEGORY_HEADER = PREFIX + "category_personal";
-
-            /**
-             * @hide
-             */
-            static Set<String> buildStringsSet() {
-                Set<String> strings = new HashSet<>();
-                strings.add(FACE_SETTINGS_FOR_WORK_TITLE);
-                strings.add(WORK_PROFILE_FINGERPRINT_LAST_DELETE_MESSAGE);
-                strings.add(WORK_PROFILE_IT_ADMIN_CANT_RESET_SCREEN_LOCK);
-                strings.add(WORK_PROFILE_SCREEN_LOCK_SETUP_MESSAGE);
-                strings.add(WORK_PROFILE_SET_UNLOCK_LAUNCH_PICKER_TITLE);
-                strings.add(WORK_PROFILE_LAST_PATTERN_ATTEMPT_BEFORE_WIPE);
-                strings.add(WORK_PROFILE_LAST_PIN_ATTEMPT_BEFORE_WIPE);
-                strings.add(WORK_PROFILE_LAST_PASSWORD_ATTEMPT_BEFORE_WIPE);
-                strings.add(WORK_PROFILE_LOCK_ATTEMPTS_FAILED);
-                strings.add(ACCESSIBILITY_CATEGORY_WORK);
-                strings.add(ACCESSIBILITY_CATEGORY_PERSONAL);
-                strings.add(ACCESSIBILITY_WORK_ACCOUNT_TITLE);
-                strings.add(ACCESSIBILITY_PERSONAL_ACCOUNT_TITLE);
-                strings.add(WORK_PROFILE_LOCATION_SWITCH_TITLE);
-                strings.add(SET_WORK_PROFILE_PASSWORD_HEADER);
-                strings.add(SET_WORK_PROFILE_PIN_HEADER);
-                strings.add(SET_WORK_PROFILE_PATTERN_HEADER);
-                strings.add(CONFIRM_WORK_PROFILE_PASSWORD_HEADER);
-                strings.add(CONFIRM_WORK_PROFILE_PIN_HEADER);
-                strings.add(CONFIRM_WORK_PROFILE_PATTERN_HEADER);
-                strings.add(REENTER_WORK_PROFILE_PASSWORD_HEADER);
-                strings.add(REENTER_WORK_PROFILE_PIN_HEADER);
-                strings.add(WORK_PROFILE_CONFIRM_PATTERN);
-                strings.add(WORK_PROFILE_CONFIRM_PIN);
-                strings.add(WORK_PROFILE_PASSWORD_REQUIRED);
-                strings.add(WORK_PROFILE_SECURITY_TITLE);
-                strings.add(WORK_PROFILE_UNIFY_LOCKS_TITLE);
-                strings.add(WORK_PROFILE_UNIFY_LOCKS_SUMMARY);
-                strings.add(WORK_PROFILE_UNIFY_LOCKS_DETAIL);
-                strings.add(WORK_PROFILE_UNIFY_LOCKS_NONCOMPLIANT);
-                strings.add(WORK_PROFILE_KEYBOARDS_AND_TOOLS);
-                strings.add(WORK_PROFILE_NOT_AVAILABLE);
-                strings.add(WORK_PROFILE_SETTING);
-                strings.add(WORK_PROFILE_SETTING_ON_SUMMARY);
-                strings.add(WORK_PROFILE_SETTING_OFF_SUMMARY);
-                strings.add(REMOVE_WORK_PROFILE);
-                strings.add(DEVICE_OWNER_INSTALLED_CERTIFICATE_AUTHORITY_WARNING);
-                strings.add(WORK_PROFILE_INSTALLED_CERTIFICATE_AUTHORITY_WARNING);
-                strings.add(WORK_PROFILE_CONFIRM_REMOVE_TITLE);
-                strings.add(WORK_PROFILE_CONFIRM_REMOVE_MESSAGE);
-                strings.add(WORK_APPS_CANNOT_ACCESS_NOTIFICATION_SETTINGS);
-                strings.add(WORK_PROFILE_SOUND_SETTINGS_SECTION_HEADER);
-                strings.add(WORK_PROFILE_USE_PERSONAL_SOUNDS_TITLE);
-                strings.add(WORK_PROFILE_USE_PERSONAL_SOUNDS_SUMMARY);
-                strings.add(WORK_PROFILE_RINGTONE_TITLE);
-                strings.add(WORK_PROFILE_NOTIFICATION_RINGTONE_TITLE);
-                strings.add(WORK_PROFILE_ALARM_RINGTONE_TITLE);
-                strings.add(WORK_PROFILE_SYNC_WITH_PERSONAL_SOUNDS_ACTIVE_SUMMARY);
-                strings.add(ENABLE_WORK_PROFILE_SYNC_WITH_PERSONAL_SOUNDS_DIALOG_TITLE);
-                strings.add(ENABLE_WORK_PROFILE_SYNC_WITH_PERSONAL_SOUNDS_DIALOG_MESSAGE);
-                strings.add(WORK_PROFILE_NOTIFICATIONS_SECTION_HEADER);
-                strings.add(WORK_PROFILE_LOCKED_NOTIFICATION_TITLE);
-                strings.add(WORK_PROFILE_LOCK_SCREEN_REDACT_NOTIFICATION_TITLE);
-                strings.add(WORK_PROFILE_LOCK_SCREEN_REDACT_NOTIFICATION_SUMMARY);
-                strings.add(WORK_PROFILE_NOTIFICATION_LISTENER_BLOCKED);
-                strings.add(CONNECTED_WORK_AND_PERSONAL_APPS_TITLE);
-                strings.add(CONNECTED_APPS_SHARE_PERMISSIONS_AND_DATA);
-                strings.add(ONLY_CONNECT_TRUSTED_APPS);
-                strings.add(HOW_TO_DISCONNECT_APPS);
-                strings.add(CONNECT_APPS_DIALOG_TITLE);
-                strings.add(CONNECT_APPS_DIALOG_SUMMARY);
-                strings.add(APP_CAN_ACCESS_PERSONAL_DATA);
-                strings.add(APP_CAN_ACCESS_PERSONAL_PERMISSIONS);
-                strings.add(INSTALL_IN_WORK_PROFILE_TO_CONNECT_PROMPT);
-                strings.add(INSTALL_IN_PERSONAL_PROFILE_TO_CONNECT_PROMPT);
-                strings.add(WORK_PROFILE_MANAGED_BY);
-                strings.add(MANAGED_BY);
-                strings.add(WORK_PROFILE_DISABLE_USAGE_ACCESS_WARNING);
-                strings.add(DISABLED_BY_IT_ADMIN_TITLE);
-                strings.add(CONTACT_YOUR_IT_ADMIN);
-                strings.add(WORK_PROFILE_ADMIN_POLICIES_WARNING);
-                strings.add(USER_ADMIN_POLICIES_WARNING);
-                strings.add(DEVICE_ADMIN_POLICIES_WARNING);
-                strings.add(WORK_PROFILE_OFF_CONDITION_TITLE);
-                strings.add(MANAGED_PROFILE_SETTINGS_TITLE);
-                strings.add(WORK_PROFILE_CONTACT_SEARCH_TITLE);
-                strings.add(WORK_PROFILE_CONTACT_SEARCH_SUMMARY);
-                strings.add(CROSS_PROFILE_CALENDAR_TITLE);
-                strings.add(CROSS_PROFILE_CALENDAR_SUMMARY);
-                strings.add(ALWAYS_ON_VPN_PERSONAL_PROFILE);
-                strings.add(ALWAYS_ON_VPN_DEVICE);
-                strings.add(ALWAYS_ON_VPN_WORK_PROFILE);
-                strings.add(CA_CERTS_PERSONAL_PROFILE);
-                strings.add(CA_CERTS_WORK_PROFILE);
-                strings.add(CA_CERTS_DEVICE);
-                strings.add(ADMIN_CAN_LOCK_DEVICE);
-                strings.add(ADMIN_CAN_WIPE_DEVICE);
-                strings.add(ADMIN_CONFIGURED_FAILED_PASSWORD_WIPE_DEVICE);
-                strings.add(ADMIN_CONFIGURED_FAILED_PASSWORD_WIPE_WORK_PROFILE);
-                strings.add(DEVICE_MANAGED_WITHOUT_NAME);
-                strings.add(DEVICE_MANAGED_WITH_NAME);
-                strings.add(WORK_PROFILE_APP_SUBTEXT);
-                strings.add(PERSONAL_PROFILE_APP_SUBTEXT);
-                strings.add(FINGERPRINT_FOR_WORK);
-                strings.add(FACE_UNLOCK_DISABLED);
-                strings.add(FINGERPRINT_UNLOCK_DISABLED);
-                strings.add(FINGERPRINT_UNLOCK_DISABLED_EXPLANATION);
-                strings.add(PIN_RECENTLY_USED);
-                strings.add(PASSWORD_RECENTLY_USED);
-                strings.add(MANAGE_DEVICE_ADMIN_APPS);
-                strings.add(NUMBER_OF_DEVICE_ADMINS_NONE);
-                strings.add(NUMBER_OF_DEVICE_ADMINS);
-                strings.add(FORGOT_PASSWORD_TITLE);
-                strings.add(FORGOT_PASSWORD_TEXT);
-                strings.add(ERROR_MOVE_DEVICE_ADMIN);
-                strings.add(DEVICE_ADMIN_SETTINGS_TITLE);
-                strings.add(REMOVE_DEVICE_ADMIN);
-                strings.add(UNINSTALL_DEVICE_ADMIN);
-                strings.add(REMOVE_AND_UNINSTALL_DEVICE_ADMIN);
-                strings.add(SELECT_DEVICE_ADMIN_APPS);
-                strings.add(NO_DEVICE_ADMINS);
-                strings.add(ACTIVATE_DEVICE_ADMIN_APP);
-                strings.add(ACTIVATE_THIS_DEVICE_ADMIN_APP);
-                strings.add(ACTIVATE_DEVICE_ADMIN_APP_TITLE);
-                strings.add(NEW_DEVICE_ADMIN_WARNING);
-                strings.add(NEW_DEVICE_ADMIN_WARNING_SIMPLIFIED);
-                strings.add(ACTIVE_DEVICE_ADMIN_WARNING);
-                strings.add(SET_PROFILE_OWNER_TITLE);
-                strings.add(SET_PROFILE_OWNER_DIALOG_TITLE);
-                strings.add(SET_PROFILE_OWNER_POSTSETUP_WARNING);
-                strings.add(OTHER_OPTIONS_DISABLED_BY_ADMIN);
-                strings.add(REMOVE_ACCOUNT_FAILED_ADMIN_RESTRICTION);
-                strings.add(IT_ADMIN_POLICY_DISABLING_INFO_URL);
-                strings.add(SHARE_REMOTE_BUGREPORT_DIALOG_TITLE);
-                strings.add(SHARE_REMOTE_BUGREPORT_FINISHED_REQUEST_CONSENT);
-                strings.add(SHARE_REMOTE_BUGREPORT_NOT_FINISHED_REQUEST_CONSENT);
-                strings.add(SHARING_REMOTE_BUGREPORT_MESSAGE);
-                strings.add(MANAGED_DEVICE_INFO);
-                strings.add(MANAGED_DEVICE_INFO_SUMMARY);
-                strings.add(MANAGED_DEVICE_INFO_SUMMARY_WITH_NAME);
-                strings.add(ENTERPRISE_PRIVACY_HEADER);
-                strings.add(INFORMATION_YOUR_ORGANIZATION_CAN_SEE_TITLE);
-                strings.add(CHANGES_MADE_BY_YOUR_ORGANIZATION_ADMIN_TITLE);
-                strings.add(YOUR_ACCESS_TO_THIS_DEVICE_TITLE);
-                strings.add(ADMIN_CAN_SEE_WORK_DATA_WARNING);
-                strings.add(ADMIN_CAN_SEE_APPS_WARNING);
-                strings.add(ADMIN_CAN_SEE_USAGE_WARNING);
-                strings.add(ADMIN_CAN_SEE_NETWORK_LOGS_WARNING);
-                strings.add(ADMIN_CAN_SEE_BUG_REPORT_WARNING);
-                strings.add(ADMIN_CAN_SEE_SECURITY_LOGS_WARNING);
-                strings.add(ADMIN_ACTION_NONE);
-                strings.add(ADMIN_ACTION_APPS_INSTALLED);
-                strings.add(ADMIN_ACTION_APPS_COUNT_ESTIMATED);
-                strings.add(ADMIN_ACTIONS_APPS_COUNT_MINIMUM);
-                strings.add(ADMIN_ACTION_ACCESS_LOCATION);
-                strings.add(ADMIN_ACTION_ACCESS_MICROPHONE);
-                strings.add(ADMIN_ACTION_ACCESS_CAMERA);
-                strings.add(ADMIN_ACTION_SET_DEFAULT_APPS);
-                strings.add(ADMIN_ACTIONS_APPS_COUNT);
-                strings.add(ADMIN_ACTION_SET_CURRENT_INPUT_METHOD);
-                strings.add(ADMIN_ACTION_SET_INPUT_METHOD_NAME);
-                strings.add(ADMIN_ACTION_SET_HTTP_PROXY);
-                strings.add(WORK_PROFILE_PRIVACY_POLICY_INFO_SUMMARY);
-                strings.add(WORK_PROFILE_PRIVACY_POLICY_INFO);
-                strings.add(CONNECTED_APPS_SEARCH_KEYWORDS);
-                strings.add(WORK_PROFILE_UNIFICATION_SEARCH_KEYWORDS);
-                strings.add(ACCOUNTS_SEARCH_KEYWORDS);
-                strings.add(CONTROLLED_BY_ADMIN_SUMMARY);
-                strings.add(WORK_PROFILE_USER_LABEL);
-                strings.add(WORK_CATEGORY_HEADER);
-                strings.add(PERSONAL_CATEGORY_HEADER);
-                return strings;
-            }
-        }
-
-        /**
-         * Class containing the identifiers used to update device management-related system strings
-         * in the Launcher package.
-         *
-         * @hide
-         */
-        public static final class Launcher {
-
-            private Launcher() {
-            }
-
-            private static final String PREFIX = "Launcher.";
-
-            /**
-             * User on-boarding title for work profile apps.
-             */
-            public static final String WORK_PROFILE_EDU = PREFIX + "WORK_PROFILE_EDU";
-
-            /**
-             * Action label to finish work profile edu.
-             */
-            public static final String WORK_PROFILE_EDU_ACCEPT = PREFIX + "WORK_PROFILE_EDU_ACCEPT";
-
-            /**
-             * Title shown when user opens work apps tab while work profile is paused.
-             */
-            public static final String WORK_PROFILE_PAUSED_TITLE =
-                    PREFIX + "WORK_PROFILE_PAUSED_TITLE";
-
-            /**
-             * Description shown when user opens work apps tab while work profile is paused.
-             */
-            public static final String WORK_PROFILE_PAUSED_DESCRIPTION =
-                    PREFIX + "WORK_PROFILE_PAUSED_DESCRIPTION";
-
-            /**
-             * Shown on the button to pause work profile.
-             */
-            public static final String WORK_PROFILE_PAUSE_BUTTON =
-                    PREFIX + "WORK_PROFILE_PAUSE_BUTTON";
-
-            /**
-             * Shown on the button to enable work profile.
-             */
-            public static final String WORK_PROFILE_ENABLE_BUTTON =
-                    PREFIX + "WORK_PROFILE_ENABLE_BUTTON";
-
-            /**
-             * Label on launcher tab to indicate work apps.
-             */
-            public static final String ALL_APPS_WORK_TAB = PREFIX + "ALL_APPS_WORK_TAB";
-
-            /**
-             * Label on launcher tab to indicate personal apps.
-             */
-            public static final String ALL_APPS_PERSONAL_TAB = PREFIX + "ALL_APPS_PERSONAL_TAB";
-
-            /**
-             * Accessibility description for launcher tab to indicate work apps.
-             */
-            public static final String ALL_APPS_WORK_TAB_ACCESSIBILITY =
-                    PREFIX + "ALL_APPS_WORK_TAB_ACCESSIBILITY";
-
-            /**
-             * Accessibility description for launcher tab to indicate personal apps.
-             */
-            public static final String ALL_APPS_PERSONAL_TAB_ACCESSIBILITY =
-                    PREFIX + "ALL_APPS_PERSONAL_TAB_ACCESSIBILITY";
-
-            /**
-             * Work folder name.
-             */
-            public static final String WORK_FOLDER_NAME = PREFIX + "WORK_FOLDER_NAME";
-
-            /**
-             * Label on widget tab to indicate work app widgets.
-             */
-            public static final String WIDGETS_WORK_TAB = PREFIX + "WIDGETS_WORK_TAB";
-
-            /**
-             * Label on widget tab to indicate personal app widgets.
-             */
-            public static final String WIDGETS_PERSONAL_TAB = PREFIX + "WIDGETS_PERSONAL_TAB";
-
-            /**
-             * Message shown when a feature is disabled by the admin (e.g. changing wallpaper).
-             */
-            public static final String DISABLED_BY_ADMIN_MESSAGE =
-                    PREFIX + "DISABLED_BY_ADMIN_MESSAGE";
-
-            /**
-             * @hide
-             */
-            static Set<String> buildStringsSet() {
-                Set<String> strings = new HashSet<>();
-                strings.add(WORK_PROFILE_EDU);
-                strings.add(WORK_PROFILE_EDU_ACCEPT);
-                strings.add(WORK_PROFILE_PAUSED_TITLE);
-                strings.add(WORK_PROFILE_PAUSED_DESCRIPTION);
-                strings.add(WORK_PROFILE_PAUSE_BUTTON);
-                strings.add(WORK_PROFILE_ENABLE_BUTTON);
-                strings.add(ALL_APPS_WORK_TAB);
-                strings.add(ALL_APPS_PERSONAL_TAB);
-                strings.add(ALL_APPS_PERSONAL_TAB_ACCESSIBILITY);
-                strings.add(ALL_APPS_WORK_TAB_ACCESSIBILITY);
-                strings.add(WORK_FOLDER_NAME);
-                strings.add(WIDGETS_WORK_TAB);
-                strings.add(WIDGETS_PERSONAL_TAB);
-                strings.add(DISABLED_BY_ADMIN_MESSAGE);
-                return strings;
-            }
         }
 
         /**
@@ -2272,49 +1417,6 @@
              * Content description for the work profile lock screen.
              */
             public static final String WORK_LOCK_ACCESSIBILITY = PREFIX + "WORK_LOCK_ACCESSIBILITY";
-
-            /**
-             * @hide
-             */
-            static Set<String> buildStringsSet() {
-                Set<String> strings = new HashSet<>();
-                strings.add(QS_WORK_PROFILE_LABEL);
-                strings.add(QS_MSG_MANAGEMENT);
-                strings.add(QS_MSG_NAMED_MANAGEMENT);
-                strings.add(QS_MSG_MANAGEMENT_MONITORING);
-                strings.add(QS_MSG_NAMED_MANAGEMENT_MONITORING);
-                strings.add(QS_MSG_MANAGEMENT_NAMED_VPN);
-                strings.add(QS_MSG_NAMED_MANAGEMENT_NAMED_VPN);
-                strings.add(QS_MSG_MANAGEMENT_MULTIPLE_VPNS);
-                strings.add(QS_MSG_NAMED_MANAGEMENT_MULTIPLE_VPNS);
-                strings.add(QS_MSG_WORK_PROFILE_MONITORING);
-                strings.add(QS_MSG_NAMED_WORK_PROFILE_MONITORING);
-                strings.add(QS_MSG_WORK_PROFILE_NETWORK);
-                strings.add(QS_MSG_WORK_PROFILE_NAMED_VPN);
-                strings.add(QS_MSG_PERSONAL_PROFILE_NAMED_VPN);
-                strings.add(QS_DIALOG_MANAGEMENT_TITLE);
-                strings.add(QS_DIALOG_VIEW_POLICIES);
-                strings.add(QS_DIALOG_MANAGEMENT);
-                strings.add(QS_DIALOG_NAMED_MANAGEMENT);
-                strings.add(QS_DIALOG_MANAGEMENT_CA_CERT);
-                strings.add(QS_DIALOG_WORK_PROFILE_CA_CERT);
-                strings.add(QS_DIALOG_MANAGEMENT_NETWORK);
-                strings.add(QS_DIALOG_WORK_PROFILE_NETWORK);
-                strings.add(QS_DIALOG_MANAGEMENT_NAMED_VPN);
-                strings.add(QS_DIALOG_MANAGEMENT_TWO_NAMED_VPN);
-                strings.add(QS_DIALOG_WORK_PROFILE_NAMED_VPN);
-                strings.add(QS_DIALOG_PERSONAL_PROFILE_NAMED_VPN);
-                strings.add(BIOMETRIC_DIALOG_WORK_PIN_LAST_ATTEMPT);
-                strings.add(BIOMETRIC_DIALOG_WORK_PATTERN_LAST_ATTEMPT);
-                strings.add(BIOMETRIC_DIALOG_WORK_PASSWORD_LAST_ATTEMPT);
-                strings.add(BIOMETRIC_DIALOG_WORK_LOCK_FAILED_ATTEMPTS);
-                strings.add(STATUS_BAR_WORK_ICON_ACCESSIBILITY);
-                strings.add(ONGOING_PRIVACY_DIALOG_WORK);
-                strings.add(KEYGUARD_MANAGEMENT_DISCLOSURE);
-                strings.add(KEYGUARD_NAMED_MANAGEMENT_DISCLOSURE);
-                strings.add(WORK_LOCK_ACCESSIBILITY);
-                return strings;
-            }
         }
 
         /**
@@ -2614,294 +1716,39 @@
              */
             public static final String WORK_PROFILE_BADGED_LABEL =
                     PREFIX + "WORK_PROFILE_BADGED_LABEL";
-
-            /**
-             * @hide
-             */
-            static Set<String> buildStringsSet() {
-                Set<String> strings = new HashSet<>();
-                strings.add(WORK_PROFILE_DELETED_TITLE);
-                strings.add(WORK_PROFILE_DELETED_FAILED_PASSWORD_ATTEMPTS_MESSAGE);
-                strings.add(WORK_PROFILE_DELETED_GENERIC_MESSAGE);
-                strings.add(WORK_PROFILE_DELETED_ORG_OWNED_MESSAGE);
-                strings.add(PERSONAL_APP_SUSPENSION_TITLE);
-                strings.add(PERSONAL_APP_SUSPENSION_MESSAGE);
-                strings.add(PERSONAL_APP_SUSPENSION_SOON_MESSAGE);
-                strings.add(PERSONAL_APP_SUSPENSION_TURN_ON_PROFILE);
-                strings.add(PRINTING_DISABLED_NAMED_ADMIN);
-                strings.add(LOCATION_CHANGED_TITLE);
-                strings.add(LOCATION_CHANGED_MESSAGE);
-                strings.add(NETWORK_LOGGING_TITLE);
-                strings.add(NETWORK_LOGGING_MESSAGE);
-                strings.add(NOTIFICATION_WORK_PROFILE_CONTENT_DESCRIPTION);
-                strings.add(NOTIFICATION_CHANNEL_DEVICE_ADMIN);
-                strings.add(SWITCH_TO_WORK_LABEL);
-                strings.add(SWITCH_TO_PERSONAL_LABEL);
-                strings.add(FORWARD_INTENT_TO_WORK);
-                strings.add(FORWARD_INTENT_TO_PERSONAL);
-                strings.add(RESOLVER_WORK_PROFILE_NOT_SUPPORTED);
-                strings.add(RESOLVER_PERSONAL_TAB);
-                strings.add(RESOLVER_WORK_TAB);
-                strings.add(RESOLVER_PERSONAL_TAB_ACCESSIBILITY);
-                strings.add(RESOLVER_WORK_TAB_ACCESSIBILITY);
-                strings.add(RESOLVER_CROSS_PROFILE_BLOCKED_TITLE);
-                strings.add(RESOLVER_CANT_SHARE_WITH_PERSONAL);
-                strings.add(RESOLVER_CANT_SHARE_WITH_WORK);
-                strings.add(RESOLVER_CANT_ACCESS_PERSONAL);
-                strings.add(RESOLVER_CANT_ACCESS_WORK);
-                strings.add(RESOLVER_WORK_PAUSED_TITLE);
-                strings.add(RESOLVER_NO_WORK_APPS);
-                strings.add(RESOLVER_NO_PERSONAL_APPS);
-                strings.add(CANT_ADD_ACCOUNT_MESSAGE);
-                strings.add(PACKAGE_INSTALLED_BY_DO);
-                strings.add(PACKAGE_UPDATED_BY_DO);
-                strings.add(PACKAGE_DELETED_BY_DO);
-                strings.add(UNLAUNCHABLE_APP_WORK_PAUSED_TITLE);
-                strings.add(UNLAUNCHABLE_APP_WORK_PAUSED_MESSAGE);
-                strings.add(PROFILE_ENCRYPTED_TITLE);
-                strings.add(PROFILE_ENCRYPTED_DETAIL);
-                strings.add(PROFILE_ENCRYPTED_MESSAGE);
-                strings.add(WORK_PROFILE_BADGED_LABEL);
-                return strings;
-            }
         }
 
         /**
          * Class containing the identifiers used to update device management-related system strings
-         * in the DocumentsUi package.
+         * in the Dialer app.
+         *
+         * @hide
          */
-        public static final class DocumentsUi {
+        public static final class Telecomm {
 
-            private DocumentsUi() {
+            private Telecomm() {
             }
 
-            private static final String PREFIX = "DocumentsUi.";
+            private static final String PREFIX = "Telecomm.";
 
             /**
-             * Title for error message shown when work profile is turned off.
+             * Missed call notification label, used when there's exactly one missed call from work
+             * contact.
              */
-            public static final String WORK_PROFILE_OFF_ERROR_TITLE =
-                    PREFIX + "WORK_PROFILE_OFF_ERROR_TITLE";
-
-            /**
-             * Button text shown when work profile is turned off.
-             */
-            public static final String WORK_PROFILE_OFF_ENABLE_BUTTON =
-                    PREFIX + "WORK_PROFILE_OFF_ENABLE_BUTTON";
-
-            /**
-             * Title for error message shown when a user's IT admin does not allow the user to
-             * select work files from a personal app.
-             */
-            public static final String CANT_SELECT_WORK_FILES_TITLE =
-                    PREFIX + "CANT_SELECT_WORK_FILES_TITLE";
-
-            /**
-             * Message shown when a user's IT admin does not allow the user to select work files
-             * from a personal app.
-             */
-            public static final String CANT_SELECT_WORK_FILES_MESSAGE =
-                    PREFIX + "CANT_SELECT_WORK_FILES_MESSAGE";
-
-            /**
-             * Title for error message shown when a user's IT admin does not allow the user to
-             * select personal files from a work app.
-             */
-            public static final String CANT_SELECT_PERSONAL_FILES_TITLE =
-                    PREFIX + "CANT_SELECT_PERSONAL_FILES_TITLE";
-
-            /**
-             * Message shown when a user's IT admin does not allow the user to select personal files
-             * from a work app.
-             */
-            public static final String CANT_SELECT_PERSONAL_FILES_MESSAGE =
-                    PREFIX + "CANT_SELECT_PERSONAL_FILES_MESSAGE";
-
-            /**
-             * Title for error message shown when a user's IT admin does not allow the user to save
-             * files from their personal profile to their work profile.
-             */
-            public static final String CANT_SAVE_TO_WORK_TITLE =
-                    PREFIX + "CANT_SAVE_TO_WORK_TITLE";
-
-            /**
-             * Message shown when a user's IT admin does not allow the user to save files from their
-             * personal profile to their work profile.
-             */
-            public static final String CANT_SAVE_TO_WORK_MESSAGE =
-                    PREFIX + "CANT_SAVE_TO_WORK_MESSAGE";
-
-            /**
-             * Title for error message shown when a user's IT admin does not allow the user to save
-             * files from their work profile to their personal profile.
-             */
-            public static final String CANT_SAVE_TO_PERSONAL_TITLE =
-                    PREFIX + "CANT_SAVE_TO_PERSONAL_TITLE";
-
-            /**
-             * Message shown when a user's IT admin does not allow the user to save files from their
-             * work profile to their personal profile.
-             */
-            public static final String CANT_SAVE_TO_PERSONAL_MESSAGE =
-                    PREFIX + "CANT_SAVE_TO_PERSONAL_MESSAGE";
-
-            /**
-             * Title for error message shown when a user tries to do something on their work
-             * device, but that action isn't allowed by their IT admin.
-             */
-            public static final String CROSS_PROFILE_NOT_ALLOWED_TITLE =
-                    PREFIX + "CROSS_PROFILE_NOT_ALLOWED_TITLE";
-
-            /**
-             * Message shown when a user tries to do something on their work device, but that action
-             * isn't allowed by their IT admin.
-             */
-            public static final String CROSS_PROFILE_NOT_ALLOWED_MESSAGE =
-                    PREFIX + "CROSS_PROFILE_NOT_ALLOWED_MESSAGE";
-
-            /**
-             * Content description text that's spoken by a screen reader for previewing a work file
-             * before opening it. Accepts file name as a param.
-             */
-            public static final String PREVIEW_WORK_FILE_ACCESSIBILITY =
-                    PREFIX + "PREVIEW_WORK_FILE_ACCESSIBILITY";
-
-            /**
-             * Label for tab and sidebar to indicate personal content.
-             */
-            public static final String PERSONAL_TAB = PREFIX + "PERSONAL_TAB";
-
-            /**
-             * Label for tab and sidebar tab to indicate work content
-             */
-            public static final String WORK_TAB = PREFIX + "WORK_TAB";
-
-            /**
-             * Accessibility label to indicate the subject(e.g. file/folder) is from work profile.
-             */
-            public static final String WORK_ACCESSIBILITY = PREFIX + "WORK_ACCESSIBILITY";
-
-            /**
-             * @hide
-             */
-            static Set<String> buildStringsSet() {
-                Set<String> strings = new HashSet<>();
-                strings.add(WORK_PROFILE_OFF_ERROR_TITLE);
-                strings.add(WORK_PROFILE_OFF_ENABLE_BUTTON);
-                strings.add(CANT_SELECT_WORK_FILES_TITLE);
-                strings.add(CANT_SELECT_WORK_FILES_MESSAGE);
-                strings.add(CANT_SELECT_PERSONAL_FILES_TITLE);
-                strings.add(CANT_SELECT_PERSONAL_FILES_MESSAGE);
-                strings.add(CANT_SAVE_TO_WORK_TITLE);
-                strings.add(CANT_SAVE_TO_WORK_MESSAGE);
-                strings.add(CANT_SAVE_TO_PERSONAL_TITLE);
-                strings.add(CANT_SAVE_TO_PERSONAL_MESSAGE);
-                strings.add(CROSS_PROFILE_NOT_ALLOWED_TITLE);
-                strings.add(CROSS_PROFILE_NOT_ALLOWED_MESSAGE);
-                strings.add(PREVIEW_WORK_FILE_ACCESSIBILITY);
-                strings.add(PERSONAL_TAB);
-                strings.add(WORK_TAB);
-                strings.add(WORK_ACCESSIBILITY);
-                return strings;
-            }
+            public static final String NOTIFICATION_MISSED_WORK_CALL_TITLE =
+                    PREFIX + "NOTIFICATION_MISSED_WORK_CALL_TITLE";
         }
 
         /**
          * Class containing the identifiers used to update device management-related system strings
-         * in the MediaProvider module.
+         * for the permission settings.
          */
-        public static final class MediaProvider {
+        public static final class PermissionSettings {
 
-            private MediaProvider() {
+            private PermissionSettings() {
             }
 
-            private static final String PREFIX = "MediaProvider.";
-
-            /**
-             * The text shown to switch to the work profile in PhotoPicker.
-             */
-            public static final String SWITCH_TO_WORK_MESSAGE =
-                    PREFIX + "SWITCH_TO_WORK_MESSAGE";
-
-            /**
-             * The text shown to switch to the personal profile in PhotoPicker.
-             */
-            public static final String SWITCH_TO_PERSONAL_MESSAGE =
-                    PREFIX + "SWITCH_TO_PERSONAL_MESSAGE";
-
-            /**
-             * The title for error dialog in PhotoPicker when the admin blocks cross user
-             * interaction for the intent.
-             */
-            public static final String BLOCKED_BY_ADMIN_TITLE =
-                    PREFIX + "BLOCKED_BY_ADMIN_TITLE";
-
-            /**
-             * The message for error dialog in PhotoPicker when the admin blocks cross user
-             * interaction from the personal profile.
-             */
-            public static final String BLOCKED_FROM_PERSONAL_MESSAGE =
-                    PREFIX + "BLOCKED_FROM_PERSONAL_MESSAGE";
-
-            /**
-             * The message for error dialog in PhotoPicker when the admin blocks cross user
-             * interaction from the work profile.
-             */
-            public static final String BLOCKED_FROM_WORK_MESSAGE =
-                    PREFIX + "BLOCKED_FROM_WORK_MESSAGE";
-
-            /**
-             * The title of the error dialog in PhotoPicker when the user tries to switch to work
-             * content, but work profile is off.
-             */
-            public static final String WORK_PROFILE_PAUSED_TITLE =
-                    PREFIX + "WORK_PROFILE_PAUSED_TITLE";
-
-            /**
-             * The message of the error dialog in PhotoPicker when the user tries to switch to work
-             * content, but work profile is off.
-             */
-            public static final String WORK_PROFILE_PAUSED_MESSAGE =
-                    PREFIX + "WORK_PROFILE_PAUSED_MESSAGE";
-
-            /**
-             * @hide
-             */
-            static Set<String> buildStringsSet() {
-                Set<String> strings = new HashSet<>();
-                strings.add(SWITCH_TO_WORK_MESSAGE);
-                strings.add(SWITCH_TO_PERSONAL_MESSAGE);
-                strings.add(BLOCKED_BY_ADMIN_TITLE);
-                strings.add(BLOCKED_FROM_PERSONAL_MESSAGE);
-                strings.add(BLOCKED_FROM_WORK_MESSAGE);
-                strings.add(WORK_PROFILE_PAUSED_TITLE);
-                strings.add(WORK_PROFILE_PAUSED_MESSAGE);
-                return strings;
-            }
-        }
-
-        /**
-         * Class containing the identifiers used to update device management-related system strings
-         * in the PermissionController module.
-         */
-        public static final class PermissionController {
-
-            private PermissionController() {
-            }
-
-            private static final String PREFIX = "PermissionController.";
-
-            /**
-             * Title for settings page to show default apps for work.
-             */
-            public static final String WORK_PROFILE_DEFAULT_APPS_TITLE =
-                    PREFIX + "WORK_PROFILE_DEFAULT_APPS_TITLE";
-
-            /**
-             * Summary indicating that a home role holder app is missing work profile support.
-             */
-            public static final String HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE =
-                    PREFIX + "HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE";
+            private static final String PREFIX = "PermissionSettings.";
 
             /**
              * Summary of a permission switch in Settings when the background access is denied by an
@@ -2930,69 +1777,30 @@
              */
             public static final String LOCATION_AUTO_GRANTED_MESSAGE =
                     PREFIX + "LOCATION_AUTO_GRANTED_MESSAGE";
-
-            /**
-             * @hide
-             */
-            static Set<String> buildStringsSet() {
-                Set<String> strings = new HashSet<>();
-                strings.add(WORK_PROFILE_DEFAULT_APPS_TITLE);
-                strings.add(HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE);
-                strings.add(BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE);
-                strings.add(BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE);
-                strings.add(FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE);
-                strings.add(LOCATION_AUTO_GRANTED_MESSAGE);
-                return strings;
-            }
         }
 
         /**
          * Class containing the identifiers used to update device management-related system strings
-         * in the Dialer app.
+         * for the default app settings.
          */
-        public static final class Dialer {
+        public static final class DefaultAppSettings {
 
-            private Dialer() {
+            private DefaultAppSettings() {
             }
 
-            private static final String PREFIX = "Dialer.";
+            private static final String PREFIX = "DefaultAppSettings.";
 
             /**
-             * The title of the in-call notification for an incoming work call.
+             * Title for settings page to show default apps for work.
              */
-            public static final String NOTIFICATION_INCOMING_WORK_CALL_TITLE =
-                    PREFIX + "NOTIFICATION_INCOMING_WORK_CALL_TITLE";
+            public static final String WORK_PROFILE_DEFAULT_APPS_TITLE =
+                    PREFIX + "WORK_PROFILE_DEFAULT_APPS_TITLE";
 
             /**
-             * The title of the in-call notification for an ongoing work call.
+             * Summary indicating that a home role holder app is missing work profile support.
              */
-            public static final String NOTIFICATION_ONGOING_WORK_CALL_TITLE =
-                    PREFIX + "NOTIFICATION_ONGOING_WORK_CALL_TITLE";
-
-            /**
-             * Missed call notification label, used when there's exactly one missed call from work
-             * contact.
-             */
-            public static final String NOTIFICATION_MISSED_WORK_CALL_TITLE =
-                    PREFIX + "NOTIFICATION_MISSED_WORK_CALL_TITLE";
-
-            /**
-             * Label for notification indicating that call is being made over wifi.
-             */
-            public static final String NOTIFICATION_WIFI_WORK_CALL_LABEL =
-                    PREFIX + "NOTIFICATION_WIFI_WORK_CALL_LABEL";
-
-            /**
-             * @hide
-             */
-            static Set<String> buildStringsSet() {
-                Set<String> strings = new HashSet<>();
-                strings.add(NOTIFICATION_INCOMING_WORK_CALL_TITLE);
-                strings.add(NOTIFICATION_ONGOING_WORK_CALL_TITLE);
-                strings.add(NOTIFICATION_MISSED_WORK_CALL_TITLE);
-                strings.add(NOTIFICATION_WIFI_WORK_CALL_LABEL);
-                return strings;
-            }
+            public static final String HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE =
+                    PREFIX + "HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE";
         }
     }
 }
diff --git a/core/java/android/app/admin/DevicePolicyResourcesManager.java b/core/java/android/app/admin/DevicePolicyResourcesManager.java
new file mode 100644
index 0000000..0672922
--- /dev/null
+++ b/core/java/android/app/admin/DevicePolicyResourcesManager.java
@@ -0,0 +1,528 @@
+/*
+ * 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 android.app.admin;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.os.RemoteException;
+import android.util.DisplayMetrics;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Supplier;
+
+/**
+ * Class containing required APIs to set, reset, and get device policy related resources.
+ */
+public class DevicePolicyResourcesManager {
+    private static String TAG = "DevicePolicyResourcesManager";
+
+    private final Context mContext;
+    private final IDevicePolicyManager mService;
+
+    /**
+     * @hide
+     */
+    protected DevicePolicyResourcesManager(Context context, IDevicePolicyManager service) {
+        mContext = context;
+        mService = service;
+    }
+
+    /**
+     * For each {@link DevicePolicyDrawableResource} item in {@code drawables}, if
+     * {@link DevicePolicyDrawableResource#getDrawableSource()} is not set, it updates the drawable
+     * resource for the combination of {@link DevicePolicyDrawableResource#getDrawableId()} and
+     * {@link DevicePolicyDrawableResource#getDrawableStyle()} to the drawable with resource ID
+     * {@link DevicePolicyDrawableResource#getResourceIdInCallingPackage()},
+     * meaning any system UI surface calling {@link #getDrawable} with {@code drawableId} and
+     * {@code drawableStyle} will get the new resource after this API is called.
+     *
+     * <p>Otherwise, if {@link DevicePolicyDrawableResource#getDrawableSource()} is set, it
+     * overrides any drawables that was set for the same {@code drawableId} and
+     * {@code drawableStyle} for the provided source.
+     *
+     * <p>Sends a broadcast with action
+     * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to registered receivers
+     * when a resource has been updated successfully.
+     *
+     * <p>Important notes to consider when using this API:
+     * <ul>
+     * <li>{@link #getDrawable} references the resource
+     * {@link DevicePolicyDrawableResource#getResourceIdInCallingPackage()} in the
+     * calling package each time it gets called. You have to ensure that the resource is always
+     * available in the calling package as long as it is used as an updated resource.
+     * <li>You still have to re-call {@code setDrawables} even if you only make changes to the
+     * content of the resource with ID
+     * {@link DevicePolicyDrawableResource#getResourceIdInCallingPackage()} as the content might be
+     * cached and would need updating.
+     * </ul>
+     *
+     * @param drawables The list of {@link DevicePolicyDrawableResource} to update.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
+    public void setDrawables(@NonNull Set<DevicePolicyDrawableResource> drawables) {
+        if (mService != null) {
+            try {
+                mService.setDrawables(new ArrayList<>(drawables));
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Removes all updated drawables for the list of {@code drawableIds} that was previously set by
+     * calling {@link #setDrawables}, meaning any subsequent calls to {@link #getDrawable} for the
+     * provided IDs with any {@code drawableStyle} and any {@code drawableSource} will return the
+     * default drawable from {@code defaultDrawableLoader}.
+     *
+     * <p>Sends a broadcast with action
+     * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to registered receivers
+     * when a resource has been reset successfully.
+     *
+     * @param drawableIds The list of IDs to remove.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
+    public void resetDrawables(@NonNull Set<String> drawableIds) {
+        if (mService != null) {
+            try {
+                mService.resetDrawables(new ArrayList<>(drawableIds));
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Returns the appropriate updated drawable for the {@code drawableId} with style
+     * {@code drawableStyle} if one was set using {@code setDrawables}, otherwise returns the
+     * drawable from {@code defaultDrawableLoader}.
+     *
+     * <p>Also returns the drawable from {@code defaultDrawableLoader} if {@code drawableId}
+     * is {@link DevicePolicyResources#UNDEFINED}.
+     *
+     * <p>Calls to this API will not return {@code null} unless no updated drawable was found
+     * and the call to {@code defaultDrawableLoader} returned {@code null}.
+     *
+     * <p>This API uses the screen density returned from {@link Resources#getConfiguration()}, to
+     * set a different value use
+     * {@link #getDrawableForDensity(String, String, int, Supplier)}.
+     *
+     * <p>Callers should register for
+     * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get notified when a
+     * resource has been updated.
+     *
+     * <p>Note that each call to this API loads the resource from the package that called
+     * {@code setDrawables} to set the updated resource.
+     *
+     * @param drawableId The drawable ID to get the updated resource for.
+     * @param drawableStyle The drawable style to use.
+     * @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
+     *                              the provided params.
+     */
+    @Nullable
+    public Drawable getDrawable(
+            @NonNull String drawableId,
+            @NonNull String drawableStyle,
+            @NonNull Supplier<Drawable> defaultDrawableLoader) {
+        return getDrawable(
+                drawableId, drawableStyle, DevicePolicyResources.UNDEFINED, defaultDrawableLoader);
+    }
+
+    /**
+     * Similar to {@link #getDrawable(String, String, Supplier)}, but also accepts
+     * a {@code drawableSource} which could result in returning a different drawable than
+     * {@link #getDrawable(String, String, Supplier)} if an override was set for that specific
+     * source.
+     *
+     * <p> If {@code drawableSource} is {@link DevicePolicyResources#UNDEFINED}, it returns the
+     * appropriate string for {@code drawableId} and {@code drawableStyle} similar to
+     * {@link #getDrawable(String, String, Supplier)}.
+     *
+     * <p>Calls to this API will not return {@code null} unless no updated drawable was found
+     * and the call to {@code defaultDrawableLoader} returned {@code null}.
+     *
+     * <p>Callers should register for
+     * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get notified when a
+     * resource has been updated.
+     *
+     * @param drawableId The drawable ID to get the updated resource for.
+     * @param drawableStyle The drawable style to use.
+     * @param drawableSource The source for the caller.
+     * @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
+     *                              the provided params.
+     */
+    @Nullable
+    public Drawable getDrawable(
+            @NonNull String drawableId,
+            @NonNull String drawableStyle,
+            @NonNull String drawableSource,
+            @NonNull Supplier<Drawable> defaultDrawableLoader) {
+
+        Objects.requireNonNull(drawableId, "drawableId can't be null");
+        Objects.requireNonNull(drawableStyle, "drawableStyle can't be null");
+        Objects.requireNonNull(drawableSource, "drawableSource can't be null");
+        Objects.requireNonNull(defaultDrawableLoader, "defaultDrawableLoader can't be null");
+
+        if (drawableId.equals(DevicePolicyResources.UNDEFINED)) {
+            return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
+        }
+        if (mService != null) {
+            try {
+                ParcelableResource resource = mService.getDrawable(
+                        drawableId, drawableStyle, drawableSource);
+                if (resource == null) {
+                    return ParcelableResource.loadDefaultDrawable(
+                            defaultDrawableLoader);
+                }
+                return resource.getDrawable(
+                        mContext,
+                        /* density= */ 0,
+                        defaultDrawableLoader);
+
+            } catch (RemoteException e) {
+                Log.e(
+                        TAG,
+                        "Error getting the updated drawable from DevicePolicyManagerService.",
+                        e);
+                return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
+            }
+        }
+        return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
+    }
+
+    /**
+     * Similar to {@link #getDrawable(String, String, Supplier)}, but also accepts
+     * {@code density}. See {@link Resources#getDrawableForDensity(int, int, Resources.Theme)}.
+     *
+     * <p>Calls to this API will not return {@code null} unless no updated drawable was found
+     * and the call to {@code defaultDrawableLoader} returned {@code null}.
+     *
+     * <p>Callers should register for
+     * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get notified when a
+     * resource has been updated.
+     *
+     * @param drawableId The drawable ID to get the updated resource for.
+     * @param drawableStyle The drawable style to use.
+     * @param density The desired screen density indicated by the resource as
+     *            found in {@link DisplayMetrics}. A value of 0 means to use the
+     *            density returned from {@link Resources#getConfiguration()}.
+     * @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
+     *                              the provided params.
+     */
+    @Nullable
+    public Drawable getDrawableForDensity(
+            @NonNull String drawableId,
+            @NonNull String drawableStyle,
+            int density,
+            @NonNull Supplier<Drawable> defaultDrawableLoader) {
+        return getDrawableForDensity(
+                drawableId,
+                drawableStyle,
+                DevicePolicyResources.UNDEFINED,
+                density,
+                defaultDrawableLoader);
+    }
+
+    /**
+     * Similar to {@link #getDrawable(String, String, String, Supplier)}, but also accepts
+     * {@code density}. See {@link Resources#getDrawableForDensity(int, int, Resources.Theme)}.
+     *
+     * <p>Calls to this API will not return {@code null} unless no updated drawable was found
+     * and the call to {@code defaultDrawableLoader} returned {@code null}.
+     *
+     * <p>Callers should register for
+     * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get notified when a
+     * resource has been updated.
+     *
+     * @param drawableId The drawable ID to get the updated resource for.
+     * @param drawableStyle The drawable style to use.
+     * @param drawableSource The source for the caller.
+     * @param density The desired screen density indicated by the resource as
+     *            found in {@link DisplayMetrics}. A value of 0 means to use the
+     *            density returned from {@link Resources#getConfiguration()}.
+     * @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
+     *                              the provided params.
+     */
+    @Nullable
+    public Drawable getDrawableForDensity(
+            @NonNull String drawableId,
+            @NonNull String drawableStyle,
+            @NonNull String drawableSource,
+            int density,
+            @NonNull Supplier<Drawable> defaultDrawableLoader) {
+
+        Objects.requireNonNull(drawableId, "drawableId can't be null");
+        Objects.requireNonNull(drawableStyle, "drawableStyle can't be null");
+        Objects.requireNonNull(drawableSource, "drawableSource can't be null");
+        Objects.requireNonNull(defaultDrawableLoader, "defaultDrawableLoader can't be null");
+
+        if (drawableId.equals(DevicePolicyResources.UNDEFINED)) {
+            return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
+        }
+        if (mService != null) {
+            try {
+                ParcelableResource resource = mService.getDrawable(
+                        drawableId, drawableStyle, drawableSource);
+                if (resource == null) {
+                    return ParcelableResource.loadDefaultDrawable(
+                            defaultDrawableLoader);
+                }
+                return resource.getDrawable(mContext, density, defaultDrawableLoader);
+            } catch (RemoteException e) {
+                Log.e(
+                        TAG,
+                        "Error getting the updated drawable from DevicePolicyManagerService.",
+                        e);
+                return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
+            }
+        }
+        return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
+    }
+
+    /**
+     * Similar to {@link #getDrawable(String, String, String, Supplier)} but returns an
+     * {@link Icon} instead of a {@link Drawable}.
+     *
+     * @param drawableId The drawable ID to get the updated resource for.
+     * @param drawableStyle The drawable style to use.
+     * @param drawableSource The source for the caller.
+     * @param defaultIcon Returned if no updated drawable was set for the provided params.
+     */
+    @Nullable
+    public Icon getDrawableAsIcon(
+            @NonNull String drawableId,
+            @NonNull String drawableStyle,
+            @NonNull String drawableSource,
+            @Nullable Icon defaultIcon) {
+        Objects.requireNonNull(drawableId, "drawableId can't be null");
+        Objects.requireNonNull(drawableStyle, "drawableStyle can't be null");
+        Objects.requireNonNull(drawableSource, "drawableSource can't be null");
+        Objects.requireNonNull(defaultIcon, "defaultIcon can't be null");
+
+        if (drawableId.equals(DevicePolicyResources.UNDEFINED)) {
+            return defaultIcon;
+        }
+        if (mService != null) {
+            try {
+                ParcelableResource resource = mService.getDrawable(
+                        drawableId, drawableStyle, drawableSource);
+                if (resource == null) {
+                    return defaultIcon;
+                }
+                return Icon.createWithResource(resource.getPackageName(), resource.getResourceId());
+            } catch (RemoteException e) {
+                Log.e(
+                        TAG,
+                        "Error getting the updated drawable from DevicePolicyManagerService.",
+                        e);
+                return defaultIcon;
+            }
+        }
+        return defaultIcon;
+    }
+
+    /**
+     * Similar to {@link #getDrawable(String, String, Supplier)} but returns an {@link Icon}
+     * instead of a {@link Drawable}.
+     *
+     * @param drawableId The drawable ID to get the updated resource for.
+     * @param drawableStyle The drawable style to use.
+     * @param defaultIcon Returned if no updated drawable was set for the provided params.
+     */
+    @Nullable
+    public Icon getDrawableAsIcon(
+            @NonNull String drawableId,
+            @NonNull String drawableStyle,
+            @Nullable Icon defaultIcon) {
+        return getDrawableAsIcon(
+                drawableId, drawableStyle, DevicePolicyResources.UNDEFINED, defaultIcon);
+    }
+
+
+    /**
+     * For each {@link DevicePolicyStringResource} item in {@code strings}, it updates the string
+     * resource for {@link DevicePolicyStringResource#getStringId()} to the string with ID
+     * {@code callingPackageResourceId}, meaning any system UI surface calling {@link #getString}
+     * with {@code stringId} will get the new resource after this API is called.
+     *
+     * <p>Sends a broadcast with action
+     * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to registered receivers
+     * when a resource has been updated successfully.
+     *
+     * <p>Important notes to consider when using this API:
+     * <ul>
+     * <li> {@link #getString} references the resource {@code callingPackageResourceId} in the
+     * calling package each time it gets called. You have to ensure that the resource is always
+     * available in the calling package as long as it is used as an updated resource.
+     * <li> You still have to re-call {@code setStrings} even if you only make changes to the
+     * content of the resource with ID {@code callingPackageResourceId} as the content might be
+     * cached and would need updating.
+     * </ul>
+     *
+     * @param strings The list of {@link DevicePolicyStringResource} to update.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
+    public void setStrings(@NonNull Set<DevicePolicyStringResource> strings) {
+        if (mService != null) {
+            try {
+                mService.setStrings(new ArrayList<>(strings));
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Removes the updated strings for the list of {@code stringIds} that was previously set by
+     * calling {@link #setStrings}, meaning any subsequent calls to {@link #getString} for the
+     * provided IDs will return the default string from {@code defaultStringLoader}.
+     *
+     * <p>Sends a broadcast with action
+     * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to registered receivers
+     * when a resource has been reset successfully.
+     *
+     * @param stringIds The list of IDs to remove the updated resources for.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
+    public void resetStrings(@NonNull Set<String> stringIds) {
+        if (mService != null) {
+            try {
+                mService.resetStrings(new ArrayList<>(stringIds));
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Returns the appropriate updated string for the {@code stringId} (see
+     * {@link DevicePolicyResources.Strings}) if one was set using
+     * {@code setStrings}, otherwise returns the string from {@code defaultStringLoader}.
+     *
+     * <p>Also returns the string from {@code defaultStringLoader} if {@code stringId} is
+     * {@link DevicePolicyResources#UNDEFINED}.
+     *
+     * <p>Calls to this API will not return {@code null} unless no updated drawable was found
+     * and the call to {@code defaultStringLoader} returned {@code null}.
+     *
+     * <p>Callers should register for
+     * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get notified when a
+     * resource has been updated.
+     *
+     * <p>Note that each call to this API loads the resource from the package that called
+     * {@code setStrings} to set the updated resource.
+     *
+     * @param stringId The IDs to get the updated resource for.
+     * @param defaultStringLoader To get the default string if no updated string was set for
+     *         {@code stringId}.
+     */
+    @Nullable
+    public String getString(
+            @NonNull String stringId,
+            @NonNull Supplier<String> defaultStringLoader) {
+
+        Objects.requireNonNull(stringId, "stringId can't be null");
+        Objects.requireNonNull(defaultStringLoader, "defaultStringLoader can't be null");
+
+        if (stringId.equals(DevicePolicyResources.UNDEFINED)) {
+            return ParcelableResource.loadDefaultString(defaultStringLoader);
+        }
+        if (mService != null) {
+            try {
+                ParcelableResource resource = mService.getString(stringId);
+                if (resource == null) {
+                    return ParcelableResource.loadDefaultString(defaultStringLoader);
+                }
+                return resource.getString(mContext, defaultStringLoader);
+            } catch (RemoteException e) {
+                Log.e(
+                        TAG,
+                        "Error getting the updated string from DevicePolicyManagerService.",
+                        e);
+                return ParcelableResource.loadDefaultString(defaultStringLoader);
+            }
+        }
+        return ParcelableResource.loadDefaultString(defaultStringLoader);
+    }
+
+    /**
+     * Similar to {@link #getString(String, Supplier)} but accepts {@code formatArgs} and returns a
+     * localized formatted string, substituting the format arguments as defined in
+     * {@link java.util.Formatter} and {@link java.lang.String#format}, (see
+     * {@link Resources#getString(int, Object...)}).
+     *
+     * <p>Calls to this API will not return {@code null} unless no updated drawable was found
+     * and the call to {@code defaultStringLoader} returned {@code null}.
+     *
+     * @param stringId The IDs to get the updated resource for.
+     * @param defaultStringLoader To get the default string if no updated string was set for
+     *         {@code stringId}.
+     * @param formatArgs The format arguments that will be used for substitution.
+     */
+    @Nullable
+    @SuppressLint("SamShouldBeLast")
+    public String getString(
+            @NonNull String stringId,
+            @NonNull Supplier<String> defaultStringLoader,
+            @NonNull Object... formatArgs) {
+
+        Objects.requireNonNull(stringId, "stringId can't be null");
+        Objects.requireNonNull(defaultStringLoader, "defaultStringLoader can't be null");
+
+        if (stringId.equals(DevicePolicyResources.UNDEFINED)) {
+            return ParcelableResource.loadDefaultString(defaultStringLoader);
+        }
+        if (mService != null) {
+            try {
+                ParcelableResource resource = mService.getString(stringId);
+                if (resource == null) {
+                    return ParcelableResource.loadDefaultString(defaultStringLoader);
+                }
+                return resource.getString(mContext, defaultStringLoader, formatArgs);
+            } catch (RemoteException e) {
+                Log.e(
+                        TAG,
+                        "Error getting the updated string from DevicePolicyManagerService.",
+                        e);
+                return ParcelableResource.loadDefaultString(defaultStringLoader);
+            }
+        }
+        return ParcelableResource.loadDefaultString(defaultStringLoader);
+    }
+}
diff --git a/core/java/android/app/admin/DevicePolicyStringResource.java b/core/java/android/app/admin/DevicePolicyStringResource.java
index b36f1408..7e59340 100644
--- a/core/java/android/app/admin/DevicePolicyStringResource.java
+++ b/core/java/android/app/admin/DevicePolicyStringResource.java
@@ -28,19 +28,19 @@
 
 /**
  * Used to pass in the required information for updating an enterprise string resource using
- * {@link DevicePolicyManager#setStrings}.
+ * {@link DevicePolicyResourcesManager#setStrings}.
  *
  * @hide
  */
 @SystemApi
 public final class DevicePolicyStringResource implements Parcelable {
-    @NonNull private final @DevicePolicyResources.UpdatableStringId String mStringId;
+    @NonNull private final String mStringId;
     private final @StringRes int mResourceIdInCallingPackage;
     @NonNull private ParcelableResource mResource;
 
     /**
      * Creates an object containing the required information for updating an enterprise string
-     * resource using {@link DevicePolicyManager#setStrings}.
+     * resource using {@link DevicePolicyResourcesManager#setStrings}.
      *
      * <p>It will be used to update the string defined by {@code stringId} to the string with ID
      * {@code resourceIdInCallingPackage} in the calling package</p>
@@ -54,14 +54,14 @@
      */
     public DevicePolicyStringResource(
             @NonNull Context context,
-            @NonNull @DevicePolicyResources.UpdatableStringId String stringId,
+            @NonNull String stringId,
             @StringRes int resourceIdInCallingPackage) {
         this(stringId, resourceIdInCallingPackage, new ParcelableResource(
                 context, resourceIdInCallingPackage, ParcelableResource.RESOURCE_TYPE_STRING));
     }
 
     private DevicePolicyStringResource(
-            @NonNull @DevicePolicyResources.UpdatableStringId String stringId,
+            @NonNull String stringId,
             @StringRes int resourceIdInCallingPackage,
             @NonNull ParcelableResource resource) {
         Objects.requireNonNull(stringId, "stringId must be provided.");
@@ -75,7 +75,6 @@
     /**
      * Returns the ID of the string to update.
      */
-    @DevicePolicyResources.UpdatableStringId
     @NonNull
     public String getStringId() {
         return mStringId;
diff --git a/core/java/android/app/admin/FactoryResetProtectionPolicy.java b/core/java/android/app/admin/FactoryResetProtectionPolicy.java
index 40ae1f0..7e95177 100644
--- a/core/java/android/app/admin/FactoryResetProtectionPolicy.java
+++ b/core/java/android/app/admin/FactoryResetProtectionPolicy.java
@@ -25,6 +25,7 @@
 import android.content.ComponentName;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.IndentingPrintWriter;
 import android.util.Log;
 import android.util.TypedXmlPullParser;
 import android.util.TypedXmlSerializer;
@@ -254,4 +255,18 @@
         return !mFactoryResetProtectionAccounts.isEmpty() && mFactoryResetProtectionEnabled;
     }
 
+    /**
+     * @hide
+     */
+    public void dump(IndentingPrintWriter pw) {
+        pw.print("factoryResetProtectionEnabled=");
+        pw.println(mFactoryResetProtectionEnabled);
+
+        pw.print("factoryResetProtectionAccounts=");
+        pw.increaseIndent();
+        for (int i = 0; i < mFactoryResetProtectionAccounts.size(); i++) {
+            pw.println(mFactoryResetProtectionAccounts.get(i));
+        }
+        pw.decreaseIndent();
+    }
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 77db146..8a9ef4b 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -17,6 +17,7 @@
 
 package android.app.admin;
 
+import android.accounts.Account;
 import android.app.admin.DevicePolicyDrawableResource;
 import android.app.admin.DevicePolicyStringResource;
 import android.app.admin.ParcelableResource;
@@ -476,7 +477,7 @@
     int getGlobalPrivateDnsMode(in ComponentName admin);
     String getGlobalPrivateDnsHost(in ComponentName admin);
 
-    void markProfileOwnerOnOrganizationOwnedDevice(in ComponentName who, int userId);
+    void setProfileOwnerOnOrganizationOwnedDevice(in ComponentName who, int userId, boolean isProfileOwnerOnOrganizationOwnedDevice);
 
     void installUpdateFromFile(in ComponentName admin, in ParcelFileDescriptor updateFileDescriptor, in StartInstallingUpdateCallback listener);
 
@@ -528,6 +529,8 @@
     UserHandle createAndProvisionManagedProfile(in ManagedProfileProvisioningParams provisioningParams, in String callerPackage);
     void provisionFullyManagedDevice(in FullyManagedDeviceProvisioningParams provisioningParams, in String callerPackage);
 
+    void finalizeWorkProfileProvisioning(in UserHandle managedProfileUser, in Account migratedAccount);
+
     void setDeviceOwnerType(in ComponentName admin, in int deviceOwnerType);
     int getDeviceOwnerType(in ComponentName admin);
 
@@ -549,13 +552,17 @@
 
     List<UserHandle> listForegroundAffiliatedUsers();
     void setDrawables(in List<DevicePolicyDrawableResource> drawables);
-    void resetDrawables(in String[] drawableIds);
+    void resetDrawables(in List<String> drawableIds);
     ParcelableResource getDrawable(String drawableId, String drawableStyle, String drawableSource);
 
     boolean isDpcDownloaded();
     void setDpcDownloaded(boolean downloaded);
 
     void setStrings(in List<DevicePolicyStringResource> strings);
-    void resetStrings(in String[] stringIds);
+    void resetStrings(in List<String> stringIds);
     ParcelableResource getString(String stringId);
+
+    boolean shouldAllowBypassingDevicePolicyManagementRoleQualification();
+
+    List<UserHandle> getPolicyManagedProfiles(in UserHandle userHandle);
 }
diff --git a/core/java/android/app/admin/ParcelableResource.java b/core/java/android/app/admin/ParcelableResource.java
index bcae284..a297665 100644
--- a/core/java/android/app/admin/ParcelableResource.java
+++ b/core/java/android/app/admin/ParcelableResource.java
@@ -43,7 +43,8 @@
 
 /**
  * Used to store the required information to load a resource that was updated using
- * {@link DevicePolicyManager#setDrawables} and {@link DevicePolicyManager#setStrings}.
+ * {@link DevicePolicyResourcesManager#setDrawables} and
+ * {@link DevicePolicyResourcesManager#setStrings}.
  *
  * @hide
  */
diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
index b170aa2..b90408d 100644
--- a/core/java/android/app/admin/SecurityLog.java
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -517,14 +517,15 @@
     public static final int TAG_PASSWORD_CHANGED = SecurityLogTags.SECURITY_PASSWORD_CHANGED;
 
     /**
-     * Indicates that the device attempts to connect to a WiFi network.
-     * The log entry contains the following information about the
+     * Indicates that an event occurred as the device attempted to connect to
+     * a WiFi network. The log entry contains the following information about the
      * event, encapsulated in an {@link Object} array and accessible via
      * {@link SecurityEvent#getData()}:
-     * <li> [0] The SSID of the network ({@code String})
-     * <li> [1] The BSSID of the network ({@code String})
-     * <li> [2] Whether the connection is successful ({@code Integer}, 1 if successful, 0 otherwise)
-     * <li> [3] Optional human-readable failure reason, empty string if none ({@code String})
+     * <li> [0] Last 2 octets of the network BSSID ({@code String}, in the form "xx:xx:xx:xx:AA:BB")
+     * <li> [1] Type of event that occurred ({@code String}). Event types are CONNECTED,
+     *      DISCONNECTED, ASSOCIATING, ASSOCIATED, EAP_METHOD_SELECTED, EAP_FAILURE,
+     *      SSID_TEMP_DISABLED, and OPEN_SSL_FAILURE.
+     * <li> [2] Optional human-readable failure reason, empty string if none ({@code String})
      */
     public static final int TAG_WIFI_CONNECTION = SecurityLogTags.SECURITY_WIFI_CONNECTION;
 
@@ -533,9 +534,8 @@
      * The log entry contains the following information about the
      * event, encapsulated in an {@link Object} array and accessible via
      * {@link SecurityEvent#getData()}:
-     * <li> [0] The SSID of the connected network ({@code String})
-     * <li> [1] The BSSID of the connected network ({@code String})
-     * <li> [2] Optional human-readable disconnection reason, empty string if none ({@code String})
+     * <li> [0] Last 2 octets of the network BSSID ({@code String}, in the form "xx:xx:xx:xx:AA:BB")
+     * <li> [1] Optional human-readable disconnection reason, empty string if none ({@code String})
      */
     public static final int TAG_WIFI_DISCONNECTION = SecurityLogTags.SECURITY_WIFI_DISCONNECTION;
 
diff --git a/core/java/android/app/admin/SecurityLogTags.logtags b/core/java/android/app/admin/SecurityLogTags.logtags
index 5f41109..b06e5a5 100644
--- a/core/java/android/app/admin/SecurityLogTags.logtags
+++ b/core/java/android/app/admin/SecurityLogTags.logtags
@@ -41,7 +41,7 @@
 210034 security_camera_policy_set               (package|3),(admin_user|1),(target_user|1),(disabled|1)
 210035 security_password_complexity_required    (package|3),(admin_user|1),(target_user|1),(complexity|1)
 210036 security_password_changed                (password_complexity|1),(target_user|1)
-210037 security_wifi_connection                 (ssid|3),(bssid|3),(success|1),(reason|3)
-210038 security_wifi_disconnection              (ssid|3),(bssid|3),(reason|3)
+210037 security_wifi_connection                 (bssid|3),(event_type|3),(reason|3)
+210038 security_wifi_disconnection              (bssid|3),(reason|3)
 210039 security_bluetooth_connection            (addr|3),(success|1),(reason|3)
 210040 security_bluetooth_disconnection         (addr|3),(reason|3)
\ No newline at end of file
diff --git a/core/java/android/app/cloudsearch/SearchResult.java b/core/java/android/app/cloudsearch/SearchResult.java
index af8adac..c6583b6 100644
--- a/core/java/android/app/cloudsearch/SearchResult.java
+++ b/core/java/android/app/cloudsearch/SearchResult.java
@@ -71,6 +71,10 @@
             EXTRAINFO_APP_BADGES,
             EXTRAINFO_ACTION_BUTTON_TEXT_PREREGISTERING,
             EXTRAINFO_ACTION_BUTTON_IMAGE_PREREGISTERING,
+            EXTRAINFO_ACTION_APP_CARD,
+            EXTRAINFO_ACTION_INSTALL_BUTTON,
+            EXTRAINFO_APP_PACKAGE_NAME,
+            EXTRAINFO_APP_INSTALL_COUNT,
             EXTRAINFO_WEB_URL,
             EXTRAINFO_WEB_ICON})
     public @interface SearchResultExtraInfoKey {}
@@ -119,6 +123,20 @@
     @SuppressLint("IntentName")
     public static final String EXTRAINFO_ACTION_BUTTON_IMAGE_PREREGISTERING =
             "android.app.cloudsearch.ACTION_BUTTON_IMAGE";
+    /** Intent for tapping the app card, PendingIntent expected. */
+    @SuppressLint("IntentName")
+    public static final String EXTRAINFO_ACTION_APP_CARD =
+            "android.app.cloudsearch.ACTION_APP_CARD";
+    /** Intent for tapping the install button, PendingIntent expected. */
+    @SuppressLint("IntentName")
+    public static final String EXTRAINFO_ACTION_INSTALL_BUTTON =
+            "android.app.cloudsearch.ACTION_INSTALL_BUTTON";
+    /** App's package name, String value expected. */
+    public static final String EXTRAINFO_APP_PACKAGE_NAME =
+            "android.app.cloudsearch.APP_PACKAGE_NAME";
+    /** App's install count, double value expected. */
+    public static final String EXTRAINFO_APP_INSTALL_COUNT =
+            "android.app.cloudsearch.APP_INSTALL_COUNT";
     /** Web content's URL, String value expected. */
     public static final String EXTRAINFO_WEB_URL = "android.app.cloudsearch.WEB_URL";
     /** Web content's domain icon, android.graphics.drawable.Icon expected. */
diff --git a/core/java/android/app/prediction/AppTargetEvent.java b/core/java/android/app/prediction/AppTargetEvent.java
index 51e3953..91da8ec 100644
--- a/core/java/android/app/prediction/AppTargetEvent.java
+++ b/core/java/android/app/prediction/AppTargetEvent.java
@@ -60,6 +60,11 @@
      */
     public static final int ACTION_UNPIN = 4;
 
+    /**
+     * Event type constant indicating an app target has been un-dismissed.
+     */
+    public static final int ACTION_UNDISMISS = 5;
+
     private final AppTarget mTarget;
     private final String mLocation;
     private final int mAction;
diff --git a/core/java/android/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl
index b786444..45146fd 100644
--- a/core/java/android/app/trust/ITrustManager.aidl
+++ b/core/java/android/app/trust/ITrustManager.aidl
@@ -26,7 +26,8 @@
  */
 interface ITrustManager {
     void reportUnlockAttempt(boolean successful, int userId);
-    void reportUserRequestedUnlock(int userId);
+    void reportUserRequestedUnlock(int userId, boolean dismissKeyguard);
+    void reportUserMayRequestUnlock(int userId);
     void reportUnlockLockout(int timeoutMs, int userId);
     void reportEnabledTrustAgentsChanged(int userId);
     void registerTrustListener(in ITrustListener trustListener);
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index 70b7de0..9e825b72 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -92,10 +92,25 @@
      * Reports that the user {@code userId} is likely interested in unlocking the device.
      *
      * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
+     *
+     * @param dismissKeyguard whether the user wants to dismiss keyguard
      */
-    public void reportUserRequestedUnlock(int userId) {
+    public void reportUserRequestedUnlock(int userId, boolean dismissKeyguard) {
         try {
-            mService.reportUserRequestedUnlock(userId);
+            mService.reportUserRequestedUnlock(userId, dismissKeyguard);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Reports that the user {@code userId} may want to unlock the device soon.
+     *
+     * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
+     */
+    public void reportUserMayRequestUnlock(int userId) {
+        try {
+            mService.reportUserMayRequestUnlock(userId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/usage/BroadcastResponseStats.java b/core/java/android/app/usage/BroadcastResponseStats.java
index e1d37e1..572c453 100644
--- a/core/java/android/app/usage/BroadcastResponseStats.java
+++ b/core/java/android/app/usage/BroadcastResponseStats.java
@@ -29,6 +29,8 @@
  * Class containing a collection of stats related to response events started from an app
  * after receiving a broadcast.
  *
+ * @see UsageStatsManager#queryBroadcastResponseStats(String, long)
+ * @see UsageStatsManager#clearBroadcastResponseStats(String, long)
  * @hide
  */
 @SystemApi
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index 2a2a9c6..d4fbdc6 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -74,12 +74,14 @@
     int getUsageSource();
     void forceUsageSourceSettingRead();
     long getLastTimeAnyComponentUsed(String packageName, String callingPackage);
-    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)")
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS)")
     BroadcastResponseStatsList queryBroadcastResponseStats(
             String packageName, long id, String callingPackage, int userId);
-    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)")
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS)")
     void clearBroadcastResponseStats(String packageName, long id, String callingPackage,
             int userId);
-    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)")
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS)")
     void clearBroadcastEvents(String callingPackage, int userId);
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG)")
+    String getAppStandbyConstant(String key);
 }
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 3a335f9..c013fcd 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -16,6 +16,7 @@
 
 package android.app.usage;
 
+import android.Manifest;
 import android.annotation.CurrentTimeMillisLong;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
@@ -1446,7 +1447,7 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)
+    @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS)
     @UserHandleAware
     @NonNull
     public List<BroadcastResponseStats> queryBroadcastResponseStats(
@@ -1479,7 +1480,7 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)
+    @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS)
     @UserHandleAware
     public void clearBroadcastResponseStats(@Nullable String packageName,
             @IntRange(from = 0) long id) {
@@ -1496,7 +1497,7 @@
      *
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)
+    @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS)
     @UserHandleAware
     public void clearBroadcastEvents() {
         try {
@@ -1505,4 +1506,15 @@
             throw re.rethrowFromSystemServer();
         }
     }
+
+    /** @hide */
+    @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
+    @Nullable
+    public String getAppStandbyConstant(@NonNull String key) {
+        try {
+            return mService.getAppStandbyConstant(key);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 1568500..56939f0 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -76,6 +76,56 @@
     private static final String LOG_TAG = "CompanionDeviceManager";
 
     /**
+     * The result code to propagate back to the originating activity, indicates the association
+     * dialog is explicitly declined by the users.
+     *
+     * @hide
+     */
+    public static final int RESULT_USER_REJECTED = 1;
+
+    /**
+     * The result code to propagate back to the originating activity, indicates the association
+     * dialog is dismissed if there's no device found after 20 seconds.
+     *
+     * @hide
+     */
+    public static final int RESULT_DISCOVERY_TIMEOUT = 2;
+
+    /**
+     * The result code to propagate back to the originating activity, indicates the internal error
+     * in CompanionDeviceManager.
+     *
+     * @hide
+     */
+    public static final int RESULT_INTERNAL_ERROR = 3;
+
+    /**
+     *  Requesting applications will receive the String in {@link Callback#onFailure} if the
+     *  association dialog is explicitly declined by the users. e.g. press the Don't allow button.
+     *
+     * @hide
+     */
+    public static final String REASON_USER_REJECTED = "user_rejected";
+
+    /**
+     *  Requesting applications will receive the String in {@link Callback#onFailure} if there's
+     *  no device found after 20 seconds.
+     *
+     * @hide
+     */
+    public static final String REASON_DISCOVERY_TIMEOUT = "discovery_timeout";
+
+    /**
+     *  Requesting applications will receive the String in {@link Callback#onFailure} if the
+     *  association dialog is in-explicitly declined by the users. e.g. phone is locked, switch to
+     *  another app or press outside the dialog.
+     *
+     * @hide
+     */
+    public static final String REASON_CANCELED = "canceled";
+
+
+    /**
      * A device, returned in the activity result of the {@link IntentSender} received in
      * {@link Callback#onDeviceFound}
      *
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index a1983ca..914b321 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -469,6 +469,10 @@
         /**
          * Called when the top activity is changed.
          *
+         * <p>Note: When there are no activities running on the virtual display, the
+         * {@link #onDisplayEmpty(int)} will be called. If the value topActivity is cached, it
+         * should be cleared when {@link #onDisplayEmpty(int)} is called.
+         *
          * @param displayId The display ID on which the activity change happened.
          * @param topActivity The component name of the top activity.
          */
diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java
index 41b1a1f..3b1ff3f 100644
--- a/core/java/android/companion/virtual/VirtualDeviceParams.java
+++ b/core/java/android/companion/virtual/VirtualDeviceParams.java
@@ -28,6 +28,8 @@
 import android.os.UserHandle;
 import android.util.ArraySet;
 
+import com.android.internal.util.Preconditions;
+
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -81,8 +83,31 @@
      */
     public static final int ACTIVITY_POLICY_DEFAULT_BLOCKED = 1;
 
+    /** @hide */
+    @IntDef(prefix = "NAVIGATION_POLICY_",
+        value = {NAVIGATION_POLICY_DEFAULT_ALLOWED, NAVIGATION_POLICY_DEFAULT_BLOCKED})
+    @Retention(RetentionPolicy.SOURCE)
+    @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+    public @interface NavigationPolicy {}
+
+    /**
+     * Indicates that tasks are allowed to navigate to other tasks on this virtual device,
+     * unless they are explicitly blocked by {@link Builder#setBlockedCrossTaskNavigations}.
+     */
+    public static final int NAVIGATION_POLICY_DEFAULT_ALLOWED = 0;
+
+    /**
+     * Indicates that tasks are blocked from navigating to other tasks by default on this virtual
+     * device, unless allowed by {@link Builder#setAllowedCrossTaskNavigations}.
+     */
+    public static final int NAVIGATION_POLICY_DEFAULT_BLOCKED = 1;
+
     private final int mLockState;
-    private final ArraySet<UserHandle> mUsersWithMatchingAccounts;
+    @NonNull private final ArraySet<UserHandle> mUsersWithMatchingAccounts;
+    @NonNull private final ArraySet<ComponentName> mAllowedCrossTaskNavigations;
+    @NonNull private final ArraySet<ComponentName> mBlockedCrossTaskNavigations;
+    @NavigationPolicy
+    private final int mDefaultNavigationPolicy;
     @NonNull private final ArraySet<ComponentName> mAllowedActivities;
     @NonNull private final ArraySet<ComponentName> mBlockedActivities;
     @ActivityPolicy
@@ -91,13 +116,25 @@
     private VirtualDeviceParams(
             @LockState int lockState,
             @NonNull Set<UserHandle> usersWithMatchingAccounts,
+            @NonNull Set<ComponentName> allowedCrossTaskNavigations,
+            @NonNull Set<ComponentName> blockedCrossTaskNavigations,
+            @NavigationPolicy int defaultNavigationPolicy,
             @NonNull Set<ComponentName> allowedActivities,
             @NonNull Set<ComponentName> blockedActivities,
             @ActivityPolicy int defaultActivityPolicy) {
+        Preconditions.checkNotNull(usersWithMatchingAccounts);
+        Preconditions.checkNotNull(allowedCrossTaskNavigations);
+        Preconditions.checkNotNull(blockedCrossTaskNavigations);
+        Preconditions.checkNotNull(allowedActivities);
+        Preconditions.checkNotNull(blockedActivities);
+
         mLockState = lockState;
         mUsersWithMatchingAccounts = new ArraySet<>(usersWithMatchingAccounts);
-        mAllowedActivities = allowedActivities == null ? null : new ArraySet<>(allowedActivities);
-        mBlockedActivities = blockedActivities == null ? null : new ArraySet<>(blockedActivities);
+        mAllowedCrossTaskNavigations = new ArraySet<>(allowedCrossTaskNavigations);
+        mBlockedCrossTaskNavigations = new ArraySet<>(blockedCrossTaskNavigations);
+        mDefaultNavigationPolicy = defaultNavigationPolicy;
+        mAllowedActivities = new ArraySet<>(allowedActivities);
+        mBlockedActivities = new ArraySet<>(blockedActivities);
         mDefaultActivityPolicy = defaultActivityPolicy;
     }
 
@@ -105,6 +142,9 @@
     private VirtualDeviceParams(Parcel parcel) {
         mLockState = parcel.readInt();
         mUsersWithMatchingAccounts = (ArraySet<UserHandle>) parcel.readArraySet(null);
+        mAllowedCrossTaskNavigations = (ArraySet<ComponentName>) parcel.readArraySet(null);
+        mBlockedCrossTaskNavigations = (ArraySet<ComponentName>) parcel.readArraySet(null);
+        mDefaultNavigationPolicy = parcel.readInt();
         mAllowedActivities = (ArraySet<ComponentName>) parcel.readArraySet(null);
         mBlockedActivities = (ArraySet<ComponentName>) parcel.readArraySet(null);
         mDefaultActivityPolicy = parcel.readInt();
@@ -130,30 +170,63 @@
     }
 
     /**
-     * Returns the set of activities allowed to be streamed, or {@code null} if all activities are
+     * Returns the set of tasks that are allowed to navigate from current task,
+     * or empty set if all tasks are allowed, except the ones explicitly blocked.
+     * If neither allowed or blocked tasks are provided, all task navigations will
+     * be be allowed by default.
+     *
+     * @see Builder#setAllowedCrossTaskNavigations(Set)
+     */
+    @NonNull
+    public Set<ComponentName> getAllowedCrossTaskNavigations() {
+        return Collections.unmodifiableSet(mAllowedCrossTaskNavigations);
+    }
+
+    /**
+     * Returns the set of tasks that are blocked from navigating from the current task,
+     * or empty set to indicate that all tasks in {@link #getAllowedCrossTaskNavigations}
+     * are allowed. If neither allowed or blocked tasks are provided, all task navigations
+     * will be be allowed by default.
+     *
+     * @see Builder#setBlockedCrossTaskNavigations(Set)
+     */
+    @NonNull
+    public Set<ComponentName> getBlockedCrossTaskNavigations() {
+        return Collections.unmodifiableSet(mBlockedCrossTaskNavigations);
+    }
+
+    /**
+     * Returns {@link #NAVIGATION_POLICY_DEFAULT_ALLOWED} if tasks are allowed to navigate on
+     * this virtual device by default, or {@link #NAVIGATION_POLICY_DEFAULT_BLOCKED} if tasks
+     * must be allowed by {@link Builder#setAllowedCrossTaskNavigations} to navigate here.
+     *
+     * @see Builder#setAllowedCrossTaskNavigations
+     * @see Builder#setBlockedCrossTaskNavigations
+     */
+    @NavigationPolicy
+    public int getDefaultNavigationPolicy() {
+        return mDefaultNavigationPolicy;
+    }
+
+    /**
+     * Returns the set of activities allowed to be streamed, or empty set if all activities are
      * allowed, except the ones explicitly blocked.
      *
      * @see Builder#setAllowedActivities(Set)
      */
     @NonNull
     public Set<ComponentName> getAllowedActivities() {
-        if (mAllowedActivities == null) {
-            return Collections.emptySet();
-        }
         return Collections.unmodifiableSet(mAllowedActivities);
     }
 
     /**
-     * Returns the set of activities that are blocked from streaming, or {@code null} to indicate
+     * Returns the set of activities that are blocked from streaming, or empty set to indicate
      * that all activities in {@link #getAllowedActivities} are allowed.
      *
      * @see Builder#setBlockedActivities(Set)
      */
     @NonNull
     public Set<ComponentName> getBlockedActivities() {
-        if (mBlockedActivities == null) {
-            return Collections.emptySet();
-        }
         return Collections.unmodifiableSet(mBlockedActivities);
     }
 
@@ -179,6 +252,9 @@
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeInt(mLockState);
         dest.writeArraySet(mUsersWithMatchingAccounts);
+        dest.writeArraySet(mAllowedCrossTaskNavigations);
+        dest.writeArraySet(mBlockedCrossTaskNavigations);
+        dest.writeInt(mDefaultNavigationPolicy);
         dest.writeArraySet(mAllowedActivities);
         dest.writeArraySet(mBlockedActivities);
         dest.writeInt(mDefaultActivityPolicy);
@@ -195,6 +271,9 @@
         VirtualDeviceParams that = (VirtualDeviceParams) o;
         return mLockState == that.mLockState
                 && mUsersWithMatchingAccounts.equals(that.mUsersWithMatchingAccounts)
+                && Objects.equals(mAllowedCrossTaskNavigations, that.mAllowedCrossTaskNavigations)
+                && Objects.equals(mBlockedCrossTaskNavigations, that.mBlockedCrossTaskNavigations)
+                && mDefaultNavigationPolicy == that.mDefaultNavigationPolicy
                 && Objects.equals(mAllowedActivities, that.mAllowedActivities)
                 && Objects.equals(mBlockedActivities, that.mBlockedActivities)
                 && mDefaultActivityPolicy == that.mDefaultActivityPolicy;
@@ -203,8 +282,9 @@
     @Override
     public int hashCode() {
         return Objects.hash(
-                mLockState, mUsersWithMatchingAccounts, mAllowedActivities, mBlockedActivities,
-                mDefaultActivityPolicy);
+                mLockState, mUsersWithMatchingAccounts, mAllowedCrossTaskNavigations,
+                mBlockedCrossTaskNavigations, mDefaultNavigationPolicy,  mAllowedActivities,
+                mBlockedActivities, mDefaultActivityPolicy);
     }
 
     @Override
@@ -213,6 +293,9 @@
         return "VirtualDeviceParams("
                 + " mLockState=" + mLockState
                 + " mUsersWithMatchingAccounts=" + mUsersWithMatchingAccounts
+                + " mAllowedCrossTaskNavigations=" + mAllowedCrossTaskNavigations
+                + " mBlockedCrossTaskNavigations=" + mBlockedCrossTaskNavigations
+                + " mDefaultNavigationPolicy=" + mDefaultNavigationPolicy
                 + " mAllowedActivities=" + mAllowedActivities
                 + " mBlockedActivities=" + mBlockedActivities
                 + " mDefaultActivityPolicy=" + mDefaultActivityPolicy
@@ -237,7 +320,12 @@
     public static final class Builder {
 
         private @LockState int mLockState = LOCK_STATE_DEFAULT;
-        private Set<UserHandle> mUsersWithMatchingAccounts;
+        @NonNull private Set<UserHandle> mUsersWithMatchingAccounts = Collections.emptySet();
+        @NonNull private Set<ComponentName> mAllowedCrossTaskNavigations = Collections.emptySet();
+        @NonNull private Set<ComponentName> mBlockedCrossTaskNavigations = Collections.emptySet();
+        @NavigationPolicy
+        private int mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_ALLOWED;
+        private boolean mDefaultNavigationPolicyConfigured = false;
         @NonNull private Set<ComponentName> mBlockedActivities = Collections.emptySet();
         @NonNull private Set<ComponentName> mAllowedActivities = Collections.emptySet();
         @ActivityPolicy
@@ -282,11 +370,76 @@
         @NonNull
         public Builder setUsersWithMatchingAccounts(
                 @NonNull Set<UserHandle> usersWithMatchingAccounts) {
+            Preconditions.checkNotNull(usersWithMatchingAccounts);
             mUsersWithMatchingAccounts = usersWithMatchingAccounts;
             return this;
         }
 
         /**
+         * Sets the tasks allowed to navigate from current task in the virtual device. Tasks
+         * not in {@code allowedCrossTaskNavigations} will be blocked from navigating to a new
+         * task. Calling this method will cause {@link #getDefaultNavigationPolicy()} to be
+         * {@link #NAVIGATION_POLICY_DEFAULT_BLOCKED}, meaning tasks not in
+         * {@code allowedCrossTaskNavigations} will be blocked from navigating here.
+         *
+         * <p>This method must not be called if {@link #setBlockedCrossTaskNavigations(Set)} has
+         * been called.
+         *
+         * @throws IllegalArgumentException if {@link #setBlockedCrossTaskNavigations(Set)} has been
+         * called.
+         *
+         * @param allowedCrossTaskNavigations A set of tasks {@link ComponentName} allowed to
+         *   navigate to new tasks in the virtual device.
+         */
+        @NonNull
+        public Builder setAllowedCrossTaskNavigations(
+                @NonNull Set<ComponentName> allowedCrossTaskNavigations) {
+            Preconditions.checkNotNull(allowedCrossTaskNavigations);
+            if (mDefaultNavigationPolicyConfigured
+                    && mDefaultNavigationPolicy != NAVIGATION_POLICY_DEFAULT_BLOCKED) {
+                throw new IllegalArgumentException(
+                     "Allowed cross task navigation and blocked task navigation cannot "
+                     + " both be set.");
+            }
+            mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_BLOCKED;
+            mDefaultNavigationPolicyConfigured = true;
+            mAllowedCrossTaskNavigations = allowedCrossTaskNavigations;
+            return this;
+        }
+
+        /**
+         * Sets the tasks blocked from navigating from current task in the virtual device.
+         * Tasks are allowed to navigate unless they are in
+         * {@code blockedCrossTaskNavigations}. Calling this method will cause
+         * {@link #NAVIGATION_POLICY_DEFAULT_ALLOWED}, meaning activities are allowed to launch
+         * unless they are in {@code blockedCrossTaskNavigations}.
+         *
+         * <p> This method must not be called if {@link #setAllowedCrossTaskNavigations(Set)} has
+         * been called.
+         *
+         * @throws IllegalArgumentException if {@link #setAllowedCrossTaskNavigations(Set)} has
+         * been called.
+         *
+         * @param blockedCrossTaskNavigations A set of tasks {@link ComponentName} to be
+         * blocked from navigating to new tasks in the virtual device.
+         */
+        @NonNull
+        public Builder setBlockedCrossTaskNavigations(
+                @NonNull Set<ComponentName> blockedCrossTaskNavigations) {
+            Preconditions.checkNotNull(blockedCrossTaskNavigations);
+            if (mDefaultNavigationPolicyConfigured
+                     && mDefaultNavigationPolicy != NAVIGATION_POLICY_DEFAULT_ALLOWED) {
+                throw new IllegalArgumentException(
+                     "Allowed cross task navigation and blocked task navigation cannot "
+                     + " be set.");
+            }
+            mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_ALLOWED;
+            mDefaultNavigationPolicyConfigured = true;
+            mBlockedCrossTaskNavigations = blockedCrossTaskNavigations;
+            return this;
+        }
+
+        /**
          * Sets the activities allowed to be launched in the virtual device. Calling this method
          * will cause {@link #getDefaultActivityPolicy()} to be
          * {@link #ACTIVITY_POLICY_DEFAULT_BLOCKED}, meaning activities not in
@@ -301,6 +454,7 @@
          */
         @NonNull
         public Builder setAllowedActivities(@NonNull Set<ComponentName> allowedActivities) {
+            Preconditions.checkNotNull(allowedActivities);
             if (mDefaultActivityPolicyConfigured
                     && mDefaultActivityPolicy != ACTIVITY_POLICY_DEFAULT_BLOCKED) {
                 throw new IllegalArgumentException(
@@ -327,6 +481,7 @@
          */
         @NonNull
         public Builder setBlockedActivities(@NonNull Set<ComponentName> blockedActivities) {
+            Preconditions.checkNotNull(blockedActivities);
             if (mDefaultActivityPolicyConfigured
                     && mDefaultActivityPolicy != ACTIVITY_POLICY_DEFAULT_ALLOWED) {
                 throw new IllegalArgumentException(
@@ -343,12 +498,12 @@
          */
         @NonNull
         public VirtualDeviceParams build() {
-            if (mUsersWithMatchingAccounts == null) {
-                mUsersWithMatchingAccounts = Collections.emptySet();
-            }
             return new VirtualDeviceParams(
                     mLockState,
                     mUsersWithMatchingAccounts,
+                    mAllowedCrossTaskNavigations,
+                    mBlockedCrossTaskNavigations,
+                    mDefaultNavigationPolicy,
                     mAllowedActivities,
                     mBlockedActivities,
                     mDefaultActivityPolicy);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2bda020..5dd68a9 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2011,9 +2011,9 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
-    @UnsupportedAppUsage
-    public void startActivityAsUser(@RequiresPermission Intent intent, @Nullable Bundle options,
-            UserHandle userId) {
+    @SystemApi
+    public void startActivityAsUser(@RequiresPermission @NonNull Intent intent,
+            @Nullable Bundle options, @NonNull UserHandle userId) {
         throw new RuntimeException("Not implemented. Must override in a subclass.");
     }
 
@@ -3913,6 +3913,7 @@
             MEDIA_METRICS_SERVICE,
             //@hide: ATTESTATION_VERIFICATION_SERVICE,
             //@hide: SAFETY_CENTER_SERVICE,
+            DISPLAY_HASH_SERVICE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ServiceName {}
@@ -3999,6 +4000,8 @@
      * <dt> {@link #DOMAIN_VERIFICATION_SERVICE} ("domain_verification")
      * <dd> A {@link android.content.pm.verify.domain.DomainVerificationManager} for accessing
      * web domain approval state.
+     * <dt> {@link #DISPLAY_HASH_SERVICE} ("display_hash")
+     * <dd> A {@link android.view.displayhash.DisplayHashManager} for management of display hashes.
      * </dl>
      *
      * <p>Note:  System services obtained via this API may be closely associated with
@@ -4082,6 +4085,8 @@
      * @see #HARDWARE_PROPERTIES_SERVICE
      * @see #DOMAIN_VERIFICATION_SERVICE
      * @see android.content.pm.verify.domain.DomainVerificationManager
+     * @see #DISPLAY_HASH_SERVICE
+     * @see android.view.displayhash.DisplayHashManager
      */
     public abstract @Nullable Object getSystemService(@ServiceName @NonNull String name);
 
@@ -4102,7 +4107,8 @@
      * {@link android.app.UiModeManager}, {@link android.app.DownloadManager},
      * {@link android.os.BatteryManager}, {@link android.app.job.JobScheduler},
      * {@link android.app.usage.NetworkStatsManager},
-     * {@link android.content.pm.verify.domain.DomainVerificationManager}.
+     * {@link android.content.pm.verify.domain.DomainVerificationManager},
+     * {@link android.view.displayhash.DisplayHashManager}.
      * </p>
      *
      * <p>
@@ -6508,22 +6514,22 @@
 
 
     /**
-     * Triggers the asynchronous revocation of a permission.
+     * Triggers the asynchronous revocation of a runtime permission. If the permission is not
+     * currently granted, nothing happens (even if later granted by the user).
      *
      * @param permName The name of the permission to be revoked.
-     * @see #revokeOwnPermissionsOnKill(Collection)
+     * @see #revokeSelfPermissionsOnKill(Collection)
+     * @throws IllegalArgumentException if the permission is not a runtime permission
      */
-    public void revokeOwnPermissionOnKill(@NonNull String permName) {
-        revokeOwnPermissionsOnKill(Collections.singletonList(permName));
+    public void revokeSelfPermissionOnKill(@NonNull String permName) {
+        revokeSelfPermissionsOnKill(Collections.singletonList(permName));
     }
 
     /**
      * Triggers the revocation of one or more permissions for the calling package. A package is only
-     * able to revoke a permission under the following conditions:
-     * <ul>
-     * <li>Each permission in {@code permissions} must be granted to the calling package.
-     * <li>Each permission in {@code permissions} must be a runtime permission.
-     * </ul>
+     * able to revoke runtime permissions. If a permission is not currently granted, it is ignored
+     * and will not get revoked (even if later granted by the user). Ultimately, you should never
+     * make assumptions about a permission status as users may grant or revoke them at any time.
      * <p>
      * Background permissions which have no corresponding foreground permission still granted once
      * the revocation is effective will also be revoked.
@@ -6549,8 +6555,9 @@
      * @param permissions Collection of permissions to be revoked.
      * @see PackageManager#getGroupOfPlatformPermission(String, Executor, Consumer)
      * @see PackageManager#getPlatformPermissionsForGroup(String, Executor, Consumer)
+     * @throws IllegalArgumentException if any of the permissions is not a runtime permission
      */
-    public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
+    public void revokeSelfPermissionsOnKill(@NonNull Collection<String> permissions) {
         throw new AbstractMethodError("Must be overridden in implementing class");
     }
 
@@ -7145,8 +7152,9 @@
     }
 
     /**
-     * Returns token if the {@link Context} is a {@link android.app.WindowContext}. Returns
-     * {@code null} otherwise.
+     * Returns the {@link IBinder} representing the associated
+     * {@link com.android.server.wm.WindowToken} if the {@link Context} is a
+     * {@link android.app.WindowContext}. Returns {@code null} otherwise.
      *
      * @hide
      */
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 9adf173..4ecd776 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -1036,8 +1036,8 @@
     }
 
     @Override
-    public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
-        mBase.revokeOwnPermissionsOnKill(permissions);
+    public void revokeSelfPermissionsOnKill(@NonNull Collection<String> permissions) {
+        mBase.revokeSelfPermissionsOnKill(permissions);
     }
 
     @Override
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 478befd..a50ff3841 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -5987,22 +5987,6 @@
     public static final String EXTRA_UID = "android.intent.extra.UID";
 
     /**
-     * Used as an optional int extra field in {@link android.content.Intent#ACTION_PACKAGE_ADDED}
-     * intents to supply the previous uid the package had been assigned.
-     * This would only be set when a package is leaving sharedUserId in an upgrade, or when a
-     * system app upgrade that had left sharedUserId is getting uninstalled.
-     */
-    public static final String EXTRA_PREVIOUS_UID = "android.intent.extra.PREVIOUS_UID";
-
-    /**
-     * Used as an optional int extra field in {@link android.content.Intent#ACTION_PACKAGE_REMOVED}
-     * intents to supply the new uid the package will be assigned.
-     * This would only be set when a package is leaving sharedUserId in an upgrade, or when a
-     * system app upgrade that had left sharedUserId is getting uninstalled.
-     */
-    public static final String EXTRA_NEW_UID = "android.intent.extra.NEW_UID";
-
-    /**
      * @hide String array of package names.
      */
     @SystemApi
@@ -6034,16 +6018,6 @@
     public static final String EXTRA_REPLACING = "android.intent.extra.REPLACING";
 
     /**
-     * Used as a boolean extra field in {@link android.content.Intent#ACTION_PACKAGE_REMOVED},
-     * {@link android.content.Intent#ACTION_UID_REMOVED}, and
-     * {@link android.content.Intent#ACTION_PACKAGE_ADDED}
-     * intents to indicate that this package is changing its UID.
-     * This would only be set when a package is leaving sharedUserId in an upgrade, or when a
-     * system app upgrade that had left sharedUserId is getting uninstalled.
-     */
-    public static final String EXTRA_UID_CHANGING = "android.intent.extra.UID_CHANGING";
-
-    /**
      * Used as an int extra field in {@link android.app.AlarmManager} pending intents
      * to tell the application being invoked how many pending alarms are being
      * delivered with the intent.  For one-shot alarms this will always be 1.
@@ -8903,8 +8877,12 @@
      * @return the value of an item previously added with putExtra(),
      * or null if no Parcelable value was found.
      *
+     * @deprecated Use the type-safer {@link #getParcelableExtra(String, Class)} starting from
+     *      Android {@link Build.VERSION_CODES#TIRAMISU}.
+     *
      * @see #putExtra(String, Parcelable)
      */
+    @Deprecated
     public @Nullable <T extends Parcelable> T getParcelableExtra(String name) {
         return mExtras == null ? null : mExtras.<T>getParcelable(name);
     }
@@ -8913,12 +8891,31 @@
      * Retrieve extended data from the intent.
      *
      * @param name The name of the desired item.
+     * @param clazz The type of the object expected.
+     *
+     * @return the value of an item previously added with putExtra(),
+     * or null if no Parcelable value was found.
+     *
+     * @see #putExtra(String, Parcelable)
+     */
+    public @Nullable <T> T getParcelableExtra(@Nullable String name, @NonNull Class<T> clazz) {
+        return mExtras == null ? null : mExtras.getParcelable(name, clazz);
+    }
+
+    /**
+     * Retrieve extended data from the intent.
+     *
+     * @param name The name of the desired item.
      *
      * @return the value of an item previously added with putExtra(),
      * or null if no Parcelable[] value was found.
      *
+     * @deprecated Use the type-safer {@link #getParcelableArrayExtra(String, Class)} starting from
+     *      Android {@link Build.VERSION_CODES#TIRAMISU}.
+     *
      * @see #putExtra(String, Parcelable[])
      */
+    @Deprecated
     public @Nullable Parcelable[] getParcelableArrayExtra(String name) {
         return mExtras == null ? null : mExtras.getParcelableArray(name);
     }
@@ -8927,13 +8924,34 @@
      * Retrieve extended data from the intent.
      *
      * @param name The name of the desired item.
+     * @param clazz The type of the items inside the array. This is only verified when unparceling.
+     *
+     * @return the value of an item previously added with putExtra(),
+     * or null if no Parcelable[] value was found.
+     *
+     * @see #putExtra(String, Parcelable[])
+     */
+    @SuppressLint({"ArrayReturn", "NullableCollection"})
+    public @Nullable <T> T[] getParcelableArrayExtra(@Nullable String name,
+            @NonNull Class<T> clazz) {
+        return mExtras == null ? null : mExtras.getParcelableArray(name, clazz);
+    }
+
+    /**
+     * Retrieve extended data from the intent.
+     *
+     * @param name The name of the desired item.
      *
      * @return the value of an item previously added with
      * putParcelableArrayListExtra(), or null if no
      * ArrayList<Parcelable> value was found.
      *
+     * @deprecated Use the type-safer {@link #getParcelableArrayListExtra(String, Class)} starting
+     *      from Android {@link Build.VERSION_CODES#TIRAMISU}.
+     *
      * @see #putParcelableArrayListExtra(String, ArrayList)
      */
+    @Deprecated
     public @Nullable <T extends Parcelable> ArrayList<T> getParcelableArrayListExtra(String name) {
         return mExtras == null ? null : mExtras.<T>getParcelableArrayList(name);
     }
@@ -8942,10 +8960,32 @@
      * Retrieve extended data from the intent.
      *
      * @param name The name of the desired item.
+     * @param clazz The type of the items inside the array list. This is only verified when
+     *     unparceling.
+     *
+     * @return the value of an item previously added with
+     * putParcelableArrayListExtra(), or null if no
+     * ArrayList<Parcelable> value was found.
+     *
+     * @see #putParcelableArrayListExtra(String, ArrayList)
+     */
+    @SuppressLint({"ConcreteCollection", "NullableCollection"})
+    public @Nullable <T> ArrayList<T> getParcelableArrayListExtra(@Nullable String name,
+            @NonNull Class<? extends T> clazz) {
+        return mExtras == null ? null : mExtras.<T>getParcelableArrayList(name, clazz);
+    }
+
+    /**
+     * Retrieve extended data from the intent.
+     *
+     * @param name The name of the desired item.
      *
      * @return the value of an item previously added with putExtra(),
      * or null if no Serializable value was found.
      *
+     * @deprecated Use the type-safer {@link #getSerializableExtra(String, Class)} starting from
+     *      Android {@link Build.VERSION_CODES#TIRAMISU}.
+     *
      * @see #putExtra(String, Serializable)
      */
     public @Nullable Serializable getSerializableExtra(String name) {
@@ -8956,6 +8996,22 @@
      * Retrieve extended data from the intent.
      *
      * @param name The name of the desired item.
+     * @param clazz The type of the object expected.
+     *
+     * @return the value of an item previously added with putExtra(),
+     * or null if no Serializable value was found.
+     *
+     * @see #putExtra(String, Serializable)
+     */
+    public @Nullable <T extends Serializable> T getSerializableExtra(@Nullable String name,
+            @NonNull Class<T> clazz) {
+        return mExtras == null ? null : mExtras.getSerializable(name, clazz);
+    }
+
+    /**
+     * Retrieve extended data from the intent.
+     *
+     * @param name The name of the desired item.
      *
      * @return the value of an item previously added with
      * putIntegerArrayListExtra(), or null if no
diff --git a/core/java/android/content/pm/AppSearchShortcutInfo.java b/core/java/android/content/pm/AppSearchShortcutInfo.java
index f20d1e6..1b84686b 100644
--- a/core/java/android/content/pm/AppSearchShortcutInfo.java
+++ b/core/java/android/content/pm/AppSearchShortcutInfo.java
@@ -349,7 +349,7 @@
                 .setDisabledReason(shortcutInfo.getDisabledReason())
                 .setPersons(shortcutInfo.getPersons())
                 .setLocusId(shortcutInfo.getLocusId())
-                .setCapabilityBindings(shortcutInfo.getCapabilityBindings())
+                .setCapabilityBindings(shortcutInfo.getCapabilityBindingsInternal())
                 .setTtlMillis(SHORTCUT_TTL)
                 .build();
     }
diff --git a/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.aidl b/core/java/android/content/pm/Capability.aidl
similarity index 83%
copy from packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.aidl
copy to core/java/android/content/pm/Capability.aidl
index a56f2f4..df3b1be 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.aidl
+++ b/core/java/android/content/pm/Capability.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.content.pm;
 
-package android.net;
-
-parcelable UnderlyingNetworkInfo;
+parcelable Capability;
\ No newline at end of file
diff --git a/core/java/android/content/pm/Capability.java b/core/java/android/content/pm/Capability.java
new file mode 100644
index 0000000..1597d31
--- /dev/null
+++ b/core/java/android/content/pm/Capability.java
@@ -0,0 +1,143 @@
+/*
+ * 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 android.content.pm;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Represents a capability that can be performed by an app, also known as App Action.
+ * Capabilities can be associated with a {@link ShortcutInfo}.
+ *
+ * @see ShortcutInfo.Builder#addCapabilityBinding(Capability, CapabilityParams)
+ */
+public final class Capability implements Parcelable {
+
+    @NonNull
+    private final String mName;
+
+    /**
+     * Constructor.
+     * @param name Name of the capability, usually maps to a built-in intent,
+     *            e.g. actions.intent.GET_MESSAGE. Note the character "/" is not permitted.
+     * @throws IllegalArgumentException If specified capability name contains the character "/".
+     *
+     * @hide
+     */
+    Capability(@NonNull final String name) {
+        Objects.requireNonNull(name);
+        if (name.contains("/")) {
+            throw new IllegalArgumentException("'/' is not permitted in the capability name");
+        }
+        mName = name;
+    }
+
+    /**
+     * Copy constructor.
+     *
+     * @hide
+     */
+    Capability(@NonNull final Capability orig) {
+        this(orig.mName);
+    }
+
+    private Capability(@NonNull final Builder builder) {
+        this(builder.mName);
+    }
+
+    private Capability(@NonNull final Parcel in) {
+        mName = in.readString();
+    }
+
+    /**
+     * Returns the name of the capability. e.g. actions.intent.GET_MESSAGE.
+     */
+    @NonNull
+    public String getName() {
+        return mName;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof Capability)) {
+            return false;
+        }
+        return mName.equals(((Capability) obj).mName);
+    }
+
+    @Override
+    public int hashCode() {
+        return mName.hashCode();
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString(mName);
+    }
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @NonNull
+    public static final Parcelable.Creator<Capability> CREATOR =
+            new Parcelable.Creator<Capability>() {
+        @Override
+        public Capability[] newArray(int size) {
+            return new Capability[size];
+        }
+
+        @Override
+        public Capability createFromParcel(@NonNull Parcel in) {
+            return new Capability(in);
+        }
+    };
+
+    /**
+     * Builder class for {@link Capability}.
+     */
+    public static final class Builder {
+
+        @NonNull
+        private final String mName;
+
+        /**
+         * Constructor.
+         * @param name Name of the capability, usually maps to a built-in intent,
+         *            e.g. actions.intent.GET_MESSAGE. Note the character "/" is not permitted.
+         * @throws IllegalArgumentException If specified capability name contains the character "/".
+         */
+        public Builder(@NonNull final String name) {
+            Objects.requireNonNull(name);
+            if (name.contains("/")) {
+                throw new IllegalArgumentException("'/' is not permitted in the capability name");
+            }
+            mName = name;
+        }
+
+        /**
+         * Creates an instance of {@link Capability}
+         */
+        @NonNull
+        public Capability build() {
+            return new Capability(this);
+        }
+    }
+}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.aidl b/core/java/android/content/pm/CapabilityParams.aidl
similarity index 82%
copy from packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.aidl
copy to core/java/android/content/pm/CapabilityParams.aidl
index a56f2f4..39f1238 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.aidl
+++ b/core/java/android/content/pm/CapabilityParams.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.content.pm;
 
-package android.net;
-
-parcelable UnderlyingNetworkInfo;
+parcelable CapabilityParams;
diff --git a/core/java/android/content/pm/CapabilityParams.java b/core/java/android/content/pm/CapabilityParams.java
new file mode 100644
index 0000000..7239bac
--- /dev/null
+++ b/core/java/android/content/pm/CapabilityParams.java
@@ -0,0 +1,215 @@
+/*
+ * 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 android.content.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.ArraySet;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Represents the parameters and its matching names which can be associated with a
+ * {@link Capability}.
+ *
+ * @see ShortcutInfo.Builder#addCapabilityBinding(Capability, CapabilityParams)
+ */
+public final class CapabilityParams implements Parcelable {
+
+    @NonNull
+    private final String mName;
+    @NonNull
+    private final String mPrimaryValue;
+    @NonNull
+    private final List<String> mAliases;
+
+    /**
+     * Constructor.
+     * @param name Name of the capability parameter.
+     *           Note the character "/" is not permitted.
+     * @param primaryValue The primary value of the parameter.
+     * @param aliases Alternative values of the parameter.
+     */
+    private CapabilityParams(@NonNull final String name,
+            @NonNull final String primaryValue, @Nullable final Collection<String> aliases) {
+        Objects.requireNonNull(name);
+        Objects.requireNonNull(primaryValue);
+        mName = name;
+        mPrimaryValue = primaryValue;
+        mAliases = aliases == null ? Collections.emptyList()
+                : Collections.unmodifiableList(new ArrayList<>(aliases));
+    }
+
+    /**
+     * Copy constructor.
+     * @hide
+     */
+    CapabilityParams(@NonNull final CapabilityParams orig) {
+        this(orig.mName, orig.mPrimaryValue, orig.mAliases);
+    }
+
+    private CapabilityParams(@NonNull final Builder builder) {
+        this(builder.mKey, builder.mPrimaryValue, builder.mAliases);
+    }
+
+    private CapabilityParams(@NonNull final Parcel in) {
+        mName = in.readString();
+        mPrimaryValue = in.readString();
+        final List<String> values = new ArrayList<>();
+        in.readStringList(values);
+        mAliases = Collections.unmodifiableList(values);
+    }
+
+    /**
+     * Name of the parameter.
+     */
+    @NonNull
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * Returns the primary name of values in this parameter.
+     */
+    @NonNull
+    public String getValue() {
+        return mPrimaryValue;
+    }
+
+    /**
+     * Returns the aliases of the values in ths parameter. Returns an empty list if there are no
+     * aliases.
+     */
+    @NonNull
+    public List<String> getAliases() {
+        return new ArrayList<>(mAliases);
+    }
+
+    /**
+     * A list of values for this parameter. The first value will be the primary name, while the
+     * rest will be alternative names.
+     * @hide
+     */
+    @NonNull
+    List<String> getValues() {
+        if (mAliases == null) {
+            return new ArrayList<>(Collections.singletonList(mPrimaryValue));
+        }
+        final List<String> ret = new ArrayList<>(mAliases.size() + 1);
+        ret.add(mPrimaryValue);
+        ret.addAll(mAliases);
+        return ret;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof CapabilityParams)) {
+            return false;
+        }
+        final CapabilityParams target = (CapabilityParams) obj;
+        return mName.equals(target.mName) && mPrimaryValue.equals(target.mPrimaryValue)
+                && mAliases.equals(target.mAliases);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mName, mPrimaryValue, mAliases);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString(mName);
+        dest.writeString(mPrimaryValue);
+        dest.writeStringList(mAliases);
+    }
+
+    @NonNull
+    public static final Parcelable.Creator<CapabilityParams> CREATOR =
+            new Parcelable.Creator<CapabilityParams>() {
+        @Override
+        public CapabilityParams[] newArray(int size) {
+            return new CapabilityParams[size];
+        }
+
+        @Override
+        public CapabilityParams createFromParcel(@NonNull Parcel in) {
+            return new CapabilityParams(in);
+        }
+    };
+
+    /**
+     * Builder class for {@link CapabilityParams}.
+     */
+    public static final class Builder {
+
+        @NonNull
+        private final String mKey;
+        @NonNull
+        private String mPrimaryValue;
+        @NonNull
+        private Set<String> mAliases;
+
+        /**
+         * Constructor.
+         * @param key key of the capability parameter.
+         *           Note the character "/" is not permitted.
+         * @param value The primary name of value in the {@link CapabilityParams}, cannot be empty.
+         */
+        public Builder(@NonNull final String key, @NonNull final String value) {
+            Objects.requireNonNull(key);
+            if (TextUtils.isEmpty(value)) {
+                throw new IllegalArgumentException("Primary value cannot be empty or null");
+            }
+            mPrimaryValue = value;
+            mKey = key;
+        }
+
+        /**
+         * Add an alias in the {@link CapabilityParams}.
+         */
+        @NonNull
+        public Builder addAlias(@NonNull final String alias) {
+            if (mAliases == null) {
+                mAliases = new ArraySet<>(1);
+            }
+            mAliases.add(alias);
+            return this;
+        }
+
+        /**
+         * Creates an instance of {@link CapabilityParams}
+         * @throws IllegalArgumentException If the specified value is empty.
+         */
+        @NonNull
+        public CapabilityParams build() {
+            return new CapabilityParams(this);
+        }
+    }
+}
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index 94f0561..66c6c81 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -104,7 +104,44 @@
                     mContext.getAttributionTag(),
                     component,
                     targetUser.getIdentifier(),
-                    true);
+                    true,
+                    null,
+                    null);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Starts the specified main activity of the caller package in the specified profile, launching
+     * in the specified activity.
+     *
+     * @param component The ComponentName of the activity to launch, it must be exported and has
+     *        action {@link android.content.Intent#ACTION_MAIN}, category
+     *        {@link android.content.Intent#CATEGORY_LAUNCHER}. Otherwise, SecurityException will
+     *        be thrown.
+     * @param targetUser The UserHandle of the profile, must be one of the users returned by
+     *        {@link #getTargetUserProfiles()}, otherwise a {@link SecurityException} will
+     *        be thrown.
+     * @param callingActivity The activity to start the new activity from for the purposes of
+     *        deciding which task the new activity should belong to. If {@code null}, the activity
+     *        will always be started in a new task.
+     * @param options The activity options or {@code null}. See {@link android.app.ActivityOptions}.
+     */
+    public void startMainActivity(@NonNull ComponentName component,
+            @NonNull UserHandle targetUser,
+            @Nullable Activity callingActivity,
+            @Nullable Bundle options) {
+        try {
+            mService.startActivityAsUser(
+                    mContext.getIApplicationThread(),
+                    mContext.getPackageName(),
+                    mContext.getAttributionTag(),
+                    component,
+                    targetUser.getIdentifier(),
+                    true,
+                    callingActivity != null ? callingActivity.getActivityToken() : null,
+                    options);
         } catch (RemoteException ex) {
             throw ex.rethrowFromSystemServer();
         }
@@ -191,6 +228,48 @@
      * @param targetUser The UserHandle of the profile, must be one of the users returned by
      *        {@link #getTargetUserProfiles()}, otherwise a {@link SecurityException} will
      *        be thrown.
+     * @param callingActivity The activity to start the new activity from for the purposes of
+     *        deciding which task the new activity should belong to. If {@code null}, the activity
+     *        will always be started in a new task.
+     * @param options The activity options or {@code null}. See {@link android.app.ActivityOptions}.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.INTERACT_ACROSS_PROFILES,
+            android.Manifest.permission.START_CROSS_PROFILE_ACTIVITIES})
+    public void startActivity(
+            @NonNull ComponentName component,
+            @NonNull UserHandle targetUser,
+            @Nullable Activity callingActivity,
+            @Nullable Bundle options) {
+        try {
+            mService.startActivityAsUser(
+                    mContext.getIApplicationThread(),
+                    mContext.getPackageName(),
+                    mContext.getAttributionTag(),
+                    component,
+                    targetUser.getIdentifier(),
+                    false,
+                    callingActivity != null ? callingActivity.getActivityToken() : null,
+                    options);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Starts the specified activity of the caller package in the specified profile. Unlike
+     * {@link #startMainActivity}, this can start any activity of the caller package, not just
+     * the main activity.
+     * The caller must have the {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES}
+     * or {@link android.Manifest.permission#START_CROSS_PROFILE_ACTIVITIES}
+     * permission and both the caller and target user profiles must be in the same profile group.
+     *
+     * @param component The ComponentName of the activity to launch. It must be exported.
+     * @param targetUser The UserHandle of the profile, must be one of the users returned by
+     *        {@link #getTargetUserProfiles()}, otherwise a {@link SecurityException} will
+     *        be thrown.
      * @hide
      */
     @SystemApi
@@ -201,7 +280,7 @@
         try {
             mService.startActivityAsUser(mContext.getIApplicationThread(),
                     mContext.getPackageName(), mContext.getAttributionTag(), component,
-                    targetUser.getIdentifier(), false);
+                    targetUser.getIdentifier(), false, null, null);
         } catch (RemoteException ex) {
             throw ex.rethrowFromSystemServer();
         }
@@ -247,7 +326,7 @@
 
         final boolean isManagedProfile = mUserManager.isManagedProfile(userHandle.getIdentifier());
         final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
-        return dpm.getString(
+        return dpm.getResources().getString(
                 getUpdatableProfileSwitchingLabelId(isManagedProfile),
                 () -> getDefaultProfileSwitchingLabel(isManagedProfile));
     }
diff --git a/core/java/android/content/pm/ICrossProfileApps.aidl b/core/java/android/content/pm/ICrossProfileApps.aidl
index e2850f1..4f2c106 100644
--- a/core/java/android/content/pm/ICrossProfileApps.aidl
+++ b/core/java/android/content/pm/ICrossProfileApps.aidl
@@ -29,7 +29,7 @@
 interface ICrossProfileApps {
     void startActivityAsUser(in IApplicationThread caller, in String callingPackage,
             in String callingFeatureId, in ComponentName component, int userId,
-            boolean launchMainActivity);
+            boolean launchMainActivity, in IBinder task, in Bundle options);
     void startActivityAsUserByIntent(in IApplicationThread caller, in String callingPackage,
             in String callingFeatureId, in Intent intent, int userId, in IBinder callingActivity,
             in Bundle options);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 0f236df..ca7d77b 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -781,7 +781,11 @@
 
     boolean isAutoRevokeWhitelisted(String packageName);
 
-    void grantImplicitAccess(int queryingUid, String visibleAuthority);
+    void makeProviderVisible(int recipientAppId, String visibleAuthority);
+
+    @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+            + ".permission.MAKE_UID_VISIBLE)")
+    void makeUidVisible(int recipientAppId, int visibleUid);
 
     IBinder getHoldLockToken();
 
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index eefa63f..f4de829 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -213,7 +213,8 @@
      * or null if there were none.  This is only filled in if the flag
      * {@link PackageManager#GET_PERMISSIONS} was set.  Each value matches
      * the corresponding entry in {@link #requestedPermissions}, and will have
-     * the flag {@link #REQUESTED_PERMISSION_GRANTED} set as appropriate.
+     * the flags {@link #REQUESTED_PERMISSION_GRANTED} and
+     * {@link #REQUESTED_PERMISSION_NEVER_FOR_LOCATION} set as appropriate.
      */
     public int[] requestedPermissionsFlags;
 
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 450e09a..236c244 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -419,8 +419,8 @@
     public @interface FileLocation{}
 
     /**
-     * The installer did not call SessionParams#setPackageSource(int) to specify the package
-     * source.
+     * The installer did not call {@link PackageInstaller.SessionParams#setPackageSource(int)} to
+     * specify the package source.
      */
     public static final int PACKAGE_SOURCE_UNSPECIFIED = 0;
 
@@ -444,8 +444,8 @@
 
     /**
      * Code indicating that the package being installed comes from a file that was downloaded to
-     * the device by the user. For use in place of PACKAGE_SOURCE_LOCAL_FILE when the installer
-     * knows the package was downloaded.
+     * the device by the user. For use in place of {@link #PACKAGE_SOURCE_LOCAL_FILE} when the
+     * installer knows the package was downloaded.
      */
     public static final int PACKAGE_SOURCE_DOWNLOADED_FILE = 4;
 
@@ -1984,7 +1984,13 @@
         }
 
         /**
-         * Sets the apk package installation source.
+         * Optionally indicate the package source of the app being installed. This is
+         * informational and may be used as a signal by the system.
+         *
+         * An installer should specify {@link #PACKAGE_SOURCE_OTHER} if no other package source
+         * constant adequately reflects the source for this session.
+         *
+         * The default value is {@link #PACKAGE_SOURCE_UNSPECIFIED}.
          */
         public void setPackageSource(@PackageSourceType int packageSource) {
             this.packageSource = packageSource;
@@ -2302,8 +2308,14 @@
          *
          * <ul>
          *     <li>{@code requireUserAction} is set to {@link #USER_ACTION_NOT_REQUIRED}.</li>
-         *     <li>The app being installed targets {@link android.os.Build.VERSION_CODES#Q API 29}
-         *     or higher.</li>
+         *     <li>The app being installed targets:
+         *          <ul>
+         *              <li>{@link android.os.Build.VERSION_CODES#Q API 29} or higher on
+         *              Android S ({@link android.os.Build.VERSION_CODES#S API 31})</li>
+         *              <li>{@link android.os.Build.VERSION_CODES#R API 30} or higher after
+         *              Android S ({@link android.os.Build.VERSION_CODES#S API 31})</li>
+         *          </ul>
+         *     </li>
          *     <li>The installer is the {@link InstallSourceInfo#getInstallingPackageName()
          *     installer of record} of an existing version of the app (in other words, this install
          *     session is an app update) or the installer is updating itself.</li>
@@ -2991,7 +3003,8 @@
         }
 
         /**
-         * Gets the apk package installation source.
+         * Get the package source that was set in
+         * {@link PackageInstaller.SessionParams#setPackageSource(int)}.
          */
         public @PackageSourceType int getPackageSource() {
             return packageSource;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index f9beaa7..227ac1a 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -4087,6 +4087,28 @@
             "android.software.incremental_delivery";
 
     /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device
+     * has the requisite kernel support for the EROFS filesystem present in 4.19 kernels as a
+     * staging driver, which lacks 0padding and big pcluster support.
+     *
+     * @hide
+     */
+    @SystemApi
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_EROFS_LEGACY = "android.software.erofs_legacy";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device
+     * has the requisite kernel support for the EROFS filesystem present in 5.10 kernels, which
+     * has 0padding, big pcluster, and chunked index support.
+     *
+     * @hide
+     */
+    @SystemApi
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_EROFS = "android.software.erofs";
+
+    /**
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
      * The device has tuner hardware to support tuner operations.
      *
@@ -4970,8 +4992,8 @@
      *         applications (which includes installed applications as well as
      *         applications with data directory i.e. applications which had been
      *         deleted with {@code DELETE_KEEP_DATA} flag set).
-     * @throws NameNotFoundException if a package with the given name cannot be
-     *             found on the system.
+     * @throws NameNotFoundException if no such package is available to the
+     *             caller.
      * @deprecated Use {@link #getPackageInfo(String, PackageInfoFlags)} instead.
      */
     @Deprecated
@@ -5007,8 +5029,8 @@
      *         applications (which includes installed applications as well as
      *         applications with data directory i.e. applications which had been
      *         deleted with {@code DELETE_KEEP_DATA} flag set).
-     * @throws NameNotFoundException if a package with the given name cannot be
-     *             found on the system.
+     * @throws NameNotFoundException if no such package is available to the
+     *             caller.
      * @deprecated Use {@link #getPackageInfo(VersionedPackage, PackageInfoFlags)} instead.
      */
     @Deprecated
@@ -5040,8 +5062,8 @@
      *         applications (which includes installed applications as well as
      *         applications with data directory i.e. applications which had been
      *         deleted with {@code DELETE_KEEP_DATA} flag set).
-     * @throws NameNotFoundException if a package with the given name cannot be
-     *             found on the system.
+     * @throws NameNotFoundException if no such package is available to the
+     *             caller.
      * @deprecated Use {@link #getPackageInfoAsUser(String, PackageInfoFlags, int)} instead.
      * @hide
      */
@@ -5166,8 +5188,8 @@
      *            desired package.
      * @return Returns an int array of the assigned GIDs, or null if there are
      *         none.
-     * @throws NameNotFoundException if a package with the given name cannot be
-     *             found on the system.
+     * @throws NameNotFoundException if no such package is available to the
+     *             caller.
      */
     public abstract int[] getPackageGids(@NonNull String packageName)
             throws NameNotFoundException;
@@ -5183,8 +5205,8 @@
      *            desired package.
      * @return Returns an int array of the assigned gids, or null if there are
      *         none.
-     * @throws NameNotFoundException if a package with the given name cannot be
-     *             found on the system.
+     * @throws NameNotFoundException if no such package is available to the
+     *             caller.
      * @deprecated Use {@link #getPackageGids(String, PackageInfoFlags)} instead.
      */
     @Deprecated
@@ -5210,8 +5232,8 @@
      * @param packageName The full name (i.e. com.google.apps.contacts) of the
      *            desired package.
      * @return Returns an integer UID who owns the given package name.
-     * @throws NameNotFoundException if a package with the given name can not be
-     *             found on the system.
+     * @throws NameNotFoundException if no such package is available to the
+     *             caller.
      * @deprecated Use {@link #getPackageUid(String, PackageInfoFlags)} instead.
      */
     @Deprecated
@@ -5237,8 +5259,8 @@
      *            desired package.
      * @param userId The user handle identifier to look up the package under.
      * @return Returns an integer UID who owns the given package name.
-     * @throws NameNotFoundException if a package with the given name can not be
-     *             found on the system.
+     * @throws NameNotFoundException if no such package is available to the
+     *             caller.
      * @hide
      */
     @SuppressWarnings("HiddenAbstractMethod")
@@ -5256,8 +5278,8 @@
      *            desired package.
      * @param userId The user handle identifier to look up the package under.
      * @return Returns an integer UID who owns the given package name.
-     * @throws NameNotFoundException if a package with the given name can not be
-     *             found on the system.
+     * @throws NameNotFoundException if no such package is available to the
+     *             caller.
      * @deprecated Use {@link #getPackageUidAsUser(String, PackageInfoFlags, int)} instead.
      * @hide
      */
@@ -10281,19 +10303,42 @@
     }
 
     /**
-     * Grants implicit visibility of the package that provides an authority to a querying UID.
+     * Makes a package that provides an authority {@code visibleAuthority} become visible to the
+     * application {@code recipientUid}.
      *
      * @throws SecurityException when called by a package other than the contacts provider
      * @hide
      */
-    public void grantImplicitAccess(int queryingUid, String visibleAuthority) {
+    public void makeProviderVisible(int recipientUid, String visibleAuthority) {
         try {
-            ActivityThread.getPackageManager().grantImplicitAccess(queryingUid, visibleAuthority);
+            ActivityThread.getPackageManager().makeProviderVisible(recipientUid, visibleAuthority);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
+    /**
+     * Makes the package associated with the uid {@code visibleUid} become visible to the
+     * recipient application. The recipient application can receive the details about the
+     * visible package if successful.
+     * <p>
+     * Read <a href="/training/basics/intents/package-visibility">package visibility</a> for more
+     * information.
+     *
+     * @param recipientUid The uid of the application that is being given access to {@code
+     *                     visibleUid}
+     * @param visibleUid The uid of the application that is becoming accessible to {@code
+     *                   recipientAppId}
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MAKE_UID_VISIBLE)
+    @TestApi
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public void makeUidVisible(int recipientUid, int visibleUid) {
+        throw new UnsupportedOperationException(
+                "makeUidVisible not implemented in subclass");
+    }
+
     // Some of the flags don't affect the query result, but let's be conservative and cache
     // each combination of flags separately.
 
diff --git a/core/java/android/content/pm/SHORTCUT_OWNERS b/core/java/android/content/pm/SHORTCUT_OWNERS
index 3688d5a..f8bba473 100644
--- a/core/java/android/content/pm/SHORTCUT_OWNERS
+++ b/core/java/android/content/pm/SHORTCUT_OWNERS
@@ -1,7 +1,6 @@
 set noparent
 
+pinyaoting@google.com
+sunnygoyal@google.com
 omakoto@google.com
 yamasani@google.com
-sunnygoyal@google.com
-mett@google.com
-pinyaoting@google.com
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 41dd5bb3..52774e3 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -52,7 +52,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.Collection;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -60,7 +60,6 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 /**
  * Represents a shortcut that can be published via {@link ShortcutManager}.
@@ -501,7 +500,8 @@
         mRank = b.mRank;
         mExtras = b.mExtras;
         mLocusId = b.mLocusId;
-        mCapabilityBindings = b.mCapabilityBindings;
+        mCapabilityBindings =
+                cloneCapabilityBindings(b.mCapabilityBindings);
         mStartingThemeResName = b.mStartingThemeResId != 0
                 ? b.mContext.getResources().getResourceName(b.mStartingThemeResId) : null;
         updateTimestamp();
@@ -652,7 +652,8 @@
             // Set this bit.
             mFlags |= FLAG_KEY_FIELDS_ONLY;
         }
-        mCapabilityBindings = source.mCapabilityBindings;
+        mCapabilityBindings = cloneCapabilityBindings(
+                source.mCapabilityBindings);
         mStartingThemeResName = source.mStartingThemeResName;
     }
 
@@ -1003,7 +1004,8 @@
             mStartingThemeResName = source.mStartingThemeResName;
         }
         if (source.mCapabilityBindings != null) {
-            mCapabilityBindings = source.mCapabilityBindings;
+            mCapabilityBindings =
+                    cloneCapabilityBindings(source.mCapabilityBindings);
         }
     }
 
@@ -1447,43 +1449,25 @@
          * <P>This method can be called multiple times to add multiple parameters to the same
          * capability.
          *
-         * @param capability capability associated with the shortcut. e.g. actions.intent
-         *                   .START_EXERCISE.
-         * @param parameterName name of the parameter associated with given capability.
-         *                      e.g. exercise.name.
-         * @param parameterValues a list of values for that parameters. The first value will be
-         *                        the primary name, while the rest will be alternative names. If
-         *                        the values are empty, then the parameter will not be saved in
-         *                        the shortcut.
+         * @param capability {@link Capability} associated with the shortcut.
+         * @param capabilityParams Optional {@link CapabilityParams} associated with given
+         *                        capability.
          */
         @NonNull
-        public Builder addCapabilityBinding(@NonNull String capability,
-                @Nullable String parameterName, @Nullable List<String> parameterValues) {
+        public Builder addCapabilityBinding(@NonNull final Capability capability,
+                @Nullable final CapabilityParams capabilityParams) {
             Objects.requireNonNull(capability);
-            if (capability.contains("/")) {
-                throw new IllegalArgumentException("Illegal character '/' is found in capability");
-            }
             if (mCapabilityBindings == null) {
                 mCapabilityBindings = new ArrayMap<>(1);
             }
-            if (!mCapabilityBindings.containsKey(capability)) {
-                mCapabilityBindings.put(capability, new ArrayMap<>(0));
+            if (!mCapabilityBindings.containsKey(capability.getName())) {
+                mCapabilityBindings.put(capability.getName(), new ArrayMap<>(0));
             }
-            if (parameterName == null || parameterValues == null || parameterValues.isEmpty()) {
+            if (capabilityParams == null) {
                 return this;
             }
-            if (parameterName.contains("/")) {
-                throw new IllegalArgumentException(
-                        "Illegal character '/' is found in parameter name");
-            }
-            final Map<String, List<String>> params = mCapabilityBindings.get(capability);
-            if (!params.containsKey(parameterName)) {
-                params.put(parameterName, parameterValues);
-                return this;
-            }
-            params.put(parameterName,
-                    Stream.of(params.get(parameterName), parameterValues)
-                            .flatMap(Collection::stream).collect(Collectors.toList()));
+            final Map<String, List<String>> params = mCapabilityBindings.get(capability.getName());
+            params.put(capabilityParams.getName(), capabilityParams.getValues());
             return this;
         }
 
@@ -2257,48 +2241,95 @@
     }
 
     /**
-     * Return true if the shortcut is included in specified surface.
+     * Return true if the shortcut is excluded from specified surface.
      */
-    public boolean isIncludedIn(@Surface int surface) {
-        return (mExcludedSurfaces & surface) == 0;
+    public boolean isExcludedFromSurfaces(@Surface int surface) {
+        return (mExcludedSurfaces & surface) != 0;
     }
 
     /**
+     * Returns a bitmask of all surfaces this shortcut is excluded from.
+     *
+     * @see ShortcutInfo.Builder#setExcludedFromSurfaces(int)
+     */
+    @Surface
+    public int getExcludedFromSurfaces() {
+        return mExcludedSurfaces;
+    }
+
+    /**
+     * Returns an immutable copy of the capability bindings using internal data structure.
      * @hide
      */
-    public Map<String, Map<String, List<String>>> getCapabilityBindings() {
-        return mCapabilityBindings;
+    @Nullable
+    public Map<String, Map<String, List<String>>> getCapabilityBindingsInternal() {
+        return cloneCapabilityBindings(mCapabilityBindings);
+    }
+
+    @Nullable
+    private static Map<String, Map<String, List<String>>> cloneCapabilityBindings(
+            @Nullable final Map<String, Map<String, List<String>>> orig) {
+        if (orig == null) {
+            return null;
+        }
+        final Map<String, Map<String, List<String>>> ret = new ArrayMap<>();
+        for (String capability : orig.keySet()) {
+            final Map<String, List<String>> params = orig.get(capability);
+            final Map<String, List<String>> clone;
+            if (params == null) {
+                clone = null;
+            } else {
+                clone = new ArrayMap<>(params.size());
+                for (String paramName : params.keySet()) {
+                    final List<String> paramValues = params.get(paramName);
+                    clone.put(paramName, Collections.unmodifiableList(paramValues));
+                }
+            }
+            ret.put(capability, Collections.unmodifiableMap(clone));
+        }
+        return Collections.unmodifiableMap(ret);
     }
 
     /**
-     * Return true if the shortcut is or can be used in specified capability.
-     */
-    public boolean hasCapability(@NonNull String capability) {
-        Objects.requireNonNull(capability);
-        return mCapabilityBindings != null && mCapabilityBindings.containsKey(capability);
-    }
-
-    /**
-     *  Returns the values of specified parameter in associated with given capability.
-     *
-     *  @param capability capability associated with the shortcut. e.g. actions.intent
-     *                   .START_EXERCISE.
-     *  @param parameterName name of the parameter associated with given capability.
-     *                       e.g. exercise.name.
+     * Return a list of {@link Capability} associated with the shortcut.
      */
     @NonNull
-    public List<String> getCapabilityParameterValues(
-            @NonNull String capability, @NonNull String parameterName) {
-        Objects.requireNonNull(capability);
-        Objects.requireNonNull(parameterName);
+    public List<Capability> getCapabilities() {
         if (mCapabilityBindings == null) {
-            return Collections.emptyList();
+            return new ArrayList<>(0);
         }
-        final Map<String, List<String>> param = mCapabilityBindings.get(capability);
-        if (param == null || !param.containsKey(parameterName)) {
-            return Collections.emptyList();
+        return mCapabilityBindings.keySet().stream().map(Capability::new)
+                .collect(Collectors.toList());
+    }
+
+    /**
+     *  Returns the {@link CapabilityParams} in associated with given capability.
+     *
+     *  @param capability {@link Capability} associated with the shortcut.
+     */
+    @NonNull
+    public List<CapabilityParams> getCapabilityParams(@NonNull final Capability capability) {
+        Objects.requireNonNull(capability);
+        if (mCapabilityBindings == null) {
+            return new ArrayList<>(0);
         }
-        return param.get(parameterName);
+        final Map<String, List<String>> param = mCapabilityBindings.get(capability.getName());
+        if (param == null) {
+            return new ArrayList<>(0);
+        }
+        final List<CapabilityParams> ret = new ArrayList<>(param.size());
+        for (String key : param.keySet()) {
+            final List<String> values = param.get(key);
+            final String primaryValue = values.get(0);
+            final List<String> aliases = values.size() == 1
+                    ? Collections.emptyList() : values.subList(1, values.size());
+            CapabilityParams.Builder builder = new CapabilityParams.Builder(key, primaryValue);
+            for (String alias : aliases) {
+                builder = builder.addAlias(alias);
+            }
+            ret.add(builder.build());
+        }
+        return ret;
     }
 
     private ShortcutInfo(Parcel source) {
@@ -2357,7 +2388,7 @@
             final Map<String, Map<String, List<String>>> capabilityBindings =
                     new ArrayMap<>(rawCapabilityBindings.size());
             rawCapabilityBindings.forEach(capabilityBindings::put);
-            mCapabilityBindings = capabilityBindings;
+            mCapabilityBindings = cloneCapabilityBindings(capabilityBindings);
         }
     }
 
@@ -2522,7 +2553,7 @@
         if (isLongLived()) {
             sb.append("Liv");
         }
-        if (!isIncludedIn(SURFACE_LAUNCHER)) {
+        if (isExcludedFromSurfaces(SURFACE_LAUNCHER)) {
             sb.append("Hid-L");
         }
         sb.append("]");
@@ -2695,6 +2726,6 @@
         mPersons = persons;
         mLocusId = locusId;
         mStartingThemeResName = startingThemeResName;
-        mCapabilityBindings = capabilityBindings;
+        mCapabilityBindings = cloneCapabilityBindings(capabilityBindings);
     }
 }
diff --git a/core/java/android/content/pm/Signature.java b/core/java/android/content/pm/Signature.java
index 3f5c5d2..d94b0d8 100644
--- a/core/java/android/content/pm/Signature.java
+++ b/core/java/android/content/pm/Signature.java
@@ -312,7 +312,7 @@
      * @hide
      */
     public static boolean areExactMatch(Signature[] a, Signature[] b) {
-        return (a.length == b.length) && ArrayUtils.containsAll(a, b)
+        return (ArrayUtils.size(a) == ArrayUtils.size(b)) && ArrayUtils.containsAll(a, b)
                 && ArrayUtils.containsAll(b, a);
     }
 
@@ -387,4 +387,4 @@
 
         return sPrime;
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/android/content/pm/SigningInfo.java b/core/java/android/content/pm/SigningInfo.java
index 7459a90..ee9aaca3 100644
--- a/core/java/android/content/pm/SigningInfo.java
+++ b/core/java/android/content/pm/SigningInfo.java
@@ -72,9 +72,11 @@
     /**
      * Returns the signing certificates this package has proven it is authorized to use. This
      * includes both the signing certificate associated with the signer of the package and the past
-     * signing certificates it included as its proof of signing certificate rotation.  This method
-     * is the preferred replacement for the {@code GET_SIGNATURES} flag used with {@link
-     * PackageManager#getPackageInfo(String, int)}.  When determining if a package is signed by a
+     * signing certificates it included as its proof of signing certificate rotation.  Signing
+     * certificates are returned in the order of rotation with the original signing certificate at
+     * index 0, and the current signing certificate at the last index. This method is the preferred
+     * replacement for the {@code GET_SIGNATURES} flag used with {@link
+     * PackageManager#getPackageInfo(String, int)}. When determining if a package is signed by a
      * desired certificate, the returned array should be checked to determine if it is one of the
      * entries.
      *
diff --git a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
index 8b86a16..a65b681 100644
--- a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
@@ -379,6 +379,30 @@
     }
 
     /**
+     * Computes the maxSdkVersion. If the package is not compatible with this platform, populates
+     * {@code outError[0]} with an error message.
+     * <p>
+     * {@code maxVers} is compared against {@code platformSdkVersion}. If {@code maxVers} is less
+     * than the {@code platformSdkVersion} then populates {@code outError[0]} with an error message.
+     * Otherwise, it returns {@code maxVers} unmodified.
+     *
+     * @param maxVers maxSdkVersion number, if specified in the application manifest, or {@code
+     *                Integer.MAX_VALUE} otherwise
+     * @param platformSdkVersion   platform SDK version number, typically Build.VERSION.SDK_INT
+     * @return the maxSdkVersion that was recognised or an error if the condition is not satisfied
+     */
+    public static ParseResult<Integer> computeMaxSdkVersion(@IntRange(from = 0) int maxVers,
+            @IntRange(from = 1) int platformSdkVersion, @NonNull ParseInput input) {
+        if (platformSdkVersion > maxVers) {
+            return input.error(PackageManager.INSTALL_FAILED_NEWER_SDK,
+                    "Requires max SDK version " + maxVers + " but is "
+                            + platformSdkVersion);
+        } else {
+            return input.success(maxVers);
+        }
+    }
+
+    /**
      * Matches a given {@code targetCode} against a set of release codeNames. Target codes can
      * either be of the form {@code [codename]}" (e.g {@code "Q"}) or of the form {@code
      * [codename].[fingerprint]} (e.g {@code "Q.cafebc561"}).
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index a05f5c9..c8bbb0c1 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -79,6 +79,13 @@
     @GuardedBy("sSync") private static ArraySet<ApkAssets> sSystemApkAssetsSet;
 
     /**
+     * Cookie value to use when the actual cookie is unknown. This value tells the system to search
+     * all the ApkAssets for the asset.
+     * @hide
+     */
+    public static final int COOKIE_UNKNOWN = -1;
+
+    /**
      * Mode for {@link #open(String, int)}: no specific information about how
      * data will be accessed.
      */
diff --git a/core/java/android/hardware/CameraStreamStats.java b/core/java/android/hardware/CameraStreamStats.java
index 7b24cc4..3952467 100644
--- a/core/java/android/hardware/CameraStreamStats.java
+++ b/core/java/android/hardware/CameraStreamStats.java
@@ -49,7 +49,7 @@
     private float[] mHistogramBins;
     private long[] mHistogramCounts;
     private long mDynamicRangeProfile;
-    private int mStreamUseCase;
+    private long mStreamUseCase;
 
     private static final String TAG = "CameraStreamStats";
 
@@ -73,7 +73,7 @@
     public CameraStreamStats(int width, int height, int format, float maxPreviewFps,
             int dataSpace, long usage, long requestCount, long errorCount,
             int startLatencyMs, int maxHalBuffers, int maxAppBuffers, long dynamicRangeProfile,
-            int streamUseCase) {
+            long streamUseCase) {
         mWidth = width;
         mHeight = height;
         mFormat = format;
@@ -135,7 +135,7 @@
         dest.writeFloatArray(mHistogramBins);
         dest.writeLongArray(mHistogramCounts);
         dest.writeLong(mDynamicRangeProfile);
-        dest.writeInt(mStreamUseCase);
+        dest.writeLong(mStreamUseCase);
     }
 
     public void readFromParcel(Parcel in) {
@@ -154,7 +154,7 @@
         mHistogramBins = in.createFloatArray();
         mHistogramCounts = in.createLongArray();
         mDynamicRangeProfile = in.readLong();
-        mStreamUseCase = in.readInt();
+        mStreamUseCase = in.readLong();
     }
 
     public int getWidth() {
@@ -217,7 +217,7 @@
         return mDynamicRangeProfile;
     }
 
-    public int getStreamUseCase() {
+    public long getStreamUseCase() {
         return mStreamUseCase;
     }
 }
diff --git a/core/java/android/hardware/SyncFence.java b/core/java/android/hardware/SyncFence.java
index cd4bf78..1660013 100644
--- a/core/java/android/hardware/SyncFence.java
+++ b/core/java/android/hardware/SyncFence.java
@@ -24,6 +24,7 @@
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
+import android.os.SystemClock;
 
 import libcore.util.NativeAllocationRegistry;
 
@@ -105,6 +106,21 @@
         }
     }
 
+    /**
+     * Creates a SyncFence from a libui Fence*
+     * DOES NOT TAKE AN ADDITIONAL REFERENCE, the caller must incref if it intends to retain
+     * ownership (eg, when using sp<Fence>)
+     * @hide
+     */
+    public SyncFence(long nativeFencePtr) {
+        mNativePtr = nativeFencePtr;
+        if (nativeFencePtr != 0) {
+            mCloser = sRegistry.registerNativeAllocation(this, mNativePtr);
+        } else {
+            mCloser = () -> {};
+        }
+    }
+
     private SyncFence() {
         mCloser = () -> {};
     }
@@ -194,7 +210,9 @@
     }
 
     /**
-     * Returns the time that the fence signaled in the CLOCK_MONOTONIC time domain.
+     * Returns the time in nanoseconds that the fence signaled in the CLOCK_MONOTONIC time domain.
+     * This corresponds to {@link System#nanoTime()} but may also be compared to
+     * {@link SystemClock#uptimeMillis()} after adjusting for milliseconds vs. nanoseconds.
      *
      * If the fence isn't valid, that is if {@link #isValid()} is false, then this returns
      * {@link #SIGNAL_TIME_INVALID}. Similarly, if an error occurs while trying to access the
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 7bebe1f..b05e6d1 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -3563,8 +3563,8 @@
      */
     @PublicKey
     @NonNull
-    public static final Key<int[]> SCALER_AVAILABLE_STREAM_USE_CASES =
-            new Key<int[]>("android.scaler.availableStreamUseCases", int[].class);
+    public static final Key<long[]> SCALER_AVAILABLE_STREAM_USE_CASES =
+            new Key<long[]>("android.scaler.availableStreamUseCases", long[].class);
 
     /**
      * <p>An array of mandatory stream combinations with stream use cases.
diff --git a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
index 465abfb..a3bc665 100644
--- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
+++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
@@ -66,7 +66,7 @@
         private final boolean mIsUltraHighResolution;
         private final boolean mIsMaximumSize;
         private final boolean mIs10BitCapable;
-        private final int mStreamUseCase;
+        private final long mStreamUseCase;
 
         /**
          * Create a new {@link MandatoryStreamInformation}.
@@ -168,7 +168,7 @@
          */
         public MandatoryStreamInformation(@NonNull List<Size> availableSizes, @Format int format,
                 boolean isMaximumSize, boolean isInput, boolean isUltraHighResolution,
-                boolean is10BitCapable, @StreamUseCase int streamUseCase) {
+                boolean is10BitCapable, @StreamUseCase long streamUseCase) {
             if (availableSizes.isEmpty()) {
                 throw new IllegalArgumentException("No available sizes");
             }
@@ -308,9 +308,9 @@
          * For {@link MandatoryStreamInformation} belonging to other mandatory stream
          * combinations, the return value will be DEFAULT. </p>
          *
-         * @return the integer stream use case.
+         * @return the long integer stream use case.
          */
-        public @StreamUseCase int getStreamUseCase() {
+        public @StreamUseCase long getStreamUseCase() {
             return mStreamUseCase;
         }
 
@@ -365,15 +365,15 @@
     /**
      * Short hand for stream use cases
      */
-    private static final int STREAM_USE_CASE_PREVIEW =
+    private static final long STREAM_USE_CASE_PREVIEW =
             CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW;
-    private static final int STREAM_USE_CASE_STILL_CAPTURE =
+    private static final long STREAM_USE_CASE_STILL_CAPTURE =
             CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE;
-    private static final int STREAM_USE_CASE_RECORD =
+    private static final long STREAM_USE_CASE_RECORD =
             CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD;
-    private static final int STREAM_USE_CASE_PREVIEW_VIDEO_STILL =
+    private static final long STREAM_USE_CASE_PREVIEW_VIDEO_STILL =
             CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL;
-    private static final int STREAM_USE_CASE_VIDEO_CALL =
+    private static final long STREAM_USE_CASE_VIDEO_CALL =
             CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL;
 
     /**
@@ -471,12 +471,12 @@
     private static final class StreamTemplate {
         public int mFormat;
         public SizeThreshold mSizeThreshold;
-        public int mStreamUseCase;
+        public long mStreamUseCase;
         public StreamTemplate(int format, SizeThreshold sizeThreshold) {
             this(format, sizeThreshold, CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT);
         }
         public StreamTemplate(@Format int format, @NonNull SizeThreshold sizeThreshold,
-                @StreamUseCase int streamUseCase) {
+                @StreamUseCase long streamUseCase) {
             mFormat = format;
             mSizeThreshold = sizeThreshold;
             mStreamUseCase = streamUseCase;
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 2350b7c..39cb7f3 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -918,9 +918,9 @@
      * @throws IllegalArgumentException If the streamUseCase isn't within the range of valid
      *                                  values.
      */
-    public void setStreamUseCase(@StreamUseCase int streamUseCase) {
+    public void setStreamUseCase(@StreamUseCase long streamUseCase) {
         // Verify that the value is in range
-        int maxUseCaseValue = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL;
+        long maxUseCaseValue = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL;
         if (streamUseCase > maxUseCaseValue &&
                 streamUseCase < CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START) {
             throw new IllegalArgumentException("Not a valid stream use case value " +
@@ -938,7 +938,7 @@
      *
      * @return the currently set stream use case
      */
-    public int getStreamUseCase() {
+    public long getStreamUseCase() {
         return mStreamUseCase;
     }
 
@@ -1067,7 +1067,7 @@
         String physicalCameraId = source.readString();
         boolean isMultiResolutionOutput = source.readInt() == 1;
         int[] sensorPixelModesUsed = source.createIntArray();
-        int streamUseCase = source.readInt();
+        long streamUseCase = source.readLong();
 
         checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
         long dynamicRangeProfile = source.readLong();
@@ -1218,7 +1218,7 @@
         // writeList doesn't seem to work well with Integer list.
         dest.writeIntArray(convertIntegerToIntList(mSensorPixelModesUsed));
         dest.writeLong(mDynamicRangeProfile);
-        dest.writeInt(mStreamUseCase);
+        dest.writeLong(mStreamUseCase);
         dest.writeInt(mTimestampBase);
         dest.writeInt(mMirrorMode);
     }
@@ -1337,7 +1337,7 @@
     // Dynamic range profile
     private long mDynamicRangeProfile;
     // Stream use case
-    private int mStreamUseCase;
+    private long mStreamUseCase;
     // Timestamp base
     private int mTimestampBase;
     // Mirroring mode
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index d9734b4..5981d27 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -781,10 +781,11 @@
      * <li>The fpsMin and fpsMax will be a multiple 30fps.</li>
      * <li>The fpsMin will be no less than 30fps, the fpsMax will be no less than 120fps.</li>
      * <li>At least one range will be a fixed FPS range where fpsMin == fpsMax.</li>
-     * <li>For each fixed FPS range, there will be one corresponding variable FPS range [30,
-     * fps_max]. These kinds of FPS ranges are suitable for preview-only use cases where the
-     * application doesn't want the camera device always produce higher frame rate than the display
-     * refresh rate.</li>
+     * <li>For each fixed FPS range, there will be one corresponding variable FPS range
+     * [30, fps_max] or [60, fps_max]. These kinds of FPS ranges are suitable for preview-only
+     * use cases where the application doesn't want the camera device always produce higher frame
+     * rate than the display refresh rate. Both 30fps and 60fps preview rate will not be
+     * supported for the same recording rate.</li>
      * </p>
      *
      * @return an array of supported high speed video recording FPS ranges The upper bound of
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 7e070bc..29221b8 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -923,14 +923,15 @@
      * @hide
      */
     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
-    public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
+    public void onPointerDown(long requestId, int sensorId, int x, int y,
+            float minor, float major) {
         if (mService == null) {
             Slog.w(TAG, "onFingerDown: no fingerprint service");
             return;
         }
 
         try {
-            mService.onPointerDown(sensorId, x, y, minor, major);
+            mService.onPointerDown(requestId, sensorId, x, y, minor, major);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -940,14 +941,14 @@
      * @hide
      */
     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
-    public void onPointerUp(int sensorId) {
+    public void onPointerUp(long requestId, int sensorId) {
         if (mService == null) {
             Slog.w(TAG, "onFingerDown: no fingerprint service");
             return;
         }
 
         try {
-            mService.onPointerUp(sensorId);
+            mService.onPointerUp(requestId, sensorId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -957,14 +958,14 @@
      * @hide
      */
     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
-    public void onUiReady(int sensorId) {
+    public void onUiReady(long requestId, int sensorId) {
         if (mService == null) {
             Slog.w(TAG, "onUiReady: no fingerprint service");
             return;
         }
 
         try {
-            mService.onUiReady(sensorId);
+            mService.onUiReady(requestId, sensorId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index cbff8b1..12114aa 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -155,13 +155,13 @@
     void addAuthenticatorsRegisteredCallback(IFingerprintAuthenticatorsRegisteredCallback callback);
 
     // Notifies about a finger touching the sensor area.
-    void onPointerDown(int sensorId, int x, int y, float minor, float major);
+    void onPointerDown(long requestId, int sensorId, int x, int y, float minor, float major);
 
     // Notifies about a finger leaving the sensor area.
-    void onPointerUp(int sensorId);
+    void onPointerUp(long requestId, int sensorId);
 
     // Notifies about the fingerprint UI being ready (e.g. HBM illumination is enabled).
-    void onUiReady(int sensorId);
+    void onUiReady(long requestId, int sensorId);
 
     // Sets the controller for managing the UDFPS overlay.
     void setUdfpsOverlayController(in IUdfpsOverlayController controller);
diff --git a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl
index 3cca1b3..dbb8e40 100644
--- a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl
+++ b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl
@@ -23,7 +23,7 @@
  */
 oneway interface IUdfpsOverlayController {
     // Shows the overlay  for the given sensor with a reason from BiometricOverlayConstants.
-    void showUdfpsOverlay(int sensorId, int reason, IUdfpsOverlayControllerCallback callback);
+    void showUdfpsOverlay(long requestId, int sensorId, int reason, IUdfpsOverlayControllerCallback callback);
 
     // Hides the overlay.
     void hideUdfpsOverlay(int sensorId);
diff --git a/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java b/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java
index df13ade..bd25b8f 100644
--- a/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java
+++ b/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java
@@ -16,9 +16,9 @@
 
 package android.hardware.location;
 
+import android.os.BadParcelableException;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.Log;
 
 /**
  * Geofence Hardware Request used for internal location services communication.
@@ -139,11 +139,8 @@
         @Override
         public GeofenceHardwareRequestParcelable createFromParcel(Parcel parcel) {
             int geofenceType = parcel.readInt();
-            if(geofenceType != GeofenceHardwareRequest.GEOFENCE_TYPE_CIRCLE) {
-                Log.e(
-                        "GeofenceHardwareRequest",
-                        String.format("Invalid Geofence type: %d", geofenceType));
-                return null;
+            if (geofenceType != GeofenceHardwareRequest.GEOFENCE_TYPE_CIRCLE) {
+                throw new BadParcelableException("Invalid Geofence type: " + geofenceType);
             }
 
             GeofenceHardwareRequest request = GeofenceHardwareRequest.createCircularGeofence(
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index c363909..a9d665c8 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -29,6 +29,7 @@
 import static java.util.Objects.requireNonNull;
 
 import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -1630,7 +1631,8 @@
          * @hide
          */
         @UnsupportedAppUsage
-        public KeyphraseRecognitionExtra(int id, int recognitionModes, int coarseConfidenceLevel,
+        public KeyphraseRecognitionExtra(int id, int recognitionModes,
+                @IntRange(from = 0, to = 100) int coarseConfidenceLevel,
                 @Nullable ConfidenceLevel[] confidenceLevels) {
             this.id = id;
             this.recognitionModes = recognitionModes;
@@ -1660,6 +1662,7 @@
          *
          * <p>The confidence level is expressed in percent (0% -100%).
          */
+        @IntRange(from = 0, to = 100)
         public int getCoarseConfidenceLevel() {
             return coarseConfidenceLevel;
         }
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 02302a2..f9ed0e3d 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -81,6 +81,7 @@
     private static final int DO_CAN_START_STYLUS_HANDWRITING = 100;
     private static final int DO_START_STYLUS_HANDWRITING = 110;
     private static final int DO_INIT_INK_WINDOW = 120;
+    private static final int DO_FINISH_STYLUS_HANDWRITING = 130;
 
     final WeakReference<InputMethodServiceInternal> mTarget;
     final Context mContext;
@@ -263,6 +264,10 @@
                 inputMethod.initInkWindow();
                 return;
             }
+            case DO_FINISH_STYLUS_HANDWRITING: {
+                inputMethod.finishStylusHandwriting();
+                return;
+            }
 
         }
         Log.w(TAG, "Unhandled message code: " + msg.what);
@@ -427,4 +432,10 @@
     public void initInkWindow() {
         mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_INIT_INK_WINDOW));
     }
+
+    @BinderThread
+    @Override
+    public void finishStylusHandwriting() {
+        mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_FINISH_STYLUS_HANDWRITING));
+    }
 }
diff --git a/core/java/android/inputmethodservice/ImsConfigurationTracker.java b/core/java/android/inputmethodservice/ImsConfigurationTracker.java
index 3c78888..30ef0a2 100644
--- a/core/java/android/inputmethodservice/ImsConfigurationTracker.java
+++ b/core/java/android/inputmethodservice/ImsConfigurationTracker.java
@@ -63,8 +63,9 @@
      */
     @MainThread
     public void onBindInput(@Nullable Resources resources) {
-        Preconditions.checkState(mInitialized,
-                "onBindInput can be called only after onInitialize().");
+        if (!mInitialized) {
+            return;
+        }
         if (mLastKnownConfig == null && resources != null) {
             mLastKnownConfig = new Configuration(resources.getConfiguration());
         }
diff --git a/core/java/android/inputmethodservice/InkWindow.java b/core/java/android/inputmethodservice/InkWindow.java
index 499634a..8289c26 100644
--- a/core/java/android/inputmethodservice/InkWindow.java
+++ b/core/java/android/inputmethodservice/InkWindow.java
@@ -27,6 +27,8 @@
 import android.os.IBinder;
 import android.util.Slog;
 import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
 import android.view.WindowManager;
 
 import com.android.internal.policy.PhoneWindow;
@@ -40,6 +42,9 @@
 
     private final WindowManager mWindowManager;
     private boolean mIsViewAdded;
+    private View mInkView;
+    private InkVisibilityListener mInkViewVisibilityListener;
+    private ViewTreeObserver.OnGlobalLayoutListener mGlobalLayoutListener;
 
     public InkWindow(@NonNull Context context) {
         super(context);
@@ -102,4 +107,77 @@
         lp.token = token;
         setAttributes(lp);
     }
+
+    @Override
+    public void addContentView(View view, ViewGroup.LayoutParams params) {
+        if (mInkView == null) {
+            mInkView = view;
+        } else if (mInkView != view) {
+            throw new IllegalStateException("Only one Child Inking view is permitted.");
+        }
+        super.addContentView(view, params);
+        initInkViewVisibilityListener();
+    }
+
+    @Override
+    public void setContentView(View view, ViewGroup.LayoutParams params) {
+        mInkView = view;
+        super.setContentView(view, params);
+        initInkViewVisibilityListener();
+    }
+
+    @Override
+    public void setContentView(View view) {
+        mInkView = view;
+        super.setContentView(view);
+        initInkViewVisibilityListener();
+    }
+
+    @Override
+    public void clearContentView() {
+        if (mGlobalLayoutListener != null && mInkView != null) {
+            mInkView.getViewTreeObserver().removeOnGlobalLayoutListener(mGlobalLayoutListener);
+        }
+        mGlobalLayoutListener = null;
+        mInkView = null;
+        super.clearContentView();
+    }
+
+    /**
+    * Listener used by InkWindow to time the dispatching of {@link MotionEvent}s to Ink view, once
+    * it is visible to user.
+    */
+    interface InkVisibilityListener {
+        void onInkViewVisible();
+    }
+
+    void setInkViewVisibilityListener(InkVisibilityListener listener) {
+        mInkViewVisibilityListener = listener;
+        initInkViewVisibilityListener();
+    }
+
+    void initInkViewVisibilityListener() {
+        if (mInkView == null || mInkViewVisibilityListener == null
+                || mGlobalLayoutListener != null) {
+            return;
+        }
+        mGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
+            @Override
+            public void onGlobalLayout() {
+                if (mInkView.isVisibleToUser()) {
+                    if (mInkViewVisibilityListener != null) {
+                        mInkViewVisibilityListener.onInkViewVisible();
+                    }
+                    mInkView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+                    mGlobalLayoutListener = null;
+                }
+            }
+        };
+        mInkView.getViewTreeObserver().addOnGlobalLayoutListener(mGlobalLayoutListener);
+    }
+
+    boolean isInkViewVisible() {
+        return getDecorView().getVisibility() == View.VISIBLE
+                && mInkView != null && mInkView.isVisibleToUser();
+    }
 }
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 656aea1..4fdd534 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -143,6 +143,7 @@
 import com.android.internal.inputmethod.InputMethodNavButtonFlags;
 import com.android.internal.inputmethod.InputMethodPrivilegedOperations;
 import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry;
+import com.android.internal.util.RingBuffer;
 import com.android.internal.view.IInlineSuggestionsRequestCallback;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.InlineSuggestionsRequestInfo;
@@ -334,6 +335,17 @@
             "persist.sys.ime.can_render_gestural_nav_buttons";
 
     /**
+     * Number of {@link MotionEvent} to buffer if IME is not ready with Ink view.
+     * This number may be configured eventually based on device's touch sampling frequency.
+     */
+    private static final int MAX_EVENTS_BUFFER = 500;
+
+    /**
+     * A circular buffer of size MAX_EVENTS_BUFFER in case IME is taking too long to add ink view.
+     **/
+    private RingBuffer<MotionEvent> mPendingEvents;
+
+    /**
      * Returns whether {@link InputMethodService} is responsible for rendering the back button and
      * the IME switcher button or not when the gestural navigation is enabled.
      *
@@ -954,7 +966,8 @@
             mInkWindow.show();
 
             // deliver previous @param stylusEvents
-            stylusEvents.forEach(mInkWindow.getDecorView()::dispatchTouchEvent);
+            stylusEvents.forEach(InputMethodService.this::onStylusHandwritingMotionEvent);
+
             // create receiver for channel
             mHandwritingEventReceiver = new SimpleBatchedInputEventReceiver(
                     channel,
@@ -963,11 +976,11 @@
                         if (!(event instanceof MotionEvent)) {
                             return false;
                         }
-                        return mInkWindow.getDecorView().dispatchTouchEvent((MotionEvent) event);
+                        onStylusHandwritingMotionEvent((MotionEvent) event);
+                        return true;
                     });
         }
 
-
         /**
          * {@inheritDoc}
          * @hide
@@ -981,6 +994,15 @@
 
         /**
          * {@inheritDoc}
+         * @hide
+         */
+        @Override
+        public void finishStylusHandwriting() {
+            InputMethodService.this.finishStylusHandwriting();
+        }
+
+        /**
+         * {@inheritDoc}
          */
         @MainThread
         @Override
@@ -2357,7 +2379,8 @@
      *
      * If the IME supports handwriting for the current input, it should return {@code true},
      * ensure its inking views are attached to the {@link #getStylusHandwritingWindow()}, and handle
-     * stylus input received on the ink window via {@link #getCurrentInputConnection()}.
+     * stylus input received from {@link #onStylusHandwritingMotionEvent(MotionEvent)} on the
+     * {@link #getStylusHandwritingWindow()} via {@link #getCurrentInputConnection()}.
      * @return {@code true} if IME can honor the request, {@code false} if IME cannot at this time.
      */
     public boolean onStartStylusHandwriting() {
@@ -2366,6 +2389,33 @@
     }
 
     /**
+     * Called after {@link #onStartStylusHandwriting()} returns {@code true} for every Stylus
+     * {@link MotionEvent}.
+     * By default, this method forwards all {@link MotionEvent}s to the
+     * {@link #getStylusHandwritingWindow()} once its visible, however IME can override it to
+     * receive them sooner.
+     * @param motionEvent {@link MotionEvent} from stylus.
+     */
+    public void onStylusHandwritingMotionEvent(@NonNull MotionEvent motionEvent) {
+        if (mInkWindow.isInkViewVisible()) {
+            mInkWindow.getDecorView().dispatchTouchEvent(motionEvent);
+        } else {
+            if (mPendingEvents == null) {
+                mPendingEvents = new RingBuffer(MotionEvent.class, MAX_EVENTS_BUFFER);
+            }
+            mPendingEvents.append(motionEvent);
+            mInkWindow.setInkViewVisibilityListener(() -> {
+                if (mPendingEvents != null && !mPendingEvents.isEmpty()) {
+                    for (MotionEvent event : mPendingEvents.toArray()) {
+                        mInkWindow.getDecorView().dispatchTouchEvent(event);
+                    }
+                    mPendingEvents.clear();
+                }
+            });
+        }
+    }
+
+    /**
      * Called when the current stylus handwriting session was finished (either by the system or
      * via {@link #finishStylusHandwriting()}.
      *
@@ -2420,7 +2470,7 @@
         mHandwritingEventReceiver = null;
         mInkWindow.hide(false /* remove */);
 
-        mPrivOps.finishStylusHandwriting(requestId);
+        mPrivOps.resetStylusHandwriting(requestId);
         mOnPreparedStylusHwCalled = false;
         onFinishStylusHandwriting();
     }
diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java
index 0f9075b..03d1151 100644
--- a/core/java/android/inputmethodservice/NavigationBarController.java
+++ b/core/java/android/inputmethodservice/NavigationBarController.java
@@ -294,8 +294,8 @@
                 dest.setTouchableInsets(
                         ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
 
-                // TODO(b/205803355): See if we can use View#OnLayoutChangeListener().
-                // TODO(b/205803355): See if we can replace DecorView#mNavigationColorViewState.view
+                // TODO(b/215443343): See if we can use View#OnLayoutChangeListener().
+                // TODO(b/215443343): See if we can replace DecorView#mNavigationColorViewState.view
                 boolean zOrderChanged = false;
                 if (decor instanceof ViewGroup) {
                     ViewGroup decorGroup = (ViewGroup) decor;
diff --git a/core/java/android/inputmethodservice/navigationbar/ButtonDispatcher.java b/core/java/android/inputmethodservice/navigationbar/ButtonDispatcher.java
index 3f26fa4..6b2db7d 100644
--- a/core/java/android/inputmethodservice/navigationbar/ButtonDispatcher.java
+++ b/core/java/android/inputmethodservice/navigationbar/ButtonDispatcher.java
@@ -67,7 +67,7 @@
         }
     };
 
-    public ButtonDispatcher(int id) {
+    ButtonDispatcher(int id) {
         mId = id;
     }
 
@@ -125,8 +125,8 @@
 
     public void setImageDrawable(KeyButtonDrawable drawable) {
         mImageDrawable = drawable;
-        final int N = mViews.size();
-        for (int i = 0; i < N; i++) {
+        final int numViews = mViews.size();
+        for (int i = 0; i < numViews; i++) {
             if (mViews.get(i) instanceof ButtonInterface) {
                 ((ButtonInterface) mViews.get(i)).setImageDrawable(mImageDrawable);
             }
@@ -143,8 +143,8 @@
         }
 
         mVisibility = visibility;
-        final int N = mViews.size();
-        for (int i = 0; i < N; i++) {
+        final int numViews = mViews.size();
+        for (int i = 0; i < numViews; i++) {
             mViews.get(i).setVisibility(mVisibility);
         }
     }
@@ -188,8 +188,8 @@
             int nextAlpha = (int) (alpha * 255);
             if (prevAlpha != nextAlpha) {
                 mAlpha = nextAlpha / 255f;
-                final int N = mViews.size();
-                for (int i = 0; i < N; i++) {
+                final int numViews = mViews.size();
+                for (int i = 0; i < numViews; i++) {
                     mViews.get(i).setAlpha(mAlpha);
                 }
             }
@@ -198,8 +198,8 @@
 
     public void setDarkIntensity(float darkIntensity) {
         mDarkIntensity = darkIntensity;
-        final int N = mViews.size();
-        for (int i = 0; i < N; i++) {
+        final int numViews = mViews.size();
+        for (int i = 0; i < numViews; i++) {
             if (mViews.get(i) instanceof ButtonInterface) {
                 ((ButtonInterface) mViews.get(i)).setDarkIntensity(darkIntensity);
             }
@@ -208,8 +208,8 @@
 
     public void setDelayTouchFeedback(boolean delay) {
         mDelayTouchFeedback = delay;
-        final int N = mViews.size();
-        for (int i = 0; i < N; i++) {
+        final int numViews = mViews.size();
+        for (int i = 0; i < numViews; i++) {
             if (mViews.get(i) instanceof ButtonInterface) {
                 ((ButtonInterface) mViews.get(i)).setDelayTouchFeedback(delay);
             }
@@ -218,55 +218,55 @@
 
     public void setOnClickListener(View.OnClickListener clickListener) {
         mClickListener = clickListener;
-        final int N = mViews.size();
-        for (int i = 0; i < N; i++) {
+        final int numViews = mViews.size();
+        for (int i = 0; i < numViews; i++) {
             mViews.get(i).setOnClickListener(mClickListener);
         }
     }
 
     public void setOnTouchListener(View.OnTouchListener touchListener) {
         mTouchListener = touchListener;
-        final int N = mViews.size();
-        for (int i = 0; i < N; i++) {
+        final int numViews = mViews.size();
+        for (int i = 0; i < numViews; i++) {
             mViews.get(i).setOnTouchListener(mTouchListener);
         }
     }
 
     public void setLongClickable(boolean isLongClickable) {
         mLongClickable = isLongClickable;
-        final int N = mViews.size();
-        for (int i = 0; i < N; i++) {
+        final int numViews = mViews.size();
+        for (int i = 0; i < numViews; i++) {
             mViews.get(i).setLongClickable(mLongClickable);
         }
     }
 
     public void setOnLongClickListener(View.OnLongClickListener longClickListener) {
         mLongClickListener = longClickListener;
-        final int N = mViews.size();
-        for (int i = 0; i < N; i++) {
+        final int numViews = mViews.size();
+        for (int i = 0; i < numViews; i++) {
             mViews.get(i).setOnLongClickListener(mLongClickListener);
         }
     }
 
     public void setOnHoverListener(View.OnHoverListener hoverListener) {
         mOnHoverListener = hoverListener;
-        final int N = mViews.size();
-        for (int i = 0; i < N; i++) {
+        final int numViews = mViews.size();
+        for (int i = 0; i < numViews; i++) {
             mViews.get(i).setOnHoverListener(mOnHoverListener);
         }
     }
 
     public void setAccessibilityDelegate(AccessibilityDelegate delegate) {
         mAccessibilityDelegate = delegate;
-        final int N = mViews.size();
-        for (int i = 0; i < N; i++) {
+        final int numViews = mViews.size();
+        for (int i = 0; i < numViews; i++) {
             mViews.get(i).setAccessibilityDelegate(delegate);
         }
     }
 
     public void setTranslation(int x, int y, int z) {
-        final int N = mViews.size();
-        for (int i = 0; i < N; i++) {
+        final int numViews = mViews.size();
+        for (int i = 0; i < numViews; i++) {
             final View view = mViews.get(i);
             view.setTranslationX(x);
             view.setTranslationY(y);
diff --git a/core/java/android/inputmethodservice/navigationbar/DeadZone.java b/core/java/android/inputmethodservice/navigationbar/DeadZone.java
index 4adc84b..382b6b0 100644
--- a/core/java/android/inputmethodservice/navigationbar/DeadZone.java
+++ b/core/java/android/inputmethodservice/navigationbar/DeadZone.java
@@ -82,7 +82,7 @@
         }
     };
 
-    public DeadZone(NavigationBarView view) {
+    DeadZone(NavigationBarView view) {
         mNavigationBarView = view;
         onConfigurationChanged(Surface.ROTATION_0);
     }
@@ -92,13 +92,15 @@
     }
 
     private float getSize(long now) {
-        if (mSizeMax == 0)
+        if (mSizeMax == 0) {
             return 0;
+        }
         long dt = (now - mLastPokeTime);
-        if (dt > mHold + mDecay)
+        if (dt > mHold + mDecay) {
             return mSizeMin;
-        if (dt < mHold)
+        } else if (dt < mHold) {
             return mSizeMax;
+        }
         return (int) lerp(mSizeMax, mSizeMin, (float) (dt - mHold) / mDecay);
     }
 
@@ -146,7 +148,7 @@
             if (DEBUG) {
                 Log.v(TAG, this + " ACTION_DOWN: " + event.getX() + "," + event.getY());
             }
-            //TODO(b/205803355): call mNavBarController.touchAutoDim(mDisplayId); here
+            //TODO(b/215443343): call mNavBarController.touchAutoDim(mDisplayId); here
             int size = (int) getSize(event.getEventTime());
             // In the vertical orientation consume taps along the left edge.
             // In horizontal orientation consume taps along the top edge.
@@ -177,8 +179,9 @@
 
     private void poke(MotionEvent event) {
         mLastPokeTime = event.getEventTime();
-        if (DEBUG)
+        if (DEBUG) {
             Log.v(TAG, "poked! size=" + getSize(mLastPokeTime));
+        }
         if (mShouldFlash) mNavigationBarView.postInvalidate();
     }
 
diff --git a/core/java/android/inputmethodservice/navigationbar/KeyButtonDrawable.java b/core/java/android/inputmethodservice/navigationbar/KeyButtonDrawable.java
index 25a443d..45c8a18 100644
--- a/core/java/android/inputmethodservice/navigationbar/KeyButtonDrawable.java
+++ b/core/java/android/inputmethodservice/navigationbar/KeyButtonDrawable.java
@@ -54,30 +54,30 @@
 final class KeyButtonDrawable extends Drawable {
 
     public static final FloatProperty<KeyButtonDrawable> KEY_DRAWABLE_ROTATE =
-        new FloatProperty<KeyButtonDrawable>("KeyButtonRotation") {
-            @Override
-            public void setValue(KeyButtonDrawable drawable, float degree) {
-                drawable.setRotation(degree);
-            }
+            new FloatProperty<KeyButtonDrawable>("KeyButtonRotation") {
+                @Override
+                public void setValue(KeyButtonDrawable drawable, float degree) {
+                    drawable.setRotation(degree);
+                }
 
-            @Override
-            public Float get(KeyButtonDrawable drawable) {
-                return drawable.getRotation();
-            }
-        };
+                @Override
+                public Float get(KeyButtonDrawable drawable) {
+                    return drawable.getRotation();
+                }
+            };
 
     public static final FloatProperty<KeyButtonDrawable> KEY_DRAWABLE_TRANSLATE_Y =
-        new FloatProperty<KeyButtonDrawable>("KeyButtonTranslateY") {
-            @Override
-            public void setValue(KeyButtonDrawable drawable, float y) {
-                drawable.setTranslationY(y);
-            }
+            new FloatProperty<KeyButtonDrawable>("KeyButtonTranslateY") {
+                @Override
+                public void setValue(KeyButtonDrawable drawable, float y) {
+                    drawable.setTranslationY(y);
+                }
 
-            @Override
-            public Float get(KeyButtonDrawable drawable) {
-                return drawable.getTranslationY();
-            }
-        };
+                @Override
+                public Float get(KeyButtonDrawable drawable) {
+                    return drawable.getTranslationY();
+                }
+            };
 
     private final Paint mIconPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
     private final Paint mShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
@@ -100,7 +100,7 @@
         }
     };
 
-    public KeyButtonDrawable(Drawable d, @ColorInt int lightColor, @ColorInt int darkColor,
+    KeyButtonDrawable(Drawable d, @ColorInt int lightColor, @ColorInt int darkColor,
             boolean horizontalFlip, Color ovalBackgroundColor) {
         this(d, new ShadowDrawableState(lightColor, darkColor,
                 d instanceof AnimatedVectorDrawable, horizontalFlip, ovalBackgroundColor));
@@ -433,8 +433,8 @@
         final boolean mSupportsAnimation;
         final Color mOvalBackgroundColor;
 
-        public ShadowDrawableState(@ColorInt int lightColor, @ColorInt int darkColor,
-                boolean animated, boolean horizontalFlip, Color ovalBackgroundColor) {
+        ShadowDrawableState(@ColorInt int lightColor, @ColorInt int darkColor, boolean animated,
+                boolean horizontalFlip, Color ovalBackgroundColor) {
             mLightColor = lightColor;
             mDarkColor = darkColor;
             mSupportsAnimation = animated;
diff --git a/core/java/android/inputmethodservice/navigationbar/KeyButtonRipple.java b/core/java/android/inputmethodservice/navigationbar/KeyButtonRipple.java
index 38a63b6..cf77c898 100644
--- a/core/java/android/inputmethodservice/navigationbar/KeyButtonRipple.java
+++ b/core/java/android/inputmethodservice/navigationbar/KeyButtonRipple.java
@@ -90,7 +90,7 @@
 
     private Type mType = Type.ROUNDED_RECT;
 
-    public KeyButtonRipple(Context ctx, View targetView, @DimenRes int maxWidthResource) {
+    KeyButtonRipple(Context ctx, View targetView, @DimenRes int maxWidthResource) {
         mMaxWidthResource = maxWidthResource;
         mMaxWidth = ctx.getResources().getDimensionPixelSize(maxWidthResource);
         mTargetView = targetView;
@@ -126,7 +126,7 @@
     private void drawSoftware(Canvas canvas) {
         if (mGlowAlpha > 0f) {
             final Paint p = getRipplePaint();
-            p.setAlpha((int)(mGlowAlpha * 255f));
+            p.setAlpha((int) (mGlowAlpha * 255f));
 
             final float w = getBounds().width();
             final float h = getBounds().height();
@@ -412,7 +412,7 @@
         mDrawingHardwareGlow = true;
         setExtendStart(CanvasProperty.createFloat(getExtendSize() / 2));
         final RenderNodeAnimator startAnim = new RenderNodeAnimator(getExtendStart(),
-                getExtendSize()/2 - GLOW_MAX_SCALE_FACTOR * getRippleSize()/2);
+                getExtendSize() / 2 - GLOW_MAX_SCALE_FACTOR * getRippleSize() / 2);
         startAnim.setDuration(ANIMATION_DURATION_SCALE);
         startAnim.setInterpolator(mInterpolator);
         startAnim.addListener(mAnimatorListener);
@@ -420,7 +420,7 @@
 
         setExtendEnd(CanvasProperty.createFloat(getExtendSize() / 2));
         final RenderNodeAnimator endAnim = new RenderNodeAnimator(getExtendEnd(),
-                getExtendSize()/2 + GLOW_MAX_SCALE_FACTOR * getRippleSize()/2);
+                getExtendSize() / 2 + GLOW_MAX_SCALE_FACTOR * getRippleSize() / 2);
         endAnim.setDuration(ANIMATION_DURATION_SCALE);
         endAnim.setInterpolator(mInterpolator);
         endAnim.addListener(mAnimatorListener);
@@ -430,13 +430,13 @@
         if (isHorizontal()) {
             mTopProp = CanvasProperty.createFloat(0f);
             mBottomProp = CanvasProperty.createFloat(getBounds().height());
-            mRxProp = CanvasProperty.createFloat(getBounds().height()/2);
-            mRyProp = CanvasProperty.createFloat(getBounds().height()/2);
+            mRxProp = CanvasProperty.createFloat(getBounds().height() / 2);
+            mRyProp = CanvasProperty.createFloat(getBounds().height() / 2);
         } else {
             mLeftProp = CanvasProperty.createFloat(0f);
             mRightProp = CanvasProperty.createFloat(getBounds().width());
-            mRxProp = CanvasProperty.createFloat(getBounds().width()/2);
-            mRyProp = CanvasProperty.createFloat(getBounds().width()/2);
+            mRxProp = CanvasProperty.createFloat(getBounds().width() / 2);
+            mRyProp = CanvasProperty.createFloat(getBounds().width() / 2);
         }
 
         mGlowScale = GLOW_MAX_SCALE_FACTOR;
diff --git a/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java b/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java
index 74d30f8..92d358f 100644
--- a/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java
+++ b/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java
@@ -89,7 +89,7 @@
     public KeyButtonView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
-        // TODO(b/205803355): Figure out better place to set this.
+        // TODO(b/215443343): Figure out better place to set this.
         switch (getId()) {
             case com.android.internal.R.id.input_method_nav_back:
                 mCode = KEYCODE_BACK;
@@ -200,8 +200,8 @@
                 postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
                 break;
             case MotionEvent.ACTION_MOVE:
-                x = (int)ev.getRawX();
-                y = (int)ev.getRawY();
+                x = (int) ev.getRawX();
+                y = (int) ev.getRawY();
 
                 float slop = getQuickStepTouchSlopPx(getContext());
                 if (Math.abs(x - mTouchDownX) > slop || Math.abs(y - mTouchDownY) > slop) {
@@ -272,23 +272,24 @@
                 : KeyButtonRipple.Type.ROUNDED_RECT);
     }
 
+    @Override
     public void playSoundEffect(int soundConstant) {
         if (!mPlaySounds) return;
         mAudioManager.playSoundEffect(soundConstant);
     }
 
-    public void sendEvent(int action, int flags) {
+    private void sendEvent(int action, int flags) {
         sendEvent(action, flags, SystemClock.uptimeMillis());
     }
 
     private void sendEvent(int action, int flags, long when) {
         if (mCode == KeyEvent.KEYCODE_BACK && flags != KeyEvent.FLAG_LONG_PRESS) {
             if (action == MotionEvent.ACTION_UP) {
-                // TODO(b/205803355): Implement notifyBackAction();
+                // TODO(b/215443343): Implement notifyBackAction();
             }
         }
 
-        // TODO(b/205803355): Consolidate this logic to somewhere else.
+        // TODO(b/215443343): Consolidate this logic to somewhere else.
         if (mContext instanceof InputMethodService) {
             final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
             final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
@@ -309,8 +310,8 @@
             switch (action) {
                 case KeyEvent.ACTION_DOWN:
                     handled = ims.onKeyDown(ev.getKeyCode(), ev);
-                    mTracking = handled && ev.getRepeatCount() == 0 &&
-                            (ev.getFlags() & KeyEvent.FLAG_START_TRACKING) != 0;
+                    mTracking = handled && ev.getRepeatCount() == 0
+                            && (ev.getFlags() & KeyEvent.FLAG_START_TRACKING) != 0;
                     break;
                 case KeyEvent.ACTION_UP:
                     handled = ims.onKeyUp(ev.getKeyCode(), ev);
diff --git a/core/java/android/inputmethodservice/navigationbar/NavigationBarFrame.java b/core/java/android/inputmethodservice/navigationbar/NavigationBarFrame.java
index f01173e..a270675 100644
--- a/core/java/android/inputmethodservice/navigationbar/NavigationBarFrame.java
+++ b/core/java/android/inputmethodservice/navigationbar/NavigationBarFrame.java
@@ -59,4 +59,4 @@
         }
         return super.dispatchTouchEvent(event);
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/android/inputmethodservice/navigationbar/NavigationBarInflaterView.java b/core/java/android/inputmethodservice/navigationbar/NavigationBarInflaterView.java
index d488890..e93bda2 100644
--- a/core/java/android/inputmethodservice/navigationbar/NavigationBarInflaterView.java
+++ b/core/java/android/inputmethodservice/navigationbar/NavigationBarInflaterView.java
@@ -121,7 +121,7 @@
         return CONFIG_NAV_BAR_LAYOUT_HANDLE;
     }
 
-    public void setButtonDispatchers(SparseArray<ButtonDispatcher> buttonDispatchers) {
+    void setButtonDispatchers(SparseArray<ButtonDispatcher> buttonDispatchers) {
         mButtonDispatchers = buttonDispatchers;
         for (int i = 0; i < buttonDispatchers.size(); i++) {
             initiallyFill(buttonDispatchers.valueAt(i));
@@ -376,7 +376,7 @@
     }
     */
 
-    public static String extractSize(String buttonSpec) {
+    private static String extractSize(String buttonSpec) {
         if (!buttonSpec.contains(SIZE_MOD_START)) {
             return null;
         }
@@ -384,7 +384,7 @@
         return buttonSpec.substring(sizeStart + 1, buttonSpec.indexOf(SIZE_MOD_END));
     }
 
-    public static String extractButton(String buttonSpec) {
+    private static String extractButton(String buttonSpec) {
         if (!buttonSpec.contains(SIZE_MOD_START)) {
             return buttonSpec;
         }
@@ -398,9 +398,9 @@
                 mButtonDispatchers.valueAt(indexOfKey).addView(v);
             }
             if (v instanceof ViewGroup) {
-                final ViewGroup viewGroup = (ViewGroup)v;
-                final int N = viewGroup.getChildCount();
-                for (int i = 0; i < N; i++) {
+                final ViewGroup viewGroup = (ViewGroup) v;
+                final int numChildViews = viewGroup.getChildCount();
+                for (int i = 0; i < numChildViews; i++) {
                     addToDispatchers(viewGroup.getChildAt(i));
                 }
             }
diff --git a/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java b/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
index a2d7105..510b14e 100644
--- a/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
+++ b/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
@@ -48,8 +48,8 @@
  * @hide
  */
 public final class NavigationBarView extends FrameLayout {
-    final static boolean DEBUG = false;
-    final static String TAG = "NavBarView";
+    private static final boolean DEBUG = false;
+    private static final String TAG = "NavBarView";
 
     // Copied from com.android.systemui.animation.Interpolators#FAST_OUT_SLOW_IN
     private static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
@@ -139,7 +139,7 @@
     }
 
     /**
-     * Applies {@param consumer} to each of the nav bar views.
+     * Applies {@code consumer} to each of the nav bar views.
      */
     public void forEachView(Consumer<View> consumer) {
         if (mHorizontal != null) {
@@ -181,7 +181,7 @@
         }
     }
 
-    public KeyButtonDrawable getBackDrawable() {
+    private KeyButtonDrawable getBackDrawable() {
         KeyButtonDrawable drawable = getDrawable(com.android.internal.R.drawable.ic_ime_nav_back);
         orientBackButton(drawable);
         return drawable;
@@ -211,7 +211,7 @@
         // Animate the back button's rotation to the new degrees and only in portrait move up the
         // back button to line up with the other buttons
         float targetY = useAltBack
-                ? - dpToPx(NAVBAR_BACK_BUTTON_IME_OFFSET, getResources())
+                ? -dpToPx(NAVBAR_BACK_BUTTON_IME_OFFSET, getResources())
                 : 0;
         ObjectAnimator navBarAnimator = ObjectAnimator.ofPropertyValuesHolder(drawable,
                 PropertyValuesHolder.ofFloat(KeyButtonDrawable.KEY_DRAWABLE_ROTATE, degrees),
@@ -233,6 +233,11 @@
         super.setLayoutDirection(layoutDirection);
     }
 
+    /**
+     * Updates the navigation icons based on {@code hints}.
+     *
+     * @param hints bit flags defined in {@link StatusBarManager}.
+     */
     public void setNavigationIconHints(int hints) {
         if (hints == mNavigationIconHints) return;
         final boolean newBackAlt = (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
@@ -250,15 +255,7 @@
         updateNavButtonIcons();
     }
 
-    public void setDisabledFlags(int disabledFlags) {
-        if (mDisabledFlags == disabledFlags) return;
-
-        mDisabledFlags = disabledFlags;
-
-        updateNavButtonIcons();
-    }
-
-    public void updateNavButtonIcons() {
+    private void updateNavButtonIcons() {
         // We have to replace or restore the back and home button icons when exiting or entering
         // carmode, respectively. Recents are not available in CarMode in nav bar so change
         // to recent icon is not required.
@@ -319,7 +316,7 @@
         mHorizontal.setVisibility(View.GONE);
     }
 
-    public void reorient() {
+    private void reorient() {
         updateCurrentView();
 
         final android.inputmethodservice.navigationbar.NavigationBarFrame frame =
@@ -372,6 +369,11 @@
         }
     }
 
+    /**
+     * Updates the dark intensity.
+     *
+     * @param intensity The intensity of darkness from {@code 0.0f} to {@code 1.0f}.
+     */
     public void setDarkIntensity(@FloatRange(from = 0.0f, to = 1.0f) float intensity) {
         for (int i = 0; i < mButtonDispatchers.size(); ++i) {
             mButtonDispatchers.valueAt(i).setDarkIntensity(intensity);
diff --git a/core/java/android/inputmethodservice/navigationbar/ReverseLinearLayout.java b/core/java/android/inputmethodservice/navigationbar/ReverseLinearLayout.java
index 68163c3..9b36cc5 100644
--- a/core/java/android/inputmethodservice/navigationbar/ReverseLinearLayout.java
+++ b/core/java/android/inputmethodservice/navigationbar/ReverseLinearLayout.java
@@ -30,9 +30,8 @@
 /**
  * Automatically reverses the order of children as they are added.
  * Also reverse the width and height values of layout params
- * @hide
  */
-public class ReverseLinearLayout extends LinearLayout {
+class ReverseLinearLayout extends LinearLayout {
 
     /** If true, the layout is reversed vs. a regular linear layout */
     private boolean mIsLayoutReverse;
@@ -40,7 +39,7 @@
     /** If true, the layout is opposite to it's natural reversity from the layout direction */
     private boolean mIsAlternativeOrder;
 
-    public ReverseLinearLayout(Context context, @Nullable AttributeSet attrs) {
+    ReverseLinearLayout(Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
     }
 
@@ -129,7 +128,7 @@
 
     public static class ReverseRelativeLayout extends RelativeLayout implements Reversible {
 
-        public ReverseRelativeLayout(Context context) {
+        ReverseRelativeLayout(Context context) {
             super(context);
         }
 
diff --git a/core/java/android/net/IVpnManager.aidl b/core/java/android/net/IVpnManager.aidl
index 070efa3..b4647ca 100644
--- a/core/java/android/net/IVpnManager.aidl
+++ b/core/java/android/net/IVpnManager.aidl
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.net.Network;
+import android.net.VpnProfileState;
 
 import com.android.internal.net.LegacyVpnInfo;
 import com.android.internal.net.VpnConfig;
@@ -40,6 +41,7 @@
     void deleteVpnProfile(String packageName);
     String startVpnProfile(String packageName);
     void stopVpnProfile(String packageName);
+    VpnProfileState getProvisionedVpnProfileState(String packageName);
 
     /** Always-on VPN APIs */
     boolean isAlwaysOnVpnPackageSupported(int userId, String packageName);
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
index 0fd3e03..3abe83b 100644
--- a/core/java/android/net/Ikev2VpnProfile.java
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -142,6 +142,7 @@
     private final boolean mIsMetered; // Defaults in builder
     private final int mMaxMtu; // Defaults in builder
     private final boolean mIsRestrictedToTestNetworks;
+    @Nullable private final IkeTunnelConnectionParams mIkeTunConnParams;
 
     private Ikev2VpnProfile(
             int type,
@@ -160,7 +161,8 @@
             int maxMtu,
             boolean restrictToTestNetworks,
             boolean excludeLocalRoutes,
-            boolean requiresInternetValidation) {
+            boolean requiresInternetValidation,
+            @Nullable IkeTunnelConnectionParams ikeTunConnParams) {
         super(type, excludeLocalRoutes, requiresInternetValidation);
 
         checkNotNull(serverAddr, MISSING_PARAM_MSG_TMPL, "Server address");
@@ -190,6 +192,8 @@
         mMaxMtu = maxMtu;
         mIsRestrictedToTestNetworks = restrictToTestNetworks;
 
+        mIkeTunConnParams = ikeTunConnParams;
+
         validate();
     }
 
@@ -375,6 +379,12 @@
         return mMaxMtu;
     }
 
+    /** Retrieves the ikeTunnelConnectionParams contains IKEv2 configurations, if any was set. */
+    @Nullable
+    public IkeTunnelConnectionParams getIkeTunnelConnectionParams() {
+        return mIkeTunConnParams;
+    }
+
     /**
      * Returns whether or not this VPN profile is restricted to test networks.
      *
@@ -403,7 +413,8 @@
                 mMaxMtu,
                 mIsRestrictedToTestNetworks,
                 mExcludeLocalRoutes,
-                mRequiresInternetValidation);
+                mRequiresInternetValidation,
+                mIkeTunConnParams);
     }
 
     @Override
@@ -429,7 +440,8 @@
                 && mMaxMtu == other.mMaxMtu
                 && mIsRestrictedToTestNetworks == other.mIsRestrictedToTestNetworks
                 && mExcludeLocalRoutes == other.mExcludeLocalRoutes
-                && mRequiresInternetValidation == other.mRequiresInternetValidation;
+                && mRequiresInternetValidation == other.mRequiresInternetValidation
+                && Objects.equals(mIkeTunConnParams, other.mIkeTunConnParams);
     }
 
     /**
@@ -504,6 +516,7 @@
     @NonNull
     public static Ikev2VpnProfile fromVpnProfile(@NonNull VpnProfile profile)
             throws GeneralSecurityException {
+        // TODO: Build the VpnProfile from mIkeTunConnParams if it exists.
         final Builder builder = new Builder(profile.server, profile.ipsecIdentifier);
         builder.setProxy(profile.proxy);
         builder.setAllowedAlgorithms(profile.getAllowedAlgorithms());
@@ -788,7 +801,7 @@
         private int mMaxMtu = PlatformVpnProfile.MAX_MTU_DEFAULT;
         private boolean mIsRestrictedToTestNetworks = false;
         private boolean mExcludeLocalRoutes = false;
-        @Nullable private IkeTunnelConnectionParams mIkeTunConnParams;
+        @Nullable private final IkeTunnelConnectionParams mIkeTunConnParams;
 
         /**
          * Creates a new builder with the basic parameters of an IKEv2/IPsec VPN.
@@ -803,6 +816,8 @@
 
             mServerAddr = serverAddr;
             mUserIdentity = identity;
+
+            mIkeTunConnParams = null;
         }
 
         /**
@@ -1135,7 +1150,8 @@
                     mMaxMtu,
                     mIsRestrictedToTestNetworks,
                     mExcludeLocalRoutes,
-                    mRequiresInternetValidation);
+                    mRequiresInternetValidation,
+                    mIkeTunConnParams);
         }
     }
 }
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 18ec8f5..2c2a703 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -580,6 +580,24 @@
     }
 
     /**
+     * Notifies that the specified {@link NetworkStatsProvider} has reached its warning threshold
+     * which was set through {@link NetworkStatsProvider#onSetWarningAndLimit(String, long, long)}.
+     *
+     * @hide
+     */
+    @RequiresPermission(anyOf = {
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+            android.Manifest.permission.NETWORK_STACK})
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public void notifyStatsProviderWarningReached() {
+        try {
+            mService.notifyStatsProviderWarningOrLimitReached();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Notifies that the specified {@link NetworkStatsProvider} has reached its quota
      * which was set through {@link NetworkStatsProvider#onSetLimit(String, long)} or
      * {@link NetworkStatsProvider#onSetWarningAndLimit(String, long, long)}.
@@ -590,7 +608,7 @@
             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
             android.Manifest.permission.NETWORK_STACK})
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-    public void notifyStatsProviderWarningOrLimitReached() {
+    public void notifyStatsProviderLimitReached() {
         try {
             mService.notifyStatsProviderWarningOrLimitReached();
         } catch (RemoteException e) {
diff --git a/core/java/android/net/SntpClient.java b/core/java/android/net/SntpClient.java
index 0eb4cf3..b05f7cf 100644
--- a/core/java/android/net/SntpClient.java
+++ b/core/java/android/net/SntpClient.java
@@ -60,7 +60,7 @@
     private static final int TRANSMIT_TIME_OFFSET = 40;
     private static final int NTP_PACKET_SIZE = 48;
 
-    private static final int NTP_PORT = 123;
+    public static final int STANDARD_NTP_PORT = 123;
     private static final int NTP_MODE_CLIENT = 3;
     private static final int NTP_MODE_SERVER = 4;
     private static final int NTP_MODE_BROADCAST = 5;
@@ -108,18 +108,21 @@
      * Sends an SNTP request to the given host and processes the response.
      *
      * @param host host name of the server.
+     * @param port port of the server.
      * @param timeout network timeout in milliseconds. the timeout doesn't include the DNS lookup
      *                time, and it applies to each individual query to the resolved addresses of
      *                the NTP server.
      * @param network network over which to send the request.
      * @return true if the transaction was successful.
      */
-    public boolean requestTime(String host, int timeout, Network network) {
+    public boolean requestTime(String host, int port, int timeout, Network network) {
         final Network networkForResolv = network.getPrivateDnsBypassingCopy();
         try {
             final InetAddress[] addresses = networkForResolv.getAllByName(host);
             for (int i = 0; i < addresses.length; i++) {
-                if (requestTime(addresses[i], NTP_PORT, timeout, networkForResolv)) return true;
+                if (requestTime(addresses[i], port, timeout, networkForResolv)) {
+                    return true;
+                }
             }
         } catch (UnknownHostException e) {
             Log.w(TAG, "Unknown host: " + host);
diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java
index c51444c..ae7d91f 100644
--- a/core/java/android/net/VpnManager.java
+++ b/core/java/android/net/VpnManager.java
@@ -161,6 +161,23 @@
             "android.net.category.EVENT_DEACTIVATED_BY_USER";
 
     /**
+     * The always-on state of this VPN was changed
+     *
+     * <p>This may be the result of a user changing VPN settings, or a Device Policy Manager app
+     * having changed the VPN policy.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED =
+            "android.net.category.EVENT_ALWAYS_ON_STATE_CHANGED";
+
+    /**
+     * The VpnProfileState at the time that this event occurred.
+     *
+     * <p>This extra may be null if the VPN was revoked by the user, or the profile was deleted.
+     */
+    public static final String EXTRA_VPN_PROFILE_STATE = "android.net.extra.VPN_PROFILE_STATE";
+
+    /**
      * The key of the session that experienced this event, as a {@code String}.
      *
      * This is the same key that was returned by {@link #startProvisionedVpnProfileSession}.
@@ -403,6 +420,21 @@
     }
 
     /**
+     * Retrieve the VpnProfileState for the profile provisioned by the calling package.
+     *
+     * @return the VpnProfileState with current information, or null if there was no profile
+     *         provisioned by the calling package.
+     */
+    @Nullable
+    public VpnProfileState getProvisionedVpnProfileState() {
+        try {
+            return mService.getProvisionedVpnProfileState(mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Resets all VPN settings back to factory defaults.
      * @hide
      */
diff --git a/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.aidl b/core/java/android/net/VpnProfileState.aidl
similarity index 86%
rename from packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.aidl
rename to core/java/android/net/VpnProfileState.aidl
index a56f2f4..add6386e 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.aidl
+++ b/core/java/android/net/VpnProfileState.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -16,4 +16,4 @@
 
 package android.net;
 
-parcelable UnderlyingNetworkInfo;
+parcelable VpnProfileState;
\ No newline at end of file
diff --git a/core/java/android/net/VpnProfileState.java b/core/java/android/net/VpnProfileState.java
new file mode 100644
index 0000000..c69ea1a
--- /dev/null
+++ b/core/java/android/net/VpnProfileState.java
@@ -0,0 +1,153 @@
+/*
+ * 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 android.net;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Describe the state of VPN.
+ */
+public final class VpnProfileState implements Parcelable {
+    /** The VPN has not been started, or some other VPN is active. */
+    public static final int STATE_DISCONNECTED = 0;
+    /** The VPN is attempting to connect, potentially after a failure. */
+    public static final int STATE_CONNECTING = 1;
+    /** The VPN was established successfully. */
+    public static final int STATE_CONNECTED = 2;
+    /** A non-recoverable error has occurred, and will not be retried. */
+    public static final int STATE_FAILED = 3;
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"STATE_"}, value = {
+            STATE_CONNECTED,
+            STATE_CONNECTING,
+            STATE_DISCONNECTED,
+            STATE_FAILED,
+    })
+    public @interface State {}
+
+    @State private final int mState;
+    private final String mSessionKey;
+    private final boolean mAlwaysOn;
+    private final boolean mLockdown;
+
+    public VpnProfileState(@State int state, @Nullable String sessionKey, boolean alwaysOn,
+            boolean lockdown) {
+        mState = state;
+        mSessionKey = sessionKey;
+        mAlwaysOn = alwaysOn;
+        mLockdown = lockdown;
+    }
+
+    /**
+     * Returns the state of the Platform VPN
+     *
+     * <p>This state represents the internal connection state of the VPN. This state may diverge
+     * from the VPN Network's state during error and recovery handling.
+     */
+    @State public int getState() {
+        return mState;
+    }
+
+    /**
+     * Retrieves the Session Key
+     *
+     * <p>The session key is an ephemeral key uniquely identifying the session for a Platform VPN.
+     * The lifetime of this key is tied to the lifetime of the VPN session. In other words,
+     * reprovisioning of the VPN profile, restarting of the device, or manually restarting the
+     * platform VPN session will result in a new VPN session, and a new key.
+     *
+     * @return the unique key for the platform VPN session, or null if it is not running.
+     */
+    @Nullable
+    public String getSessionId() {
+        return mSessionKey;
+    }
+
+    /**
+     * Returns the always-on status of the PlatformVpnProfile.
+     *
+     * <p>If the PlatformVpnProfile is set to be running in always-on mode, the system will ensure
+     * that the profile is always started, and restarting it when necessary (e.g. after reboot).
+     *
+     * <p>Always-on can be set by an appropriately privileged user via the Settings VPN menus, or by
+     * the Device Policy Manager app programmatically.
+     *
+     * See DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
+     */
+    public boolean isAlwaysOn() {
+        return mAlwaysOn;
+    }
+
+    /**
+     * Returns the lockdown mode status of the PlatformVpnProfile.
+     *
+     * <p>In lockdown mode, the system will ensure that apps are not allowed to bypass the VPN,
+     * including during startup or failure of the VPN.
+     *
+     * <p>Lockdown mode can be set by an appropriately privileged user via the Settings VPN menus,
+     * or by the Device Policy Manager app programmatically.
+     *
+     * See DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
+     */
+    public boolean isLockdownEnabled() {
+        return mLockdown;
+    }
+
+    /**
+     * Implement the Parcelable interface
+     */
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Implement the Parcelable interface
+     */
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeInt(mState);
+        out.writeString(mSessionKey);
+        out.writeBoolean(mAlwaysOn);
+        out.writeBoolean(mLockdown);
+    }
+
+    @NonNull
+    public static final Parcelable.Creator<VpnProfileState> CREATOR =
+            new Parcelable.Creator<VpnProfileState>() {
+                public VpnProfileState createFromParcel(Parcel in) {
+                    return new VpnProfileState(in);
+                }
+
+                public VpnProfileState[] newArray(int size) {
+                    return new VpnProfileState[size];
+                }
+            };
+
+    private VpnProfileState(Parcel in) {
+        mState = in.readInt();
+        mSessionKey = in.readString();
+        mAlwaysOn = in.readBoolean();
+        mLockdown = in.readBoolean();
+    }
+}
diff --git a/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java b/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java
index 2dd3aaa1..5c9989e 100644
--- a/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java
+++ b/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java
@@ -27,6 +27,7 @@
 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
 import android.annotation.NonNull;
+import android.annotation.StringDef;
 import android.annotation.SystemApi;
 import android.net.NetworkIdentity;
 import android.net.NetworkStatsCollection;
@@ -47,6 +48,8 @@
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.net.ProtocolException;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -76,6 +79,15 @@
      */
     public static final String PREFIX_UID_TAG = "uid_tag";
 
+    /** @hide */
+    @StringDef(prefix = {"PREFIX_"}, value = {
+        PREFIX_XT,
+        PREFIX_UID,
+        PREFIX_UID_TAG,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Prefix {}
+
     private static final HashMap<String, String> sPrefixLegacyFileNameMap =
             new HashMap<String, String>() {{
                 put(PREFIX_XT, "netstats_xt.bin");
@@ -141,13 +153,13 @@
 
     // Get /data/system/netstats_*.bin legacy files. Does not check for existence.
     @NonNull
-    private static File getLegacyBinFileForPrefix(@NonNull String prefix) {
+    private static File getLegacyBinFileForPrefix(@NonNull @Prefix String prefix) {
         return new File(getPlatformSystemDir(), sPrefixLegacyFileNameMap.get(prefix));
     }
 
     // List /data/system/netstats/[xt|uid|uid_tag].<start>-<end> legacy files.
     @NonNull
-    private static ArrayList<File> getPlatformFileListForPrefix(@NonNull String prefix) {
+    private static ArrayList<File> getPlatformFileListForPrefix(@NonNull @Prefix String prefix) {
         final ArrayList<File> list = new ArrayList<>();
         final File platformFiles = new File(getPlatformBaseDir(), "netstats");
         if (platformFiles.exists()) {
@@ -207,7 +219,7 @@
      */
     @NonNull
     public static NetworkStatsCollection readPlatformCollection(
-            @NonNull String prefix, long bucketDuration) throws IOException {
+            @NonNull @Prefix String prefix, long bucketDuration) throws IOException {
         final NetworkStatsCollection.Builder builder =
                 new NetworkStatsCollection.Builder(bucketDuration);
 
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java
index de76c8f..f4ca1b5 100644
--- a/core/java/android/os/BatteryConsumer.java
+++ b/core/java/android/os/BatteryConsumer.java
@@ -165,6 +165,7 @@
             PROCESS_STATE_FOREGROUND,
             PROCESS_STATE_BACKGROUND,
             PROCESS_STATE_FOREGROUND_SERVICE,
+            PROCESS_STATE_CACHED,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ProcessState {
@@ -175,8 +176,9 @@
     public static final int PROCESS_STATE_FOREGROUND = 1;
     public static final int PROCESS_STATE_BACKGROUND = 2;
     public static final int PROCESS_STATE_FOREGROUND_SERVICE = 3;
+    public static final int PROCESS_STATE_CACHED = 4;
 
-    public static final int PROCESS_STATE_COUNT = 4;
+    public static final int PROCESS_STATE_COUNT = 5;
 
     private static final String[] sProcessStateNames = new String[PROCESS_STATE_COUNT];
 
@@ -186,6 +188,7 @@
         sProcessStateNames[PROCESS_STATE_FOREGROUND] = "fg";
         sProcessStateNames[PROCESS_STATE_BACKGROUND] = "bg";
         sProcessStateNames[PROCESS_STATE_FOREGROUND_SERVICE] = "fgs";
+        sProcessStateNames[PROCESS_STATE_CACHED] = "cached";
     }
 
     private static final int[] SUPPORTED_POWER_COMPONENTS_PER_PROCESS_STATE = {
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index de1dc80..06c35b5 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -680,6 +680,8 @@
                 return BatteryConsumer.PROCESS_STATE_BACKGROUND;
             case BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE:
                 return BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE;
+            case BatteryStats.Uid.PROCESS_STATE_CACHED:
+                return BatteryConsumer.PROCESS_STATE_CACHED;
             default:
                 return BatteryConsumer.PROCESS_STATE_UNSPECIFIED;
         }
@@ -2681,7 +2683,7 @@
     public static final String[] RADIO_ACCESS_TECHNOLOGY_NAMES = {"Other", "LTE", "NR"};
 
     /**
-     * Returns the time in microseconds that the mobile radio has been active on a
+     * Returns the time in milliseconds that the mobile radio has been active on a
      * given Radio Access Technology (RAT), at a given frequency (NR RAT only), for a given
      * transmission power level.
      *
@@ -2700,6 +2702,46 @@
             @ServiceState.FrequencyRange int frequencyRange, int signalStrength,
             long elapsedRealtimeMs);
 
+    /**
+     * Returns the time in milliseconds that the mobile radio has been actively transmitting data on
+     * a given Radio Access Technology (RAT), at a given frequency (NR RAT only), for a given
+     * transmission power level.
+     *
+     * @param rat            Radio Access Technology {@see RadioAccessTechnology}
+     * @param frequencyRange frequency range {@see ServiceState.FrequencyRange}, only needed for
+     *                       RADIO_ACCESS_TECHNOLOGY_NR. Use
+     *                       {@link ServiceState.FREQUENCY_RANGE_UNKNOWN} for other Radio Access
+     *                       Technologies.
+     * @param signalStrength the cellular signal strength. {@see CellSignalStrength#getLevel()}
+     * @param elapsedRealtimeMs current elapsed realtime
+     * @return time (in milliseconds) the mobile radio spent actively transmitting data in the
+     *         specified state, while on battery. Returns {@link DURATION_UNAVAILABLE} if
+     *         data unavailable.
+     * @hide
+     */
+    public abstract long getActiveTxRadioDurationMs(@RadioAccessTechnology int rat,
+            @ServiceState.FrequencyRange int frequencyRange, int signalStrength,
+            long elapsedRealtimeMs);
+
+    /**
+     * Returns the time in milliseconds that the mobile radio has been actively receiving data on a
+     * given Radio Access Technology (RAT), at a given frequency (NR RAT only), for a given
+     * transmission power level.
+     *
+     * @param rat            Radio Access Technology {@see RadioAccessTechnology}
+     * @param frequencyRange frequency range {@see ServiceState.FrequencyRange}, only needed for
+     *                       RADIO_ACCESS_TECHNOLOGY_NR. Use
+     *                       {@link ServiceState.FREQUENCY_RANGE_UNKNOWN} for other Radio Access
+     *                       Technologies.
+     * @param elapsedRealtimeMs current elapsed realtime
+     * @return time (in milliseconds) the mobile radio spent actively receiving data in the
+     *         specified state, while on battery. Returns {@link DURATION_UNAVAILABLE} if
+     *         data unavailable.
+     * @hide
+     */
+    public abstract long getActiveRxRadioDurationMs(@RadioAccessTechnology int rat,
+            @ServiceState.FrequencyRange int frequencyRange, long elapsedRealtimeMs);
+
     static final String[] WIFI_SUPPL_STATE_NAMES = {
         "invalid", "disconn", "disabled", "inactive", "scanning",
         "authenticating", "associating", "associated", "4-way-handshake",
@@ -2720,6 +2762,13 @@
     public static final long POWER_DATA_UNAVAILABLE = -1L;
 
     /**
+     * Returned value if duration data is unavailable.
+     *
+     * {@hide}
+     */
+    public static final long DURATION_UNAVAILABLE = -1L;
+
+    /**
      * Returns the battery consumption (in microcoulombs) of bluetooth, derived from on
      * device power measurement data.
      * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
@@ -4093,6 +4142,10 @@
                 "    Mmwave frequency (greater than 6GHz):\n"};
         final String signalStrengthHeader =
                 "      Signal Strength Time:\n";
+        final String txHeader =
+                "      Tx Time:\n";
+        final String rxHeader =
+                "      Rx Time: ";
         final String[] signalStrengthDescription = new String[]{
                 "        unknown:  ",
                 "        poor:     ",
@@ -4144,6 +4197,29 @@
                     sb.append(")\n");
                 }
 
+                sb.append(prefix);
+                sb.append(txHeader);
+                for (int strength = 0; strength < numSignalStrength; strength++) {
+                    final long timeMs = getActiveTxRadioDurationMs(rat, freqLvl, strength,
+                            rawRealtimeMs);
+                    if (timeMs <= 0) continue;
+                    hasFreqData = true;
+                    sb.append(prefix);
+                    sb.append(signalStrengthDescription[strength]);
+                    formatTimeMs(sb, timeMs);
+                    sb.append("(");
+                    sb.append(formatRatioLocked(timeMs, totalActiveTimesMs));
+                    sb.append(")\n");
+                }
+
+                sb.append(prefix);
+                sb.append(rxHeader);
+                final long rxTimeMs = getActiveRxRadioDurationMs(rat, freqLvl, rawRealtimeMs);
+                formatTimeMs(sb, rxTimeMs);
+                sb.append("(");
+                sb.append(formatRatioLocked(rxTimeMs, totalActiveTimesMs));
+                sb.append(")\n");
+
                 if (hasFreqData) {
                     hasData = true;
                     pw.print(sb);
@@ -5655,6 +5731,7 @@
                         .setMaxStatsAgeMs(0)
                         .includePowerModels()
                         .includeProcessStateData()
+                        .includeVirtualUids()
                         .build());
         stats.dump(pw, prefix);
 
diff --git a/core/java/android/os/BatteryUsageStatsQuery.java b/core/java/android/os/BatteryUsageStatsQuery.java
index 37bd51b..b3f4d98 100644
--- a/core/java/android/os/BatteryUsageStatsQuery.java
+++ b/core/java/android/os/BatteryUsageStatsQuery.java
@@ -42,6 +42,7 @@
             FLAG_BATTERY_USAGE_STATS_POWER_PROFILE_MODEL,
             FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY,
             FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA,
+            FLAG_BATTERY_USAGE_STATS_INCLUDE_VIRTUAL_UIDS,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface BatteryUsageStatsFlags {}
@@ -69,6 +70,8 @@
 
     public static final int FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA = 0x0008;
 
+    public static final int FLAG_BATTERY_USAGE_STATS_INCLUDE_VIRTUAL_UIDS = 0x0010;
+
     private static final long DEFAULT_MAX_STATS_AGE_MS = 5 * 60 * 1000;
 
     private final int mFlags;
@@ -271,6 +274,15 @@
         }
 
         /**
+         * Requests to return attribution data for virtual UIDs such as
+         * {@link Process#SDK_SANDBOX_VIRTUAL_UID}.
+         */
+        public Builder includeVirtualUids() {
+            mFlags |= BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_VIRTUAL_UIDS;
+            return this;
+        }
+
+        /**
          * Requests to aggregate stored snapshots between the two supplied timestamps
          * @param fromTimestamp Exclusive starting timestamp, as per System.currentTimeMillis()
          * @param toTimestamp Inclusive ending timestamp, as per System.currentTimeMillis()
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 1c85f69..42e6ac4 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -406,7 +406,7 @@
         public static final String CODENAME = getString("ro.build.version.codename");
 
         /**
-         * All known codenames starting from {@link VERSION_CODES.Q}.
+         * All known codenames that are present in {@link VERSION_CODES}.
          *
          * <p>This includes in development codenames as well, i.e. if {@link #CODENAME} is not "REL"
          * then the value of that is present in this set.
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index a19b51b..cf28c16 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -989,7 +989,7 @@
      * Otherwise, this method might throw an exception or return {@code null}.
      *
      * @param key a String, or {@code null}
-     * @param clazz The type of the items inside the array
+     * @param clazz The type of the items inside the array. This is only verified when unparceling.
      * @return a Parcelable[] value, or {@code null}
      */
     @SuppressLint({"ArrayReturn", "NullableCollection"})
@@ -1053,7 +1053,8 @@
      * Otherwise, this method might throw an exception or return {@code null}.
      *
      * @param key   a String, or {@code null}
-     * @param clazz The type of the items inside the array list
+     * @param clazz The type of the items inside the array list. This is only verified when
+     *     unparceling.
      * @return an ArrayList<T> value, or {@code null}
      */
     @SuppressLint("NullableCollection")
@@ -1103,6 +1104,8 @@
      * </ul>
      *
      * @param key a String, or null
+     * @param clazz The type of the items inside the sparse array. This is only verified when
+     *     unparceling.
      * @return a SparseArray of T values, or null
      */
     @SuppressWarnings("unchecked")
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 0a7a407..ecdc803 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -478,10 +478,20 @@
     }
 
     /** {@hide} */
+    public static File getDataMiscCeSharedSdkSandboxDirectory(int userId, String packageName) {
+        return buildPath(getDataMiscCeDirectory(userId), "sdksandbox", packageName, "shared");
+    }
+
+    /** {@hide} */
     public static File getDataMiscDeDirectory(int userId) {
         return buildPath(getDataDirectory(), "misc_de", String.valueOf(userId));
     }
 
+    /** {@hide} */
+    public static File getDataMiscDeSharedSdkSandboxDirectory(int userId, String packageName) {
+        return buildPath(getDataMiscDeDirectory(userId), "sdksandbox", packageName, "shared");
+    }
+
     private static File getDataProfilesDeDirectory(int userId) {
         return buildPath(getDataDirectory(), "misc", "profiles", "cur", String.valueOf(userId));
     }
diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java
index 010459d..9e47a70 100644
--- a/core/java/android/os/IBinder.java
+++ b/core/java/android/os/IBinder.java
@@ -293,7 +293,10 @@
      *
      * @return Returns the result from {@link Binder#onTransact}.  A successful call
      * generally returns true; false generally means the transaction code was not
-     * understood.
+     * understood.  For a oneway call to a different process false should never be
+     * returned.  If a oneway call is made to code in the same process (usually to
+     * a C++ or Rust implementation), then there are no oneway semantics, and
+     * false can still be returned.
      */
     public boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags)
         throws RemoteException;
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 39ca596..3cde031 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -109,7 +109,7 @@
     boolean someUserHasAccount(in String accountName, in String accountType);
     String getProfileType(int userId);
     boolean isMediaSharedWithParent(int userId);
-    boolean isCredentialSharedWithParent(int userId);
+    boolean isCredentialSharableWithParent(int userId);
     boolean isDemoUser(int userId);
     boolean isPreCreated(int userId);
     UserInfo createProfileForUserEvenWhenDisallowedWithThrow(in String name, in String userType, int flags,
diff --git a/core/java/android/os/IpcDataCache.java b/core/java/android/os/IpcDataCache.java
index 00734c80..0efa34c 100644
--- a/core/java/android/os/IpcDataCache.java
+++ b/core/java/android/os/IpcDataCache.java
@@ -16,12 +16,12 @@
 
 package android.os;
 
-import android.app.PropertyInvalidatedCache;
-import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.StringDef;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.app.PropertyInvalidatedCache;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -267,6 +267,25 @@
     };
 
     /**
+     * The list of cache namespaces.  Each namespace corresponds to an sepolicy domain.  A
+     * namespace is owned by a single process, although a single process can have more
+     * than one namespace (system_server, as an example).
+     * @hide
+     */
+    @StringDef(
+        prefix = { "MODULE_"
+        },
+        value = {
+            MODULE_TEST,
+            MODULE_SYSTEM,
+            MODULE_BLUETOOTH,
+            MODULE_TELEPHONY
+        }
+    )
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface IpcDataCacheModule { }
+
+    /**
      * The module used for unit tests and cts tests.  It is expected that no process in
      * the system has permissions to write properties with this module.
      * @hide
@@ -304,7 +323,8 @@
      */
     @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
     @TestApi
-    public IpcDataCache(int maxEntries, @NonNull String module, @NonNull String api,
+    public IpcDataCache(int maxEntries, @NonNull @IpcDataCacheModule String module,
+            @NonNull String api,
             @NonNull String cacheName, @NonNull QueryHandler<Query, Result> computer) {
         super(maxEntries, module, api, cacheName, computer);
     }
@@ -358,7 +378,8 @@
      */
     @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
     @TestApi
-    public static void invalidateCache(@NonNull String module, @NonNull String api) {
+    public static void invalidateCache(@NonNull @IpcDataCacheModule String module,
+            @NonNull String api) {
         PropertyInvalidatedCache.invalidateCache(module, api);
     }
 }
diff --git a/core/java/android/os/ParcelableHolder.java b/core/java/android/os/ParcelableHolder.java
index 368ee2d..a739ba3 100644
--- a/core/java/android/os/ParcelableHolder.java
+++ b/core/java/android/os/ParcelableHolder.java
@@ -179,7 +179,11 @@
      * Read ParcelableHolder from a parcel.
      */
     public void readFromParcel(@NonNull Parcel parcel) {
-        this.mStability = parcel.readInt();
+        int wireStability = parcel.readInt();
+        if (this.mStability != wireStability) {
+            throw new IllegalArgumentException("Expected stability " + this.mStability
+                                               + " but got " + wireStability);
+        }
 
         mParcelable = null;
 
diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java
index 6051712..522807b 100644
--- a/core/java/android/os/PowerComponents.java
+++ b/core/java/android/os/PowerComponents.java
@@ -292,6 +292,10 @@
                 procState = BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsageSlice
                         .FOREGROUND_SERVICE;
                 break;
+            case BatteryConsumer.PROCESS_STATE_CACHED:
+                procState = BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsageSlice
+                        .CACHED;
+                break;
             default:
                 throw new IllegalArgumentException("Unknown process state: " + processState);
         }
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index ab74199..82d4443 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -218,14 +218,15 @@
     /**
      * Set the value for the given {@code key} to {@code val}.
      *
-     * @throws IllegalArgumentException if the {@code val} exceeds 91 characters
+     * @throws IllegalArgumentException for non read-only properties if the {@code val} exceeds
+     * 91 characters
      * @throws RuntimeException if the property cannot be set, for example, if it was blocked by
      * SELinux. libc will log the underlying reason.
      * @hide
      */
     @UnsupportedAppUsage
     public static void set(@NonNull String key, @Nullable String val) {
-        if (val != null && !val.startsWith("ro.") && val.length() > PROP_VALUE_MAX) {
+        if (val != null && !key.startsWith("ro.") && val.length() > PROP_VALUE_MAX) {
             throw new IllegalArgumentException("value of system property '" + key
                     + "' is longer than " + PROP_VALUE_MAX + " characters: " + val);
         }
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 043e688..a4f6004 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -107,9 +107,6 @@
     public static final long TRACE_TAG_RRO = 1L << 26;
     /** @hide */
     public static final long TRACE_TAG_THERMAL = 1L << 27;
-    /** @hide */
-
-    public static final long TRACE_TAG_APEX_MANAGER = 1L << 18;
 
     private static final long TRACE_TAG_NOT_READY = 1L << 63;
     private static final int MAX_SECTION_NAME_LEN = 127;
diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java
index a1ff923..91d231e 100644
--- a/core/java/android/os/UidBatteryConsumer.java
+++ b/core/java/android/os/UidBatteryConsumer.java
@@ -119,6 +119,8 @@
                     skipEmptyComponents);
             appendProcessStateData(sb, BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE,
                     skipEmptyComponents);
+            appendProcessStateData(sb, BatteryConsumer.PROCESS_STATE_CACHED,
+                    skipEmptyComponents);
             pw.print(sb);
         }
 
@@ -202,20 +204,24 @@
         private static final String PACKAGE_NAME_UNINITIALIZED = "";
         private final BatteryStats.Uid mBatteryStatsUid;
         private final int mUid;
+        private final boolean mIsVirtualUid;
         private String mPackageWithHighestDrain = PACKAGE_NAME_UNINITIALIZED;
         private boolean mExcludeFromBatteryUsageStats;
 
         public Builder(BatteryConsumerData data, @NonNull BatteryStats.Uid batteryStatsUid) {
-            super(data, CONSUMER_TYPE_UID);
-            mBatteryStatsUid = batteryStatsUid;
-            mUid = batteryStatsUid.getUid();
-            data.putLong(COLUMN_INDEX_UID, mUid);
+            this(data, batteryStatsUid, batteryStatsUid.getUid());
         }
 
         public Builder(BatteryConsumerData data, int uid) {
+            this(data, null, uid);
+        }
+
+        private Builder(BatteryConsumerData data, @Nullable BatteryStats.Uid batteryStatsUid,
+                int uid) {
             super(data, CONSUMER_TYPE_UID);
-            mBatteryStatsUid = null;
+            mBatteryStatsUid = batteryStatsUid;
             mUid = uid;
+            mIsVirtualUid = mUid == Process.SDK_SANDBOX_VIRTUAL_UID;
             data.putLong(COLUMN_INDEX_UID, mUid);
         }
 
@@ -232,6 +238,10 @@
             return mUid;
         }
 
+        public boolean isVirtualUid() {
+            return mIsVirtualUid;
+        }
+
         /**
          * Sets the name of the package owned by this UID that consumed the highest amount
          * of power since BatteryStats reset.
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index a715c69..c4cb319 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -17,7 +17,7 @@
 package android.os;
 
 import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_BADGED_LABEL;
-import static android.app.admin.DevicePolicyResources.Strings.UNDEFINED;
+import static android.app.admin.DevicePolicyResources.UNDEFINED;
 
 import android.Manifest;
 import android.accounts.AccountManager;
@@ -1703,12 +1703,40 @@
 
     /**
      * A response code from {@link #removeUserWhenPossible(UserHandle, boolean)} indicating that
-     * an error occurred that prevented the user from being removed or set as ephemeral.
+     * an unknown error occurred that prevented the user from being removed or set as ephemeral.
      *
      * @hide
      */
     @SystemApi
-    public static final int REMOVE_RESULT_ERROR = 3;
+    public static final int REMOVE_RESULT_ERROR_UNKNOWN = -1;
+
+    /**
+     * A response code from {@link #removeUserWhenPossible(UserHandle, boolean)} indicating that
+     * the user could not be removed due to a {@link #DISALLOW_REMOVE_MANAGED_PROFILE} or
+     * {@link #DISALLOW_REMOVE_USER} user restriction.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int REMOVE_RESULT_ERROR_USER_RESTRICTION = -2;
+
+    /**
+     * A response code from {@link #removeUserWhenPossible(UserHandle, boolean)} indicating that
+     * user being removed does not exist.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int REMOVE_RESULT_ERROR_USER_NOT_FOUND = -3;
+
+    /**
+     * A response code from {@link #removeUserWhenPossible(UserHandle, boolean)} indicating that
+     * user being removed is a {@link UserHandle#SYSTEM} user which can't be removed.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int REMOVE_RESULT_ERROR_SYSTEM_USER = -4;
 
     /**
      * Possible response codes from {@link #removeUserWhenPossible(UserHandle, boolean)}.
@@ -1719,7 +1747,10 @@
             REMOVE_RESULT_REMOVED,
             REMOVE_RESULT_DEFERRED,
             REMOVE_RESULT_ALREADY_BEING_REMOVED,
-            REMOVE_RESULT_ERROR,
+            REMOVE_RESULT_ERROR_USER_RESTRICTION,
+            REMOVE_RESULT_ERROR_USER_NOT_FOUND,
+            REMOVE_RESULT_ERROR_SYSTEM_USER,
+            REMOVE_RESULT_ERROR_UNKNOWN,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface RemoveResult {}
@@ -2155,9 +2186,17 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
-            Manifest.permission.GET_ACCOUNTS_PRIVILEGED})
-    @UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.TIRAMISU)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.CREATE_USERS,
+            android.Manifest.permission.QUERY_USERS,
+            android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED})
+    @UserHandleAware(
+            enabledSinceTargetSdkVersion = Build.VERSION_CODES.TIRAMISU,
+            requiresAnyOfPermissionsIfNotCaller = {
+                    android.Manifest.permission.MANAGE_USERS,
+                    android.Manifest.permission.CREATE_USERS,
+                    android.Manifest.permission.QUERY_USERS})
     public boolean isUserNameSet() {
         try {
             return mService.isUserNameSet(getContextUserIfAppropriate());
@@ -2261,8 +2300,11 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.CREATE_USERS,
+            android.Manifest.permission.QUERY_USERS})
     @UserHandleAware
-    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
     public boolean isUserOfType(@NonNull String userType) {
         try {
             return mService.isUserOfType(mUserId, userType);
@@ -4718,7 +4760,7 @@
             return label;
         }
         DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
-        return dpm.getString(
+        return dpm.getResources().getString(
                 getUpdatableUserBadgedLabelId(userId),
                 () -> getDefaultUserBadgedLabel(label, userId),
                 /* formatArgs= */ label);
@@ -4763,7 +4805,7 @@
     }
 
     /**
-     * Returns {@code true} if the user shares lock settings credential with its parent user
+     * Returns whether the user can have shared lockscreen credential with its parent user.
      *
      * This API only works for {@link UserManager#isProfile() profiles}
      * and will always return false for any other user type.
@@ -4776,9 +4818,9 @@
                     Manifest.permission.MANAGE_USERS,
                     Manifest.permission.INTERACT_ACROSS_USERS})
     @SuppressAutoDoc
-    public boolean isCredentialSharedWithParent() {
+    public boolean isCredentialSharableWithParent() {
         try {
-            return mService.isCredentialSharedWithParent(mUserId);
+            return mService.isCredentialSharableWithParent(mUserId);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
@@ -4846,8 +4888,10 @@
      * the {@link #DISALLOW_REMOVE_USER} or {@link #DISALLOW_REMOVE_MANAGED_PROFILE} restriction
      *
      * @return the {@link RemoveResult} code: {@link #REMOVE_RESULT_REMOVED},
-     * {@link #REMOVE_RESULT_DEFERRED}, {@link #REMOVE_RESULT_ALREADY_BEING_REMOVED}, or
-     * {@link #REMOVE_RESULT_ERROR}.
+     * {@link #REMOVE_RESULT_DEFERRED}, {@link #REMOVE_RESULT_ALREADY_BEING_REMOVED},
+     * {@link #REMOVE_RESULT_ERROR_USER_RESTRICTION}, {@link #REMOVE_RESULT_ERROR_USER_NOT_FOUND},
+     * {@link #REMOVE_RESULT_ERROR_SYSTEM_USER}, or {@link #REMOVE_RESULT_ERROR_UNKNOWN}. All error
+     * codes have negative values.
      *
      * @hide
      */
@@ -4864,6 +4908,19 @@
     }
 
     /**
+     * Check if {@link #removeUserWhenPossible} returned a success code which means that the user
+     * has been removed or is slated for removal.
+     *
+     * @param result is {@link #RemoveResult} code return by {@link #removeUserWhenPossible}.
+     * @return {@code true} if it is a success code.
+     * @hide
+     */
+    @SystemApi
+    public static boolean isRemoveResultSuccessful(@RemoveResult int result) {
+        return result >= 0;
+    }
+
+    /**
      * Updates the user's name.
      *
      * @param userId the user's integer id
diff --git a/core/java/android/os/VibrationAttributes.java b/core/java/android/os/VibrationAttributes.java
index 642c618..5bed32c 100644
--- a/core/java/android/os/VibrationAttributes.java
+++ b/core/java/android/os/VibrationAttributes.java
@@ -167,11 +167,27 @@
     public static final int FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF = 0x2;
 
     /**
+     * Flag requesting vibration effect to be played with fresh user settings values.
+     *
+     * <p>This flag is not protected by any permission, but vibrations that use it require an extra
+     * query of user vibration intensity settings, ringer mode and other controls that affect the
+     * vibration effect playback, which can increase the latency for the overall request.
+     *
+     * <p>This is intended to be used on scenarios where the user settings might have changed
+     * recently, and needs to be applied to this vibration, like settings controllers that preview
+     * newly set intensities to the user.
+     *
+     * @hide
+     */
+    public static final int FLAG_INVALIDATE_SETTINGS_CACHE = 0x3;
+
+    /**
      * All flags supported by vibrator service, update it when adding new flag.
      * @hide
      */
     public static final int FLAG_ALL_SUPPORTED =
-            FLAG_BYPASS_INTERRUPTION_POLICY | FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF;
+            FLAG_BYPASS_INTERRUPTION_POLICY | FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF
+                    | FLAG_INVALIDATE_SETTINGS_CACHE;
 
     /** Creates a new {@link VibrationAttributes} instance with given usage. */
     public static @NonNull VibrationAttributes createForUsage(@Usage int usage) {
@@ -446,8 +462,10 @@
         }
 
         /**
-         * Set flags
-         * @param flags combination of flags to be set.
+         * Sets only the flags specified in the bitmask, leaving the other supported flag values
+         * unchanged in the builder.
+         *
+         * @param flags Combination of flags to be set.
          * @param mask Bit range that should be changed.
          * @return the same Builder instance.
          */
@@ -456,5 +474,18 @@
             mFlags = (mFlags & ~mask) | (flags & mask);
             return this;
         }
+
+        /**
+         * Set all supported flags with given combination of flags, overriding any previous values
+         * set to this builder.
+         *
+         * @param flags combination of flags to be set.
+         * @return the same Builder instance.
+         *
+         * @hide
+         */
+        public @NonNull Builder setFlags(@Flag int flags) {
+            return setFlags(flags, FLAG_ALL_SUPPORTED);
+        }
     }
 }
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 7832dcc..a0f6598 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -78,37 +78,10 @@
      */
     String getMountedObbPath(in String rawPath) = 24;
     /**
-     * Decrypts any encrypted volumes.
-     */
-    int decryptStorage(in String password) = 26;
-    /**
-     * Encrypts storage.
-     */
-    int encryptStorage(int type, in String password) = 27;
-    /**
-     * Changes the encryption password.
-     */
-    int changeEncryptionPassword(int type, in String password) = 28;
-    /**
      * Returns list of all mountable volumes for the specified userId
      */
     StorageVolume[] getVolumeList(int userId, in String callingPackage, int flags) = 29;
     /**
-     * Determines the encryption state of the volume.
-     * @return a numerical value. See {@code ENCRYPTION_STATE_*} for possible
-     * values.
-     * Note that this has been replaced in most cases by the APIs in
-     * StorageManager (see isEncryptable and below)
-     * This is still useful to get the error state when encryption has failed
-     * and CryptKeeper needs to throw up a screen advising the user what to do
-     */
-    int getEncryptionState() = 31;
-    /**
-     * Verify the encryption password against the stored volume.  This method
-     * may only be called by the system process.
-     */
-    int verifyEncryptionPassword(in String password) = 32;
-    /**
      * Ensure that all directories along given path exist, creating parent
      * directories as needed. Validates that given path is absolute and that it
      * contains no relative "." or ".." paths or symlinks. Also ensures that
@@ -117,32 +90,6 @@
      */
     void mkdirs(in String callingPkg, in String path) = 34;
     /**
-     * Determines the type of the encryption password
-     * @return PasswordType
-     */
-    int getPasswordType() = 35;
-    /**
-     * Get password from vold
-     * @return password or empty string
-     */
-    String getPassword() = 36;
-    /**
-     * Securely clear password from vold
-     */
-    oneway void clearPassword() = 37;
-    /**
-     * Set a field in the crypto header.
-     * @param field field to set
-     * @param contents contents to set in field
-     */
-    oneway void setField(in String field, in String contents) = 38;
-    /**
-     * Gets a field from the crypto header.
-     * @param field field to get
-     * @return contents of field
-     */
-    String getField(in String field) = 39;
-    /**
      * Report the time of the last maintenance operation such as fstrim.
      * @return Timestamp of the last maintenance operation, in the
      *     System.currentTimeMillis() time base
@@ -178,7 +125,6 @@
     boolean isUserKeyUnlocked(int userId) = 65;
     void prepareUserStorage(in String volumeUuid, int userId, int serialNumber, int flags) = 66;
     void destroyUserStorage(in String volumeUuid, int userId, int flags) = 67;
-    boolean isConvertibleToFBE() = 68;
     void addUserKeyAuth(int userId, int serialNumber, in byte[] secret) = 70;
     void fixateNewestUserKeyAuth(int userId) = 71;
     void fstrim(int flags, IVoldTaskListener listener) = 72;
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 312abf8..646a709 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -301,28 +301,7 @@
 
     /** @hide The volume is not encrypted. */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public static final int ENCRYPTION_STATE_NONE =
-            IVold.ENCRYPTION_STATE_NONE;
-
-    /** @hide The volume has been encrypted succesfully. */
-    public static final int ENCRYPTION_STATE_OK =
-            IVold.ENCRYPTION_STATE_OK;
-
-    /** @hide The volume is in a bad state. */
-    public static final int ENCRYPTION_STATE_ERROR_UNKNOWN =
-            IVold.ENCRYPTION_STATE_ERROR_UNKNOWN;
-
-    /** @hide Encryption is incomplete */
-    public static final int ENCRYPTION_STATE_ERROR_INCOMPLETE =
-            IVold.ENCRYPTION_STATE_ERROR_INCOMPLETE;
-
-    /** @hide Encryption is incomplete and irrecoverable */
-    public static final int ENCRYPTION_STATE_ERROR_INCONSISTENT =
-            IVold.ENCRYPTION_STATE_ERROR_INCONSISTENT;
-
-    /** @hide Underlying data is corrupt */
-    public static final int ENCRYPTION_STATE_ERROR_CORRUPT =
-            IVold.ENCRYPTION_STATE_ERROR_CORRUPT;
+    public static final int ENCRYPTION_STATE_NONE = 1;
 
     private static volatile IStorageManager sStorageManager = null;
 
@@ -3033,25 +3012,10 @@
     @GuardedBy("mFuseAppLoopLock")
     private @Nullable FuseAppLoop mFuseAppLoop = null;
 
-    /// Consts to match the password types in cryptfs.h
     /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public static final int CRYPT_TYPE_PASSWORD = IVold.PASSWORD_TYPE_PASSWORD;
+    public static final int CRYPT_TYPE_PASSWORD = 0;
     /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public static final int CRYPT_TYPE_DEFAULT = IVold.PASSWORD_TYPE_DEFAULT;
-    /** @hide */
-    public static final int CRYPT_TYPE_PATTERN = IVold.PASSWORD_TYPE_PATTERN;
-    /** @hide */
-    public static final int CRYPT_TYPE_PIN = IVold.PASSWORD_TYPE_PIN;
-
-    // Constants for the data available via StorageManagerService.getField.
-    /** @hide */
-    public static final String SYSTEM_LOCALE_KEY = "SystemLocale";
-    /** @hide */
-    public static final String OWNER_INFO_KEY = "OwnerInfo";
-    /** @hide */
-    public static final String PATTERN_VISIBLE_KEY = "PatternVisible";
-    /** @hide */
-    public static final String PASSWORD_VISIBLE_KEY = "PasswordVisible";
+    public static final int CRYPT_TYPE_DEFAULT = 1;
 }
diff --git a/core/java/android/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl
index c9dd06c..e3f02e7 100644
--- a/core/java/android/permission/IPermissionController.aidl
+++ b/core/java/android/permission/IPermissionController.aidl
@@ -59,6 +59,6 @@
     void getHibernationEligibility(
                 in String packageName,
                 in AndroidFuture callback);
-    void revokeOwnPermissionsOnKill(in String packageName, in List<String> permissions,
+    void revokeSelfPermissionsOnKill(in String packageName, in List<String> permissions,
             in AndroidFuture callback);
 }
diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl
index 619c870..6a93b35 100644
--- a/core/java/android/permission/IPermissionManager.aidl
+++ b/core/java/android/permission/IPermissionManager.aidl
@@ -76,8 +76,6 @@
 
     List<SplitPermissionInfoParcelable> getSplitPermissions();
 
-    void revokeOwnPermissionsOnKill(String packageName, in List<String> permissions);
-
     void startOneTimePermissionSession(String packageName, int userId, long timeout,
             long revokeAfterKilledDelay, int importanceToResetTimer,
             int importanceToKeepSessionAlive);
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index a005ab4e..3c2c7f0 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -916,15 +916,15 @@
      * @param packageName The name of the package for which the permissions will be revoked.
      * @param permissions List of permissions to be revoked.
      *
-     * @see Context#revokeOwnPermissionsOnKill(java.util.Collection)
+     * @see Context#revokeSelfPermissionsOnKill(java.util.Collection)
      *
      * @hide
      */
-    public void revokeOwnPermissionsOnKill(@NonNull String packageName,
+    public void revokeSelfPermissionsOnKill(@NonNull String packageName,
             @NonNull List<String> permissions) {
         mRemoteService.postAsync(service -> {
             AndroidFuture<Void> callback = new AndroidFuture<>();
-            service.revokeOwnPermissionsOnKill(packageName, permissions, callback);
+            service.revokeSelfPermissionsOnKill(packageName, permissions, callback);
             return callback;
         }).whenComplete((result, err) -> {
             if (err != null) {
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 3292e71..4efffc5a 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -40,6 +40,7 @@
 import android.content.Intent;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
@@ -339,10 +340,10 @@
      * @param permissions List of permissions to be revoked.
      * @param callback Callback waiting for operation to be complete.
      *
-     * @see PermissionManager#revokeOwnPermissionsOnKill(java.util.Collection)
+     * @see android.content.Context#revokeSelfPermissionsOnKill(java.util.Collection)
      */
     @BinderThread
-    public void onRevokeOwnPermissionsOnKill(@NonNull String packageName,
+    public void onRevokeSelfPermissionsOnKill(@NonNull String packageName,
             @NonNull List<String> permissions, @NonNull Runnable callback) {
         throw new AbstractMethodError("Must be overridden in implementing class");
     }
@@ -703,13 +704,19 @@
             }
 
             @Override
-            public void revokeOwnPermissionsOnKill(@NonNull String packageName,
+            public void revokeSelfPermissionsOnKill(@NonNull String packageName,
                     @NonNull List<String> permissions, @NonNull AndroidFuture callback) {
                 try {
-                    enforceSomePermissionsGrantedToCaller(
-                            Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
                     Objects.requireNonNull(callback);
-                    onRevokeOwnPermissionsOnKill(packageName, permissions,
+
+                    final int callingUid = Binder.getCallingUid();
+                    int targetPackageUid = getPackageManager().getPackageUid(packageName,
+                            PackageManager.PackageInfoFlags.of(0));
+                    if (targetPackageUid != callingUid) {
+                        enforceSomePermissionsGrantedToCaller(
+                                Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
+                    }
+                    onRevokeSelfPermissionsOnKill(packageName, permissions,
                             () -> callback.complete(null));
                 } catch (Throwable t) {
                     callback.completeExceptionally(t);
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index c509de6..6972875 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -76,7 +76,6 @@
 import com.android.internal.util.CollectionUtils;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
@@ -251,6 +250,10 @@
      * will evaluate the permission access based on the current fg/bg state of the app and
      * leave a record that the data was accessed.
      *
+     * <p>Requires the start of the AttributionSource chain to have the UPDATE_APP_OPS_STATS
+     * permission for the app op accesses to be given the TRUSTED_PROXY/PROXIED flags, otherwise the
+     * accesses will have the UNTRUSTED flags.
+     *
      * @param permission The permission to check.
      * @param attributionSource the permission identity
      * @param message A message describing the reason the permission was checked
@@ -260,6 +263,7 @@
      * @see #checkPermissionForPreflight(String, AttributionSource)
      */
     @PermissionCheckerManager.PermissionResult
+    @RequiresPermission(value = Manifest.permission.UPDATE_APP_OPS_STATS, conditional = true)
     public int checkPermissionForDataDelivery(@NonNull String permission,
             @NonNull AttributionSource attributionSource, @Nullable String message) {
         return PermissionChecker.checkPermissionForDataDelivery(mContext, permission,
@@ -279,9 +283,14 @@
      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
      *     or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
      *
+     * <p>Requires the start of the AttributionSource chain to have the UPDATE_APP_OPS_STATS
+     * permission for the app op accesses to be given the TRUSTED_PROXY/PROXIED flags, otherwise the
+     * accesses will have the UNTRUSTED flags.
+     *
      * @see #checkPermissionForDataDelivery(String, AttributionSource, String)
      */
     @PermissionCheckerManager.PermissionResult
+    @RequiresPermission(value = Manifest.permission.UPDATE_APP_OPS_STATS, conditional = true)
     public int checkPermissionForStartDataDelivery(@NonNull String permission,
             @NonNull AttributionSource attributionSource, @Nullable String message) {
         return PermissionChecker.checkPermissionForDataDelivery(mContext, permission,
@@ -321,6 +330,10 @@
      * will evaluate the permission access based on the current fg/bg state of the app and
      * leave a record that the data was accessed.
      *
+     * <p>Requires the start of the AttributionSource chain to have the UPDATE_APP_OPS_STATS
+     * permission for the app op accesses to be given the TRUSTED_PROXY/PROXIED flags, otherwise the
+     * accesses will have the UNTRUSTED flags.
+     *
      * @param permission The permission to check.
      * @param attributionSource the permission identity
      * @param message A message describing the reason the permission was checked
@@ -330,6 +343,7 @@
      * @see #checkPermissionForPreflight(String, AttributionSource)
      */
     @PermissionCheckerManager.PermissionResult
+    @RequiresPermission(value = Manifest.permission.UPDATE_APP_OPS_STATS, conditional = true)
     public int checkPermissionForDataDeliveryFromDataSource(@NonNull String permission,
             @NonNull AttributionSource attributionSource, @Nullable String message) {
         return PermissionChecker.checkPermissionForDataDeliveryFromDataSource(mContext, permission,
@@ -626,19 +640,6 @@
     }
 
     /**
-     * @see Context#revokeOwnPermissionsOnKill(Collection)
-     * @hide
-     */
-    public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
-        try {
-            mPermissionManager.revokeOwnPermissionsOnKill(mContext.getPackageName(),
-                    new ArrayList<String>(permissions));
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Gets the state flags associated with a permission.
      *
      * @param packageName the package name for which to get the flags
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 0b57842..4ed939c 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -47,6 +47,7 @@
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.icu.text.ListFormatter;
+import android.location.LocationManager;
 import android.media.AudioManager;
 import android.os.Process;
 import android.os.UserHandle;
@@ -411,10 +412,13 @@
     }
 
     /**
-     * Returns true if the app supports subattribution.
+     * Returns true if the app satisfies subattribution policies and supports it
      */
     private boolean isSubattributionSupported(String packageName, int uid) {
         try {
+            if (!isLocationProvider(packageName)) {
+                return false;
+            }
             PackageManager userPkgManager =
                     getUserContext(UserHandle.getUserHandleForUid(uid)).getPackageManager();
             ApplicationInfo appInfo = userPkgManager.getApplicationInfoAsUser(packageName,
@@ -430,6 +434,15 @@
     }
 
     /**
+     * @param packageName
+     * @return If the package is location provider
+     */
+    private boolean isLocationProvider(String packageName) {
+        return Objects.requireNonNull(
+                mContext.getSystemService(LocationManager.class)).isProviderPackage(packageName);
+    }
+
+    /**
      * Get the raw usages from the system, and then parse out the ones that are not recent enough,
      * determine which permission group each belongs in, and removes duplicates (if the same app
      * uses multiple permissions of the same group). Stores the package name, attribution tag, user,
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 052e4d0..4731504 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -74,6 +74,13 @@
     public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager";
 
     /**
+     * Namespace for activity manager, specific to the "component alias" feature. We needed a
+     * different namespace in order to avoid phonetype from resetting it.
+     * @hide
+     */
+    public static final String NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS = "activity_manager_ca";
+
+    /**
      * Namespace for all activity manager related features that are used at the native level.
      * These features are applied at reboot.
      *
@@ -322,6 +329,13 @@
     public static final String NAMESPACE_NNAPI_NATIVE = "nnapi_native";
 
     /**
+     * Namespace for all OnDevicePersonalization related feature.
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_ON_DEVICE_PERSONALIZATION = "on_device_personalization";
+
+    /**
      * Namespace for features related to the Package Manager Service.
      *
      * @hide
@@ -586,6 +600,13 @@
     public static final String NAMESPACE_SELECTION_TOOLBAR = "selection_toolbar";
 
     /**
+     * Definitions for voice interaction related functions.
+     *
+     * @hide
+     */
+    public static final String NAMESPACE_VOICE_INTERACTION = "voice_interaction";
+
+    /**
      * List of namespaces which can be read without READ_DEVICE_CONFIG permission
      *
      * @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index cfef7ad..5bd77ab 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -86,6 +86,7 @@
 import android.util.MemoryIntArray;
 import android.view.Display;
 import android.view.MotionEvent;
+import android.view.ViewConfiguration;
 import android.view.Window;
 import android.view.WindowManager.LayoutParams;
 import android.widget.Editor;
@@ -2143,10 +2144,10 @@
     /**
      * Intent extra: The id of a setting restricted by supervisors.
      * <p>
-     * Type: Integer with a value from the SupervisorVerificationSetting annotation below.
+     * Type: Integer with a value from the one of the SUPERVISOR_VERIFICATION_* constants below.
      * <ul>
-     * <li>{@link #SUPERVISOR_VERIFICATION_SETTING_UNKNOWN}
-     * <li>{@link #SUPERVISOR_VERIFICATION_SETTING_BIOMETRICS}
+     * <li>{@see #SUPERVISOR_VERIFICATION_SETTING_UNKNOWN}
+     * <li>{@see #SUPERVISOR_VERIFICATION_SETTING_BIOMETRICS}
      * </ul>
      * </p>
      */
@@ -2154,12 +2155,14 @@
             "android.provider.extra.SUPERVISOR_RESTRICTED_SETTING_KEY";
 
     /**
-     * Unknown setting.
+     * The unknown setting can usually be ignored and is used for compatibility with future
+     * supervisor settings.
      */
     public static final int SUPERVISOR_VERIFICATION_SETTING_UNKNOWN = 0;
 
     /**
-     * Biometric settings for supervisors.
+     * Settings for supervisors to control what kinds of biometric sensors, such a face and
+     * fingerprint scanners, can be used on the device.
      */
     public static final int SUPERVISOR_VERIFICATION_SETTING_BIOMETRICS = 1;
 
@@ -7475,6 +7478,16 @@
                 "accessibility_shortcut_dialog_shown";
 
         /**
+         * Setting specifying if the timeout restriction
+         * {@link ViewConfiguration#getAccessibilityShortcutKeyTimeout()}
+         * of the accessibility shortcut dialog is skipped.
+         *
+         * @hide
+         */
+        public static final String SKIP_ACCESSIBILITY_SHORTCUT_DIALOG_TIMEOUT_RESTRICTION =
+                "skip_accessibility_shortcut_dialog_timeout_restriction";
+
+        /**
          * Setting specifying the accessibility services, accessibility shortcut targets,
          * or features to be toggled via the accessibility shortcut.
          *
@@ -10729,14 +10742,6 @@
                 "communal_mode_trusted_networks";
 
         /**
-         * Setting to allow Fast Pair scans to be enabled.
-         * @hide
-         */
-        @SystemApi
-        @Readable
-        public static final String FAST_PAIR_SCAN_ENABLED = "fast_pair_scan_enabled";
-
-        /**
          * Setting to store denylisted system languages by the CEC {@code <Set Menu Language>}
          * confirmation dialog.
          *
diff --git a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java
index 0cb69a4..61fd041 100644
--- a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java
+++ b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java
@@ -167,10 +167,7 @@
     protected WrappedApplicationKey(Parcel in) {
         mAlias = in.readString();
         mEncryptedKeyMaterial = in.createByteArray();
-        // Check if there is still data to be read.
-        if (in.dataAvail() > 0) {
-            mMetadata = in.createByteArray();
-        }
+        mMetadata = in.createByteArray();
     }
 
     @Override
diff --git a/core/java/android/service/ambientcontext/AmbientContextDetectionResult.java b/core/java/android/service/ambientcontext/AmbientContextDetectionResult.java
index 227194e..a216ed5 100644
--- a/core/java/android/service/ambientcontext/AmbientContextDetectionResult.java
+++ b/core/java/android/service/ambientcontext/AmbientContextDetectionResult.java
@@ -26,6 +26,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Represents a {@code AmbientContextEvent} detection result reported by the detection service.
@@ -127,7 +128,9 @@
         private @NonNull String mPackageName;
         private long mBuilderFieldsSet = 0L;
 
-        public Builder() {
+        public Builder(@NonNull String packageName) {
+            Objects.requireNonNull(packageName);
+            mPackageName = packageName;
         }
 
         /**
@@ -144,26 +147,37 @@
         }
 
         /**
-         * The package to deliver the response to.
+         * Adds a list of events to the builder.
          */
-        public @NonNull Builder setPackageName(@NonNull String value) {
+        public @NonNull Builder addEvents(@NonNull List<AmbientContextEvent> values) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x2;
-            mPackageName = value;
+            if (mEvents == null) {
+                mBuilderFieldsSet |= 0x1;
+                mEvents = new ArrayList<>();
+            }
+            mEvents.addAll(values);
+            return this;
+        }
+
+        /**
+         * Clears all events from the builder.
+         */
+        public @NonNull Builder clearEvents() {
+            checkNotUsed();
+            if (mEvents != null) {
+                mEvents.clear();
+            }
             return this;
         }
 
         /** Builds the instance. This builder should not be touched after calling this! */
         public @NonNull AmbientContextDetectionResult build() {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x4; // Mark builder used
+            mBuilderFieldsSet |= 0x2; // Mark builder used
 
             if ((mBuilderFieldsSet & 0x1) == 0) {
                 mEvents = new ArrayList<>();
             }
-            if ((mBuilderFieldsSet & 0x2) == 0) {
-                mPackageName = "";
-            }
             AmbientContextDetectionResult o = new AmbientContextDetectionResult(
                     mEvents,
                     mPackageName);
@@ -171,7 +185,7 @@
         }
 
         private void checkNotUsed() {
-            if ((mBuilderFieldsSet & 0x4) != 0) {
+            if ((mBuilderFieldsSet & 0x2) != 0) {
                 throw new IllegalStateException(
                         "This Builder should not be reused. Use a new Builder instance instead");
             }
diff --git a/core/java/android/service/ambientcontext/AmbientContextDetectionService.java b/core/java/android/service/ambientcontext/AmbientContextDetectionService.java
index 6224aa1..8cf3411 100644
--- a/core/java/android/service/ambientcontext/AmbientContextDetectionService.java
+++ b/core/java/android/service/ambientcontext/AmbientContextDetectionService.java
@@ -134,12 +134,18 @@
     }
 
     /**
-     * Starts detection and provides detected events to the statusConsumer. The ongoing detection
-     * will keep running, until onStopDetection is called. If there were previously requested
-     * detection from the same package, the previous request will be replaced with the new request.
-     * The implementation should keep track of whether the user consented each requested
-     * AmbientContextEvent for the app. If not consented, the statusConsumer should get a response
-     * with STATUS_ACCESS_DENIED.
+     * Called when a client app requests starting detection of the events in the request. The
+     * implementation should keep track of whether the user has explicitly consented to detecting
+     * the events using on-going ambient sensor (e.g. microphone), and agreed to share the
+     * detection results with this client app. If the user has not consented, the detection
+     * should not start, and the statusConsumer should get a response with STATUS_ACCESS_DENIED.
+     * If the user has made the consent and the underlying services are available, the
+     * implementation should start detection and provide detected events to the
+     * detectionResultConsumer. If the type of event needs immediate attention, the implementation
+     * should send result as soon as detected. Otherwise, the implementation can bulk send response.
+     * The ongoing detection will keep running, until onStopDetection is called. If there were
+     * previously requested detection from the same package, regardless of the type of events in
+     * the request, the previous request will be replaced with the new request.
      *
      * @param request The request with events to detect.
      * @param packageName the requesting app's package name
diff --git a/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.java b/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.java
index 3e92f39..199e674 100644
--- a/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.java
+++ b/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.java
@@ -24,6 +24,8 @@
 
 import com.android.internal.util.AnnotationValidations;
 
+import java.util.Objects;
+
 /**
  * Represents a status for the {@code AmbientContextDetectionService}.
  *
@@ -121,7 +123,9 @@
         private @NonNull String mPackageName;
         private long mBuilderFieldsSet = 0L;
 
-        public Builder() {
+        public Builder(@NonNull String packageName) {
+            Objects.requireNonNull(packageName);
+            mPackageName = packageName;
         }
 
         /**
@@ -134,27 +138,14 @@
             return this;
         }
 
-        /**
-         * The package to deliver the response to.
-         */
-        public @NonNull Builder setPackageName(@NonNull String value) {
-            checkNotUsed();
-            mBuilderFieldsSet |= 0x2;
-            mPackageName = value;
-            return this;
-        }
-
         /** Builds the instance. This builder should not be touched after calling this! */
         public @NonNull AmbientContextDetectionServiceStatus build() {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x4; // Mark builder used
+            mBuilderFieldsSet |= 0x2; // Mark builder used
 
             if ((mBuilderFieldsSet & 0x1) == 0) {
                 mStatusCode = AmbientContextManager.STATUS_UNKNOWN;
             }
-            if ((mBuilderFieldsSet & 0x2) == 0) {
-                mPackageName = "";
-            }
             AmbientContextDetectionServiceStatus o = new AmbientContextDetectionServiceStatus(
                     mStatusCode,
                     mPackageName);
@@ -162,7 +153,7 @@
         }
 
         private void checkNotUsed() {
-            if ((mBuilderFieldsSet & 0x4) != 0) {
+            if ((mBuilderFieldsSet & 0x2) != 0) {
                 throw new IllegalStateException(
                         "This Builder should not be reused. Use a new Builder instance instead");
             }
diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java
index b701e07..e9f099a 100644
--- a/core/java/android/service/autofill/Dataset.java
+++ b/core/java/android/service/autofill/Dataset.java
@@ -876,7 +876,7 @@
          * if (filter != null) {
          *     fieldBuilder.setFilter(filter);
          * }
-         * Presentations.Builder presentationsBuilder = new Presentations.Builder(id);
+         * Presentations.Builder presentationsBuilder = new Presentations.Builder();
          * if (presentation != null) {
          *     presentationsBuilder.setMenuPresentation(presentation);
          * }
diff --git a/core/java/android/service/autofill/Field.java b/core/java/android/service/autofill/Field.java
index 8c905a6..d63cf33 100644
--- a/core/java/android/service/autofill/Field.java
+++ b/core/java/android/service/autofill/Field.java
@@ -18,7 +18,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillValue;
 
 import com.android.internal.util.DataClass;
@@ -26,10 +25,9 @@
 import java.util.regex.Pattern;
 
 /**
- * This class is used to set all information of a field. Such as the
- * {@link AutofillId} of the field, the {@link AutofillValue} to be autofilled,
- * a <a href="#Filtering">explicit filter</a>, and presentations to be visualized,
- * etc.
+ * This class is used to set all information of a field. Such as the {@link AutofillValue}
+ * to be autofilled, a <a href="#Filtering">explicit filter</a>, and presentations to be
+ * visualized, etc.
  */
 public final class Field {
 
diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java
index 7a8f6f4..0fb9f57 100644
--- a/core/java/android/service/autofill/FillEventHistory.java
+++ b/core/java/android/service/autofill/FillEventHistory.java
@@ -160,6 +160,7 @@
                             event.mDetectedFieldClassifications);
                 }
                 parcel.writeInt(event.mSaveDialogNotShowReason);
+                parcel.writeInt(event.mUiType);
             }
         }
     }
@@ -278,6 +279,29 @@
         @Retention(RetentionPolicy.SOURCE)
         public @interface NoSaveReason{}
 
+        /** The autofill suggestion presentation is unknown, this will be set for the event
+         * that is unrelated to fill Ui presentation */
+        public static final int UI_TYPE_UNKNOWN = 0;
+
+        /** The autofill suggestion is shown as a menu popup presentation. */
+        public static final int UI_TYPE_MENU = 1;
+
+        /** The autofill suggestion is shown as a keyboard inline presentation. */
+        public static final int UI_TYPE_INLINE = 2;
+
+        /** The autofill suggestion is shown as a dialog presentation. */
+        public static final int UI_TYPE_DIALOG = 3;
+
+        /** @hide */
+        @IntDef(prefix = { "UI_TYPE_" }, value = {
+                UI_TYPE_UNKNOWN,
+                UI_TYPE_MENU,
+                UI_TYPE_INLINE,
+                UI_TYPE_DIALOG
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface UiType {}
+
         @EventIds private final int mEventType;
         @Nullable private final String mDatasetId;
         @Nullable private final Bundle mClientState;
@@ -298,6 +322,10 @@
 
         @NoSaveReason private final int mSaveDialogNotShowReason;
 
+
+        @UiType
+        private final int mUiType;
+
         /**
          * Returns the type of the event.
          *
@@ -498,6 +526,21 @@
         }
 
         /**
+         * Returns fill suggestion ui presentation type which corresponds to types
+         * defined in {@link android.service.autofill.Presentations).
+         *
+         * <p><b>Note: </b>Only set on events of type {@link #TYPE_DATASETS_SHOWN} and
+         * {@link #TYPE_DATASET_SELECTED}. For the other event types, the type is set to
+         * {@link #UI_TYPE_UNKNOWN }.
+         *
+         * @return The ui presentation type shown for user.
+         */
+        @UiType
+        public int getUiType() {
+            return mUiType;
+        }
+
+        /**
          * Creates a new event.
          *
          * @param eventType The type of the event
@@ -573,6 +616,49 @@
                 @Nullable AutofillId[] detectedFieldIds,
                 @Nullable FieldClassification[] detectedFieldClassifications,
                 int saveDialogNotShowReason) {
+            this(eventType, datasetId, clientState, selectedDatasetIds, ignoredDatasetIds,
+                    changedFieldIds, changedDatasetIds, manuallyFilledFieldIds,
+                    manuallyFilledDatasetIds, detectedFieldIds, detectedFieldClassifications,
+                    saveDialogNotShowReason, UI_TYPE_UNKNOWN);
+        }
+
+        /**
+         * Creates a new event.
+         *
+         * @param eventType The type of the event
+         * @param datasetId The dataset the event was on, or {@code null} if the event was on the
+         *                  whole response.
+         * @param clientState The client state associated with the event.
+         * @param selectedDatasetIds The ids of datasets selected by the user.
+         * @param ignoredDatasetIds The ids of datasets NOT select by the user.
+         * @param changedFieldIds The ids of fields changed by the user.
+         * @param changedDatasetIds The ids of the datasets that havd values matching the
+         * respective entry on {@code changedFieldIds}.
+         * @param manuallyFilledFieldIds The ids of fields that were manually entered by the user
+         * and belonged to datasets.
+         * @param manuallyFilledDatasetIds The ids of datasets that had values matching the
+         * respective entry on {@code manuallyFilledFieldIds}.
+         * @param detectedFieldClassifications the field classification matches.
+         * @param saveDialogNotShowReason The reason why a save dialog was not shown.
+         * @param uiType The ui presentation type for fill suggestion.
+         *
+         * @throws IllegalArgumentException If the length of {@code changedFieldIds} and
+         * {@code changedDatasetIds} doesn't match.
+         * @throws IllegalArgumentException If the length of {@code manuallyFilledFieldIds} and
+         * {@code manuallyFilledDatasetIds} doesn't match.
+         *
+         * @hide
+         */
+        public Event(int eventType, @Nullable String datasetId, @Nullable Bundle clientState,
+                @Nullable List<String> selectedDatasetIds,
+                @Nullable ArraySet<String> ignoredDatasetIds,
+                @Nullable ArrayList<AutofillId> changedFieldIds,
+                @Nullable ArrayList<String> changedDatasetIds,
+                @Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
+                @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
+                @Nullable AutofillId[] detectedFieldIds,
+                @Nullable FieldClassification[] detectedFieldClassifications,
+                int saveDialogNotShowReason, int uiType) {
             mEventType = Preconditions.checkArgumentInRange(eventType, 0, TYPE_DATASETS_SHOWN,
                     "eventType");
             mDatasetId = datasetId;
@@ -581,16 +667,16 @@
             mIgnoredDatasetIds = ignoredDatasetIds;
             if (changedFieldIds != null) {
                 Preconditions.checkArgument(!ArrayUtils.isEmpty(changedFieldIds)
-                        && changedDatasetIds != null
-                        && changedFieldIds.size() == changedDatasetIds.size(),
+                                && changedDatasetIds != null
+                                && changedFieldIds.size() == changedDatasetIds.size(),
                         "changed ids must have same length and not be empty");
             }
             mChangedFieldIds = changedFieldIds;
             mChangedDatasetIds = changedDatasetIds;
             if (manuallyFilledFieldIds != null) {
                 Preconditions.checkArgument(!ArrayUtils.isEmpty(manuallyFilledFieldIds)
-                        && manuallyFilledDatasetIds != null
-                        && manuallyFilledFieldIds.size() == manuallyFilledDatasetIds.size(),
+                                && manuallyFilledDatasetIds != null
+                                && manuallyFilledFieldIds.size() == manuallyFilledDatasetIds.size(),
                         "manually filled ids must have same length and not be empty");
             }
             mManuallyFilledFieldIds = manuallyFilledFieldIds;
@@ -602,12 +688,14 @@
             mSaveDialogNotShowReason = Preconditions.checkArgumentInRange(saveDialogNotShowReason,
                     NO_SAVE_UI_REASON_NONE, NO_SAVE_UI_REASON_DATASET_MATCH,
                     "saveDialogNotShowReason");
+            mUiType = uiType;
         }
 
         @Override
         public String toString() {
             return "FillEvent [datasetId=" + mDatasetId
-                    + ", type=" + mEventType
+                    + ", type=" + eventToString(mEventType)
+                    + ", uiType=" + uiTypeToString(mUiType)
                     + ", selectedDatasets=" + mSelectedDatasetIds
                     + ", ignoredDatasetIds=" + mIgnoredDatasetIds
                     + ", changedFieldIds=" + mChangedFieldIds
@@ -620,6 +708,38 @@
                     + ", saveDialogNotShowReason=" + mSaveDialogNotShowReason
                     + "]";
         }
+
+        private static String eventToString(int eventType) {
+            switch (eventType) {
+                case TYPE_DATASET_SELECTED:
+                    return "TYPE_DATASET_SELECTED";
+                case TYPE_DATASET_AUTHENTICATION_SELECTED:
+                    return "TYPE_DATASET_AUTHENTICATION_SELECTED";
+                case TYPE_AUTHENTICATION_SELECTED:
+                    return "TYPE_AUTHENTICATION_SELECTED";
+                case TYPE_SAVE_SHOWN:
+                    return "TYPE_SAVE_SHOWN";
+                case TYPE_CONTEXT_COMMITTED:
+                    return "TYPE_CONTEXT_COMMITTED";
+                case TYPE_DATASETS_SHOWN:
+                    return "TYPE_DATASETS_SHOWN";
+                default:
+                    return "TYPE_UNKNOWN";
+            }
+        }
+
+        private static String uiTypeToString(int uiType) {
+            switch (uiType) {
+                case UI_TYPE_MENU:
+                    return "UI_TYPE_MENU";
+                case UI_TYPE_INLINE:
+                    return "UI_TYPE_INLINE";
+                case UI_TYPE_DIALOG:
+                    return "UI_TYPE_FILL_DIALOG";
+                default:
+                    return "UI_TYPE_UNKNOWN";
+            }
+        }
     }
 
     public static final @android.annotation.NonNull Parcelable.Creator<FillEventHistory> CREATOR =
@@ -660,13 +780,14 @@
                                 ? FieldClassification.readArrayFromParcel(parcel)
                                 : null;
                         final int saveDialogNotShowReason = parcel.readInt();
+                        final int uiType = parcel.readInt();
 
                         selection.addEvent(new Event(eventType, datasetId, clientState,
                                 selectedDatasetIds, ignoredDatasets,
                                 changedFieldIds, changedDatasetIds,
                                 manuallyFilledFieldIds, manuallyFilledDatasetIds,
                                 detectedFieldIds, detectedFieldClassifications,
-                                saveDialogNotShowReason));
+                                saveDialogNotShowReason, uiType));
                     }
                     return selection;
                 }
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index e4d3732..431a88d 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -97,13 +97,13 @@
      */
     public static final @RequestFlags int FLAG_VIEW_NOT_FOCUSED = 0x10;
 
-    // The flag value 0x20 has been defined in AutofillManager.
+    // The flag value 0x20 has been used.
 
     /**
-     * Indicates the request is coming from the activity just started.
-     * @hide
+     * Indicates the request supports fill dialog presentation for the fields, the
+     * system will send the request when the activity just started.
      */
-    public static final @RequestFlags int FLAG_ACTIVITY_START = 0x40;
+    public static final @RequestFlags int FLAG_SUPPORTS_FILL_DIALOG = 0x40;
 
     /** @hide */
     public static final int INVALID_REQUEST_ID = Integer.MIN_VALUE;
@@ -140,8 +140,10 @@
     /**
      * Gets the flags associated with this request.
      *
-     * @return any combination of {@link #FLAG_MANUAL_REQUEST} and
+     * @return any combination of {@link #FLAG_MANUAL_REQUEST},
+     *         {@link #FLAG_SUPPORTS_FILL_DIALOG} and
      *         {@link #FLAG_COMPATIBILITY_MODE_REQUEST}.
+     *
      */
     private final @RequestFlags int mFlags;
 
@@ -199,7 +201,7 @@
         FLAG_COMPATIBILITY_MODE_REQUEST,
         FLAG_PASSWORD_INPUT_TYPE,
         FLAG_VIEW_NOT_FOCUSED,
-        FLAG_ACTIVITY_START
+        FLAG_SUPPORTS_FILL_DIALOG
     })
     @Retention(RetentionPolicy.SOURCE)
     @DataClass.Generated.Member
@@ -223,8 +225,8 @@
                     return "FLAG_PASSWORD_INPUT_TYPE";
             case FLAG_VIEW_NOT_FOCUSED:
                     return "FLAG_VIEW_NOT_FOCUSED";
-            case FLAG_ACTIVITY_START:
-                    return "FLAG_ACTIVITY_START";
+            case FLAG_SUPPORTS_FILL_DIALOG:
+                    return "FLAG_SUPPORTS_FILL_DIALOG";
             default: return Integer.toHexString(value);
         }
     }
@@ -253,7 +255,8 @@
      * @param flags
      *   Gets the flags associated with this request.
      *
-     *   @return any combination of {@link #FLAG_MANUAL_REQUEST} and
+     *   @return any combination of {@link #FLAG_MANUAL_REQUEST},
+     *           {@link #FLAG_SUPPORTS_FILL_DIALOG} and
      *           {@link #FLAG_COMPATIBILITY_MODE_REQUEST}.
      * @param inlineSuggestionsRequest
      *   Gets the {@link InlineSuggestionsRequest} associated
@@ -299,7 +302,7 @@
                         | FLAG_COMPATIBILITY_MODE_REQUEST
                         | FLAG_PASSWORD_INPUT_TYPE
                         | FLAG_VIEW_NOT_FOCUSED
-                        | FLAG_ACTIVITY_START);
+                        | FLAG_SUPPORTS_FILL_DIALOG);
         this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
         this.mDelayedFillIntentSender = delayedFillIntentSender;
 
@@ -347,7 +350,8 @@
     /**
      * Gets the flags associated with this request.
      *
-     * @return any combination of {@link #FLAG_MANUAL_REQUEST} and
+     * @return any combination of {@link #FLAG_MANUAL_REQUEST},
+     *         {@link #FLAG_SUPPORTS_FILL_DIALOG} and
      *         {@link #FLAG_COMPATIBILITY_MODE_REQUEST}.
      */
     @DataClass.Generated.Member
@@ -458,7 +462,7 @@
                         | FLAG_COMPATIBILITY_MODE_REQUEST
                         | FLAG_PASSWORD_INPUT_TYPE
                         | FLAG_VIEW_NOT_FOCUSED
-                        | FLAG_ACTIVITY_START);
+                        | FLAG_SUPPORTS_FILL_DIALOG);
         this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
         this.mDelayedFillIntentSender = delayedFillIntentSender;
 
@@ -480,10 +484,10 @@
     };
 
     @DataClass.Generated(
-            time = 1643386870464L,
+            time = 1647644111186L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/service/autofill/FillRequest.java",
-            inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_NOT_FOCUSED\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_ACTIVITY_START\npublic static final  int INVALID_REQUEST_ID\nprivate final  int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate final @android.annotation.Nullable android.content.IntentSender mDelayedFillIntentSender\nprivate  void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+            inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_NOT_FOCUSED\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_SUPPORTS_FILL_DIALOG\npublic static final  int INVALID_REQUEST_ID\nprivate final  int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate final @android.annotation.Nullable android.content.IntentSender mDelayedFillIntentSender\nprivate  void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/service/displayhash/DisplayHashingService.java b/core/java/android/service/displayhash/DisplayHashingService.java
index f22d40e..3fac23b 100644
--- a/core/java/android/service/displayhash/DisplayHashingService.java
+++ b/core/java/android/service/displayhash/DisplayHashingService.java
@@ -68,9 +68,6 @@
     private DisplayHashingServiceWrapper mWrapper;
     private Handler mHandler;
 
-    public DisplayHashingService() {
-    }
-
     @Override
     public void onCreate() {
         super.onCreate();
diff --git a/core/java/android/service/games/GameSession.java b/core/java/android/service/games/GameSession.java
index 1548f52..0115294 100644
--- a/core/java/android/service/games/GameSession.java
+++ b/core/java/android/service/games/GameSession.java
@@ -426,6 +426,7 @@
      *                 or failed.
      * @throws IllegalStateException if this method is called prior to {@link #onCreate}.
      */
+    @RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY)
     public void takeScreenshot(@NonNull Executor executor, @NonNull ScreenshotCallback callback) {
         if (mGameSessionController == null) {
             throw new IllegalStateException("Can not call before onCreate()");
diff --git a/core/java/android/service/games/GameSessionTrampolineActivity.java b/core/java/android/service/games/GameSessionTrampolineActivity.java
index ddea098..3d97d0f 100644
--- a/core/java/android/service/games/GameSessionTrampolineActivity.java
+++ b/core/java/android/service/games/GameSessionTrampolineActivity.java
@@ -51,7 +51,6 @@
             startActivityAsCaller(
                     getIntent().getParcelableExtra(INTENT_KEY),
                     getIntent().getBundleExtra(OPTIONS_KEY),
-                    null,
                     false,
                     getUserId(),
                     REQUEST_CODE);
diff --git a/core/java/android/service/gatekeeper/GateKeeperResponse.java b/core/java/android/service/gatekeeper/GateKeeperResponse.java
index 7ed733c..9d648a6 100644
--- a/core/java/android/service/gatekeeper/GateKeeperResponse.java
+++ b/core/java/android/service/gatekeeper/GateKeeperResponse.java
@@ -105,7 +105,7 @@
             dest.writeInt(mTimeout);
         } else if (mResponseCode == RESPONSE_OK) {
             dest.writeInt(mShouldReEnroll ? 1 : 0);
-            if (mPayload != null) {
+            if (mPayload != null && mPayload.length > 0) {
                 dest.writeInt(mPayload.length);
                 dest.writeByteArray(mPayload);
             } else {
diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletClient.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletClient.java
index 38659e1..091bf79 100644
--- a/core/java/android/service/quickaccesswallet/QuickAccessWalletClient.java
+++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletClient.java
@@ -42,7 +42,19 @@
      */
     @NonNull
     static QuickAccessWalletClient create(@NonNull Context context) {
-        return new QuickAccessWalletClientImpl(context);
+        return create(context, null /* bgExecutor */);
+    }
+
+    /**
+     * Create a client for accessing wallet cards from the {@link QuickAccessWalletService}. If the
+     * service is unavailable, {@link #isWalletServiceAvailable()} will return false.
+     * @param context Context.
+     * @param bgExecutor A background {@link Executor} for service registration.
+     * @hide
+     */
+    @NonNull
+    static QuickAccessWalletClient create(@NonNull Context context, @Nullable Executor bgExecutor) {
+        return new QuickAccessWalletClientImpl(context, bgExecutor);
     }
 
     /**
diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java
index 95b51ea..a3304a9 100644
--- a/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java
+++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java
@@ -67,6 +67,7 @@
     private final Context mContext;
     private final Queue<ApiCaller> mRequestQueue;
     private final Map<WalletServiceEventListener, String> mEventListeners;
+    private final Executor mLifecycleExecutor;
     private boolean mIsConnected;
     /** Timeout for active service connections (1 minute) */
     private static final long SERVICE_CONNECTION_TIMEOUT_MS = 60 * 1000;
@@ -79,10 +80,11 @@
 
     private static final int MSG_TIMEOUT_SERVICE = 5;
 
-    QuickAccessWalletClientImpl(@NonNull Context context) {
+    QuickAccessWalletClientImpl(@NonNull Context context, @Nullable Executor bgExecutor) {
         mContext = context.getApplicationContext();
         mServiceInfo = QuickAccessWalletServiceInfo.tryCreate(context);
         mHandler = new Handler(Looper.getMainLooper());
+        mLifecycleExecutor = (bgExecutor == null) ? Runnable::run : bgExecutor;
         mRequestQueue = new LinkedList<>();
         mEventListeners = new HashMap<>(1);
     }
@@ -369,7 +371,7 @@
         Intent intent = new Intent(SERVICE_INTERFACE);
         intent.setComponent(mServiceInfo.getComponentName());
         int flags = Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY;
-        mContext.bindService(intent, this, flags);
+        mLifecycleExecutor.execute(() -> mContext.bindService(intent, this, flags));
         resetServiceConnectionTimeout();
     }
 
@@ -411,7 +413,7 @@
             return;
         }
         mIsConnected = false;
-        mContext.unbindService(/*conn=*/ this);
+        mLifecycleExecutor.execute(() -> mContext.unbindService(/*conn=*/ this));
         mService = null;
         mEventListeners.clear();
         mRequestQueue.clear();
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index b507328..0829d28 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -15,18 +15,19 @@
  */
 package android.service.quicksettings;
 
-import android.Manifest;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.app.Dialog;
 import android.app.Service;
+import android.app.StatusBarManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
 import android.graphics.drawable.Icon;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -147,13 +148,6 @@
             "android.service.quicksettings.TOGGLEABLE_TILE";
 
     /**
-     * Used to notify SysUI that Listening has be requested.
-     * @hide
-     */
-    public static final String ACTION_REQUEST_LISTENING =
-            "android.service.quicksettings.action.REQUEST_LISTENING";
-
-    /**
      * @hide
      */
     public static final String EXTRA_SERVICE = "service";
@@ -482,14 +476,24 @@
      *
      * This method is only applicable to tiles that have {@link #META_DATA_ACTIVE_TILE} defined
      * as true on their TileService Manifest declaration, and will do nothing otherwise.
+     *
+     * For apps targeting {@link Build.VERSION_CODES#TIRAMISU} or later, this call may throw
+     * the following exceptions if the request is not valid:
+     * <ul>
+     *     <li> {@link NullPointerException} if {@code component} is {@code null}.</li>
+     *     <li> {@link SecurityException} if the package of {@code component} does not match
+     *     the calling package or if the calling user cannot act on behalf of the user from the
+     *     {@code context}.</li>
+     *     <li> {@link IllegalArgumentException} if the user of the {@code context} is not the
+     *     current user.</li>
+     * </ul>
      */
     public static final void requestListeningState(Context context, ComponentName component) {
-        final ComponentName sysuiComponent = ComponentName.unflattenFromString(
-                context.getResources().getString(
-                        com.android.internal.R.string.config_systemUIServiceComponent));
-        Intent intent = new Intent(ACTION_REQUEST_LISTENING);
-        intent.putExtra(Intent.EXTRA_COMPONENT_NAME, component);
-        intent.setPackage(sysuiComponent.getPackageName());
-        context.sendBroadcast(intent, Manifest.permission.BIND_QUICK_SETTINGS_TILE);
+        StatusBarManager sbm = context.getSystemService(StatusBarManager.class);
+        if (sbm == null) {
+            Log.e(TAG, "No StatusBarManager service found");
+            return;
+        }
+        sbm.requestTileServiceListeningState(component);
     }
 }
diff --git a/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.aidl b/core/java/android/service/trust/GrantTrustResult.aidl
similarity index 82%
copy from packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.aidl
copy to core/java/android/service/trust/GrantTrustResult.aidl
index a56f2f4..d24a6bc 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.aidl
+++ b/core/java/android/service/trust/GrantTrustResult.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.net;
+package android.service.trust;
 
-parcelable UnderlyingNetworkInfo;
+parcelable GrantTrustResult;
diff --git a/core/java/android/service/trust/GrantTrustResult.java b/core/java/android/service/trust/GrantTrustResult.java
new file mode 100644
index 0000000..5b06bb8
--- /dev/null
+++ b/core/java/android/service/trust/GrantTrustResult.java
@@ -0,0 +1,178 @@
+/*
+ * 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 android.service.trust;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Result type for a callback in a call to
+ * {@link TrustAgentService#grantTrust(CharSequence, long, int)}.
+ *
+ * @hide
+ */
+@DataClass
+@SystemApi
+public final class GrantTrustResult implements Parcelable {
+
+    /** Result status is unknown to this version of the SDK. */
+    public static final int STATUS_UNKNOWN = 0;
+
+    /** The device went from locked to unlocked as a result of the call. */
+    public static final int STATUS_UNLOCKED_BY_GRANT = 1;
+
+    /** The status code of the result. */
+    @Status
+    private int mStatus;
+
+
+
+    // Code below generated by codegen v1.0.23.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/trust/GrantTrustResult.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /** @hide */
+    @IntDef(prefix = "STATUS_", value = {
+        STATUS_UNKNOWN,
+        STATUS_UNLOCKED_BY_GRANT
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @DataClass.Generated.Member
+    public @interface Status {}
+
+    @NonNull
+    @DataClass.Generated.Member
+    public static String statusToString(@Status int value) {
+        switch (value) {
+            case STATUS_UNKNOWN:
+                    return "STATUS_UNKNOWN";
+            case STATUS_UNLOCKED_BY_GRANT:
+                    return "STATUS_UNLOCKED_BY_GRANT";
+            default: return Integer.toHexString(value);
+        }
+    }
+
+    /**
+     * Creates a new GrantTrustResult.
+     *
+     * @param status
+     *   The status code of the result.
+     */
+    @DataClass.Generated.Member
+    public GrantTrustResult(
+            @Status int status) {
+        this.mStatus = status;
+
+        if (!(mStatus == STATUS_UNKNOWN)
+                && !(mStatus == STATUS_UNLOCKED_BY_GRANT)) {
+            throw new java.lang.IllegalArgumentException(
+                    "status was " + mStatus + " but must be one of: "
+                            + "STATUS_UNKNOWN(" + STATUS_UNKNOWN + "), "
+                            + "STATUS_UNLOCKED_BY_GRANT(" + STATUS_UNLOCKED_BY_GRANT + ")");
+        }
+
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * The status code of the result.
+     */
+    @DataClass.Generated.Member
+    public @Status int getStatus() {
+        return mStatus;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeInt(mStatus);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ GrantTrustResult(@NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        int status = in.readInt();
+
+        this.mStatus = status;
+
+        if (!(mStatus == STATUS_UNKNOWN)
+                && !(mStatus == STATUS_UNLOCKED_BY_GRANT)) {
+            throw new java.lang.IllegalArgumentException(
+                    "status was " + mStatus + " but must be one of: "
+                            + "STATUS_UNKNOWN(" + STATUS_UNKNOWN + "), "
+                            + "STATUS_UNLOCKED_BY_GRANT(" + STATUS_UNLOCKED_BY_GRANT + ")");
+        }
+
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<GrantTrustResult> CREATOR
+            = new Parcelable.Creator<GrantTrustResult>() {
+        @Override
+        public GrantTrustResult[] newArray(int size) {
+            return new GrantTrustResult[size];
+        }
+
+        @Override
+        public GrantTrustResult createFromParcel(@NonNull android.os.Parcel in) {
+            return new GrantTrustResult(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1648138312806L,
+            codegenVersion = "1.0.23",
+            sourceFile = "frameworks/base/core/java/android/service/trust/GrantTrustResult.java",
+            inputSignatures = "public static final  int STATUS_UNKNOWN\npublic static final  int STATUS_UNLOCKED_BY_GRANT\nprivate @android.service.trust.GrantTrustResult.Status int mStatus\nclass GrantTrustResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/service/trust/ITrustAgentService.aidl b/core/java/android/service/trust/ITrustAgentService.aidl
index ec3b857..70c29a6 100644
--- a/core/java/android/service/trust/ITrustAgentService.aidl
+++ b/core/java/android/service/trust/ITrustAgentService.aidl
@@ -25,7 +25,8 @@
  */
 interface ITrustAgentService {
     oneway void onUnlockAttempt(boolean successful);
-    oneway void onUserRequestedUnlock();
+    oneway void onUserRequestedUnlock(boolean dismissKeyguard);
+    oneway void onUserMayRequestUnlock();
     oneway void onUnlockLockout(int timeoutMs);
     oneway void onTrustTimeout();
     oneway void onDeviceLocked();
diff --git a/core/java/android/service/trust/ITrustAgentServiceCallback.aidl b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
index 6b11e74..e9e40c0 100644
--- a/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
+++ b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
@@ -18,13 +18,15 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.UserHandle;
+import com.android.internal.infra.AndroidFuture;
 
 /**
  * Communication channel from the TrustAgentService back to TrustManagerService.
  * @hide
  */
 oneway interface ITrustAgentServiceCallback {
-    void grantTrust(CharSequence message, long durationMs, int flags);
+    void grantTrust(
+        CharSequence message, long durationMs, int flags, in AndroidFuture resultCallback);
     void revokeTrust();
     void lockUser();
     void setManagingTrust(boolean managingTrust);
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index 8f6e1e0..559313a 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -19,6 +19,7 @@
 import android.Manifest;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
 import android.app.Service;
@@ -39,9 +40,12 @@
 import android.util.Log;
 import android.util.Slog;
 
+import com.android.internal.infra.AndroidFuture;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.List;
+import java.util.function.Consumer;
 
 /**
  * A service that notifies the system about whether it believes the environment of the device
@@ -183,6 +187,7 @@
     private static final int MSG_ESCROW_TOKEN_STATE_RECEIVED = 8;
     private static final int MSG_ESCROW_TOKEN_REMOVED = 9;
     private static final int MSG_USER_REQUESTED_UNLOCK = 10;
+    private static final int MSG_USER_MAY_REQUEST_UNLOCK = 11;
 
     private static final String EXTRA_TOKEN = "token";
     private static final String EXTRA_TOKEN_HANDLE = "token_handle";
@@ -217,7 +222,10 @@
                     onUnlockAttempt(msg.arg1 != 0);
                     break;
                 case MSG_USER_REQUESTED_UNLOCK:
-                    onUserRequestedUnlock();
+                    onUserRequestedUnlock(msg.arg1 != 0);
+                    break;
+                case MSG_USER_MAY_REQUEST_UNLOCK:
+                    onUserMayRequestUnlock();
                     break;
                 case MSG_UNLOCK_LOCKOUT:
                     onDeviceUnlockLockout(msg.arg1);
@@ -297,16 +305,37 @@
     }
 
     /**
+     * Called when the user has interacted with the locked device such that they are likely to want
+     * it to be unlocked soon. This approximates the timing when, for example, the platform would
+     * check for face authentication to unlock the device.
+     *
+     * This signal can be used for the agent to make preparations to quickly unlock the device
+     * with {@link #onUserRequestedUnlock}. Agents should not unlock the device based solely on this
+     * signal. There is no guarantee that this method will be called before
+     * {@link #onUserRequestedUnlock(boolean)}.
+     */
+    public void onUserMayRequestUnlock() {
+    }
+
+    /**
      * Called when the user has interacted with the locked device such that they likely want it
-     * to be unlocked. This approximates the timing when, for example, the platform would check for
-     * face authentication to unlock the device.
+     * to be unlocked.
+     *
+     * When this is called, there is a high probability that the user wants to unlock the device and
+     * that a biometric method is either not available or not the optimal method at this time. For
+     * example, this may be called after some kinds of biometric authentication failure.
+     *
+     * A call to this method may be preceded by a call to {@link #onUserMayRequestUnlock} which
+     * the agent can use as a signal to prepare for a subsequent call to this method.
      *
      * To attempt to unlock the device, the agent needs to call
      * {@link #grantTrust(CharSequence, long, int)}.
      *
+     * @param dismissKeyguard true when the user wants keyguard dismissed
+     *
      * @see #FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE
      */
-    public void onUserRequestedUnlock() {
+    public void onUserRequestedUnlock(boolean dismissKeyguard) {
     }
 
     /**
@@ -399,26 +428,10 @@
     }
 
     /**
-     * Call to grant trust on the device.
+     * Attempts to grant trust on the device.
      *
-     * @param message describes why the device is trusted, e.g. "Trusted by location".
-     * @param durationMs amount of time in milliseconds to keep the device in a trusted state.
-     *    Trust for this agent will automatically be revoked when the timeout expires unless
-     *    extended by a subsequent call to this function. The timeout is measured from the
-     *    invocation of this function as dictated by {@link SystemClock#elapsedRealtime())}.
-     *    For security reasons, the value should be no larger than necessary.
-     *    The value may be adjusted by the system as necessary to comply with a policy controlled
-     *    by the system or {@link DevicePolicyManager} restrictions. See {@link #onTrustTimeout()}
-     *    for determining when trust expires.
-     * @param initiatedByUser this is a hint to the system that trust is being granted as the
-     *    direct result of user action - such as solving a security challenge. The hint is used
-     *    by the system to optimize the experience. Behavior may vary by device and release, so
-     *    one should only set this parameter if it meets the above criteria rather than relying on
-     *    the behavior of any particular device or release. Corresponds to
-     *    {@link #FLAG_GRANT_TRUST_INITIATED_BY_USER}.
-     * @throws IllegalStateException if the agent is not currently managing trust.
-     *
-     * @deprecated use {@link #grantTrust(CharSequence, long, int)} instead.
+     * @param initiatedByUser see {@link #FLAG_GRANT_TRUST_INITIATED_BY_USER}
+     * @deprecated use {@link #grantTrust(CharSequence, long, int, Consumer)} instead.
      */
     @Deprecated
     public final void grantTrust(
@@ -427,7 +440,17 @@
     }
 
     /**
-     * Call to grant trust on the device.
+     * Attempts to grant trust on the device.
+     * @deprecated use {@link #grantTrust(CharSequence, long, int, Consumer)} instead.
+     */
+    @Deprecated
+    public final void grantTrust(
+            final CharSequence message, final long durationMs, @GrantTrustFlags final int flags) {
+        grantTrust(message, durationMs, flags, null);
+    }
+
+    /**
+     * Attempts to grant trust on the device.
      *
      * @param message describes why the device is trusted, e.g. "Trusted by location".
      * @param durationMs amount of time in milliseconds to keep the device in a trusted state.
@@ -438,19 +461,36 @@
      *    The value may be adjusted by the system as necessary to comply with a policy controlled
      *    by the system or {@link DevicePolicyManager} restrictions. See {@link #onTrustTimeout()}
      *    for determining when trust expires.
-     * @param flags TBDocumented
+     * @param flags flags to control call: see constants prefixed by {@code FLAG_GRANT_TRUST_}.
+     * @param resultCallback may be called with the results of the grant
      * @throws IllegalStateException if the agent is not currently managing trust.
+     *
+     * See {@link GrantTrustResult} for the cases where {@code resultCallback} will be called.
      */
     public final void grantTrust(
-            final CharSequence message, final long durationMs, @GrantTrustFlags final int flags) {
+            @NonNull final CharSequence message,
+            final long durationMs,
+            @GrantTrustFlags final int flags,
+            @Nullable final Consumer<GrantTrustResult> resultCallback) {
         synchronized (mLock) {
             if (!mManagingTrust) {
                 throw new IllegalStateException("Cannot grant trust if agent is not managing trust."
                         + " Call setManagingTrust(true) first.");
             }
+
+            // Prepare future for the IPC
+            AndroidFuture<GrantTrustResult> future = new AndroidFuture<>();
+            future.thenAccept(result -> {
+                if (resultCallback != null) {
+                    // Instead of taking an explicit executor, we post this to mHandler to be
+                    // consistent with the other event methods in this class.
+                    mHandler.post(() -> resultCallback.accept(result));
+                }
+            });
+
             if (mCallback != null) {
                 try {
-                    mCallback.grantTrust(message.toString(), durationMs, flags);
+                    mCallback.grantTrust(message.toString(), durationMs, flags, future);
                 } catch (RemoteException e) {
                     onError("calling enableTrust()");
                 }
@@ -460,7 +500,7 @@
                 mPendingGrantTrustTask = new Runnable() {
                     @Override
                     public void run() {
-                        grantTrust(message, durationMs, flags);
+                        grantTrust(message, durationMs, flags, resultCallback);
                     }
                 };
             }
@@ -666,8 +706,14 @@
         }
 
         @Override
-        public void onUserRequestedUnlock() {
-            mHandler.obtainMessage(MSG_USER_REQUESTED_UNLOCK).sendToTarget();
+        public void onUserRequestedUnlock(boolean dismissKeyguard) {
+            mHandler.obtainMessage(MSG_USER_REQUESTED_UNLOCK, dismissKeyguard ? 1 : 0, 0)
+                    .sendToTarget();
+        }
+
+        @Override
+        public void onUserMayRequestUnlock() {
+            mHandler.obtainMessage(MSG_USER_MAY_REQUEST_UNLOCK).sendToTarget();
         }
 
         @Override
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index bec5d1b..bc42da6 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -851,7 +851,8 @@
     @RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD})
     public void triggerHardwareRecognitionEventForTest(int status, int soundModelHandle,
             boolean captureAvailable, int captureSession, int captureDelayMs, int capturePreambleMs,
-            boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data) {
+            boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data,
+            @NonNull List<KeyphraseRecognitionExtra> keyphraseRecognitionExtras) {
         Log.d(TAG, "triggerHardwareRecognitionEventForTest()");
         synchronized (mLock) {
             if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) {
@@ -862,7 +863,8 @@
                 mModelManagementService.triggerHardwareRecognitionEventForTest(
                         new KeyphraseRecognitionEvent(status, soundModelHandle, captureAvailable,
                                 captureSession, captureDelayMs, capturePreambleMs, triggerInData,
-                                captureFormat, data, null /* keyphraseExtras */),
+                                captureFormat, data, keyphraseRecognitionExtras.toArray(
+                                new KeyphraseRecognitionExtra[0])),
                         mInternalCallback);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index a2938a8..c20fc75 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -24,6 +24,7 @@
 import static android.graphics.Matrix.MSKEW_Y;
 import static android.view.SurfaceControl.METADATA_WINDOW_TYPE;
 import static android.view.View.SYSTEM_UI_FLAG_VISIBLE;
+import static android.view.ViewRootImpl.LOCAL_LAYOUT;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 
 import android.animation.Animator;
@@ -39,6 +40,7 @@
 import android.app.WallpaperColors;
 import android.app.WallpaperInfo;
 import android.app.WallpaperManager;
+import android.app.WindowConfiguration;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
@@ -252,10 +254,13 @@
         final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
         final InsetsSourceControl[] mTempControls = new InsetsSourceControl[0];
         final MergedConfiguration mMergedConfiguration = new MergedConfiguration();
+        final Bundle mSyncSeqIdBundle = new Bundle();
         private final Point mSurfaceSize = new Point();
         private final Point mLastSurfaceSize = new Point();
         private final Matrix mTmpMatrix = new Matrix();
         private final float[] mTmpValues = new float[9];
+        private final WindowLayout mWindowLayout = new WindowLayout();
+        private final Rect mTempRect = new Rect();
 
         final WindowManager.LayoutParams mLayout
                 = new WindowManager.LayoutParams();
@@ -391,7 +396,7 @@
             @Override
             public void resized(ClientWindowFrames frames, boolean reportDraw,
                     MergedConfiguration mergedConfiguration, boolean forceLayout,
-                    boolean alwaysConsumeSystemBars, int displayId) {
+                    boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, int resizeMode) {
                 Message msg = mCaller.obtainMessageIO(MSG_WINDOW_RESIZED,
                         reportDraw ? 1 : 0,
                         mergedConfiguration);
@@ -1090,7 +1095,8 @@
                             | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 
                     final Configuration config = mMergedConfiguration.getMergedConfiguration();
-                    final Rect maxBounds = config.windowConfiguration.getMaxBounds();
+                    final WindowConfiguration winConfig = config.windowConfiguration;
+                    final Rect maxBounds = winConfig.getMaxBounds();
                     if (myWidth == ViewGroup.LayoutParams.MATCH_PARENT
                             && myHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
                         mLayout.width = myWidth;
@@ -1148,10 +1154,28 @@
                         mLayout.surfaceInsets.set(0, 0, 0, 0);
                     }
 
-                    final int relayoutResult = mSession.relayout(
-                            mWindow, mLayout, mWidth, mHeight,
-                            View.VISIBLE, 0, mWinFrames, mMergedConfiguration, mSurfaceControl,
-                            mInsetsState, mTempControls);
+                    int relayoutResult = 0;
+                    if (LOCAL_LAYOUT) {
+                        if (!mSurfaceControl.isValid()) {
+                            relayoutResult = mSession.updateVisibility(mWindow, mLayout,
+                                    View.VISIBLE, mMergedConfiguration, mSurfaceControl,
+                                    mInsetsState, mTempControls);
+                        }
+
+                        final Rect displayCutoutSafe = mTempRect;
+                        mInsetsState.getDisplayCutoutSafe(displayCutoutSafe);
+                        mWindowLayout.computeFrames(mLayout, mInsetsState, displayCutoutSafe,
+                                winConfig.getBounds(), winConfig.getWindowingMode(), mWidth,
+                                mHeight, mRequestedVisibilities, null /* attachedWindowFrame */,
+                                1f /* compatScale */, mWinFrames);
+
+                        mSession.updateLayout(mWindow, mLayout, 0 /* flags */, mWinFrames, mWidth,
+                                mHeight);
+                    } else {
+                        relayoutResult = mSession.relayout(mWindow, mLayout, mWidth, mHeight,
+                                View.VISIBLE, 0, mWinFrames, mMergedConfiguration,
+                                mSurfaceControl, mInsetsState, mTempControls, mSyncSeqIdBundle);
+                    }
 
                     final int transformHint = SurfaceControl.rotationToBufferTransform(
                             (mDisplayInstallOrientation + mDisplay.getRotation()) % 4);
@@ -1201,7 +1225,7 @@
                             null /* ignoringVisibilityState */, config.isScreenRound(),
                             false /* alwaysConsumeSystemBars */, mLayout.softInputMode,
                             mLayout.flags, SYSTEM_UI_FLAG_VISIBLE, mLayout.type,
-                            config.windowConfiguration.getWindowingMode(), null /* typeSideMap */);
+                            winConfig.getWindowingMode(), null /* typeSideMap */);
 
                     if (!fixedSize) {
                         final Rect padding = mIWallpaperEngine.mDisplayPadding;
@@ -1338,7 +1362,8 @@
                         mSurfaceCreated = true;
                         if (redrawNeeded) {
                             resetWindowPages();
-                            mSession.finishDrawing(mWindow, null /* postDrawTransaction */);
+                            mSession.finishDrawing(mWindow, null /* postDrawTransaction */,
+                                                   Integer.MAX_VALUE);
                             processLocalColors(mPendingXOffset, mPendingXOffsetStep);
                             notifyColorsChanged();
                         }
diff --git a/core/java/android/speech/RecognitionSupport.java b/core/java/android/speech/RecognitionSupport.java
index 43c8e1b..60c3b63 100644
--- a/core/java/android/speech/RecognitionSupport.java
+++ b/core/java/android/speech/RecognitionSupport.java
@@ -17,6 +17,8 @@
 package android.speech;
 
 import android.annotation.NonNull;
+import android.content.Context;
+import android.content.Intent;
 import android.os.Parcelable;
 
 import com.android.internal.util.DataClass;
@@ -34,19 +36,63 @@
 )
 public final class RecognitionSupport implements Parcelable {
 
+    /**
+     * Support for this request is ready for use on this device for the returned languages.
+     *
+     * @deprecated See {@link #getInstalledOnDeviceLanguages()}.
+     */
+    @NonNull
+    @Deprecated
+    @DataClass.PluralOf("installedLanguage")
+    private List<String> mInstalledLanguages = List.of();
+
+    /**
+     * Support for this request is scheduled for download for the returned languages.
+     *
+     * @deprecated See {@link #getPendingOnDeviceLanguages()}.
+     */
+    @NonNull
+    @Deprecated
+    @DataClass.PluralOf("pendingLanguage")
+    private List<String> mPendingLanguages = List.of();
+
+    /**
+     * These languages are supported but need to be downloaded before use. See {@link
+     * SpeechRecognizer#triggerModelDownload(Intent)}.
+     *
+     * @deprecated See {@link #getSupportedOnDeviceLanguages()}.
+     */
+    @NonNull
+    @Deprecated
+    @DataClass.PluralOf("supportedLanguage")
+    private List<String> mSupportedLanguages = List.of();
+
     /** Support for this request is ready for use on this device for the returned languages. */
     @NonNull
-    @DataClass.PluralOf("installedLanguage")
-    private List<String> mInstalledLanguages = null;
+    @DataClass.PluralOf("installedOnDeviceLanguage")
+    private List<String> mInstalledOnDeviceLanguages = List.of();
 
     /** Support for this request is scheduled for download for the returned languages. */
-    @DataClass.PluralOf("pendingLanguage")
-    @NonNull private List<String> mPendingLanguages = null;
-
-    /** These languages are supported but need to be downloaded before use. */
     @NonNull
-    @DataClass.PluralOf("supportedLanguage")
-    private List<String> mSupportedLanguages = null;
+    @DataClass.PluralOf("pendingOnDeviceLanguage")
+    private List<String> mPendingOnDeviceLanguages = List.of();
+
+    /**
+     * These languages are supported but need to be downloaded before use. See {@link
+     * SpeechRecognizer#triggerModelDownload(Intent)}.
+     */
+    @NonNull
+    @DataClass.PluralOf("supportedOnDeviceLanguage")
+    private List<String> mSupportedOnDeviceLanguages = List.of();
+
+    /**
+     * Support for this request is available via a remote implementation. {@link SpeechRecognizer}
+     * created via {@link SpeechRecognizer#createOnDeviceSpeechRecognizer(Context)} are expected to
+     * return an empty list.
+     */
+    @NonNull
+    @DataClass.PluralOf("onlineLanguage")
+    private List<String> mOnlineLanguages = List.of();
 
 
 
@@ -65,44 +111,108 @@
 
     @DataClass.Generated.Member
     /* package-private */ RecognitionSupport(
-            @NonNull List<String> installedLanguages,
-            @NonNull List<String> pendingLanguages,
-            @NonNull List<String> supportedLanguages) {
+            @NonNull @Deprecated List<String> installedLanguages,
+            @NonNull @Deprecated List<String> pendingLanguages,
+            @NonNull @Deprecated List<String> supportedLanguages,
+            @NonNull List<String> installedOnDeviceLanguages,
+            @NonNull List<String> pendingOnDeviceLanguages,
+            @NonNull List<String> supportedOnDeviceLanguages,
+            @NonNull List<String> onlineLanguages) {
         this.mInstalledLanguages = installedLanguages;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mInstalledLanguages);
+        com.android.internal.util.AnnotationValidations.validate(
+                Deprecated.class, null, mInstalledLanguages);
         this.mPendingLanguages = pendingLanguages;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mPendingLanguages);
+        com.android.internal.util.AnnotationValidations.validate(
+                Deprecated.class, null, mPendingLanguages);
         this.mSupportedLanguages = supportedLanguages;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mSupportedLanguages);
+        com.android.internal.util.AnnotationValidations.validate(
+                Deprecated.class, null, mSupportedLanguages);
+        this.mInstalledOnDeviceLanguages = installedOnDeviceLanguages;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mInstalledOnDeviceLanguages);
+        this.mPendingOnDeviceLanguages = pendingOnDeviceLanguages;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mPendingOnDeviceLanguages);
+        this.mSupportedOnDeviceLanguages = supportedOnDeviceLanguages;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mSupportedOnDeviceLanguages);
+        this.mOnlineLanguages = onlineLanguages;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mOnlineLanguages);
 
         // onConstructed(); // You can define this method to get a callback
     }
 
     /**
      * Support for this request is ready for use on this device for the returned languages.
+     *
+     * @deprecated See {@link #getInstalledOnDeviceLanguages()}.
      */
     @DataClass.Generated.Member
-    public @NonNull List<String> getInstalledLanguages() {
+    @NonNull @Deprecated public List<String> getInstalledLanguages() {
         return mInstalledLanguages;
     }
 
     /**
      * Support for this request is scheduled for download for the returned languages.
+     *
+     * @deprecated See {@link #getPendingOnDeviceLanguages()}.
+     */
+    @DataClass.Generated.Member
+    @NonNull @Deprecated public List<String> getPendingLanguages() {
+        return mPendingLanguages;
+    }
+
+    /**
+     * These languages are supported but need to be downloaded before use. See {@link
+     * SpeechRecognizer#triggerModelDownload(Intent)}.
+     *
+     * @deprecated See {@link #getSupportedOnDeviceLanguages()}.
+     */
+    @DataClass.Generated.Member
+    @NonNull @Deprecated public List<String> getSupportedLanguages() {
+        return mSupportedLanguages;
+    }
+
+    /**
+     * Support for this request is ready for use on this device for the returned languages.
+     */
+    @DataClass.Generated.Member
+    public @NonNull List<String> getInstalledOnDeviceLanguages() {
+        return mInstalledOnDeviceLanguages;
+    }
+
+    /**
+     * Support for this request is scheduled for download for the returned languages.
      */
     @DataClass.Generated.Member
-    public @NonNull List<String> getPendingLanguages() {
-        return mPendingLanguages;
+    public @NonNull List<String> getPendingOnDeviceLanguages() {
+        return mPendingOnDeviceLanguages;
     }
 
     /**
-     * These languages are supported but need to be downloaded before use.
+     * These languages are supported but need to be downloaded before use. See {@link
+     * SpeechRecognizer#triggerModelDownload(Intent)}.
      */
     @DataClass.Generated.Member
-    public @NonNull List<String> getSupportedLanguages() {
-        return mSupportedLanguages;
+    public @NonNull List<String> getSupportedOnDeviceLanguages() {
+        return mSupportedOnDeviceLanguages;
+    }
+
+    /**
+     * Support for this request is available via a remote implementation. {@link SpeechRecognizer}
+     * created via {@link SpeechRecognizer#createOnDeviceSpeechRecognizer(Context)} are expected to
+     * return an empty list.
+     */
+    @DataClass.Generated.Member
+    public @NonNull List<String> getOnlineLanguages() {
+        return mOnlineLanguages;
     }
 
     @Override
@@ -114,7 +224,11 @@
         return "RecognitionSupport { " +
                 "installedLanguages = " + mInstalledLanguages + ", " +
                 "pendingLanguages = " + mPendingLanguages + ", " +
-                "supportedLanguages = " + mSupportedLanguages +
+                "supportedLanguages = " + mSupportedLanguages + ", " +
+                "installedOnDeviceLanguages = " + mInstalledOnDeviceLanguages + ", " +
+                "pendingOnDeviceLanguages = " + mPendingOnDeviceLanguages + ", " +
+                "supportedOnDeviceLanguages = " + mSupportedOnDeviceLanguages + ", " +
+                "onlineLanguages = " + mOnlineLanguages +
         " }";
     }
 
@@ -133,7 +247,11 @@
         return true
                 && java.util.Objects.equals(mInstalledLanguages, that.mInstalledLanguages)
                 && java.util.Objects.equals(mPendingLanguages, that.mPendingLanguages)
-                && java.util.Objects.equals(mSupportedLanguages, that.mSupportedLanguages);
+                && java.util.Objects.equals(mSupportedLanguages, that.mSupportedLanguages)
+                && java.util.Objects.equals(mInstalledOnDeviceLanguages, that.mInstalledOnDeviceLanguages)
+                && java.util.Objects.equals(mPendingOnDeviceLanguages, that.mPendingOnDeviceLanguages)
+                && java.util.Objects.equals(mSupportedOnDeviceLanguages, that.mSupportedOnDeviceLanguages)
+                && java.util.Objects.equals(mOnlineLanguages, that.mOnlineLanguages);
     }
 
     @Override
@@ -146,6 +264,10 @@
         _hash = 31 * _hash + java.util.Objects.hashCode(mInstalledLanguages);
         _hash = 31 * _hash + java.util.Objects.hashCode(mPendingLanguages);
         _hash = 31 * _hash + java.util.Objects.hashCode(mSupportedLanguages);
+        _hash = 31 * _hash + java.util.Objects.hashCode(mInstalledOnDeviceLanguages);
+        _hash = 31 * _hash + java.util.Objects.hashCode(mPendingOnDeviceLanguages);
+        _hash = 31 * _hash + java.util.Objects.hashCode(mSupportedOnDeviceLanguages);
+        _hash = 31 * _hash + java.util.Objects.hashCode(mOnlineLanguages);
         return _hash;
     }
 
@@ -158,6 +280,10 @@
         dest.writeStringList(mInstalledLanguages);
         dest.writeStringList(mPendingLanguages);
         dest.writeStringList(mSupportedLanguages);
+        dest.writeStringList(mInstalledOnDeviceLanguages);
+        dest.writeStringList(mPendingOnDeviceLanguages);
+        dest.writeStringList(mSupportedOnDeviceLanguages);
+        dest.writeStringList(mOnlineLanguages);
     }
 
     @Override
@@ -177,16 +303,42 @@
         in.readStringList(pendingLanguages);
         List<String> supportedLanguages = new java.util.ArrayList<>();
         in.readStringList(supportedLanguages);
+        List<String> installedOnDeviceLanguages = new java.util.ArrayList<>();
+        in.readStringList(installedOnDeviceLanguages);
+        List<String> pendingOnDeviceLanguages = new java.util.ArrayList<>();
+        in.readStringList(pendingOnDeviceLanguages);
+        List<String> supportedOnDeviceLanguages = new java.util.ArrayList<>();
+        in.readStringList(supportedOnDeviceLanguages);
+        List<String> onlineLanguages = new java.util.ArrayList<>();
+        in.readStringList(onlineLanguages);
 
         this.mInstalledLanguages = installedLanguages;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mInstalledLanguages);
+        com.android.internal.util.AnnotationValidations.validate(
+                Deprecated.class, null, mInstalledLanguages);
         this.mPendingLanguages = pendingLanguages;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mPendingLanguages);
+        com.android.internal.util.AnnotationValidations.validate(
+                Deprecated.class, null, mPendingLanguages);
         this.mSupportedLanguages = supportedLanguages;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mSupportedLanguages);
+        com.android.internal.util.AnnotationValidations.validate(
+                Deprecated.class, null, mSupportedLanguages);
+        this.mInstalledOnDeviceLanguages = installedOnDeviceLanguages;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mInstalledOnDeviceLanguages);
+        this.mPendingOnDeviceLanguages = pendingOnDeviceLanguages;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mPendingOnDeviceLanguages);
+        this.mSupportedOnDeviceLanguages = supportedOnDeviceLanguages;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mSupportedOnDeviceLanguages);
+        this.mOnlineLanguages = onlineLanguages;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mOnlineLanguages);
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -212,9 +364,13 @@
     @DataClass.Generated.Member
     public static final class Builder {
 
-        private @NonNull List<String> mInstalledLanguages;
-        private @NonNull List<String> mPendingLanguages;
-        private @NonNull List<String> mSupportedLanguages;
+        private @NonNull @Deprecated List<String> mInstalledLanguages;
+        private @NonNull @Deprecated List<String> mPendingLanguages;
+        private @NonNull @Deprecated List<String> mSupportedLanguages;
+        private @NonNull List<String> mInstalledOnDeviceLanguages;
+        private @NonNull List<String> mPendingOnDeviceLanguages;
+        private @NonNull List<String> mSupportedOnDeviceLanguages;
+        private @NonNull List<String> mOnlineLanguages;
 
         private long mBuilderFieldsSet = 0L;
 
@@ -223,9 +379,12 @@
 
         /**
          * Support for this request is ready for use on this device for the returned languages.
+         *
+         * @deprecated See {@link #getInstalledOnDeviceLanguages()}.
          */
         @DataClass.Generated.Member
-        public @NonNull Builder setInstalledLanguages(@NonNull List<String> value) {
+        @Deprecated @NonNull
+        public Builder setInstalledLanguages(@NonNull @Deprecated List<String> value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x1;
             mInstalledLanguages = value;
@@ -234,7 +393,8 @@
 
         /** @see #setInstalledLanguages */
         @DataClass.Generated.Member
-        public @NonNull Builder addInstalledLanguage(@NonNull String value) {
+        @Deprecated @NonNull
+        public Builder addInstalledLanguage(@NonNull String value) {
             if (mInstalledLanguages == null) setInstalledLanguages(new java.util.ArrayList<>());
             mInstalledLanguages.add(value);
             return this;
@@ -242,9 +402,12 @@
 
         /**
          * Support for this request is scheduled for download for the returned languages.
+         *
+         * @deprecated See {@link #getPendingOnDeviceLanguages()}.
          */
         @DataClass.Generated.Member
-        public @NonNull Builder setPendingLanguages(@NonNull List<String> value) {
+        @Deprecated @NonNull
+        public Builder setPendingLanguages(@NonNull @Deprecated List<String> value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x2;
             mPendingLanguages = value;
@@ -253,17 +416,22 @@
 
         /** @see #setPendingLanguages */
         @DataClass.Generated.Member
-        public @NonNull Builder addPendingLanguage(@NonNull String value) {
+        @Deprecated @NonNull
+        public Builder addPendingLanguage(@NonNull String value) {
             if (mPendingLanguages == null) setPendingLanguages(new java.util.ArrayList<>());
             mPendingLanguages.add(value);
             return this;
         }
 
         /**
-         * These languages are supported but need to be downloaded before use.
+         * These languages are supported but need to be downloaded before use. See {@link
+         * SpeechRecognizer#triggerModelDownload(Intent)}.
+         *
+         * @deprecated See {@link #getSupportedOnDeviceLanguages()}.
          */
         @DataClass.Generated.Member
-        public @NonNull Builder setSupportedLanguages(@NonNull List<String> value) {
+        @Deprecated @NonNull
+        public Builder setSupportedLanguages(@NonNull @Deprecated List<String> value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x4;
             mSupportedLanguages = value;
@@ -272,35 +440,131 @@
 
         /** @see #setSupportedLanguages */
         @DataClass.Generated.Member
-        public @NonNull Builder addSupportedLanguage(@NonNull String value) {
+        @Deprecated @NonNull
+        public Builder addSupportedLanguage(@NonNull String value) {
             if (mSupportedLanguages == null) setSupportedLanguages(new java.util.ArrayList<>());
             mSupportedLanguages.add(value);
             return this;
         }
 
+        /**
+         * Support for this request is ready for use on this device for the returned languages.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setInstalledOnDeviceLanguages(@NonNull List<String> value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x8;
+            mInstalledOnDeviceLanguages = value;
+            return this;
+        }
+
+        /** @see #setInstalledOnDeviceLanguages */
+        @DataClass.Generated.Member
+        public @NonNull Builder addInstalledOnDeviceLanguage(@NonNull String value) {
+            if (mInstalledOnDeviceLanguages == null) setInstalledOnDeviceLanguages(new java.util.ArrayList<>());
+            mInstalledOnDeviceLanguages.add(value);
+            return this;
+        }
+
+        /**
+         * Support for this request is scheduled for download for the returned languages.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setPendingOnDeviceLanguages(@NonNull List<String> value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x10;
+            mPendingOnDeviceLanguages = value;
+            return this;
+        }
+
+        /** @see #setPendingOnDeviceLanguages */
+        @DataClass.Generated.Member
+        public @NonNull Builder addPendingOnDeviceLanguage(@NonNull String value) {
+            if (mPendingOnDeviceLanguages == null) setPendingOnDeviceLanguages(new java.util.ArrayList<>());
+            mPendingOnDeviceLanguages.add(value);
+            return this;
+        }
+
+        /**
+         * These languages are supported but need to be downloaded before use. See {@link
+         * SpeechRecognizer#triggerModelDownload(Intent)}.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setSupportedOnDeviceLanguages(@NonNull List<String> value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x20;
+            mSupportedOnDeviceLanguages = value;
+            return this;
+        }
+
+        /** @see #setSupportedOnDeviceLanguages */
+        @DataClass.Generated.Member
+        public @NonNull Builder addSupportedOnDeviceLanguage(@NonNull String value) {
+            if (mSupportedOnDeviceLanguages == null) setSupportedOnDeviceLanguages(new java.util.ArrayList<>());
+            mSupportedOnDeviceLanguages.add(value);
+            return this;
+        }
+
+        /**
+         * Support for this request is available via a remote implementation. {@link SpeechRecognizer}
+         * created via {@link SpeechRecognizer#createOnDeviceSpeechRecognizer(Context)} are expected to
+         * return an empty list.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setOnlineLanguages(@NonNull List<String> value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x40;
+            mOnlineLanguages = value;
+            return this;
+        }
+
+        /** @see #setOnlineLanguages */
+        @DataClass.Generated.Member
+        public @NonNull Builder addOnlineLanguage(@NonNull String value) {
+            if (mOnlineLanguages == null) setOnlineLanguages(new java.util.ArrayList<>());
+            mOnlineLanguages.add(value);
+            return this;
+        }
+
         /** Builds the instance. This builder should not be touched after calling this! */
         public @NonNull RecognitionSupport build() {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x8; // Mark builder used
+            mBuilderFieldsSet |= 0x80; // Mark builder used
 
             if ((mBuilderFieldsSet & 0x1) == 0) {
-                mInstalledLanguages = null;
+                mInstalledLanguages = List.of();
             }
             if ((mBuilderFieldsSet & 0x2) == 0) {
-                mPendingLanguages = null;
+                mPendingLanguages = List.of();
             }
             if ((mBuilderFieldsSet & 0x4) == 0) {
-                mSupportedLanguages = null;
+                mSupportedLanguages = List.of();
+            }
+            if ((mBuilderFieldsSet & 0x8) == 0) {
+                mInstalledOnDeviceLanguages = List.of();
+            }
+            if ((mBuilderFieldsSet & 0x10) == 0) {
+                mPendingOnDeviceLanguages = List.of();
+            }
+            if ((mBuilderFieldsSet & 0x20) == 0) {
+                mSupportedOnDeviceLanguages = List.of();
+            }
+            if ((mBuilderFieldsSet & 0x40) == 0) {
+                mOnlineLanguages = List.of();
             }
             RecognitionSupport o = new RecognitionSupport(
                     mInstalledLanguages,
                     mPendingLanguages,
-                    mSupportedLanguages);
+                    mSupportedLanguages,
+                    mInstalledOnDeviceLanguages,
+                    mPendingOnDeviceLanguages,
+                    mSupportedOnDeviceLanguages,
+                    mOnlineLanguages);
             return o;
         }
 
         private void checkNotUsed() {
-            if ((mBuilderFieldsSet & 0x8) != 0) {
+            if ((mBuilderFieldsSet & 0x80) != 0) {
                 throw new IllegalStateException(
                         "This Builder should not be reused. Use a new Builder instance instead");
             }
@@ -308,10 +572,10 @@
     }
 
     @DataClass.Generated(
-            time = 1644582623366L,
+            time = 1647890081869L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/speech/RecognitionSupport.java",
-            inputSignatures = "private @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"installedLanguage\") java.util.List<java.lang.String> mInstalledLanguages\nprivate @com.android.internal.util.DataClass.PluralOf(\"pendingLanguage\") @android.annotation.NonNull java.util.List<java.lang.String> mPendingLanguages\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"supportedLanguage\") java.util.List<java.lang.String> mSupportedLanguages\nclass RecognitionSupport extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
+            inputSignatures = "private @android.annotation.NonNull @java.lang.Deprecated @com.android.internal.util.DataClass.PluralOf(\"installedLanguage\") java.util.List<java.lang.String> mInstalledLanguages\nprivate @android.annotation.NonNull @java.lang.Deprecated @com.android.internal.util.DataClass.PluralOf(\"pendingLanguage\") java.util.List<java.lang.String> mPendingLanguages\nprivate @android.annotation.NonNull @java.lang.Deprecated @com.android.internal.util.DataClass.PluralOf(\"supportedLanguage\") java.util.List<java.lang.String> mSupportedLanguages\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"installedOnDeviceLanguage\") java.util.List<java.lang.String> mInstalledOnDeviceLanguages\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"pendingOnDeviceLanguage\") java.util.List<java.lang.String> mPendingOnDeviceLanguages\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"supportedOnDeviceLanguage\") java.util.List<java.lang.String> mSupportedOnDeviceLanguages\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"onlineLanguage\") java.util.List<java.lang.String> mOnlineLanguages\nclass RecognitionSupport extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index c1fcd66..a3696e3 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -27,6 +27,7 @@
 import android.os.Build;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.service.carrier.CarrierService;
 import android.telephony.Annotation.CallState;
 import android.telephony.Annotation.DataActivityType;
 import android.telephony.Annotation.DisconnectCauses;
@@ -36,7 +37,7 @@
 import android.telephony.Annotation.RadioPowerState;
 import android.telephony.Annotation.SimActivationState;
 import android.telephony.Annotation.SrvccState;
-import android.telephony.TelephonyManager.CarrierPrivilegesListener;
+import android.telephony.TelephonyManager.CarrierPrivilegesCallback;
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.ims.ImsReasonInfo;
 import android.util.ArraySet;
@@ -44,17 +45,19 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.listeners.ListenerExecutor;
-import com.android.internal.telephony.ICarrierPrivilegesListener;
+import com.android.internal.telephony.ICarrierPrivilegesCallback;
 import com.android.internal.telephony.IOnSubscriptionsChangedListener;
 import com.android.internal.telephony.ITelephonyRegistry;
 
 import java.lang.ref.WeakReference;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.WeakHashMap;
 import java.util.concurrent.Executor;
+import java.util.stream.Collectors;
 
 /**
  * A centralized place to notify telephony related status changes, e.g, {@link ServiceState} update
@@ -1260,63 +1263,79 @@
                 pkgName, attributionTag, callback, new int[0], notifyNow);
     }
 
-    private static class CarrierPrivilegesListenerWrapper extends ICarrierPrivilegesListener.Stub
+    private static class CarrierPrivilegesCallbackWrapper extends ICarrierPrivilegesCallback.Stub
             implements ListenerExecutor {
-        private final WeakReference<CarrierPrivilegesListener> mListener;
-        private final Executor mExecutor;
+        @NonNull private final WeakReference<CarrierPrivilegesCallback> mCallback;
+        @NonNull private final Executor mExecutor;
 
-        CarrierPrivilegesListenerWrapper(CarrierPrivilegesListener listener, Executor executor) {
-            mListener = new WeakReference<>(listener);
+        CarrierPrivilegesCallbackWrapper(
+                @NonNull CarrierPrivilegesCallback callback, @NonNull Executor executor) {
+            mCallback = new WeakReference<>(callback);
             mExecutor = executor;
         }
 
         @Override
         public void onCarrierPrivilegesChanged(
-                List<String> privilegedPackageNames, int[] privilegedUids) {
+                @NonNull List<String> privilegedPackageNames, @NonNull int[] privilegedUids) {
+            // AIDL interface does not support Set, keep the List/Array and translate them here
+            Set<String> privilegedPkgNamesSet = Set.copyOf(privilegedPackageNames);
+            Set<Integer> privilegedUidsSet = Arrays.stream(privilegedUids).boxed().collect(
+                    Collectors.toSet());
             Binder.withCleanCallingIdentity(
                     () ->
                             executeSafely(
                                     mExecutor,
-                                    mListener::get,
-                                    cpl ->
-                                            cpl.onCarrierPrivilegesChanged(
-                                                    privilegedPackageNames, privilegedUids)));
+                                    mCallback::get,
+                                    cpc ->
+                                            cpc.onCarrierPrivilegesChanged(
+                                                    privilegedPkgNamesSet, privilegedUidsSet)));
+        }
+
+        @Override
+        public void onCarrierServiceChanged(@Nullable String packageName, int uid) {
+            Binder.withCleanCallingIdentity(
+                    () ->
+                            executeSafely(
+                                    mExecutor,
+                                    mCallback::get,
+                                    cpc -> cpc.onCarrierServiceChanged(packageName, uid)));
         }
     }
 
-    @GuardedBy("sCarrierPrivilegeListeners")
-    private static final WeakHashMap<
-                    CarrierPrivilegesListener, WeakReference<CarrierPrivilegesListenerWrapper>>
-            sCarrierPrivilegeListeners = new WeakHashMap<>();
+    @NonNull
+    @GuardedBy("sCarrierPrivilegeCallbacks")
+    private static final WeakHashMap<CarrierPrivilegesCallback,
+            WeakReference<CarrierPrivilegesCallbackWrapper>>
+            sCarrierPrivilegeCallbacks = new WeakHashMap<>();
 
     /**
-     * Registers a {@link CarrierPrivilegesListener} on the given {@code logicalSlotIndex} to
+     * Registers a {@link CarrierPrivilegesCallback} on the given {@code logicalSlotIndex} to
      * receive callbacks when the set of packages with carrier privileges changes. The callback will
      * immediately be called with the latest state.
      *
      * @param logicalSlotIndex The SIM slot to listen on
      * @param executor The executor where {@code listener} will be invoked
-     * @param listener The callback to register
+     * @param callback The callback to register
      */
-    public void addCarrierPrivilegesListener(
+    public void addCarrierPrivilegesCallback(
             int logicalSlotIndex,
             @NonNull @CallbackExecutor Executor executor,
-            @NonNull CarrierPrivilegesListener listener) {
-        if (listener == null || executor == null) {
-            throw new IllegalArgumentException("listener and executor must be non-null");
+            @NonNull CarrierPrivilegesCallback callback) {
+        if (callback == null || executor == null) {
+            throw new IllegalArgumentException("callback and executor must be non-null");
         }
-        synchronized (sCarrierPrivilegeListeners) {
-            WeakReference<CarrierPrivilegesListenerWrapper> existing =
-                    sCarrierPrivilegeListeners.get(listener);
+        synchronized (sCarrierPrivilegeCallbacks) {
+            WeakReference<CarrierPrivilegesCallbackWrapper> existing =
+                    sCarrierPrivilegeCallbacks.get(callback);
             if (existing != null && existing.get() != null) {
-                Log.d(TAG, "addCarrierPrivilegesListener: listener already registered");
+                Log.d(TAG, "addCarrierPrivilegesCallback: callback already registered");
                 return;
             }
-            CarrierPrivilegesListenerWrapper wrapper =
-                    new CarrierPrivilegesListenerWrapper(listener, executor);
-            sCarrierPrivilegeListeners.put(listener, new WeakReference<>(wrapper));
+            CarrierPrivilegesCallbackWrapper wrapper =
+                    new CarrierPrivilegesCallbackWrapper(callback, executor);
+            sCarrierPrivilegeCallbacks.put(callback, new WeakReference<>(wrapper));
             try {
-                sRegistry.addCarrierPrivilegesListener(
+                sRegistry.addCarrierPrivilegesCallback(
                         logicalSlotIndex,
                         wrapper,
                         mContext.getOpPackageName(),
@@ -1328,22 +1347,22 @@
     }
 
     /**
-     * Unregisters a {@link CarrierPrivilegesListener}.
+     * Unregisters a {@link CarrierPrivilegesCallback}.
      *
-     * @param listener The callback to unregister
+     * @param callback The callback to unregister
      */
-    public void removeCarrierPrivilegesListener(@NonNull CarrierPrivilegesListener listener) {
-        if (listener == null) {
+    public void removeCarrierPrivilegesCallback(@NonNull CarrierPrivilegesCallback callback) {
+        if (callback == null) {
             throw new IllegalArgumentException("listener must be non-null");
         }
-        synchronized (sCarrierPrivilegeListeners) {
-            WeakReference<CarrierPrivilegesListenerWrapper> ref =
-                    sCarrierPrivilegeListeners.remove(listener);
+        synchronized (sCarrierPrivilegeCallbacks) {
+            WeakReference<CarrierPrivilegesCallbackWrapper> ref =
+                    sCarrierPrivilegeCallbacks.remove(callback);
             if (ref == null) return;
-            CarrierPrivilegesListenerWrapper wrapper = ref.get();
+            CarrierPrivilegesCallbackWrapper wrapper = ref.get();
             if (wrapper == null) return;
             try {
-                sRegistry.removeCarrierPrivilegesListener(wrapper, mContext.getOpPackageName());
+                sRegistry.removeCarrierPrivilegesCallback(wrapper, mContext.getOpPackageName());
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -1359,15 +1378,33 @@
      */
     public void notifyCarrierPrivilegesChanged(
             int logicalSlotIndex,
-            @NonNull List<String> privilegedPackageNames,
-            @NonNull int[] privilegedUids) {
+            @NonNull Set<String> privilegedPackageNames,
+            @NonNull Set<Integer> privilegedUids) {
         if (privilegedPackageNames == null || privilegedUids == null) {
             throw new IllegalArgumentException(
                     "privilegedPackageNames and privilegedUids must be non-null");
         }
         try {
-            sRegistry.notifyCarrierPrivilegesChanged(
-                    logicalSlotIndex, privilegedPackageNames, privilegedUids);
+            // AIDL doesn't support Set yet. Convert Set to List/Array
+            List<String> pkgList = List.copyOf(privilegedPackageNames);
+            int[] uids = privilegedUids.stream().mapToInt(Number::intValue).toArray();
+            sRegistry.notifyCarrierPrivilegesChanged(logicalSlotIndex, pkgList, uids);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Notify listeners that the {@link CarrierService} for current user has changed.
+     *
+     * @param logicalSlotIndex the SIM slot the change occurred on
+     * @param packageName the package name of the changed {@link CarrierService}
+     * @param uid the UID of the changed {@link CarrierService}
+     */
+    public void notifyCarrierServiceChanged(int logicalSlotIndex, @Nullable String packageName,
+            int uid) {
+        try {
+            sRegistry.notifyCarrierServiceChanged(logicalSlotIndex, packageName, uid);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java
index fee23f4..9ed57c3 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -103,7 +103,7 @@
      * @param includePad set whether to include extra space beyond font ascent and descent which is
      *                   needed to avoid clipping in some scripts
      * @param ellipsize whether to ellipsize the text if width of the text is longer than the
-     *                  requested width
+     *                  requested width. null if ellipsis is not applied.
      * @param ellipsizedWidth the width to which this Layout is ellipsizing. If {@code ellipsize} is
      *                        {@code null}, or is {@link TextUtils.TruncateAt#MARQUEE} this value is
      *                        not used, {@code outerWidth} is used instead
@@ -116,7 +116,7 @@
             @NonNull CharSequence source, @NonNull TextPaint paint,
             @IntRange(from = 0) int outerWidth,
             @NonNull Alignment align, @NonNull BoringLayout.Metrics metrics,
-            boolean includePad, @NonNull TextUtils.TruncateAt ellipsize,
+            boolean includePad, @Nullable TextUtils.TruncateAt ellipsize,
             @IntRange(from = 0) int ellipsizedWidth, boolean useFallbackLineSpacing) {
         return new BoringLayout(source, paint, outerWidth, align, 1f, 0f, metrics, includePad,
                 ellipsize, ellipsizedWidth, useFallbackLineSpacing);
@@ -146,6 +146,7 @@
         mEllipsizedWidth = outerwidth;
         mEllipsizedStart = 0;
         mEllipsizedCount = 0;
+        mUseFallbackLineSpacing = false;
 
         init(source, paint, align, metrics, includePad, true, false /* useFallbackLineSpacing */);
         return this;
@@ -169,7 +170,7 @@
      * @param includePad set whether to include extra space beyond font ascent and descent which is
      *                   needed to avoid clipping in some scripts
      * @param ellipsize whether to ellipsize the text if width of the text is longer than the
-     *                  requested width
+     *                  requested width. null if ellipsis not applied.
      * @param ellipsizedWidth the width to which this Layout is ellipsizing. If {@code ellipsize} is
      *                        {@code null}, or is {@link TextUtils.TruncateAt#MARQUEE} this value is
      *                        not used, {@code outerWidth} is used instead
@@ -181,7 +182,7 @@
     public @NonNull BoringLayout replaceOrMake(@NonNull CharSequence source,
             @NonNull TextPaint paint, @IntRange(from = 0) int outerWidth,
             @NonNull Alignment align, @NonNull BoringLayout.Metrics metrics, boolean includePad,
-            @NonNull TextUtils.TruncateAt ellipsize, @IntRange(from = 0) int ellipsizedWidth,
+            @Nullable TextUtils.TruncateAt ellipsize, @IntRange(from = 0) int ellipsizedWidth,
             boolean useFallbackLineSpacing) {
         boolean trust;
 
@@ -200,6 +201,8 @@
             trust = false;
         }
 
+        mUseFallbackLineSpacing = useFallbackLineSpacing;
+
         init(getText(), paint, align, metrics, includePad, trust,
                 useFallbackLineSpacing);
         return this;
@@ -252,6 +255,7 @@
         mEllipsizedWidth = outerwidth;
         mEllipsizedStart = 0;
         mEllipsizedCount = 0;
+        mUseFallbackLineSpacing = false;
 
         init(source, paint, align, metrics, includePad, true, false /* useFallbackLineSpacing */);
     }
@@ -294,7 +298,7 @@
      * @param includePad set whether to include extra space beyond font ascent and descent which is
      *                   needed to avoid clipping in some scripts
      * @param ellipsize whether to ellipsize the text if width of the text is longer than the
-     *                  requested {@code outerWidth}
+     *                  requested {@code outerWidth}. null if ellipsis is not applied.
      * @param ellipsizedWidth the width to which this Layout is ellipsizing. If {@code ellipsize} is
      *                        {@code null}, or is {@link TextUtils.TruncateAt#MARQUEE} this value is
      *                        not used, {@code outerWidth} is used instead
@@ -307,7 +311,7 @@
             @NonNull CharSequence source, @NonNull TextPaint paint,
             @IntRange(from = 0) int outerWidth, @NonNull Alignment align, float spacingMult,
             float spacingAdd, @NonNull BoringLayout.Metrics metrics, boolean includePad,
-            @NonNull TextUtils.TruncateAt ellipsize, @IntRange(from = 0) int ellipsizedWidth,
+            @Nullable TextUtils.TruncateAt ellipsize, @IntRange(from = 0) int ellipsizedWidth,
             boolean useFallbackLineSpacing) {
         /*
          * It is silly to have to call super() and then replaceWith(),
@@ -331,6 +335,7 @@
             trust = false;
         }
 
+        mUseFallbackLineSpacing = useFallbackLineSpacing;
         init(getText(), paint, align, metrics, includePad, trust, useFallbackLineSpacing);
     }
 
diff --git a/core/java/android/text/PrecomputedText.java b/core/java/android/text/PrecomputedText.java
index 9307e56..f31a690 100644
--- a/core/java/android/text/PrecomputedText.java
+++ b/core/java/android/text/PrecomputedText.java
@@ -99,7 +99,7 @@
         private final @Layout.HyphenationFrequency int mHyphenationFrequency;
 
         // The line break configuration for calculating text wrapping.
-        private final @Nullable LineBreakConfig mLineBreakConfig;
+        private final @NonNull LineBreakConfig mLineBreakConfig;
 
         /**
          * A builder for creating {@link Params}.
@@ -119,7 +119,7 @@
                     Layout.HYPHENATION_FREQUENCY_NORMAL;
 
             // The line break configuration for calculating text wrapping.
-            private @Nullable LineBreakConfig mLineBreakConfig;
+            private @NonNull LineBreakConfig mLineBreakConfig = LineBreakConfig.NONE;
 
             /**
              * Builder constructor.
@@ -212,7 +212,7 @@
         // For the external developers, use Builder instead.
         /** @hide */
         public Params(@NonNull TextPaint paint,
-                @Nullable LineBreakConfig lineBreakConfig,
+                @NonNull LineBreakConfig lineBreakConfig,
                 @NonNull TextDirectionHeuristic textDir,
                 @Layout.BreakStrategy int strategy,
                 @Layout.HyphenationFrequency int frequency) {
@@ -260,11 +260,12 @@
         }
 
         /**
-         * Return the line break configuration for this text.
+         * Returns the {@link LineBreakConfig} for this text.
          *
-         * @return the current line break configuration, null if no line break configuration is set.
+         * @return the current line break configuration. The {@link LineBreakConfig} with default
+         * values will be returned if no line break configuration is set.
          */
-        public @Nullable LineBreakConfig getLineBreakConfig() {
+        public @NonNull LineBreakConfig getLineBreakConfig() {
             return mLineBreakConfig;
         }
 
@@ -297,9 +298,9 @@
         /** @hide */
         public @CheckResultUsableResult int checkResultUsable(@NonNull TextPaint paint,
                 @NonNull TextDirectionHeuristic textDir, @Layout.BreakStrategy int strategy,
-                @Layout.HyphenationFrequency int frequency, @Nullable LineBreakConfig lbConfig) {
+                @Layout.HyphenationFrequency int frequency, @NonNull LineBreakConfig lbConfig) {
             if (mBreakStrategy == strategy && mHyphenationFrequency == frequency
-                    && isLineBreakEquals(mLineBreakConfig, lbConfig)
+                    && mLineBreakConfig.equals(lbConfig)
                     && mPaint.equalsForTextMeasurement(paint)) {
                 return mTextDir == textDir ? USABLE : NEED_RECOMPUTE;
             } else {
@@ -308,29 +309,6 @@
         }
 
         /**
-         * Check the two LineBreakConfig instances are equal.
-         * This method assumes they are equal if one parameter is null and the other parameter has
-         * a LineBreakStyle value of LineBreakConfig.LINE_BREAK_STYLE_NONE.
-         *
-         * @param o1 the first LineBreakConfig instance.
-         * @param o2 the second LineBreakConfig instance.
-         * @return true if the two LineBreakConfig instances are equal.
-         */
-        private boolean isLineBreakEquals(LineBreakConfig o1, LineBreakConfig o2) {
-            if (Objects.equals(o1, o2)) {
-                return true;
-            }
-            if (o1 == null && (o2 != null
-                    && o2.getLineBreakStyle() == LineBreakConfig.LINE_BREAK_STYLE_NONE)) {
-                return true;
-            } else if (o2 == null && (o1 != null
-                    && o1.getLineBreakStyle() == LineBreakConfig.LINE_BREAK_STYLE_NONE)) {
-                return true;
-            }
-            return false;
-        }
-
-        /**
          * Check if the same text layout.
          *
          * @return true if this and the given param result in the same text layout
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index b10fc37..2f85d2b6 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -112,6 +112,7 @@
             b.mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
             b.mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE;
             b.mJustificationMode = Layout.JUSTIFICATION_MODE_NONE;
+            b.mLineBreakConfig = LineBreakConfig.NONE;
             return b;
         }
 
@@ -410,7 +411,8 @@
          *
          * @param lineBreakConfig the line break configuration for text wrapping.
          * @return this builder, useful for chaining.
-         * @see android.widget.TextView#setLineBreakConfig
+         * @see android.widget.TextView#setLineBreakStyle
+         * @see android.widget.TextView#setLineBreakWordStyle
          */
         @NonNull
         public Builder setLineBreakConfig(@NonNull LineBreakConfig lineBreakConfig) {
@@ -454,7 +456,7 @@
         @Nullable private int[] mRightIndents;
         private int mJustificationMode;
         private boolean mAddLastLineLineSpacing;
-        private LineBreakConfig mLineBreakConfig;
+        private LineBreakConfig mLineBreakConfig = LineBreakConfig.NONE;
 
         private final Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
 
diff --git a/core/java/android/util/IconDrawableFactory.java b/core/java/android/util/IconDrawableFactory.java
index 5bb263a..e3bc510 100644
--- a/core/java/android/util/IconDrawableFactory.java
+++ b/core/java/android/util/IconDrawableFactory.java
@@ -16,8 +16,8 @@
 package android.util;
 
 import static android.app.admin.DevicePolicyResources.Drawables.Style.SOLID_COLORED;
-import static android.app.admin.DevicePolicyResources.Drawables.UNDEFINED;
 import static android.app.admin.DevicePolicyResources.Drawables.WORK_PROFILE_ICON_BADGE;
+import static android.app.admin.DevicePolicyResources.UNDEFINED;
 
 import android.annotation.UserIdInt;
 import android.app.admin.DevicePolicyManager;
@@ -88,7 +88,7 @@
         }
         if (mUm.hasBadge(userId)) {
 
-            Drawable badge = mDpm.getDrawable(
+            Drawable badge = mDpm.getResources().getDrawable(
                     getUpdatableUserIconBadgeId(userId),
                     SOLID_COLORED,
                     () -> getDefaultUserIconBadge(userId));
diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java
index aebc5e8..01a037a 100644
--- a/core/java/android/util/NtpTrustedTime.java
+++ b/core/java/android/util/NtpTrustedTime.java
@@ -140,6 +140,10 @@
 
     /** An in-memory config override for use during tests. */
     @Nullable
+    private Integer mPortForTests;
+
+    /** An in-memory config override for use during tests. */
+    @Nullable
     private Duration mTimeoutForTests;
 
     // Declared volatile and accessed outside of synchronized blocks to avoid blocking reads during
@@ -163,9 +167,11 @@
      * Overrides the NTP server config for tests. Passing {@code null} to a parameter clears the
      * test value, i.e. so the normal value will be used next time.
      */
-    public void setServerConfigForTests(@Nullable String hostname, @Nullable Duration timeout) {
+    public void setServerConfigForTests(
+            @Nullable String hostname, @Nullable Integer port, @Nullable Duration timeout) {
         synchronized (this) {
             mHostnameForTests = hostname;
+            mPortForTests = port;
             mTimeoutForTests = timeout;
         }
     }
@@ -195,8 +201,9 @@
             if (LOGD) Log.d(TAG, "forceRefresh() from cache miss");
             final SntpClient client = new SntpClient();
             final String serverName = connectionInfo.getServer();
+            final int port = connectionInfo.getPort();
             final int timeoutMillis = connectionInfo.getTimeoutMillis();
-            if (client.requestTime(serverName, timeoutMillis, network)) {
+            if (client.requestTime(serverName, port, timeoutMillis, network)) {
                 long ntpCertainty = client.getRoundTripTime() / 2;
                 mTimeResult = new TimeResult(
                         client.getNtpTime(), client.getNtpTimeReference(), ntpCertainty);
@@ -297,10 +304,12 @@
     private static class NtpConnectionInfo {
 
         @NonNull private final String mServer;
+        private final int mPort;
         private final int mTimeoutMillis;
 
-        NtpConnectionInfo(@NonNull String server, int timeoutMillis) {
+        NtpConnectionInfo(@NonNull String server, int port, int timeoutMillis) {
             mServer = Objects.requireNonNull(server);
+            mPort = port;
             mTimeoutMillis = timeoutMillis;
         }
 
@@ -309,6 +318,11 @@
             return mServer;
         }
 
+        @NonNull
+        public int getPort() {
+            return mPort;
+        }
+
         int getTimeoutMillis() {
             return mTimeoutMillis;
         }
@@ -317,6 +331,7 @@
         public String toString() {
             return "NtpConnectionInfo{"
                     + "mServer='" + mServer + '\''
+                    + ", mPort='" + mPort + '\''
                     + ", mTimeoutMillis=" + mTimeoutMillis
                     + '}';
         }
@@ -341,6 +356,13 @@
             }
         }
 
+        final Integer port;
+        if (mPortForTests != null) {
+            port = mPortForTests;
+        } else {
+            port = SntpClient.STANDARD_NTP_PORT;
+        }
+
         final int timeoutMillis;
         if (mTimeoutForTests != null) {
             timeoutMillis = (int) mTimeoutForTests.toMillis();
@@ -350,7 +372,8 @@
             timeoutMillis = Settings.Global.getInt(
                     resolver, Settings.Global.NTP_TIMEOUT, defaultTimeoutMillis);
         }
-        return TextUtils.isEmpty(hostname) ? null : new NtpConnectionInfo(hostname, timeoutMillis);
+        return TextUtils.isEmpty(hostname) ? null :
+            new NtpConnectionInfo(hostname, port, timeoutMillis);
     }
 
     /** Prints debug information. */
diff --git a/core/java/android/util/TimingsTraceLog.java b/core/java/android/util/TimingsTraceLog.java
index 066709f..48a5cea 100644
--- a/core/java/android/util/TimingsTraceLog.java
+++ b/core/java/android/util/TimingsTraceLog.java
@@ -147,7 +147,7 @@
      * Logs a duration so it can be parsed by external tools for performance reporting.
      */
     public void logDuration(String name, long timeMs) {
-        Slog.d(mTag, name + " took to complete: " + timeMs + "ms");
+        Slog.v(mTag, name + " took to complete: " + timeMs + "ms");
     }
 
     /**
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 43c07c8..7e0b794 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -992,6 +992,9 @@
                     // Unchecked cast - an app that puts other objects in this bundle with this
                     // key will crash.
                     RectF textLocation = ((RectF) textLocations[i]);
+                    if (textLocation == null) {
+                        continue;
+                    }
                     textLocation.scale(applicationScale);
                     if (spec != null) {
                         textLocation.scale(spec.scale);
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index c1fa079..60593ca 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -779,7 +779,9 @@
                                 + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
                     }
                     frameTimeNanos = startNanos - lastFrameOffset;
-                    frameData.setFrameTimeNanos(frameTimeNanos);
+                    DisplayEventReceiver.VsyncEventData latestVsyncEventData =
+                            mDisplayEventReceiver.getLatestVsyncEventData();
+                    frameData.updateFrameData(frameTimeNanos, latestVsyncEventData);
                 }
 
                 if (frameTimeNanos < mLastFrameTimeNanos) {
@@ -877,7 +879,9 @@
                     }
                     frameTimeNanos = now - lastFrameOffset;
                     mLastFrameTimeNanos = frameTimeNanos;
-                    frameData.setFrameTimeNanos(frameTimeNanos);
+                    DisplayEventReceiver.VsyncEventData latestVsyncEventData =
+                            mDisplayEventReceiver.getLatestVsyncEventData();
+                    frameData.updateFrameData(frameTimeNanos, latestVsyncEventData);
                 }
             }
         }
@@ -1012,11 +1016,6 @@
             return mVsyncId;
         }
 
-        /** Sets the vsync ID. */
-        void resetVsyncId() {
-            mVsyncId = FrameInfo.INVALID_VSYNC_ID;
-        }
-
         /**
          * The time in {@link System#nanoTime()} timebase which this frame is expected to be
          * presented.
@@ -1061,17 +1060,15 @@
         }
 
         private long mFrameTimeNanos;
-        private final FrameTimeline[] mFrameTimelines;
-        private final FrameTimeline mPreferredFrameTimeline;
+        private FrameTimeline[] mFrameTimelines;
+        private FrameTimeline mPreferredFrameTimeline;
 
-        void setFrameTimeNanos(long frameTimeNanos) {
+        void updateFrameData(long frameTimeNanos,
+                DisplayEventReceiver.VsyncEventData latestVsyncEventData) {
             mFrameTimeNanos = frameTimeNanos;
-            for (FrameTimeline ft : mFrameTimelines) {
-                // The ID is no longer valid because the frame time that was registered with the ID
-                // no longer matches.
-                // TODO(b/205721584): Ask SF for valid vsync information.
-                ft.resetVsyncId();
-            }
+            mFrameTimelines = convertFrameTimelines(latestVsyncEventData);
+            mPreferredFrameTimeline =
+                mFrameTimelines[latestVsyncEventData.preferredFrameTimelineIndex];
         }
 
         /** The time in nanoseconds when the frame started being rendered. */
@@ -1091,6 +1088,19 @@
         public FrameTimeline getPreferredFrameTimeline() {
             return mPreferredFrameTimeline;
         }
+
+        private FrameTimeline[] convertFrameTimelines(
+                DisplayEventReceiver.VsyncEventData vsyncEventData) {
+            FrameTimeline[] frameTimelines =
+                    new FrameTimeline[vsyncEventData.frameTimelines.length];
+            for (int i = 0; i < vsyncEventData.frameTimelines.length; i++) {
+                DisplayEventReceiver.VsyncEventData.FrameTimeline frameTimeline =
+                        vsyncEventData.frameTimelines[i];
+                frameTimelines[i] = new FrameTimeline(frameTimeline.vsyncId,
+                        frameTimeline.expectedPresentTime, frameTimeline.deadline);
+            }
+            return frameTimelines;
+        }
     }
 
     /**
diff --git a/core/java/android/view/ContentRecordingSession.java b/core/java/android/view/ContentRecordingSession.java
index db4ec11..c66c70af 100644
--- a/core/java/android/view/ContentRecordingSession.java
+++ b/core/java/android/view/ContentRecordingSession.java
@@ -66,10 +66,11 @@
     private int mContentToRecord = RECORD_CONTENT_DISPLAY;
 
     /**
-     * The window token of the layer of the hierarchy to record.
-     * The display content if {@link #getContentToRecord()} is
-     * {@link RecordContent#RECORD_CONTENT_DISPLAY}, or task if {@link #getContentToRecord()} is
-     * {@link RecordContent#RECORD_CONTENT_TASK}.
+     * The token of the layer of the hierarchy to record.
+     * If {@link #getContentToRecord()} is @link RecordContent#RECORD_CONTENT_DISPLAY}, then
+     * represents the WindowToken corresponding to the DisplayContent to record.
+     * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
+     * represents the {@link android.window.WindowContainerToken} of the Task to record.
      */
     @VisibleForTesting
     @Nullable
@@ -192,10 +193,11 @@
     }
 
     /**
-     * The window token of the layer of the hierarchy to record.
-     * The display content if {@link #getContentToRecord()} is
-     * {@link RecordContent#RECORD_CONTENT_DISPLAY}, or task if {@link #getContentToRecord()} is
-     * {@link RecordContent#RECORD_CONTENT_TASK}.
+     * {The token of the layer of the hierarchy to record.
+     * If {@link #getContentToRecord()} is @link RecordContent#RECORD_CONTENT_DISPLAY}, then
+     * represents the WindowToken corresponding to the DisplayContent to record.
+     * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
+     * represents the {@link android.window.WindowContainerToken} of the Task to record.
      */
     @DataClass.Generated.Member
     public @VisibleForTesting @Nullable IBinder getTokenToRecord() {
@@ -231,10 +233,11 @@
     }
 
     /**
-     * The window token of the layer of the hierarchy to record.
-     * The display content if {@link #getContentToRecord()} is
-     * {@link RecordContent#RECORD_CONTENT_DISPLAY}, or task if {@link #getContentToRecord()} is
-     * {@link RecordContent#RECORD_CONTENT_TASK}.
+     * {The token of the layer of the hierarchy to record.
+     * If {@link #getContentToRecord()} is @link RecordContent#RECORD_CONTENT_DISPLAY}, then
+     * represents the WindowToken corresponding to the DisplayContent to record.
+     * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
+     * represents the {@link android.window.WindowContainerToken} of the Task to record.
      */
     @DataClass.Generated.Member
     public @NonNull ContentRecordingSession setTokenToRecord(@VisibleForTesting @NonNull IBinder value) {
@@ -390,10 +393,11 @@
         }
 
         /**
-         * The window token of the layer of the hierarchy to record.
-         * The display content if {@link #getContentToRecord()} is
-         * {@link RecordContent#RECORD_CONTENT_DISPLAY}, or task if {@link #getContentToRecord()} is
-         * {@link RecordContent#RECORD_CONTENT_TASK}.
+         * {The token of the layer of the hierarchy to record.
+         * If {@link #getContentToRecord()} is @link RecordContent#RECORD_CONTENT_DISPLAY}, then
+         * represents the WindowToken corresponding to the DisplayContent to record.
+         * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
+         * represents the {@link android.window.WindowContainerToken} of the Task to record.
          */
         @DataClass.Generated.Member
         public @NonNull Builder setTokenToRecord(@VisibleForTesting @NonNull IBinder value) {
@@ -433,7 +437,7 @@
     }
 
     @DataClass.Generated(
-            time = 1644843382972L,
+            time = 1645803878639L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/view/ContentRecordingSession.java",
             inputSignatures = "public static final  int RECORD_CONTENT_DISPLAY\npublic static final  int RECORD_CONTENT_TASK\nprivate  int mDisplayId\nprivate @android.view.ContentRecordingSession.RecordContent int mContentToRecord\nprivate @com.android.internal.annotations.VisibleForTesting @android.annotation.Nullable android.os.IBinder mTokenToRecord\npublic static  android.view.ContentRecordingSession createDisplaySession(android.os.IBinder)\npublic static  android.view.ContentRecordingSession createTaskSession(android.os.IBinder)\npublic static  boolean isValid(android.view.ContentRecordingSession)\npublic static  boolean isSameDisplay(android.view.ContentRecordingSession,android.view.ContentRecordingSession)\nclass ContentRecordingSession extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genToString=true, genSetters=true, genEqualsHashCode=true)")
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 7d8e998..5f0098c 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -762,35 +762,42 @@
     }
 
     /**
-     * Gets the size of the display, in pixels.
-     * Value returned by this method does not necessarily represent the actual raw size
-     * (native resolution) of the display.
-     * <p>
-     * 1. The returned size may be adjusted to exclude certain system decor elements
-     * that are always visible.
-     * </p><p>
-     * 2. It may be scaled to provide compatibility with older applications that
-     * were originally designed for smaller displays.
-     * </p><p>
-     * 3. It can be different depending on the WindowManager to which the display belongs.
-     * </p><p>
-     * - If requested from non-Activity context (e.g. Application context via
-     * {@code (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE)})
-     * it will report the size of the entire display based on current rotation and with subtracted
-     * system decoration areas.
-     * </p><p>
-     * - If requested from activity (either using {@code getWindowManager()} or
-     * {@code (WindowManager) getSystemService(Context.WINDOW_SERVICE)}) resulting size will
-     * correspond to current app window size. In this case it can be smaller than physical size in
-     * multi-window mode.
-     * </p><p>
-     * Typically for the purposes of layout apps should make a request from activity context
-     * to obtain size available for the app content.
-     * </p>
+     * Gets the size of the display in pixels.
      *
-     * @param outSize A {@link Point} object to receive the size information.
-     * @deprecated Use {@link WindowManager#getCurrentWindowMetrics()} to obtain an instance of
-     * {@link WindowMetrics} and use {@link WindowMetrics#getBounds()} instead.
+     * <p>The return value does not necessarily represent the actual size (native resolution) of the
+     * display. The returned size might be adjusted to exclude certain system decor elements that
+     * are always visible, or the size might be scaled to provide compatibility with older
+     * applications that were originally designed for smaller displays.
+     *
+     * <p>The returned size can also be different depending on the WindowManager bound to the
+     * display:
+     * <ul>
+     *     <li>If size is requested from an activity (either using a WindowManager accessed by
+     *         {@code getWindowManager()} or {@code getSystemService(Context.WINDOW_SERVICE)}), the
+     *         size of the current app window is returned. As a result, in multi-window mode, the
+     *         returned size can be smaller than the size of the device screen.
+     *     <li>If size is requested from a non-activity context (for example, the application
+     *         context, where the WindowManager is accessed by
+     *         {@code getApplicationContext().getSystemService(Context.WINDOW_SERVICE)}), the
+     *         returned size can vary depending on API level:
+     *         <ul>
+     *             <li>API level 29 and below &mdash; The size of the entire display (based on
+     *                 current rotation) minus system decoration areas is returned.
+     *             <li>API level 30 and above &mdash; The size of the top running activity in the
+     *                 current process is returned. If the current process has no running
+     *                 activities, the size of the device default display, including system
+     *                 decoration areas, is returned.
+     *         </ul>
+     * </ul>
+     *
+     * <p>For layout purposes, apps should make a request from an activity context to obtain the
+     * size of the display area available for app content.
+     *
+     * @param outSize A {@link Point} object which receives the display size information.
+     *
+     * @deprecated Use {@link WindowMetrics} instead. Obtain a {@code WindowMetrics} instance by
+     *     calling {@link WindowManager#getCurrentWindowMetrics()}, then call
+     *     {@link WindowMetrics#getBounds()} to get the dimensions of the application window.
      */
     @Deprecated
     public void getSize(Point outSize) {
@@ -806,8 +813,9 @@
      * Gets the size of the display as a rectangle, in pixels.
      *
      * @param outSize A {@link Rect} object to receive the size information.
+     *
      * @deprecated Use {@link WindowMetrics#getBounds()} to get the dimensions of the application
-     * window area.
+     * window.
      */
     @Deprecated
     public void getRectSize(Rect outSize) {
@@ -1379,32 +1387,39 @@
     }
 
     /**
-     * Gets display metrics that describe the size and density of this display.
-     * The size returned by this method does not necessarily represent the
-     * actual raw size (native resolution) of the display.
-     * <p>
-     * 1. The returned size may be adjusted to exclude certain system decor elements
-     * that are always visible.
-     * </p><p>
-     * 2. It may be scaled to provide compatibility with older applications that
-     * were originally designed for smaller displays.
-     * </p><p>
-     * 3. It can be different depending on the WindowManager to which the display belongs.
-     * </p><p>
-     * - If requested from non-Activity context (e.g. Application context via
-     * {@code (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE)})
-     * metrics will report the size of the entire display based on current rotation and with
-     * subtracted system decoration areas.
-     * </p><p>
-     * - If requested from activity (either using {@code getWindowManager()} or
-     * {@code (WindowManager) getSystemService(Context.WINDOW_SERVICE)}) resulting metrics will
-     * correspond to current app window metrics. In this case the size can be smaller than physical
-     * size in multi-window mode.
-     * </p>
+     * Gets the size and density of this display.
      *
-     * @param outMetrics A {@link DisplayMetrics} object to receive the metrics.
+     * <p>The size returned does not necessarily represent the actual size (native resolution) of
+     * the display. The returned size might be adjusted to exclude certain system decor elements
+     * that are always visible, or the size might be scaled to provide compatibility with older
+     * applications that were originally designed for smaller displays.
+     *
+     * <p>The returned size can also be different depending on the WindowManager associated with the
+     * display:
+     * <ul>
+     *     <li>If metrics are requested from an activity (either using a WindowManager accessed by
+     *         {@code getWindowManager()} or {@code getSystemService(Context.WINDOW_SERVICE)}), the
+     *         returned metrics provide the size of the current app window. As a result, in
+     *         multi-window mode, the returned size can be smaller than the size of the device
+     *         screen.
+     *     <li>If metrics are requested from a non-activity context (for example, the application
+     *         context, where the WindowManager is accessed by
+     *         {@code getApplicationContext().getSystemService(Context.WINDOW_SERVICE)}), the
+     *         returned size can vary depending on API level:
+     *         <ul>
+     *             <li>API level 29 and below &mdash; The returned metrics provide the size of the
+     *                 entire display (based on current rotation) minus system decoration areas.
+     *             <li>API level 30 and above &mdash; The returned metrics provide the size of the
+     *                 top running activity in the current process. If the current process has no
+     *                 running activities, the metrics provide the size of the default display of
+     *                 the device, including system decoration areas.
+     *         </ul>
+     * </ul>
+     *
+     * @param outMetrics A {@link DisplayMetrics} object which receives the display metrics.
+     *
      * @deprecated Use {@link WindowMetrics#getBounds()} to get the dimensions of the application
-     * window area, and {@link Configuration#densityDpi} to get the current density.
+     *     window. Use {@link Configuration#densityDpi} to get the display density.
      */
     @Deprecated
     public void getMetrics(DisplayMetrics outMetrics) {
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index 774bab4..3a74b2e 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -84,6 +84,7 @@
     private static native void nativeDispose(long receiverPtr);
     @FastNative
     private static native void nativeScheduleVsync(long receiverPtr);
+    private static native VsyncEventData nativeGetLatestVsyncEventData(long receiverPtr);
 
     /**
      * Creates a display event receiver.
@@ -279,6 +280,13 @@
         }
     }
 
+    /**
+     * Gets the latest vsync event data from surface flinger.
+     */
+    VsyncEventData getLatestVsyncEventData() {
+        return nativeGetLatestVsyncEventData(mReceiverPtr);
+    }
+
     // Called from native code.
     @SuppressWarnings("unused")
     private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame,
diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index c1413be..61098d6 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -55,10 +55,10 @@
      */
     private final int mTouchSlop;
     /**
-     * The timeout used to distinguish tap from handwriting. If the stylus doesn't move before this
-     * timeout, it's not considered as handwriting.
+     * The timeout used to distinguish tap or long click from handwriting. If the stylus doesn't
+     * move before this timeout, it's not considered as handwriting.
      */
-    private final long mTapTimeoutInMillis;
+    private final long mHandwritingTimeoutInMillis;
 
     private State mState = new State();
     private final HandwritingAreaTracker mHandwritingAreasTracker = new HandwritingAreaTracker();
@@ -90,7 +90,7 @@
     public HandwritingInitiator(@NonNull ViewConfiguration viewConfiguration,
             @NonNull InputMethodManager inputMethodManager) {
         mTouchSlop = viewConfiguration.getScaledTouchSlop();
-        mTapTimeoutInMillis = ViewConfiguration.getTapTimeout();
+        mHandwritingTimeoutInMillis = ViewConfiguration.getLongPressTimeout();
         mImm = inputMethodManager;
     }
 
@@ -145,7 +145,7 @@
 
                 final long timeElapsed =
                         motionEvent.getEventTime() - mState.mStylusDownTimeInMillis;
-                if (timeElapsed > mTapTimeoutInMillis) {
+                if (timeElapsed > mHandwritingTimeoutInMillis) {
                     reset();
                     return;
                 }
@@ -249,19 +249,19 @@
             return;
         }
 
-        Rect handwritingArea = getViewHandwritingArea(connectedView);
-        if (handwritingArea != null) {
-            if (contains(handwritingArea, mState.mStylusDownX, mState.mStylusDownY)) {
-                startHandwriting(connectedView);
-            }
+        final Rect handwritingArea = getViewHandwritingArea(connectedView);
+        if (contains(handwritingArea, mState.mStylusDownX, mState.mStylusDownY)) {
+            startHandwriting(connectedView);
+        } else {
+            reset();
         }
-        reset();
     }
 
     /** For test only. */
     @VisibleForTesting
     public void startHandwriting(@NonNull View view) {
         mImm.startStylusHandwriting(view);
+        reset();
     }
 
     /**
@@ -287,7 +287,7 @@
         final View connectedView = getConnectedView();
         if (connectedView != null && connectedView.isAutoHandwritingEnabled()) {
             final Rect handwritingArea = getViewHandwritingArea(connectedView);
-            if (handwritingArea != null && contains(handwritingArea, x, y)) {
+            if (contains(handwritingArea, x, y)) {
                 return connectedView;
             }
         }
@@ -298,8 +298,7 @@
         for (HandwritableViewInfo viewInfo : handwritableViewInfos) {
             final View view = viewInfo.getView();
             if (!view.isAutoHandwritingEnabled()) continue;
-            final Rect rect = viewInfo.getHandwritingArea();
-            if (rect != null && contains(rect, x, y)) {
+            if (contains(viewInfo.getHandwritingArea(), x, y)) {
                 return viewInfo.getView();
             }
         }
@@ -315,12 +314,15 @@
     private static Rect getViewHandwritingArea(@NonNull View view) {
         final ViewParent viewParent = view.getParent();
         if (viewParent != null && view.isAttachedToWindow() && view.isAggregatedVisible()) {
-            Rect handwritingArea = view.getHandwritingArea();
-            if (handwritingArea == null) {
-                handwritingArea = new Rect(0, 0, view.getWidth(), view.getHeight());
+            final Rect localHandwritingArea = view.getHandwritingArea();
+            final Rect globalHandwritingArea = new Rect();
+            if (localHandwritingArea != null) {
+                globalHandwritingArea.set(localHandwritingArea);
+            } else {
+                globalHandwritingArea.set(0, 0, view.getWidth(), view.getHeight());
             }
-            if (viewParent.getChildVisibleRect(view, handwritingArea, null)) {
-                return handwritingArea;
+            if (viewParent.getChildVisibleRect(view, globalHandwritingArea, null)) {
+                return globalHandwritingArea;
             }
         }
         return null;
@@ -329,7 +331,8 @@
     /**
      * Return true if the (x, y) is inside by the given {@link Rect}.
      */
-    private boolean contains(@NonNull Rect rect, float x, float y) {
+    private boolean contains(@Nullable Rect rect, float x, float y) {
+        if (rect == null) return false;
         return x >= rect.left && x < rect.right && y >= rect.top && y < rect.bottom;
     }
 
@@ -481,17 +484,18 @@
             if (!mIsDirty) {
                 return true;
             }
-            final Rect localRect = view.getHandwritingArea();
-            if (localRect == null) {
+            final Rect handwritingArea = view.getHandwritingArea();
+            if (handwritingArea == null) {
                 return false;
             }
 
             ViewParent parent = view.getParent();
             if (parent != null) {
-                final Rect newRect = new Rect(localRect);
-                if (parent.getChildVisibleRect(view, newRect, null /* offset */)) {
-                    mHandwritingArea = newRect;
-                } else {
+                if (mHandwritingArea == null) {
+                    mHandwritingArea = new Rect();
+                }
+                mHandwritingArea.set(handwritingArea);
+                if (!parent.getChildVisibleRect(view, mHandwritingArea, null /* offset */)) {
                     mHandwritingArea = null;
                 }
             }
diff --git a/core/java/android/view/IPinnedTaskListener.aidl b/core/java/android/view/IPinnedTaskListener.aidl
index 7d39ffe..595a846 100644
--- a/core/java/android/view/IPinnedTaskListener.aidl
+++ b/core/java/android/view/IPinnedTaskListener.aidl
@@ -47,7 +47,7 @@
      * Called when the set of actions for the current PiP activity changes, or when the listener
      * is first registered to allow the listener to synchronize its state with the controller.
      */
-    void onActionsChanged(in ParceledListSlice<RemoteAction> actions);
+    void onActionsChanged(in ParceledListSlice<RemoteAction> actions, in RemoteAction closeAction);
 
     /**
      * Called by the window manager to notify the listener that Activity (was or is in pinned mode)
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 12421ed..5dcf393 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -55,7 +55,8 @@
 
     void resized(in ClientWindowFrames frames, boolean reportDraw,
             in MergedConfiguration newMergedConfiguration,
-            boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId);
+            boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
+            int syncSeqId, int resizeMode);
 
     /**
      * Called when the window insets configuration has changed.
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 5c7c844..7098602 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -104,7 +104,43 @@
             int requestedWidth, int requestedHeight, int viewVisibility,
             int flags, out ClientWindowFrames outFrames,
             out MergedConfiguration outMergedConfiguration, out SurfaceControl outSurfaceControl,
-            out InsetsState insetsState, out InsetsSourceControl[] activeControls);
+            out InsetsState insetsState, out InsetsSourceControl[] activeControls,
+            out Bundle bundle);
+
+    /**
+     * Changes the view visibility and the attributes of a window. This should only be called when
+     * the visibility of the root view is changed. This returns a valid surface if the root view is
+     * visible. This also returns the latest information for the caller to compute its window frame.
+     *
+     * @param window The window being updated.
+     * @param attrs If non-null, new attributes to apply to the window.
+     * @param viewVisibility Window root view's visibility.
+     * @param outMergedConfiguration New config container that holds global, override and merged
+     * config for window, if it is now becoming visible and the merged configuration has changed
+     * since it was last displayed.
+     * @param outSurfaceControl Object in which is placed the new display surface.
+     * @param outInsetsState The current insets state in the system.
+     * @param outActiveControls The insets source controls for the caller to override the insets
+     * state in the system.
+     *
+     * @return int Result flags: {@link WindowManagerGlobal#RELAYOUT_FIRST_TIME}.
+     */
+    int updateVisibility(IWindow window, in WindowManager.LayoutParams attrs, int viewVisibility,
+            out MergedConfiguration outMergedConfiguration, out SurfaceControl outSurfaceControl,
+            out InsetsState outInsetsState, out InsetsSourceControl[] outActiveControls);
+
+    /**
+     * Reports the layout results and the attributes of a window to the server.
+     *
+     * @param window The window being reported.
+     * @param attrs If non-null, new attributes to apply to the window.
+     * @param flags Request flags: {@link WindowManagerGlobal#RELAYOUT_INSETS_PENDING}.
+     * @param clientFrames the window frames computed by the client.
+     * @param requestedWidth The width the window wants to be.
+     * @param requestedHeight The height the window wants to be.
+     */
+    oneway void updateLayout(IWindow window, in WindowManager.LayoutParams attrs, int flags,
+            in ClientWindowFrames clientFrames, int requestedWidth, int requestedHeight);
 
     /*
      * Notify the window manager that an application is relaunching and
@@ -142,7 +178,8 @@
      * is null if there is no sync required.
      */
     @UnsupportedAppUsage
-    oneway void finishDrawing(IWindow window, in SurfaceControl.Transaction postDrawTransaction);
+    oneway void finishDrawing(IWindow window, in SurfaceControl.Transaction postDrawTransaction,
+            int seqId);
 
     @UnsupportedAppUsage
     oneway void setInTouchMode(boolean showFocus);
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 71c1b7c..a4841f6 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -23,6 +23,7 @@
 import static android.view.InsetsState.ITYPE_IME;
 import static android.view.InsetsState.toInternalType;
 import static android.view.InsetsState.toPublicType;
+import static android.view.ViewRootImpl.CAPTION_ON_SHELL;
 import static android.view.WindowInsets.Type.all;
 import static android.view.WindowInsets.Type.ime;
 
@@ -682,9 +683,15 @@
 
     @VisibleForTesting
     public boolean onStateChanged(InsetsState state) {
-        boolean stateChanged = !mState.equals(state, true /* excludingCaptionInsets */,
-                        false /* excludeInvisibleIme */)
-                || !captionInsetsUnchanged();
+        boolean stateChanged = false;
+        if (!CAPTION_ON_SHELL) {
+            stateChanged = !mState.equals(state, true /* excludingCaptionInsets */,
+                    false /* excludeInvisibleIme */)
+                    || captionInsetsUnchanged();
+        } else {
+            stateChanged = !mState.equals(state, false /* excludingCaptionInsets */,
+                    false /* excludeInvisibleIme */);
+        }
         if (!stateChanged && mLastDispatchedState.equals(state)) {
             return false;
         }
@@ -758,16 +765,20 @@
     }
 
     private boolean captionInsetsUnchanged() {
+        if (CAPTION_ON_SHELL) {
+            return false;
+        }
         if (mState.peekSource(ITYPE_CAPTION_BAR) == null
                 && mCaptionInsetsHeight == 0) {
-            return true;
+            return false;
         }
         if (mState.peekSource(ITYPE_CAPTION_BAR) != null
                 && mCaptionInsetsHeight
                 == mState.peekSource(ITYPE_CAPTION_BAR).getFrame().height()) {
-            return true;
+            return false;
         }
-        return false;
+
+        return true;
     }
 
     private void startResizingAnimationIfNeeded(InsetsState fromState) {
@@ -1582,11 +1593,15 @@
 
     @Override
     public void setCaptionInsetsHeight(int height) {
+        // This method is to be removed once the caption is moved to the shell.
+        if (CAPTION_ON_SHELL) {
+            return;
+        }
         if (mCaptionInsetsHeight != height) {
             mCaptionInsetsHeight = height;
             if (mCaptionInsetsHeight != 0) {
-                mState.getSource(ITYPE_CAPTION_BAR).setFrame(new Rect(mFrame.left, mFrame.top,
-                        mFrame.right, mFrame.top + mCaptionInsetsHeight));
+                mState.getSource(ITYPE_CAPTION_BAR).setFrame(mFrame.left, mFrame.top,
+                        mFrame.right, mFrame.top + mCaptionInsetsHeight);
             } else {
                 mState.removeSource(ITYPE_CAPTION_BAR);
             }
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 64f5668..da582c5 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -64,6 +64,7 @@
 import android.view.Surface.OutOfResourcesException;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
 import com.android.internal.util.VirtualRefBasePtr;
 
 import dalvik.system.CloseGuard;
@@ -82,6 +83,7 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
 
 /**
  * Handle to an on-screen Surface managed by the system compositor. The SurfaceControl is
@@ -212,7 +214,7 @@
     private static native void nativeReparent(long transactionObj, long nativeObject,
             long newParentNativeObject);
     private static native void nativeSetBuffer(long transactionObj, long nativeObject,
-            HardwareBuffer buffer, long fencePtr);
+            HardwareBuffer buffer, long fencePtr, Consumer<SyncFence> releaseCallback);
     private static native void nativeSetBufferTransform(long transactionObj, long nativeObject,
             int transform);
     private static native void nativeSetDataSpace(long transactionObj, long nativeObject,
@@ -2961,6 +2963,8 @@
         @NonNull
         public Transaction setScale(@NonNull SurfaceControl sc, float scaleX, float scaleY) {
             checkPreconditions(sc);
+            Preconditions.checkArgument(scaleX >= 0, "Negative value passed in for scaleX");
+            Preconditions.checkArgument(scaleY >= 0, "Negative value passed in for scaleY");
             nativeSetScale(mNativeObject, sc.mNativeObject, scaleX, scaleY);
             return this;
         }
@@ -3205,6 +3209,7 @@
         public @NonNull Transaction setCrop(@NonNull SurfaceControl sc, @Nullable Rect crop) {
             checkPreconditions(sc);
             if (crop != null) {
+                Preconditions.checkArgument(crop.isValid(), "Crop isn't valid.");
                 nativeSetWindowCrop(mNativeObject, sc.mNativeObject,
                         crop.left, crop.top, crop.right, crop.bottom);
             } else {
@@ -3740,18 +3745,62 @@
          */
         public @NonNull Transaction setBuffer(@NonNull SurfaceControl sc,
                 @Nullable HardwareBuffer buffer, @Nullable SyncFence fence) {
+            return setBuffer(sc, buffer, fence, null);
+        }
+
+        /**
+         * Updates the HardwareBuffer displayed for the SurfaceControl.
+         *
+         * Note that the buffer must be allocated with {@link HardwareBuffer#USAGE_COMPOSER_OVERLAY}
+         * as well as {@link HardwareBuffer#USAGE_GPU_SAMPLED_IMAGE} as the surface control might
+         * be composited using either an overlay or using the GPU.
+         *
+         * A presentation fence may be passed to improve performance by allowing the buffer
+         * to complete rendering while it is waiting for the transaction to be applied.
+         * For example, if the buffer is being produced by rendering with OpenGL ES then
+         * a fence created with
+         * {@link android.opengl.EGLExt#eglDupNativeFenceFDANDROID(EGLDisplay, EGLSync)} can be
+         * used to allow the GPU rendering to be concurrent with the transaction. The compositor
+         * will wait for the fence to be signaled before the buffer is displayed. If multiple
+         * buffers are set as part of the same transaction, the presentation fences of all of them
+         * must signal before any buffer is displayed. That is, the entire transaction is delayed
+         * until all presentation fences have signaled, ensuring the transaction remains consistent.
+         *
+         * A releaseCallback may be passed to know when the buffer is safe to be reused. This
+         * is recommended when attempting to render continuously using SurfaceControl transactions
+         * instead of through {@link Surface}, as it provides a safe & reliable way to know when
+         * a buffer can be re-used. The callback will be invoked with a {@link SyncFence} which,
+         * if {@link SyncFence#isValid() valid}, must be waited on prior to using the buffer. This
+         * can either be done directly with {@link SyncFence#awaitForever()} or it may be done
+         * indirectly such as passing it as a release fence to
+         * {@link android.media.Image#setFence(SyncFence)} when using
+         * {@link android.media.ImageReader}.
+         *
+         * @param sc The SurfaceControl to update
+         * @param buffer The buffer to be displayed
+         * @param fence The presentation fence. If null or invalid, this is equivalent to
+         *              {@link #setBuffer(SurfaceControl, HardwareBuffer)}
+         * @param releaseCallback The callback to invoke when the buffer being set has been released
+         *                        by a later transaction. That is, the point at which it is safe
+         *                        to re-use the buffer.
+         * @return this
+         */
+        public @NonNull Transaction setBuffer(@NonNull SurfaceControl sc,
+                @Nullable HardwareBuffer buffer, @Nullable SyncFence fence,
+                @Nullable Consumer<SyncFence> releaseCallback) {
             checkPreconditions(sc);
             if (fence != null) {
                 synchronized (fence.getLock()) {
                     nativeSetBuffer(mNativeObject, sc.mNativeObject, buffer,
-                            fence.getNativeFence());
+                            fence.getNativeFence(), releaseCallback);
                 }
             } else {
-                nativeSetBuffer(mNativeObject, sc.mNativeObject, buffer, 0);
+                nativeSetBuffer(mNativeObject, sc.mNativeObject, buffer, 0, releaseCallback);
             }
             return this;
         }
 
+
         /**
          * Sets the buffer transform that should be applied to the current buffer.
          *
@@ -4090,4 +4139,10 @@
 
         return -1;
     }
+
+    // Called by native
+    private static void invokeReleaseCallback(Consumer<SyncFence> callback, long nativeFencePtr) {
+        SyncFence fence = new SyncFence(nativeFencePtr);
+        callback.accept(fence);
+    }
 }
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index a13579d..406281d 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -401,7 +401,7 @@
     public void relayout(WindowManager.LayoutParams attrs,
             WindowlessWindowManager.ResizeCompleteCallback callback) {
         mViewRoot.setLayoutParams(attrs, false);
-        mViewRoot.setReportNextDraw();
+        mViewRoot.setReportNextDraw(true /* syncBuffer */);
         mWm.setCompletionCallback(mViewRoot.mWindow.asBinder(), callback);
     }
 
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 4138556..c04b096 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -50,6 +50,7 @@
 import com.android.internal.view.SurfaceCallbackHelper;
 
 import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.Consumer;
 
@@ -203,8 +204,6 @@
 
     private int mSurfaceFlags = SurfaceControl.HIDDEN;
 
-    private int mPendingReportDraws;
-
     /**
      * Transaction that should be used from the render thread. This transaction is only thread safe
      * with other calls directly from the render thread.
@@ -212,11 +211,6 @@
     private final SurfaceControl.Transaction mRtTransaction = new SurfaceControl.Transaction();
 
     /**
-     * Used on the main thread to set the transaction that will be synced with the main window.
-     */
-    private final Transaction mSyncTransaction = new Transaction();
-
-    /**
      * Transaction that should be used whe
      * {@link HardwareRenderer.FrameDrawingCallback#onFrameDraw} is invoked. All
      * frame callbacks can use the same transaction since they will be thread safe
@@ -391,31 +385,12 @@
         }
     }
 
-    private void performDrawFinished(@Nullable Transaction t) {
-        if (t != null) {
-            mSyncTransaction.merge(t);
+    private void performDrawFinished() {
+        mDrawFinished = true;
+        if (mAttachedToWindow) {
+            mParent.requestTransparentRegion(SurfaceView.this);
+            invalidate();
         }
-
-        if (mPendingReportDraws > 0) {
-            mDrawFinished = true;
-            if (mAttachedToWindow) {
-                mParent.requestTransparentRegion(SurfaceView.this);
-                notifyDrawFinished();
-                invalidate();
-            }
-        } else {
-            Log.e(TAG, System.identityHashCode(this) + "finished drawing"
-                    + " but no pending report draw (extra call"
-                    + " to draw completion runnable?)");
-        }
-    }
-
-    void notifyDrawFinished() {
-        ViewRootImpl viewRoot = getViewRootImpl();
-        if (viewRoot != null) {
-            viewRoot.pendingDrawFinished(mSyncTransaction);
-        }
-        mPendingReportDraws--;
     }
 
     @Override
@@ -438,10 +413,6 @@
             mGlobalListenersAdded = false;
         }
 
-        while (mPendingReportDraws > 0) {
-            notifyDrawFinished();
-        }
-
         mRequestedVisible = false;
 
         updateSurface();
@@ -993,10 +964,17 @@
                     return;
                 }
 
-                final boolean realSizeChanged = performSurfaceTransaction(viewRoot,
-                        translator, creating, sizeChanged, hintChanged, surfaceUpdateTransaction);
                 final boolean redrawNeeded = sizeChanged || creating || hintChanged
                         || (mVisible && !mDrawFinished);
+                final TransactionCallback transactionCallback =
+                        redrawNeeded ? new TransactionCallback() : null;
+                if (redrawNeeded && viewRoot.wasRelayoutRequested() && viewRoot.isInSync()) {
+                    mBlastBufferQueue.syncNextTransaction(
+                            false /* acquireSingleBuffer */,
+                            transactionCallback::onTransactionReady);
+                }
+                final boolean realSizeChanged = performSurfaceTransaction(viewRoot,
+                        translator, creating, sizeChanged, hintChanged, surfaceUpdateTransaction);
 
                 try {
                     SurfaceHolder.Callback[] callbacks = null;
@@ -1015,9 +993,7 @@
                             mIsCreating = true;
                             if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
                                     + "visibleChanged -- surfaceCreated");
-                            if (callbacks == null) {
-                                callbacks = getSurfaceCallbacks();
-                            }
+                            callbacks = getSurfaceCallbacks();
                             for (SurfaceHolder.Callback c : callbacks) {
                                 c.surfaceCreated(mSurfaceHolder);
                             }
@@ -1035,32 +1011,7 @@
                             }
                         }
                         if (redrawNeeded) {
-                            if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
-                                    + "surfaceRedrawNeeded");
-                            if (callbacks == null) {
-                                callbacks = getSurfaceCallbacks();
-                            }
-
-                            final boolean wasRelayoutRequested = viewRoot.wasRelayoutRequested();
-                            if (wasRelayoutRequested && (mBlastBufferQueue != null)) {
-                                mBlastBufferQueue.syncNextTransaction(
-                                        false /* acquireSingleBuffer */,
-                                        this::onDrawFinished);
-                            }
-                            mPendingReportDraws++;
-                            viewRoot.drawPending();
-                            SurfaceCallbackHelper sch = new SurfaceCallbackHelper(() -> {
-                                if (mBlastBufferQueue != null) {
-                                    mBlastBufferQueue.stopContinuousSyncTransaction();
-                                }
-                                // If relayout was requested, then a callback from BBQ will
-                                // be invoked with the sync transaction. onDrawFinished will be
-                                // called in there
-                                if (!wasRelayoutRequested) {
-                                    onDrawFinished(null);
-                                }
-                            });
-                            sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
+                            redrawNeeded(callbacks, transactionCallback);
                         }
                     }
                 } finally {
@@ -1079,6 +1030,64 @@
         }
     }
 
+    private void redrawNeeded(SurfaceHolder.Callback[] callbacks,
+            @Nullable TransactionCallback transactionCallback) {
+        if (DEBUG) {
+            Log.i(TAG, System.identityHashCode(this) + " surfaceRedrawNeeded");
+        }
+        final SurfaceHolder.Callback[] capturedCallbacks =
+                callbacks == null ? getSurfaceCallbacks() : callbacks;
+
+        ViewRootImpl viewRoot = getViewRootImpl();
+        boolean isVriSync = viewRoot.addToSync(syncBufferCallback ->
+                redrawNeededAsync(capturedCallbacks, () -> {
+                    if (mBlastBufferQueue != null) {
+                        mBlastBufferQueue.stopContinuousSyncTransaction();
+                    }
+
+                    Transaction t = null;
+                    if (transactionCallback != null && mBlastBufferQueue != null) {
+                        t = transactionCallback.waitForTransaction();
+                    }
+                    // If relayout was requested, then a callback from BBQ will
+                    // be invoked with the sync transaction. onDrawFinished will be
+                    // called in there
+                    syncBufferCallback.onBufferReady(t);
+                    onDrawFinished();
+                }));
+
+        // If isVriSync, then everything was setup in the addToSync.
+        if (isVriSync) {
+            return;
+        }
+
+        redrawNeededAsync(capturedCallbacks, this::onDrawFinished);
+    }
+
+    private void redrawNeededAsync(SurfaceHolder.Callback[] callbacks,
+            Runnable callbacksCollected) {
+        SurfaceCallbackHelper sch = new SurfaceCallbackHelper(callbacksCollected);
+        sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
+    }
+
+    private static class TransactionCallback {
+        private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
+        private Transaction mTransaction;
+
+        Transaction waitForTransaction() {
+            try {
+                mCountDownLatch.await();
+            } catch (InterruptedException e) {
+            }
+            return mTransaction;
+        }
+
+        void onTransactionReady(Transaction t) {
+            mTransaction = t;
+            mCountDownLatch.countDown();
+        }
+    }
+
     /**
      * Copy the Surface from the SurfaceControl or the blast adapter.
      *
@@ -1189,13 +1198,13 @@
         mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, mFormat);
     }
 
-    private void onDrawFinished(@Nullable Transaction t) {
+    private void onDrawFinished() {
         if (DEBUG) {
             Log.i(TAG, System.identityHashCode(this) + " "
                     + "finishedDrawing");
         }
 
-        runOnUiThread(() -> performDrawFinished(t));
+        runOnUiThread(this::performDrawFinished);
     }
 
     /**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c222991..7d823b1 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -11939,13 +11939,22 @@
     @NonNull
     List<Rect> collectPreferKeepClearRects() {
         ListenerInfo info = mListenerInfo;
-        final List<Rect> list = new ArrayList<>();
+        boolean keepBoundsClear =
+                (info != null && info.mPreferKeepClear) || mPreferKeepClearForFocus;
+        boolean hasCustomKeepClearRects = info != null && info.mKeepClearRects != null;
 
-        if ((info != null && info.mPreferKeepClear) || mPreferKeepClearForFocus) {
+        if (!keepBoundsClear && !hasCustomKeepClearRects) {
+            return Collections.emptyList();
+        } else if (keepBoundsClear && !hasCustomKeepClearRects) {
+            return Collections.singletonList(new Rect(0, 0, getWidth(), getHeight()));
+        }
+
+        final List<Rect> list = new ArrayList<>();
+        if (keepBoundsClear) {
             list.add(new Rect(0, 0, getWidth(), getHeight()));
         }
 
-        if (info != null && info.mKeepClearRects != null) {
+        if (hasCustomKeepClearRects) {
             list.addAll(info.mKeepClearRects);
         }
 
@@ -12016,7 +12025,6 @@
 
     /**
      * Return the handwriting areas set on this view, in its local coordinates.
-     * Notice: the caller of this method should not modify the Rect returned.
      * @see #setHandwritingArea(Rect)
      *
      * @hide
@@ -12025,7 +12033,7 @@
     public Rect getHandwritingArea() {
         final ListenerInfo info = mListenerInfo;
         if (info != null) {
-            return info.mHandwritingArea;
+            return new Rect(info.mHandwritingArea);
         }
         return null;
     }
@@ -14650,6 +14658,7 @@
         int selectionStart;
         int selectionEnd;
         if (extendSelection && isAccessibilitySelectionExtendable()) {
+            prepareForExtendedAccessibilitySelection();
             selectionStart = getAccessibilitySelectionStart();
             if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) {
                 selectionStart = forward ? segmentStart : segmentEnd;
@@ -14689,6 +14698,14 @@
     }
 
     /**
+     * Prepare for extended selection.
+     * @hide
+     */
+    public void prepareForExtendedAccessibilitySelection() {
+        return;
+    }
+
+    /**
      * @hide
      */
     public int getAccessibilitySelectionStart() {
@@ -15617,7 +15634,7 @@
      * @param event the KeyEvent object that defines the button action
      */
     public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (event.hasNoModifiers() && KeyEvent.isConfirmKey(keyCode)) {
+        if (KeyEvent.isConfirmKey(keyCode) && event.hasNoModifiers()) {
             if ((mViewFlags & ENABLED_MASK) == DISABLED) {
                 return true;
             }
@@ -15674,7 +15691,7 @@
      * @param event   The KeyEvent object that defines the button action.
      */
     public boolean onKeyUp(int keyCode, KeyEvent event) {
-        if (event.hasNoModifiers() && KeyEvent.isConfirmKey(keyCode)) {
+        if (KeyEvent.isConfirmKey(keyCode) && event.hasNoModifiers()) {
             if ((mViewFlags & ENABLED_MASK) == DISABLED) {
                 return true;
             }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index bde761e..fa3834d 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -23,8 +23,6 @@
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.InputDevice.SOURCE_CLASS_NONE;
 import static android.view.InsetsState.ITYPE_IME;
-import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
-import static android.view.InsetsState.ITYPE_STATUS_BAR;
 import static android.view.InsetsState.SIZE;
 import static android.view.View.PFLAG_DRAW_ANIMATION;
 import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
@@ -53,8 +51,8 @@
 import static android.view.ViewRootImplProto.WINDOW_ATTRIBUTES;
 import static android.view.ViewRootImplProto.WIN_FRAME;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
-import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
 import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
+import static android.view.WindowCallbacks.RESIZE_MODE_INVALID;
 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
@@ -80,13 +78,13 @@
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
-import static android.view.WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_DOCKED;
-import static android.view.WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_FREEFORM;
+import static android.view.WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS;
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_FOCUS_CONTROLLER;
 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER;
@@ -277,6 +275,19 @@
     private static final boolean ENABLE_INPUT_LATENCY_TRACKING = true;
 
     /**
+     * Whether the caption is drawn by the shell.
+     * @hide
+     */
+    public static final boolean CAPTION_ON_SHELL = false;
+
+    /**
+     * Whether the client should compute the window frame on its own.
+     * @hide
+     */
+    public static final boolean LOCAL_LAYOUT =
+            SystemProperties.getBoolean("persist.debug.local_layout", false);
+
+    /**
      * Set this system property to true to force the view hierarchy to render
      * at 60 Hz. This can be used to measure the potential framerate.
      */
@@ -397,10 +408,8 @@
     private static boolean sAlwaysAssignFocus;
 
     /**
-     * This list must only be modified by the main thread, so a lock is only needed when changing
-     * the list or when accessing the list from a non-main thread.
+     * This list must only be modified by the main thread.
      */
-    @GuardedBy("mWindowCallbacks")
     final ArrayList<WindowCallbacks> mWindowCallbacks = new ArrayList<>();
     @UnsupportedAppUsage
     @UiContext
@@ -497,9 +506,10 @@
     public boolean mIsAnimating;
 
     private boolean mUseMTRenderer;
+    private boolean mPendingDragResizing;
     private boolean mDragResizing;
     private boolean mInvalidateRootRequested;
-    private int mResizeMode;
+    private int mResizeMode = RESIZE_MODE_INVALID;
     private int mCanvasOffsetX;
     private int mCanvasOffsetY;
     private boolean mActivityRelaunched;
@@ -546,7 +556,6 @@
 
     private final Rect mVisRect = new Rect(); // used to retrieve visible rect of focused view.
     private final Rect mTempRect = new Rect();
-    private final Rect mTempRect2 = new Rect();
 
     private final WindowLayout mWindowLayout = new WindowLayout();
 
@@ -578,11 +587,16 @@
 
 
     boolean mReportNextDraw;
+
     /**
-     * Set whether the draw should use blast sync. This is in case the draw is canceled,
-     * but will be rescheduled. We still want the next draw to be sync.
+     * Set whether the draw should send the buffer to system server. When set to true, VRI will
+     * create a sync transaction with BBQ and send the resulting buffer to system server. If false,
+     * VRI will not try to sync a buffer in BBQ, but still report when a draw occurred.
      */
-    boolean mNextDrawUseBlastSync;
+    private boolean mSyncBuffer = false;
+
+    int mSyncSeqId = 0;
+    int mLastSyncSeqId = 0;
 
     boolean mFullRedrawNeeded;
     boolean mNewSurfaceNeeded;
@@ -803,6 +817,10 @@
         return mHandwritingInitiator;
     }
 
+    private final SurfaceSyncer mSurfaceSyncer = new SurfaceSyncer();
+    private int mLastSyncId = -1;
+    private SurfaceSyncer.SyncBufferCallback mSyncBufferCallback;
+
     /**
      * Keeps track of the last frame number that was attempted to draw. Should only be accessed on
      * the RenderThread.
@@ -824,6 +842,23 @@
 
     private int mLastTransformHint = Integer.MIN_VALUE;
 
+    /**
+     * A temporary object used so relayoutWindow can return the latest SyncSeqId
+     * system. The SyncSeqId system was designed to work without synchronous relayout
+     * window, and actually synchronous relayout window presents a problem.  We could have
+     * a sequence like this:
+     *    1. We send MSG_RESIZED to the client with a new syncSeqId to begin a new sync
+     *    2. Due to scheduling the client executes performTraversals before calling MSG_RESIZED
+     *    3. Coincidentally for some random reason it also calls relayout
+     *    4. It observes the new state from relayout, and so the next frame will contain the state
+     * However it hasn't received the seqId yet, and so under the designed operation of
+     * seqId flowing through MSG_RESIZED, the next frame wouldn't be synced. Since it
+     * contains our target sync state, we need to sync it! This problem won't come up once
+     * we get rid of synchronous relayout, until then, we use this bundle to channel the
+     * integer back over relayout.
+     */
+    private Bundle mRelayoutBundle = new Bundle();
+
     private String mTag = TAG;
 
     public ViewRootImpl(Context context, Display display) {
@@ -867,6 +902,7 @@
         mDensity = context.getResources().getDisplayMetrics().densityDpi;
         mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
         mFallbackEventHandler = new PhoneFallbackEventHandler(context);
+        // TODO(b/222696368): remove getSfInstance usage and use vsyncId for transactions
         mChoreographer = useSfChoreographer
                 ? Choreographer.getSfInstance() : Choreographer.getInstance();
         mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
@@ -949,15 +985,11 @@
     }
 
     public void addWindowCallbacks(WindowCallbacks callback) {
-        synchronized (mWindowCallbacks) {
-            mWindowCallbacks.add(callback);
-        }
+        mWindowCallbacks.add(callback);
     }
 
     public void removeWindowCallbacks(WindowCallbacks callback) {
-        synchronized (mWindowCallbacks) {
-            mWindowCallbacks.remove(callback);
-        }
+        mWindowCallbacks.remove(callback);
     }
 
     public void reportDrawFinish() {
@@ -1198,8 +1230,7 @@
                         displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(),
                         UNSPECIFIED_LENGTH, UNSPECIFIED_LENGTH,
                         mInsetsController.getRequestedVisibilities(),
-                        getAttachedWindowFrame(), 1f /* compactScale */,
-                        mTmpFrames.displayFrame, mTempRect2, mTmpFrames.frame);
+                        getAttachedWindowFrame(), 1f /* compactScale */, mTmpFrames);
                 setFrame(mTmpFrames.frame);
                 registerBackCallbackOnWindow();
                 if (!WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) {
@@ -1679,17 +1710,26 @@
         final MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg2;
         final boolean forceNextWindowRelayout = args.argi1 != 0;
         final int displayId = args.argi3;
-        final Rect backdropFrame = frames.backdropFrame;
+        final int resizeMode = args.argi5;
 
-        final boolean frameChanged = !mWinFrame.equals(frames.frame);
-        final boolean backdropFrameChanged = !mPendingBackDropFrame.equals(backdropFrame);
+        final Rect frame = frames.frame;
+        final Rect displayFrame = frames.displayFrame;
+        if (mTranslator != null) {
+            mTranslator.translateRectInScreenToAppWindow(frame);
+            mTranslator.translateRectInScreenToAppWindow(displayFrame);
+        }
+        final boolean frameChanged = !mWinFrame.equals(frame);
         final boolean configChanged = !mLastReportedMergedConfiguration.equals(mergedConfiguration);
         final boolean displayChanged = mDisplay.getDisplayId() != displayId;
-        if (msg == MSG_RESIZED && !frameChanged && !backdropFrameChanged && !configChanged
-                && !displayChanged && !forceNextWindowRelayout) {
+        final boolean resizeModeChanged = mResizeMode != resizeMode;
+        if (msg == MSG_RESIZED && !frameChanged && !configChanged && !displayChanged
+                && !resizeModeChanged && !forceNextWindowRelayout) {
             return;
         }
 
+        mPendingDragResizing = resizeMode != RESIZE_MODE_INVALID;
+        mResizeMode = resizeMode;
+
         if (configChanged) {
             // If configuration changed - notify about that and, maybe, about move to display.
             performConfigurationChange(mergedConfiguration, false /* force */,
@@ -1699,11 +1739,20 @@
             onMovedToDisplay(displayId, mLastConfigurationFromResources);
         }
 
-        setFrame(frames.frame);
-        mTmpFrames.displayFrame.set(frames.displayFrame);
-        mPendingBackDropFrame.set(backdropFrame);
+        setFrame(frame);
+        mTmpFrames.displayFrame.set(displayFrame);
+
+        if (mDragResizing && mUseMTRenderer) {
+            boolean fullscreen = frame.equals(mPendingBackDropFrame);
+            for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
+                mWindowCallbacks.get(i).onWindowSizeIsChanging(mPendingBackDropFrame, fullscreen,
+                        mAttachInfo.mVisibleInsets, mAttachInfo.mStableInsets);
+            }
+        }
+
         mForceNextWindowRelayout = forceNextWindowRelayout;
         mPendingAlwaysConsumeSystemBars = args.argi2 != 0;
+        mSyncSeqId = args.argi4;
 
         if (msg == MSG_RESIZED_REPORT) {
             reportNextDraw();
@@ -1771,6 +1820,7 @@
         updateInternalDisplay(displayId, mView.getResources());
         mImeFocusController.onMovedToDisplay();
         mAttachInfo.mDisplayState = mDisplay.getState();
+        mDisplayInstallOrientation = mDisplay.getInstallOrientation();
         // Internal state updated, now notify the view hierarchy.
         mView.dispatchMovedToDisplay(mDisplay, config);
     }
@@ -2280,17 +2330,17 @@
      */
     void updateCompatSysUiVisibility(@InternalInsetsType int type, boolean visible,
             boolean hasControl) {
-        if (type != ITYPE_STATUS_BAR && type != ITYPE_NAVIGATION_BAR) {
+        @InsetsType final int publicType = InsetsState.toPublicType(type);
+        if (publicType != Type.statusBars() && publicType != Type.navigationBars()) {
             return;
         }
         final SystemUiVisibilityInfo info = mCompatibleVisibilityInfo;
-        final int systemUiFlag = type == ITYPE_STATUS_BAR
+        final int systemUiFlag = publicType == Type.statusBars()
                 ? View.SYSTEM_UI_FLAG_FULLSCREEN
                 : View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
-        final boolean wasVisible = (info.globalVisibility & systemUiFlag) == 0;
         if (visible) {
             info.globalVisibility &= ~systemUiFlag;
-            if (!wasVisible && hasControl) {
+            if (hasControl && (mAttachInfo.mSystemUiVisibility & systemUiFlag) != 0) {
                 // The local system UI visibility can only be cleared while we have the control.
                 info.localChanges |= systemUiFlag;
             }
@@ -2561,6 +2611,9 @@
     }
 
     private boolean updateCaptionInsets() {
+        if (CAPTION_ON_SHELL) {
+            return false;
+        }
         if (!(mView instanceof DecorView)) return false;
         final int captionInsetsHeight = ((DecorView) mView).getCaptionInsetsHeight();
         final Rect captionFrame = new Rect();
@@ -2607,7 +2660,6 @@
     private void performTraversals() {
         // cache mView since it is used so much below...
         final View host = mView;
-
         if (DBG) {
             System.out.println("======================================");
             System.out.println("performTraversals");
@@ -2852,8 +2904,6 @@
                 mView.onSystemBarAppearanceChanged(mDispatchedSystemBarAppearance);
             }
         }
-        final boolean wasReportNextDraw = mReportNextDraw;
-        boolean useBlastSync = mNextDrawUseBlastSync;
 
         if (mFirst || windowShouldResize || viewVisibilityChanged || params != null
                 || mForceNextWindowRelayout) {
@@ -2885,19 +2935,14 @@
                     mViewFrameInfo.flags |= FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED;
                 }
                 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
-                final boolean freeformResizing = (relayoutResult
-                        & RELAYOUT_RES_DRAG_RESIZING_FREEFORM) != 0;
-                final boolean dockedResizing = (relayoutResult
-                        & RELAYOUT_RES_DRAG_RESIZING_DOCKED) != 0;
-                final boolean dragResizing = freeformResizing || dockedResizing;
-                if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_BLAST_SYNC) != 0) {
+                final boolean dragResizing = mPendingDragResizing;
+                if (mSyncSeqId > mLastSyncSeqId) {
+                    mLastSyncSeqId = mSyncSeqId;
                     if (DEBUG_BLAST) {
                         Log.d(mTag, "Relayout called with blastSync");
                     }
                     reportNextDraw();
-                    if (isHardwareEnabled()) {
-                        useBlastSync = true;
-                    }
+                    mSyncBuffer = true;
                 }
 
                 final boolean surfaceControlChanged =
@@ -3032,9 +3077,6 @@
 
                 if (mDragResizing != dragResizing) {
                     if (dragResizing) {
-                        mResizeMode = freeformResizing
-                                ? RESIZE_MODE_FREEFORM
-                                : RESIZE_MODE_DOCKED_DIVIDER;
                         final boolean backdropSizeMatchesFrame =
                                 mWinFrame.width() == mPendingBackDropFrame.width()
                                         && mWinFrame.height() == mPendingBackDropFrame.height();
@@ -3136,12 +3178,9 @@
             // done to achieve a more hermetic fix for S, but it's entirely
             // possible that checking the most recent value is actually more
             // correct here.
-            if (!mStopped || wasReportNextDraw) {
-                boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
-                        (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
-                if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
-                        || mHeight != host.getMeasuredHeight() || dispatchApplyInsets ||
-                        updatedConfiguration) {
+            if (!mStopped || mReportNextDraw) {
+                if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()
+                        || dispatchApplyInsets || updatedConfiguration) {
                     int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width,
                             lp.privateFlags);
                     int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height,
@@ -3208,7 +3247,7 @@
             prepareSurfaces();
         }
 
-        final boolean didLayout = layoutRequested && (!mStopped || wasReportNextDraw);
+        final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
         boolean triggerGlobalLayoutListener = didLayout
                 || mAttachInfo.mRecomputeGlobalAttributes;
         if (didLayout) {
@@ -3401,45 +3440,37 @@
 
         mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes);
 
-        // Remember if we must report the next draw.
         if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
             reportNextDraw();
         }
 
-        boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
-        if (mBLASTDrawConsumer != null) {
-            useBlastSync = true;
+        boolean cancelAndRedraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw();
+        if (!cancelAndRedraw) {
+            createSyncIfNeeded();
         }
 
-        if (!cancelDraw) {
+        if (!isViewVisible) {
+            if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
+                for (int i = 0; i < mPendingTransitions.size(); ++i) {
+                    mPendingTransitions.get(i).endChangingAnimations();
+                }
+                mPendingTransitions.clear();
+            }
+
+            if (mSyncBufferCallback != null) {
+                mSyncBufferCallback.onBufferReady(null);
+            }
+        } else if (cancelAndRedraw) {
+            // Try again
+            scheduleTraversals();
+        } else {
             if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
                 for (int i = 0; i < mPendingTransitions.size(); ++i) {
                     mPendingTransitions.get(i).startChangingAnimations();
                 }
                 mPendingTransitions.clear();
             }
-            performDraw(useBlastSync);
-            mNextDrawUseBlastSync = false;
-        } else {
-            if (isViewVisible) {
-                // Try again
-                mNextDrawUseBlastSync = useBlastSync;
-                scheduleTraversals();
-            } else {
-                if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
-                    for (int i = 0; i < mPendingTransitions.size(); ++i) {
-                        mPendingTransitions.get(i).endChangingAnimations();
-                    }
-                    mPendingTransitions.clear();
-                }
-
-                // We may never draw since it's not visible. Report back that we're finished
-                // drawing.
-                if (!wasReportNextDraw && mReportNextDraw) {
-                    mReportNextDraw = false;
-                    pendingDrawFinished();
-                }
-            }
+            performDraw();
         }
 
         if (mAttachInfo.mContentCaptureEvents != null) {
@@ -3448,6 +3479,48 @@
 
         mIsInTraversal = false;
         mRelayoutRequested = false;
+
+        if (!cancelAndRedraw) {
+            mReportNextDraw = false;
+            mSyncBufferCallback = null;
+            mSyncBuffer = false;
+            if (mLastSyncId != -1) {
+                mSurfaceSyncer.markSyncReady(mLastSyncId);
+                mLastSyncId = -1;
+            }
+        }
+    }
+
+    private void createSyncIfNeeded() {
+        // Started a sync already.
+        if (mLastSyncId != -1) {
+            return;
+        }
+
+        Consumer<Transaction> syncConsumer = null;
+        final int seqId = mSyncSeqId;
+
+        if (mBLASTDrawConsumer != null) {
+            syncConsumer = mBLASTDrawConsumer;
+            mBLASTDrawConsumer = null;
+        } else if (mReportNextDraw) {
+            syncConsumer = transaction -> {
+                mSurfaceChangedTransaction.merge(transaction);
+                reportDrawFinished(seqId);
+            };
+        }
+
+        if (syncConsumer != null) {
+            final Consumer<Transaction> capturedSyncConsumer = syncConsumer;
+            mLastSyncId = mSurfaceSyncer.setupSync(transaction -> {
+                // Callback will be invoked on executor thread so post to main thread.
+                mHandler.postAtFrontOfQueue(() -> capturedSyncConsumer.accept(transaction));
+            });
+            if (DEBUG_BLAST) {
+                Log.d(mTag, "Setup new sync id=" + mLastSyncId);
+            }
+            mSurfaceSyncer.addToSync(mLastSyncId, mSyncTarget);
+        }
     }
 
     private void notifyContentCatpureEvents() {
@@ -4061,57 +4134,13 @@
         }
     }
 
-    /**
-     * A count of the number of calls to pendingDrawFinished we
-     * require to notify the WM drawing is complete.
-     */
-    int mDrawsNeededToReport = 0;
-
-    /**
-     * Delay notifying WM of draw finished until
-     * a balanced call to pendingDrawFinished.
-     */
-    void drawPending() {
-        mDrawsNeededToReport++;
-    }
-
-    void pendingDrawFinished(Transaction t) {
-        if (mDrawsNeededToReport == 0) {
-            throw new RuntimeException("Unbalanced drawPending/pendingDrawFinished calls");
-        }
-
-        if (t != null) {
-            if (DEBUG_BLAST) {
-                Log.d(mTag, "Merging transaction into main window transaction");
-            }
-            mSurfaceChangedTransaction.merge(t);
-        }
-
-        mDrawsNeededToReport--;
-        if (mDrawsNeededToReport == 0) {
-            reportDrawFinished();
-        } else if (DEBUG_BLAST) {
-            Log.d(mTag, "pendingDrawFinished. Waiting on draw reported mDrawsNeededToReport="
-                    + mDrawsNeededToReport);
-        }
-    }
-
-    void pendingDrawFinished() {
-        pendingDrawFinished(null);
-    }
-
-    private void postDrawFinished() {
-        mHandler.sendEmptyMessage(MSG_DRAW_FINISHED);
-    }
-
-    private void reportDrawFinished() {
+    private void reportDrawFinished(int seqId) {
         if (DEBUG_BLAST) {
-            Log.d(mTag, "reportDrawFinished");
+            Log.d(mTag, "reportDrawFinished " + Debug.getCallers(5));
         }
-        mDrawsNeededToReport = 0;
 
         try {
-            mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction);
+            mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction, seqId);
         } catch (RemoteException e) {
             Log.e(mTag, "Unable to report draw finished", e);
             mSurfaceChangedTransaction.apply();
@@ -4127,6 +4156,19 @@
         return mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled();
     }
 
+    boolean addToSync(SurfaceSyncer.SyncTarget syncable) {
+        if (mLastSyncId == -1) {
+            return false;
+        }
+        mSurfaceSyncer.addToSync(mLastSyncId, syncable);
+        return true;
+    }
+
+
+    public boolean isInSync() {
+        return mLastSyncId != -1;
+    }
+
     private void addFrameCommitCallbackIfNeeded() {
         if (!isHardwareEnabled()) {
             return;
@@ -4157,188 +4199,82 @@
         });
     }
 
-    private HardwareRenderer.FrameCommitCallback createFrameCommitCallbackForSync(
-            boolean useBlastSync, boolean reportNextDraw, Consumer<Transaction> blastSyncConsumer) {
-        return didProduceBuffer -> {
-            if (DEBUG_BLAST) {
-                Log.d(mTag, "Received frameCommittedCallback "
-                        + " lastAttemptedDrawFrameNum=" + mRtLastAttemptedDrawFrameNum
-                        + " didProduceBuffer=" + didProduceBuffer);
-            }
-
-            // If frame wasn't drawn, clear out the next transaction so it doesn't affect the next
-            // draw attempt. The next transaction and transaction complete callback were only set
-            // for the current draw attempt.
-            final Transaction pendingTransactions;
-            if (!didProduceBuffer) {
-                mBlastBufferQueue.syncNextTransaction(null);
-                // Get the transactions that were sent to mergeWithNextTransaction since the
-                // frame didn't draw on this vsync. It's possible the frame will draw later, but
-                // it's better to not be sync than to block on a frame that may never come.
-                pendingTransactions = mBlastBufferQueue.gatherPendingTransactions(
-                        mRtLastAttemptedDrawFrameNum);
-                if (!useBlastSync && !reportNextDraw) {
-                    pendingTransactions.apply();
-                }
-            } else {
-                pendingTransactions = null;
-            }
-            // Post at front of queue so the buffer can be processed immediately and allow RT
-            // to continue processing new buffers. If RT tries to process buffers before the sync
-            // buffer is applied, the new buffers will not get acquired and could result in a
-            // deadlock. UI thread would wait on RT, but RT would be blocked waiting for a free
-            // buffer.
-            mHandler.postAtFrontOfQueue(() -> {
-                if (!didProduceBuffer && useBlastSync) {
-                    mSurfaceChangedTransaction.merge(pendingTransactions);
-                    if (blastSyncConsumer != null) {
-                        blastSyncConsumer.accept(mSurfaceChangedTransaction);
-                    }
-                }
-
-                // This is to ensure pendingDrawFinished is only called exactly one time per draw
-                // attempt when reportNextDraw is true. Since, we sometimes create a sync
-                // transaction callback, the callback will handle calling pendingDrawFinished.
-                // However, there are cases where the transaction callback may not be called.
-                // 1. If useBlastSync is false, then we know that a sync transaction callback was
-                // not created so we won't invoke pendingDrawFinished there.
-                // 2. If the draw didn't produce a frame, didProduceBuffer == false, then we know
-                // the sync transaction callback will not be invoked even if one was set up.
-                if (reportNextDraw && (!didProduceBuffer || !useBlastSync)) {
-                    pendingDrawFinished();
-                }
-            });
-
-        };
-    }
-
     @Nullable
-    private FrameDrawingCallback createFrameDrawingCallbackIfNeeded(boolean useBlastSync,
-            boolean reportNextDraw) {
+    private void registerFrameDrawingCallbackForBlur() {
         if (!isHardwareEnabled()) {
-            return null;
+            return;
         }
         final boolean hasBlurUpdates = mBlurRegionAggregator.hasUpdates();
         final boolean needsCallbackForBlur = hasBlurUpdates || mBlurRegionAggregator.hasRegions();
 
-        if (!useBlastSync && !needsCallbackForBlur && !reportNextDraw && !mHasPendingTransactions) {
-            return null;
-        }
-
-        final Consumer<SurfaceControl.Transaction> blastSyncConsumer = mBLASTDrawConsumer;
-        mBLASTDrawConsumer = null;
-
-        if (DEBUG_BLAST) {
-            Log.d(mTag, "Creating frameDrawingCallback"
-                    + " nextDrawUseBlastSync=" + useBlastSync
-                    + " reportNextDraw=" + reportNextDraw
-                    + " hasBlurUpdates=" + hasBlurUpdates
-                    + " hasBlastSyncConsumer=" + (blastSyncConsumer != null)
-                    + " mHasPendingTransactions=" + mHasPendingTransactions);
+        if (!needsCallbackForBlur) {
+            return;
         }
 
         final BackgroundBlurDrawable.BlurRegion[] blurRegionsForFrame =
-                needsCallbackForBlur ?  mBlurRegionAggregator.getBlurRegionsCopyForRT() : null;
-        final boolean hasPendingTransactions = mHasPendingTransactions;
-        mHasPendingTransactions = false;
+                mBlurRegionAggregator.getBlurRegionsCopyForRT();
 
         // The callback will run on the render thread.
-        return new FrameDrawingCallback() {
+        registerRtFrameCallback((frame) -> mBlurRegionAggregator
+                .dispatchBlurTransactionIfNeeded(frame, blurRegionsForFrame, hasBlurUpdates));
+    }
+
+    private void registerCallbackForPendingTransactions() {
+        registerRtFrameCallback(new FrameDrawingCallback() {
+            @Override
+            public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) {
+                if ((syncResult
+                        & (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) {
+                    mBlastBufferQueue.applyPendingTransactions(frame);
+                    return null;
+                }
+
+                return didProduceBuffer -> {
+                    if (!didProduceBuffer) {
+                        mBlastBufferQueue.applyPendingTransactions(frame);
+                    }
+                };
+
+            }
+
             @Override
             public void onFrameDraw(long frame) {
             }
-
-            @Override
-            public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) {
-                if (DEBUG_BLAST) {
-                    Log.d(mTag,
-                            "Received frameDrawingCallback syncResult=" + syncResult + " frameNum="
-                                    + frame + ".");
-                }
-
-                mRtLastAttemptedDrawFrameNum = frame;
-
-                if (needsCallbackForBlur) {
-                    mBlurRegionAggregator.dispatchBlurTransactionIfNeeded(frame,
-                            blurRegionsForFrame, hasBlurUpdates);
-                }
-
-                if (mBlastBufferQueue == null) {
-                    return null;
-                }
-
-                if (!useBlastSync && !reportNextDraw && !hasPendingTransactions) {
-                    return null;
-                }
-
-                // If the syncResults are SYNC_LOST_SURFACE_REWARD_IF_FOUND or
-                // SYNC_CONTEXT_IS_STOPPED it means nothing will draw. There's no need to set up
-                // any blast sync or commit callback, and the code should directly call
-                // pendingDrawFinished.
-                if ((syncResult
-                        & (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) {
-                    if (reportNextDraw) {
-                        mHandler.postAtFrontOfQueue(() -> pendingDrawFinished());
-                    }
-                    return null;
-                }
-
-                if (DEBUG_BLAST) {
-                    Log.d(mTag, "Setting up sync and frameCommitCallback");
-                }
-
-                if (useBlastSync) {
-                    // Frame callbacks will always occur after submitting draw requests and before
-                    // the draw actually occurs. This will ensure that we set the next transaction
-                    // for the frame that's about to get drawn and not on a previous frame.
-                    mBlastBufferQueue.syncNextTransaction(
-                            t -> {
-                                mHandler.postAtFrontOfQueue(() -> {
-                                    mSurfaceChangedTransaction.merge(t);
-                                    if (blastSyncConsumer != null) {
-                                        blastSyncConsumer.accept(mSurfaceChangedTransaction);
-                                    }
-
-                                    if (reportNextDraw) {
-                                        pendingDrawFinished();
-                                    }
-                                });
-                            });
-                }
-
-                return createFrameCommitCallbackForSync(useBlastSync, reportNextDraw,
-                        blastSyncConsumer);
-            }
-        };
+        });
     }
 
-    private void performDraw(boolean useBlastSync) {
+    private void performDraw() {
         if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
             return;
         } else if (mView == null) {
             return;
         }
 
-        final boolean fullRedrawNeeded = mFullRedrawNeeded || mReportNextDraw || useBlastSync;
+        final boolean fullRedrawNeeded = mFullRedrawNeeded || mSyncBufferCallback != null;
         mFullRedrawNeeded = false;
 
         mIsDrawing = true;
         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
 
-        FrameDrawingCallback frameDrawingCallback = createFrameDrawingCallbackIfNeeded(useBlastSync,
-                mReportNextDraw);
-        if (frameDrawingCallback != null) {
-            mAttachInfo.mThreadedRenderer.registerRtFrameCallback(frameDrawingCallback);
-        }
+        registerFrameDrawingCallbackForBlur();
         addFrameCommitCallbackIfNeeded();
-        boolean usingAsyncReport = isHardwareEnabled() && (useBlastSync || mReportNextDraw);
+
+        boolean usingAsyncReport = isHardwareEnabled() && mSyncBufferCallback != null;
+        if (usingAsyncReport) {
+            registerCallbacksForSync(mSyncBuffer, mSyncBufferCallback);
+        } else if (mHasPendingTransactions) {
+            // These callbacks are only needed if there's no sync involved and there were calls to
+            // applyTransactionOnDraw. These callbacks check if the draw failed for any reason and
+            // apply those transactions directly so they don't get stuck forever.
+            registerCallbackForPendingTransactions();
+        }
+        mHasPendingTransactions = false;
 
         try {
             boolean canUseAsync = draw(fullRedrawNeeded);
             if (usingAsyncReport && !canUseAsync) {
                 mAttachInfo.mThreadedRenderer.setFrameCallback(null);
                 usingAsyncReport = false;
-                mAttachInfo.mThreadedRenderer.unregisterRtFrameCallback(frameDrawingCallback);
             }
         } finally {
             mIsDrawing = false;
@@ -4356,7 +4292,6 @@
         }
 
         if (mReportNextDraw) {
-            mReportNextDraw = false;
 
             // if we're using multi-thread renderer, wait for the window frame draws
             if (mWindowDrawCountDown != null) {
@@ -4377,7 +4312,11 @@
             }
 
             if (mSurfaceHolder != null && mSurface.isValid()) {
-                SurfaceCallbackHelper sch = new SurfaceCallbackHelper(this::postDrawFinished);
+                final SurfaceSyncer.SyncBufferCallback syncBufferCallback = mSyncBufferCallback;
+                SurfaceCallbackHelper sch = new SurfaceCallbackHelper(() ->
+                        mHandler.post(() -> syncBufferCallback.onBufferReady(null)));
+                mSyncBufferCallback = null;
+
                 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
 
                 sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
@@ -4385,9 +4324,11 @@
                 if (mAttachInfo.mThreadedRenderer != null) {
                     mAttachInfo.mThreadedRenderer.fence();
                 }
-                pendingDrawFinished();
             }
         }
+        if (mSyncBufferCallback != null && !usingAsyncReport) {
+            mSyncBufferCallback.onBufferReady(null);
+        }
         if (mPerformContentCapture) {
             performContentCaptureInitialReport();
         }
@@ -5396,7 +5337,6 @@
     private static final int MSG_REQUEST_KEYBOARD_SHORTCUTS = 26;
     private static final int MSG_UPDATE_POINTER_ICON = 27;
     private static final int MSG_POINTER_CAPTURE_CHANGED = 28;
-    private static final int MSG_DRAW_FINISHED = 29;
     private static final int MSG_INSETS_CHANGED = 30;
     private static final int MSG_INSETS_CONTROL_CHANGED = 31;
     private static final int MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED = 32;
@@ -5459,8 +5399,6 @@
                     return "MSG_UPDATE_POINTER_ICON";
                 case MSG_POINTER_CAPTURE_CHANGED:
                     return "MSG_POINTER_CAPTURE_CHANGED";
-                case MSG_DRAW_FINISHED:
-                    return "MSG_DRAW_FINISHED";
                 case MSG_INSETS_CHANGED:
                     return "MSG_INSETS_CHANGED";
                 case MSG_INSETS_CONTROL_CHANGED:
@@ -5589,8 +5527,6 @@
                         mTmpFrames.frame.top = t;
                         mTmpFrames.frame.bottom = t + h;
                         setFrame(mTmpFrames.frame);
-
-                        mPendingBackDropFrame.set(mWinFrame);
                         maybeHandleWindowMove(mWinFrame);
                     }
                     break;
@@ -5693,9 +5629,6 @@
                     final boolean hasCapture = msg.arg1 != 0;
                     handlePointerCaptureChanged(hasCapture);
                 } break;
-                case MSG_DRAW_FINISHED: {
-                    pendingDrawFinished();
-                } break;
                 case MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED: {
                     systemGestureExclusionChanged();
                 }   break;
@@ -8024,7 +7957,6 @@
 
     private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
             boolean insetsPending) throws RemoteException {
-
         mRelayoutRequested = true;
         float appScale = mAttachInfo.mApplicationScale;
         boolean restore = false;
@@ -8050,21 +7982,71 @@
         final int requestedWidth = (int) (mView.getMeasuredWidth() * appScale + 0.5f);
         final int requestedHeight = (int) (mView.getMeasuredHeight() * appScale + 0.5f);
 
-        int relayoutResult = mWindowSession.relayout(mWindow, params,
-                requestedWidth, requestedHeight, viewVisibility,
-                insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
-                mTmpFrames, mPendingMergedConfiguration, mSurfaceControl, mTempInsets,
-                mTempControls);
+        mWillMove = false;
+        mWillResize = false;
+        int relayoutResult = 0;
+        WindowConfiguration winConfig = getConfiguration().windowConfiguration;
+        if (LOCAL_LAYOUT) {
+            if (mFirst || viewVisibility != mViewVisibility) {
+                relayoutResult = mWindowSession.updateVisibility(mWindow, params, viewVisibility,
+                        mPendingMergedConfiguration, mSurfaceControl, mTempInsets, mTempControls);
+                if (mTranslator != null) {
+                    mTranslator.translateInsetsStateInScreenToAppWindow(mTempInsets);
+                    mTranslator.translateSourceControlsInScreenToAppWindow(mTempControls);
+                }
+                mInsetsController.onStateChanged(mTempInsets);
+                mInsetsController.onControlsChanged(mTempControls);
+
+                mPendingAlwaysConsumeSystemBars =
+                        (relayoutResult & RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS) != 0;
+            }
+            final InsetsState state = mInsetsController.getState();
+            final Rect displayCutoutSafe = mTempRect;
+            state.getDisplayCutoutSafe(displayCutoutSafe);
+            if (mWindowAttributes.type == TYPE_APPLICATION_STARTING) {
+                // TODO(b/210378379): Remove the special logic.
+                // Letting starting window use the window bounds from the pending config is for the
+                // fixed rotation, because the config is not overridden before the starting window
+                // is created.
+                winConfig = mPendingMergedConfiguration.getMergedConfiguration()
+                        .windowConfiguration;
+            }
+            mWindowLayout.computeFrames(mWindowAttributes, state, displayCutoutSafe,
+                    winConfig.getBounds(), winConfig.getWindowingMode(), requestedWidth,
+                    requestedHeight, mInsetsController.getRequestedVisibilities(),
+                    getAttachedWindowFrame(), 1f /* compatScale */, mTmpFrames);
+
+            mWindowSession.updateLayout(mWindow, params,
+                    insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mTmpFrames,
+                    requestedWidth, requestedHeight);
+
+        } else {
+            relayoutResult = mWindowSession.relayout(mWindow, params,
+                    requestedWidth, requestedHeight, viewVisibility,
+                    insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
+                    mTmpFrames, mPendingMergedConfiguration, mSurfaceControl, mTempInsets,
+                    mTempControls, mRelayoutBundle);
+            mSyncSeqId = mRelayoutBundle.getInt("seqid");
+
+            if (mTranslator != null) {
+                mTranslator.translateRectInScreenToAppWindow(mTmpFrames.frame);
+                mTranslator.translateRectInScreenToAppWindow(mTmpFrames.displayFrame);
+                mTranslator.translateInsetsStateInScreenToAppWindow(mTempInsets);
+                mTranslator.translateSourceControlsInScreenToAppWindow(mTempControls);
+            }
+            mInsetsController.onStateChanged(mTempInsets);
+            mInsetsController.onControlsChanged(mTempControls);
+
+            mPendingAlwaysConsumeSystemBars =
+                    (relayoutResult & RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS) != 0;
+        }
 
         final int transformHint = SurfaceControl.rotationToBufferTransform(
                 (mDisplayInstallOrientation + mDisplay.getRotation()) % 4);
 
-        final WindowConfiguration winConfig = getConfiguration().windowConfiguration;
-        final boolean dragResizing = (relayoutResult
-                & (RELAYOUT_RES_DRAG_RESIZING_DOCKED | RELAYOUT_RES_DRAG_RESIZING_FREEFORM)) != 0;
         WindowLayout.computeSurfaceSize(mWindowAttributes, winConfig.getMaxBounds(), requestedWidth,
-                requestedHeight, mTmpFrames.frame, dragResizing, mSurfaceSize);
-      
+                requestedHeight, mTmpFrames.frame, mPendingDragResizing, mSurfaceSize);
+
         final boolean transformHintChanged = transformHint != mLastTransformHint;
         final boolean sizeChanged = !mLastSurfaceSize.equals(mSurfaceSize);
         final boolean surfaceControlChanged =
@@ -8089,7 +8071,6 @@
                     getConfiguration().windowConfiguration.getBounds());
         }
 
-        mPendingBackDropFrame.set(mTmpFrames.backdropFrame);
         if (mSurfaceControl.isValid()) {
             if (!useBLAST()) {
                 mSurface.copyFrom(mSurfaceControl);
@@ -8111,23 +8092,10 @@
             destroySurface();
         }
 
-        mPendingAlwaysConsumeSystemBars =
-                (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS) != 0;
-
         if (restore) {
             params.restore();
         }
-
-        if (mTranslator != null) {
-            mTranslator.translateRectInScreenToAppWindow(mTmpFrames.frame);
-            mTranslator.translateInsetsStateInScreenToAppWindow(mTempInsets);
-            mTranslator.translateSourceControlsInScreenToAppWindow(mTempControls);
-        }
         setFrame(mTmpFrames.frame);
-        mWillMove = false;
-        mWillResize = false;
-        mInsetsController.onStateChanged(mTempInsets);
-        mInsetsController.onControlsChanged(mTempControls);
         return relayoutResult;
     }
 
@@ -8164,6 +8132,13 @@
 
     private void setFrame(Rect frame) {
         mWinFrame.set(frame);
+
+        // Surface position is now inherited from parent, and BackdropFrameRenderer uses backdrop
+        // frame to position content. Thus, we just keep the size of backdrop frame, and remove the
+        // offset to avoid double offset from display origin.
+        mPendingBackDropFrame.set(frame);
+        mPendingBackDropFrame.offsetTo(0, 0);
+
         mInsetsController.onFrameChanged(mOverrideInsetsFrame != null ?
             mOverrideInsetsFrame : frame);
     }
@@ -8480,7 +8455,7 @@
                             if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
                                     & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
                                 mWindowSession.finishDrawing(
-                                        mWindow, null /* postDrawTransaction */);
+                                    mWindow, null /* postDrawTransaction */, Integer.MAX_VALUE);
                             }
                         } catch (RemoteException e) {
                         }
@@ -8554,29 +8529,9 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     private void dispatchResized(ClientWindowFrames frames, boolean reportDraw,
             MergedConfiguration mergedConfiguration, boolean forceLayout,
-            boolean alwaysConsumeSystemBars, int displayId) {
-        final Rect frame = frames.frame;
-        final Rect backDropFrame = frames.backdropFrame;
-        if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString()
-                + " reportDraw=" + reportDraw
-                + " backDropFrame=" + backDropFrame);
-
-        // Tell all listeners that we are resizing the window so that the chrome can get
-        // updated as fast as possible on a separate thread,
-        if (mDragResizing && mUseMTRenderer) {
-            boolean fullscreen = frame.equals(backDropFrame);
-            synchronized (mWindowCallbacks) {
-                for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
-                    mWindowCallbacks.get(i).onWindowSizeIsChanging(backDropFrame, fullscreen,
-                            mAttachInfo.mVisibleInsets, mAttachInfo.mStableInsets);
-                }
-            }
-        }
+            boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, int resizeMode) {
 
         Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
-        if (mTranslator != null) {
-            mTranslator.translateRectInScreenToAppWindow(frame);
-        }
         SomeArgs args = SomeArgs.obtain();
         final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid());
         args.arg1 = sameProcessCall ? new ClientWindowFrames(frames) : frames;
@@ -8585,6 +8540,9 @@
         args.argi1 = forceLayout ? 1 : 0;
         args.argi2 = alwaysConsumeSystemBars ? 1 : 0;
         args.argi3 = displayId;
+        args.argi4 = syncSeqId;
+        args.argi5 = resizeMode;
+
         msg.obj = args;
         mHandler.sendMessage(msg);
     }
@@ -9876,8 +9834,8 @@
     }
 
     private void reportNextDraw() {
-        if (mReportNextDraw == false) {
-            drawPending();
+        if (DEBUG_BLAST) {
+            Log.d(mTag, "reportNextDraw " + Debug.getCallers(5));
         }
         mReportNextDraw = true;
     }
@@ -9888,9 +9846,14 @@
      * This method is only supposed to be used to speed up the interaction from SystemUI and window
      * manager when waiting for the first frame to be drawn when turning on the screen. DO NOT USE
      * unless you fully understand this interaction.
+     *
+     * @param syncBuffer If true, the transaction that contains the buffer from the draw should be
+     *                   sent to system to be synced. If false, VRI will not try to sync the buffer,
+     *                   but only report back that a buffer was drawn.
      * @hide
      */
-    public void setReportNextDraw() {
+    public void setReportNextDraw(boolean syncBuffer) {
+        mSyncBuffer = syncBuffer;
         reportNextDraw();
         invalidate();
     }
@@ -9969,11 +9932,11 @@
         @Override
         public void resized(ClientWindowFrames frames, boolean reportDraw,
                 MergedConfiguration mergedConfiguration, boolean forceLayout,
-                boolean alwaysConsumeSystemBars, int displayId) {
+                boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, int resizeMode) {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
                 viewAncestor.dispatchResized(frames, reportDraw, mergedConfiguration, forceLayout,
-                        alwaysConsumeSystemBars, displayId);
+                        alwaysConsumeSystemBars, displayId, syncSeqId, resizeMode);
             }
         }
 
@@ -10891,7 +10854,7 @@
             }
         };
         mOnBackInvokedDispatcher.registerOnBackInvokedCallback(
-                mCompatOnBackInvokedCallback, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+                OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCompatOnBackInvokedCallback);
     }
 
     private void unregisterCompatOnBackInvokedCallback() {
@@ -10916,14 +10879,15 @@
         return mWindowSession;
     }
 
-    private void registerCallbacksForSync(
+    private void registerCallbacksForSync(boolean syncBuffer,
             final SurfaceSyncer.SyncBufferCallback syncBufferCallback) {
         if (!isHardwareEnabled()) {
-            // TODO: correctly handle when hardware disabled
-            syncBufferCallback.onBufferReady(null);
             return;
         }
 
+        if (DEBUG_BLAST) {
+            Log.d(mTag, "registerCallbacksForSync syncBuffer=" + syncBuffer);
+        }
         mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() {
             @Override
             public void onFrameDraw(long frame) {
@@ -10952,7 +10916,9 @@
                     Log.d(mTag, "Setting up sync and frameCommitCallback");
                 }
 
-                mBlastBufferQueue.syncNextTransaction(t -> syncBufferCallback.onBufferReady(t));
+                if (syncBuffer) {
+                    mBlastBufferQueue.syncNextTransaction(syncBufferCallback::onBufferReady);
+                }
 
                 return didProduceBuffer -> {
                     if (DEBUG_BLAST) {
@@ -10966,18 +10932,40 @@
                     // were only set for the current draw attempt.
                     if (!didProduceBuffer) {
                         mBlastBufferQueue.syncNextTransaction(null);
+
                         // Gather the transactions that were sent to mergeWithNextTransaction
                         // since the frame didn't draw on this vsync. It's possible the frame will
                         // draw later, but it's better to not be sync than to block on a frame that
                         // may never come.
                         syncBufferCallback.onBufferReady(
                                 mBlastBufferQueue.gatherPendingTransactions(frame));
+                        return;
+                    }
+
+                    // If we didn't request to sync a buffer, then we won't get the
+                    // syncNextTransaction callback. Instead, just report back to the Syncer so it
+                    // knows that this sync request is complete.
+                    if (!syncBuffer) {
+                        syncBufferCallback.onBufferReady(null);
                     }
                 };
             }
         });
     }
 
-    public final SurfaceSyncer.SyncTarget mSyncTarget =
-            syncBufferCallback -> registerCallbacksForSync(syncBufferCallback);
+    public final SurfaceSyncer.SyncTarget mSyncTarget = this::readyToSync;
+
+    private void readyToSync(SurfaceSyncer.SyncBufferCallback syncBufferCallback) {
+        if (mSyncBufferCallback != null) {
+            Log.d(mTag, "Already set sync for the next draw.");
+            mSyncBufferCallback.onBufferReady(null);
+        }
+        if (DEBUG_BLAST) {
+            Log.d(mTag, "Setting syncFrameCallback");
+        }
+        mSyncBufferCallback = syncBufferCallback;
+        if (!mIsInTraversal && !mTraversalScheduled) {
+            scheduleTraversals();
+        }
+    }
 }
diff --git a/core/java/android/view/ViewRootInsetsControllerHost.java b/core/java/android/view/ViewRootInsetsControllerHost.java
index 9793f8c..4387701 100644
--- a/core/java/android/view/ViewRootInsetsControllerHost.java
+++ b/core/java/android/view/ViewRootInsetsControllerHost.java
@@ -171,8 +171,9 @@
     public void setSystemBarsAppearance(int appearance, int mask) {
         mViewRoot.mWindowAttributes.privateFlags |= PRIVATE_FLAG_APPEARANCE_CONTROLLED;
         final InsetsFlags insetsFlags = mViewRoot.mWindowAttributes.insetsFlags;
-        if (insetsFlags.appearance != appearance) {
-            insetsFlags.appearance = (insetsFlags.appearance & ~mask) | (appearance & mask);
+        final int newAppearance = (insetsFlags.appearance & ~mask) | (appearance & mask);
+        if (insetsFlags.appearance != newAppearance) {
+            insetsFlags.appearance = newAppearance;
             mViewRoot.mWindowAttributesChanged = true;
             mViewRoot.scheduleTraversals();
         }
diff --git a/core/java/android/view/WindowCallbacks.java b/core/java/android/view/WindowCallbacks.java
index a997302..a7f0ef0 100644
--- a/core/java/android/view/WindowCallbacks.java
+++ b/core/java/android/view/WindowCallbacks.java
@@ -28,9 +28,21 @@
  */
 public interface WindowCallbacks {
 
-    public static final int RESIZE_MODE_INVALID = -1;
-    public static final int RESIZE_MODE_FREEFORM = 0;
-    public static final int RESIZE_MODE_DOCKED_DIVIDER = 1;
+    int RESIZE_MODE_INVALID = -1;
+
+    /**
+     * The window is being resized by dragging one of the window corners,
+     * in this case the surface would be fullscreen-sized. The client should
+     * render to the actual frame location (instead of (0,curScrollY)).
+     */
+    int RESIZE_MODE_FREEFORM = 0;
+
+    /**
+     * The window is being resized by dragging on the docked divider. The client should render
+     * at (0, 0) and extend its background to the background frame passed into
+     * {@link IWindow#resized}.
+     */
+    int RESIZE_MODE_DOCKED_DIVIDER = 1;
 
     /**
      * Called by the system when the window got changed by the user, before the layouter got called.
diff --git a/core/java/android/view/WindowLayout.java b/core/java/android/view/WindowLayout.java
index ad9f21b..b7b71f1 100644
--- a/core/java/android/view/WindowLayout.java
+++ b/core/java/android/view/WindowLayout.java
@@ -42,6 +42,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.util.Log;
+import android.window.ClientWindowFrames;
 
 /**
  * Computes window frames.
@@ -56,15 +57,17 @@
     private final Rect mTempDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
     private final Rect mTempRect = new Rect();
 
-    public boolean computeFrames(WindowManager.LayoutParams attrs, InsetsState state,
+    public void computeFrames(WindowManager.LayoutParams attrs, InsetsState state,
             Rect displayCutoutSafe, Rect windowBounds, @WindowingMode int windowingMode,
             int requestedWidth, int requestedHeight, InsetsVisibilities requestedVisibilities,
-            Rect attachedWindowFrame, float compatScale, Rect outDisplayFrame, Rect outParentFrame,
-            Rect outFrame) {
+            Rect attachedWindowFrame, float compatScale, ClientWindowFrames outFrames) {
         final int type = attrs.type;
         final int fl = attrs.flags;
         final int pfl = attrs.privateFlags;
         final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN;
+        final Rect outDisplayFrame = outFrames.displayFrame;
+        final Rect outParentFrame = outFrames.parentFrame;
+        final Rect outFrame = outFrames.frame;
 
         // Compute bounds restricted by insets
         final Insets insets = state.calculateInsets(windowBounds, attrs.getFitInsetsTypes(),
@@ -95,7 +98,7 @@
         final DisplayCutout cutout = state.getDisplayCutout();
         final Rect displayCutoutSafeExceptMaybeBars = mTempDisplayCutoutSafeExceptMaybeBarsRect;
         displayCutoutSafeExceptMaybeBars.set(displayCutoutSafe);
-        boolean clippedByDisplayCutout = false;
+        outFrames.isParentFrameClippedByDisplayCutout = false;
         if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS && !cutout.isEmpty()) {
             // Ensure that windows with a non-ALWAYS display cutout mode are laid out in
             // the cutout safe zone.
@@ -158,7 +161,7 @@
             if (!attachedInParent && !floatingInScreenWindow) {
                 mTempRect.set(outParentFrame);
                 outParentFrame.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
-                clippedByDisplayCutout = !mTempRect.equals(outParentFrame);
+                outFrames.isParentFrameClippedByDisplayCutout = !mTempRect.equals(outParentFrame);
             }
             outDisplayFrame.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
         }
@@ -176,6 +179,8 @@
         final boolean hasCompatScale = compatScale != 1f;
         final int pw = outParentFrame.width();
         final int ph = outParentFrame.height();
+        final boolean extendedByCutout =
+                (attrs.privateFlags & PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT) != 0;
         int rw = requestedWidth;
         int rh = requestedHeight;
         float x, y;
@@ -183,11 +188,13 @@
 
         // If the view hierarchy hasn't been measured, the requested width and height would be
         // UNSPECIFIED_LENGTH. This can happen in the first layout of a window or in the simulated
-        // layout.
-        if (rw == UNSPECIFIED_LENGTH) {
+        // layout. If extendedByCutout is true, we cannot use the requested lengths. Otherwise,
+        // the window frame might be extended again because the requested lengths may come from the
+        // window frame.
+        if (rw == UNSPECIFIED_LENGTH || extendedByCutout) {
             rw = attrs.width >= 0 ? attrs.width : pw;
         }
-        if (rh == UNSPECIFIED_LENGTH) {
+        if (rh == UNSPECIFIED_LENGTH || extendedByCutout) {
             rh = attrs.height >= 0 ? attrs.height : ph;
         }
 
@@ -259,37 +266,21 @@
             Gravity.applyDisplay(attrs.gravity, outDisplayFrame, outFrame);
         }
 
-        if ((attrs.privateFlags & PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT) != 0
-                && !cutout.isEmpty()) {
-            // If the actual frame covering a display cutout, and the window is requesting to extend
-            // it's requested frame, re-do the frame calculation after getting the new requested
-            // size.
+        if (extendedByCutout && !displayCutoutSafe.contains(outFrame)) {
             mTempRect.set(outFrame);
-            // Do nothing if the display cutout and window don't overlap entirely. This may happen
-            // when the cutout is not on the same side with the window.
-            boolean shouldExpand = false;
-            final Rect [] cutoutBounds = cutout.getBoundingRectsAll();
-            for (Rect cutoutBound : cutoutBounds) {
-                if (cutoutBound.isEmpty()) continue;
-                if (mTempRect.contains(cutoutBound) || cutoutBound.contains(mTempRect)) {
-                    shouldExpand = true;
-                    break;
-                }
-            }
-            if (shouldExpand) {
-                // Try to fit move the bar to avoid the display cutout first. Make sure the clip
-                // flags are not set to make the window move.
-                final int clipFlags = DISPLAY_CLIP_VERTICAL | DISPLAY_CLIP_HORIZONTAL;
-                Gravity.applyDisplay(attrs.gravity & ~clipFlags, displayCutoutSafe,
-                        mTempRect);
+
+            // Move the frame into displayCutoutSafe.
+            final int clipFlags = DISPLAY_CLIP_VERTICAL | DISPLAY_CLIP_HORIZONTAL;
+            Gravity.applyDisplay(attrs.gravity & ~clipFlags, displayCutoutSafe,
+                    mTempRect);
+
+            if (mTempRect.intersect(outDisplayFrame)) {
                 outFrame.union(mTempRect);
             }
         }
 
         if (DEBUG) Log.d(TAG, "computeWindowFrames " + attrs.getTitle()
-                + " outFrame=" + outFrame.toShortString()
-                + " outParentFrame=" + outParentFrame.toShortString()
-                + " outDisplayFrame=" + outDisplayFrame.toShortString()
+                + " outFrames=" + outFrames
                 + " windowBounds=" + windowBounds.toShortString()
                 + " attachedWindowFrame=" + (attachedWindowFrame != null
                         ? attachedWindowFrame.toShortString()
@@ -302,8 +293,6 @@
                 + " attrs=" + attrs
                 + " state=" + state
                 + " requestedVisibilities=" + requestedVisibilities);
-
-        return clippedByDisplayCutout;
     }
 
     public static void computeSurfaceSize(WindowManager.LayoutParams attrs, Rect maxBounds,
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 2dc5fbd..29a9926 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -60,55 +60,27 @@
     private static boolean sUseBLASTAdapter = false;
 
     /**
-     * The user is navigating with keys (not the touch screen), so
-     * navigational focus should be shown.
-     */
-    public static final int RELAYOUT_RES_IN_TOUCH_MODE = 0x1;
-
-    /**
      * This is the first time the window is being drawn,
      * so the client must call drawingFinished() when done
      */
-    public static final int RELAYOUT_RES_FIRST_TIME = 0x2;
+    public static final int RELAYOUT_RES_FIRST_TIME = 1;
 
     /**
      * The window manager has changed the surface from the last call.
      */
-    public static final int RELAYOUT_RES_SURFACE_CHANGED = 0x4;
-
-    /**
-     * The window is being resized by dragging on the docked divider. The client should render
-     * at (0, 0) and extend its background to the background frame passed into
-     * {@link IWindow#resized}.
-     */
-    public static final int RELAYOUT_RES_DRAG_RESIZING_DOCKED = 0x8;
-
-    /**
-     * The window is being resized by dragging one of the window corners,
-     * in this case the surface would be fullscreen-sized. The client should
-     * render to the actual frame location (instead of (0,curScrollY)).
-     */
-    public static final int RELAYOUT_RES_DRAG_RESIZING_FREEFORM = 0x10;
+    public static final int RELAYOUT_RES_SURFACE_CHANGED = 1 << 1;
 
     /**
      * The window manager has changed the size of the surface from the last call.
      */
-    public static final int RELAYOUT_RES_SURFACE_RESIZED = 0x20;
+    public static final int RELAYOUT_RES_SURFACE_RESIZED = 1 << 2;
 
     /**
      * In multi-window we force show the system bars. Because we don't want that the surface size
      * changes in this mode, we instead have a flag whether the system bar sizes should always be
      * consumed, so the app is treated like there is no virtual system bars at all.
      */
-    public static final int RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS = 0x40;
-
-    /**
-     * This flag indicates the client should not directly submit it's next frame,
-     * but instead should pass it in the postDrawTransaction of
-     * {@link WindowManagerService#finishDrawing}. This is used by the WM
-     * BLASTSyncEngine to synchronize rendering of multiple windows.
-     */
-    public static final int RELAYOUT_RES_BLAST_SYNC = 0x80;
+    public static final int RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS = 1 << 3;
 
     /**
      * Flag for relayout: the client will be later giving
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index a270c92..385a80d 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -22,6 +22,7 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
@@ -217,9 +218,13 @@
             throw new IllegalArgumentException(
                     "Invalid window token (never added or removed already)");
         }
+        removeSurface(state.mSurfaceControl);
+    }
 
+    /** Separate from {@link #remove} so that subclasses can put removal on a sync transaction. */
+    protected void removeSurface(SurfaceControl sc) {
         try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) {
-            t.remove(state.mSurfaceControl).apply();
+            t.remove(sc).apply();
         }
     }
 
@@ -277,7 +282,7 @@
             int requestedWidth, int requestedHeight, int viewFlags, int flags,
             ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
             SurfaceControl outSurfaceControl, InsetsState outInsetsState,
-            InsetsSourceControl[] outActiveControls) {
+            InsetsSourceControl[] outActiveControls, Bundle outSyncSeqIdBundle) {
         final State state;
         synchronized (this) {
             state = mStateForWindow.get(window.asBinder());
@@ -327,8 +332,22 @@
             outInsetsState.set(mInsetsState);
         }
 
-        // Include whether the window is in touch mode.
-        return isInTouchMode() ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0;
+        return 0;
+    }
+
+    @Override
+    public int updateVisibility(IWindow window, WindowManager.LayoutParams inAttrs,
+            int viewVisibility, MergedConfiguration outMergedConfiguration,
+            SurfaceControl outSurfaceControl, InsetsState outInsetsState,
+            InsetsSourceControl[] outActiveControls) {
+        // TODO(b/161810301): Finish the implementation.
+        return 0;
+    }
+
+    @Override
+    public void updateLayout(IWindow window, WindowManager.LayoutParams inAttrs, int flags,
+            ClientWindowFrames clientWindowFrames, int requestedWidth, int requestedHeight) {
+        // TODO(b/161810301): Finish the implementation.
     }
 
     @Override
@@ -354,7 +373,7 @@
 
     @Override
     public void finishDrawing(android.view.IWindow window,
-            android.view.SurfaceControl.Transaction postDrawTransaction) {
+            android.view.SurfaceControl.Transaction postDrawTransaction, int seqId) {
         synchronized (this) {
             final ResizeCompleteCallback c =
                 mResizeCompletionForWindow.get(window.asBinder());
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index fadbdbb..464414d8 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -646,11 +646,9 @@
      * @param bg The background color.  If 0, no background.  Currently must
      * be black, with any desired alpha level.
      *
-     * @deprecated None of window animations are running with background color.
      */
-    @Deprecated
     public void setBackgroundColor(@ColorInt int bg) {
-        // The background color is not needed any more, do nothing.
+        mBackgroundColor = bg;
     }
 
     /**
@@ -824,13 +822,10 @@
 
     /**
      * Returns the background color behind the animation.
-     *
-     * @deprecated None of window animations are running with background color.
      */
-    @Deprecated
     @ColorInt
     public int getBackgroundColor() {
-        return 0;
+        return mBackgroundColor;
     }
 
     /**
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index a8cc114..6fa6d39 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -16,9 +16,9 @@
 
 package android.view.autofill;
 
-import static android.service.autofill.FillRequest.FLAG_ACTIVITY_START;
 import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
 import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
+import static android.service.autofill.FillRequest.FLAG_SUPPORTS_FILL_DIALOG;
 import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED;
 import static android.view.ContentInfo.SOURCE_AUTOFILL;
 import static android.view.autofill.Helper.sDebug;
@@ -26,7 +26,6 @@
 import static android.view.autofill.Helper.toList;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
-import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -47,22 +46,17 @@
 import android.content.pm.ResolveInfo;
 import android.graphics.Rect;
 import android.metrics.LogMaker;
-import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.ICancellationSignal;
 import android.os.Looper;
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.provider.DeviceConfig;
 import android.service.autofill.AutofillService;
-import android.service.autofill.FillCallback;
 import android.service.autofill.FillEventHistory;
-import android.service.autofill.IFillCallback;
 import android.service.autofill.UserData;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -82,7 +76,6 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeProvider;
 import android.view.accessibility.AccessibilityWindowInfo;
-import android.view.inputmethod.InlineSuggestionsRequest;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.EditText;
 import android.widget.TextView;
@@ -107,7 +100,6 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
-import java.util.concurrent.Executor;
 
 import sun.misc.Cleaner;
 
@@ -176,12 +168,6 @@
  * shows an autofill save UI if the value of savable views have changed. If the user selects the
  * option to Save, the current value of the views is then sent to the autofill service.
  *
- * <p>There is another choice for the application to provide it's datasets to the Autofill framework
- * by setting an {@link AutofillRequestCallback} through
- * {@link #setAutofillRequestCallback(Executor, AutofillRequestCallback)}. The application can use
- * its callback instead of the default {@link AutofillService}. See
- * {@link AutofillRequestCallback} for more details.
- *
  * <h3 id="additional-notes">Additional notes</h3>
  *
  * <p>It is safe to call <code>AutofillManager</code> methods from any thread.
@@ -307,7 +293,6 @@
     /** @hide */ public static final int FLAG_ADD_CLIENT_DEBUG = 0x2;
     /** @hide */ public static final int FLAG_ADD_CLIENT_VERBOSE = 0x4;
     /** @hide */ public static final int FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY = 0x8;
-    /** @hide */ public static final int FLAG_ENABLED_CLIENT_SUGGESTIONS = 0x20;
 
     // NOTE: flag below is used by the session start receiver only, hence it can have values above
     /** @hide */ public static final int RECEIVER_FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY = 0x1;
@@ -637,11 +622,6 @@
     @GuardedBy("mLock")
     private boolean mEnabledForAugmentedAutofillOnly;
 
-    @GuardedBy("mLock")
-    @Nullable private AutofillRequestCallback mAutofillRequestCallback;
-    @GuardedBy("mLock")
-    @Nullable private Executor mRequestCallbackExecutor;
-
     /**
      * Indicates whether there are any fields that need to do a fill request
      * after the activity starts.
@@ -1118,7 +1098,7 @@
             return;
         }
 
-        int flags = FLAG_ACTIVITY_START;
+        int flags = FLAG_SUPPORTS_FILL_DIALOG;
         flags |= FLAG_VIEW_NOT_FOCUSED;
         notifyViewEntered(view, flags);
     }
@@ -1955,32 +1935,6 @@
         return new AutofillId(parent.getAutofillViewId(), virtualId);
     }
 
-    /**
-     * Sets the client's suggestions callback for autofill.
-     *
-     * @see AutofillRequestCallback
-     *
-     * @param executor specifies the thread upon which the callbacks will be invoked.
-     * @param callback which handles autofill request to provide client's suggestions.
-     */
-    public void setAutofillRequestCallback(@NonNull @CallbackExecutor Executor executor,
-            @NonNull AutofillRequestCallback callback) {
-        synchronized (mLock) {
-            mRequestCallbackExecutor = executor;
-            mAutofillRequestCallback = callback;
-        }
-    }
-
-    /**
-     * clears the client's suggestions callback for autofill.
-     */
-    public void clearAutofillRequestCallback() {
-        synchronized (mLock) {
-            mRequestCallbackExecutor = null;
-            mAutofillRequestCallback = null;
-        }
-    }
-
     @GuardedBy("mLock")
     private void startSessionLocked(@NonNull AutofillId id, @NonNull Rect bounds,
             @NonNull AutofillValue value, int flags) {
@@ -2041,13 +1995,6 @@
                 }
             }
 
-            if (mAutofillRequestCallback != null) {
-                if (sDebug) {
-                    Log.d(TAG, "startSession with the client suggestions provider");
-                }
-                flags |= FLAG_ENABLED_CLIENT_SUGGESTIONS;
-            }
-
             mService.startSession(client.autofillClientGetActivityToken(),
                     mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
                     mCallback != null, flags, clientActivity,
@@ -2399,28 +2346,6 @@
         }
     }
 
-    private void onFillRequest(InlineSuggestionsRequest request,
-            CancellationSignal cancellationSignal, FillCallback callback) {
-        final AutofillRequestCallback autofillRequestCallback;
-        final Executor executor;
-        synchronized (mLock) {
-            autofillRequestCallback = mAutofillRequestCallback;
-            executor = mRequestCallbackExecutor;
-        }
-        if (autofillRequestCallback != null && executor != null) {
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                executor.execute(() ->
-                        autofillRequestCallback.onFillRequest(
-                                request, cancellationSignal, callback));
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
-        } else {
-            callback.onSuccess(null);
-        }
-    }
-
     /** @hide */
     public static final int SET_STATE_FLAG_ENABLED = 0x01;
     /** @hide */
@@ -3121,17 +3046,19 @@
     }
 
     /**
-     * If autofill suggestions for a dialog-style UI are available for {@code view}, shows a dialog
-     * allowing the user to select a suggestion and returns {@code true}.
+     * If autofill suggestions for a
+     * <a href="{@docRoot}reference/android/service/autofill/Dataset.html#FillDialogUI">
+     * dialog-style UI</a> are available for {@code view}, shows a dialog allowing the user to
+     * select a suggestion and returns {@code true}.
      * <p>
      * The dialog may not be available if the autofill service does not support it, or if the
      * autofill request has not returned a response yet.
      * <p>
-     * It is recommended to call this method the first time a user focuses on an autofill-able form,
-     * and to avoid showing the input method if the dialog is shown. If this method returns
-     * {@code false}, you should then instead show the input method (assuming that is how the
-     * view normally handles the focus event). If the user re-focuses on the view, you should not
-     * call this method again so as to not disrupt usage of the input method.
+     * It is recommended apps to call this method the first time a user focuses on
+     * an autofill-able form, and to avoid showing the input method if the dialog is shown. If
+     * this method returns {@code false}, you should then instead show the input method (assuming
+     * that is how the view normally handles the focus event). If the user re-focuses on the view,
+     * you should not call this method again so as to not disrupt usage of the input method.
      *
      * @param view the view for which to show autofill suggestions. This is typically a view
      *             receiving a focus event. The autofill suggestions shown will include content for
@@ -3150,11 +3077,26 @@
     }
 
     /**
-     * Like {@link #showAutofillDialog(View)} but for virtual views.
+     * If autofill suggestions for a
+     * <a href="{@docRoot}reference/android/service/autofill/Dataset.html#FillDialogUI">
+     * dialog-style UI</a> are available for virtual {@code view}, shows a dialog allowing the user
+     * to select a suggestion and returns {@code true}.
+     * <p>
+     * The dialog may not be shown if the autofill service does not support it, if the autofill
+     * request has not returned a response yet, if the dialog was shown previously, or if the
+     * input method is already shown.
+     * <p>
+     * It is recommended apps to call this method the first time a user focuses on
+     * an autofill-able form, and to avoid showing the input method if the dialog is shown. If
+     * this method returns {@code false}, you should then instead show the input method (assuming
+     * that is how the view normally handles the focus event). If the user re-focuses on the view,
+     * you should not call this method again so as to not disrupt usage of the input method.
      *
-     * @param virtualId id identifying the virtual child inside the parent view.
+     * @param view the view hosting the virtual view hierarchy which is used to show autofill
+     *            suggestions.
+     * @param virtualId id identifying the virtual view inside the host view.
+     * @return {@code true} if the autofill dialog is being shown
      */
-    // TODO(b/210926084): Consider whether to include the one-time show logic within this method.
     public boolean showAutofillDialog(@NonNull View view, int virtualId) {
         Objects.requireNonNull(view);
         if (shouldShowAutofillDialog(getAutofillId(view, virtualId))) {
@@ -3868,23 +3810,6 @@
             }
         }
 
-        @Override
-        public void requestFillFromClient(int id, InlineSuggestionsRequest request,
-                IFillCallback callback) {
-            final AutofillManager afm = mAfm.get();
-            if (afm != null) {
-                ICancellationSignal transport = CancellationSignal.createTransport();
-                try {
-                    callback.onCancellable(transport);
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Error requesting a cancellation", e);
-                }
-
-                afm.onFillRequest(request, CancellationSignal.fromTransport(transport),
-                        new FillCallback(callback, id));
-            }
-        }
-
         public void notifyFillDialogTriggerIds(List<AutofillId> ids) {
             final AutofillManager afm = mAfm.get();
             if (afm != null) {
diff --git a/core/java/android/view/autofill/AutofillRequestCallback.java b/core/java/android/view/autofill/AutofillRequestCallback.java
deleted file mode 100644
index e632a58..0000000
--- a/core/java/android/view/autofill/AutofillRequestCallback.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view.autofill;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.CancellationSignal;
-import android.service.autofill.FillCallback;
-import android.view.inputmethod.InlineSuggestionsRequest;
-
-/**
- * <p>This class is used to provide some input suggestions to the Autofill framework.
- *
- * <P>When the user is requested to input something, Autofill will try to query input suggestions
- * for the user choosing. If the application want to provide some internal input suggestions,
- * implements this callback and register via
- * {@link AutofillManager#setAutofillRequestCallback(java.util.concurrent.Executor,
- * AutofillRequestCallback)}. Autofill will callback the
- * {@link #onFillRequest(InlineSuggestionsRequest, CancellationSignal, FillCallback)} to request
- * input suggestions.
- *
- * <P>To make sure the callback to take effect, must register before the autofill session starts.
- * If the autofill session is started, calls {@link AutofillManager#cancel()} to finish current
- * session, and then the callback will be used at the next restarted session.
- *
- * <P>To create a {@link android.service.autofill.FillResponse}, application should fetch
- * {@link AutofillId}s from its view structure. Below is an example:
- * <pre class="prettyprint">
- * AutofillId usernameId = findViewById(R.id.username).getAutofillId();
- * AutofillId passwordId = findViewById(R.id.password).getAutofillId();
- * </pre>
- * To learn more about creating a {@link android.service.autofill.FillResponse}, read
- * <a href="/guide/topics/text/autofill-services#fill">Fill out client views</a>.
- *
- * <P>To fallback to the default {@link android.service.autofill.AutofillService}, just respond
- * a null of the {@link android.service.autofill.FillResponse}. And then Autofill will do a fill
- * request with the default {@link android.service.autofill.AutofillService}. Or clear the callback
- * from {@link AutofillManager} via {@link AutofillManager#clearAutofillRequestCallback()}. If the
- * client would like to keep no suggestions for the field, respond with an empty
- * {@link android.service.autofill.FillResponse} which has no dataset.
- *
- * <P>IMPORTANT: This should not be used for displaying anything other than input suggestions, or
- * the keyboard may choose to block your app from the inline strip.
- */
-public interface AutofillRequestCallback {
-    /**
-     * Called by the Android system to decide if a screen can be autofilled by the callback.
-     *
-     * @param inlineSuggestionsRequest the {@link InlineSuggestionsRequest request} to handle if
-     *     currently inline suggestions are supported and can be displayed.
-     * @param cancellationSignal signal for observing cancellation requests. The system will use
-     *     this to notify you that the fill result is no longer needed and you should stop
-     *     handling this fill request in order to save resources.
-     * @param callback object used to notify the result of the request.
-     */
-    void onFillRequest(@Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
-            @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback);
-}
diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
index 2e5967c..51afe4c 100644
--- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
@@ -24,11 +24,9 @@
 import android.content.IntentSender;
 import android.graphics.Rect;
 import android.os.IBinder;
-import android.service.autofill.IFillCallback;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillValue;
 import android.view.autofill.IAutofillWindowPresenter;
-import android.view.inputmethod.InlineSuggestionsRequest;
 import android.view.KeyEvent;
 
 import com.android.internal.os.IResultReceiver;
@@ -144,12 +142,6 @@
    void requestShowSoftInput(in AutofillId id);
 
     /**
-     * Requests to determine if a screen can be autofilled by the client app.
-     */
-    void requestFillFromClient(int id, in InlineSuggestionsRequest request,
-            in IFillCallback callback);
-
-    /**
      * Notifies autofill ids that require to show the fill dialog.
      */
     void notifyFillDialogTriggerIds(in List<AutofillId> ids);
diff --git a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
index 70279cc..c78b810 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
@@ -111,22 +111,6 @@
     private @Nullable InlinePresentationSpec mInlineTooltipPresentationSpec;
 
     /**
-     * Whether the IME supports inline suggestions from the default Autofill service that
-     * provides the input view.
-     *
-     * Note: The default value is {@code true}.
-     */
-    private boolean mServiceSupported;
-
-    /**
-     * Whether the IME supports inline suggestions from the application that provides the
-     * input view.
-     *
-     * Note: The default value is {@code true}.
-     */
-    private boolean mClientSupported;
-
-    /**
      * @hide
      * @see {@link #mHostInputToken}.
      */
@@ -220,14 +204,6 @@
         return Bundle.EMPTY;
     }
 
-    private static boolean defaultServiceSupported() {
-        return true;
-    }
-
-    private static boolean defaultClientSupported() {
-        return true;
-    }
-
     /** @hide */
     abstract static class BaseBuilder {
         abstract Builder setInlinePresentationSpecs(
@@ -240,25 +216,15 @@
         abstract Builder setHostDisplayId(int value);
     }
 
-    /** @hide */
-    public boolean isServiceSupported() {
-        return mServiceSupported;
-    }
-
-    /** @hide */
-    public boolean isClientSupported() {
-        return mClientSupported;
-    }
 
 
-
-    // Code below generated by codegen v1.0.22.
+    // Code below generated by codegen v1.0.23.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
     //
     // To regenerate run:
-    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
+    // $ codegen $ANDROID_BUILD_TOP/./frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
     //
     // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
     //   Settings > Editor > Code Style > Formatter Control
@@ -274,9 +240,7 @@
             @NonNull Bundle extras,
             @Nullable IBinder hostInputToken,
             int hostDisplayId,
-            @Nullable InlinePresentationSpec inlineTooltipPresentationSpec,
-            boolean serviceSupported,
-            boolean clientSupported) {
+            @Nullable InlinePresentationSpec inlineTooltipPresentationSpec) {
         this.mMaxSuggestionCount = maxSuggestionCount;
         this.mInlinePresentationSpecs = inlinePresentationSpecs;
         com.android.internal.util.AnnotationValidations.validate(
@@ -293,8 +257,6 @@
         this.mHostInputToken = hostInputToken;
         this.mHostDisplayId = hostDisplayId;
         this.mInlineTooltipPresentationSpec = inlineTooltipPresentationSpec;
-        this.mServiceSupported = serviceSupported;
-        this.mClientSupported = clientSupported;
 
         onConstructed();
     }
@@ -378,9 +340,7 @@
     }
 
     /**
-     * The {@link InlinePresentationSpec} for the inline suggestion tooltip in the response.
-     *
-     * @see android.service.autofill.InlinePresentation#createTooltipPresentation(Slice, InlinePresentationSpec)
+     * Specifies the UI specification for the inline suggestion tooltip in the response.
      */
     @DataClass.Generated.Member
     public @Nullable InlinePresentationSpec getInlineTooltipPresentationSpec() {
@@ -401,9 +361,7 @@
                 "extras = " + mExtras + ", " +
                 "hostInputToken = " + mHostInputToken + ", " +
                 "hostDisplayId = " + mHostDisplayId + ", " +
-                "inlineTooltipPresentationSpec = " + mInlineTooltipPresentationSpec + ", " +
-                "serviceSupported = " + mServiceSupported + ", " +
-                "clientSupported = " + mClientSupported +
+                "inlineTooltipPresentationSpec = " + mInlineTooltipPresentationSpec +
         " }";
     }
 
@@ -427,9 +385,7 @@
                 && extrasEquals(that.mExtras)
                 && java.util.Objects.equals(mHostInputToken, that.mHostInputToken)
                 && mHostDisplayId == that.mHostDisplayId
-                && java.util.Objects.equals(mInlineTooltipPresentationSpec, that.mInlineTooltipPresentationSpec)
-                && mServiceSupported == that.mServiceSupported
-                && mClientSupported == that.mClientSupported;
+                && java.util.Objects.equals(mInlineTooltipPresentationSpec, that.mInlineTooltipPresentationSpec);
     }
 
     @Override
@@ -447,8 +403,6 @@
         _hash = 31 * _hash + java.util.Objects.hashCode(mHostInputToken);
         _hash = 31 * _hash + mHostDisplayId;
         _hash = 31 * _hash + java.util.Objects.hashCode(mInlineTooltipPresentationSpec);
-        _hash = 31 * _hash + Boolean.hashCode(mServiceSupported);
-        _hash = 31 * _hash + Boolean.hashCode(mClientSupported);
         return _hash;
     }
 
@@ -459,8 +413,6 @@
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
         int flg = 0;
-        if (mServiceSupported) flg |= 0x100;
-        if (mClientSupported) flg |= 0x200;
         if (mHostInputToken != null) flg |= 0x20;
         if (mInlineTooltipPresentationSpec != null) flg |= 0x80;
         dest.writeInt(flg);
@@ -486,8 +438,6 @@
         // static FieldType unparcelFieldName(Parcel in) { ... }
 
         int flg = in.readInt();
-        boolean serviceSupported = (flg & 0x100) != 0;
-        boolean clientSupported = (flg & 0x200) != 0;
         int maxSuggestionCount = in.readInt();
         List<InlinePresentationSpec> inlinePresentationSpecs = new ArrayList<>();
         in.readParcelableList(inlinePresentationSpecs, InlinePresentationSpec.class.getClassLoader(), android.widget.inline.InlinePresentationSpec.class);
@@ -514,8 +464,6 @@
         this.mHostInputToken = hostInputToken;
         this.mHostDisplayId = hostDisplayId;
         this.mInlineTooltipPresentationSpec = inlineTooltipPresentationSpec;
-        this.mServiceSupported = serviceSupported;
-        this.mClientSupported = clientSupported;
 
         onConstructed();
     }
@@ -549,8 +497,6 @@
         private @Nullable IBinder mHostInputToken;
         private int mHostDisplayId;
         private @Nullable InlinePresentationSpec mInlineTooltipPresentationSpec;
-        private boolean mServiceSupported;
-        private boolean mClientSupported;
 
         private long mBuilderFieldsSet = 0L;
 
@@ -683,9 +629,7 @@
         }
 
         /**
-         * The {@link InlinePresentationSpec} for the inline suggestion tooltip in the response.
-         *
-         * @see android.service.autofill.InlinePresentation#createTooltipPresentation(Slice, InlinePresentationSpec)s
+         * Specifies the UI specification for the inline suggestion tooltip in the response.
          */
         @DataClass.Generated.Member
         public @NonNull Builder setInlineTooltipPresentationSpec(@NonNull InlinePresentationSpec value) {
@@ -695,38 +639,10 @@
             return this;
         }
 
-        /**
-         * Whether the IME supports inline suggestions from the default Autofill service that
-         * provides the input view.
-         *
-         * Note: The default value is {@code true}.
-         */
-        @DataClass.Generated.Member
-        public @NonNull Builder setServiceSupported(boolean value) {
-            checkNotUsed();
-            mBuilderFieldsSet |= 0x100;
-            mServiceSupported = value;
-            return this;
-        }
-
-        /**
-         * Whether the IME supports inline suggestions from the application that provides the
-         * input view.
-         *
-         * Note: The default value is {@code true}.
-         */
-        @DataClass.Generated.Member
-        public @NonNull Builder setClientSupported(boolean value) {
-            checkNotUsed();
-            mBuilderFieldsSet |= 0x200;
-            mClientSupported = value;
-            return this;
-        }
-
         /** Builds the instance. This builder should not be touched after calling this! */
         public @NonNull InlineSuggestionsRequest build() {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x400; // Mark builder used
+            mBuilderFieldsSet |= 0x100; // Mark builder used
 
             if ((mBuilderFieldsSet & 0x1) == 0) {
                 mMaxSuggestionCount = defaultMaxSuggestionCount();
@@ -749,12 +665,6 @@
             if ((mBuilderFieldsSet & 0x80) == 0) {
                 mInlineTooltipPresentationSpec = defaultInlineTooltipPresentationSpec();
             }
-            if ((mBuilderFieldsSet & 0x100) == 0) {
-                mServiceSupported = defaultServiceSupported();
-            }
-            if ((mBuilderFieldsSet & 0x200) == 0) {
-                mClientSupported = defaultClientSupported();
-            }
             InlineSuggestionsRequest o = new InlineSuggestionsRequest(
                     mMaxSuggestionCount,
                     mInlinePresentationSpecs,
@@ -763,14 +673,12 @@
                     mExtras,
                     mHostInputToken,
                     mHostDisplayId,
-                    mInlineTooltipPresentationSpec,
-                    mServiceSupported,
-                    mClientSupported);
+                    mInlineTooltipPresentationSpec);
             return o;
         }
 
         private void checkNotUsed() {
-            if ((mBuilderFieldsSet & 0x400) != 0) {
+            if ((mBuilderFieldsSet & 0x100) != 0) {
                 throw new IllegalStateException(
                         "This Builder should not be reused. Use a new Builder instance instead");
             }
@@ -778,10 +686,10 @@
     }
 
     @DataClass.Generated(
-            time = 1615798784918L,
-            codegenVersion = "1.0.22",
+            time = 1621415989607L,
+            codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java",
-            inputSignatures = "public static final  int SUGGESTION_COUNT_UNLIMITED\nprivate final  int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.widget.inline.InlinePresentationSpec> mInlinePresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @android.annotation.NonNull android.os.Bundle mExtras\nprivate @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate  int mHostDisplayId\nprivate @android.annotation.Nullable android.widget.inline.InlinePresentationSpec mInlineTooltipPresentationSpec\nprivate  boolean mServiceSupported\nprivate  boolean mClientSupported\nprivate static final @android.compat.annotation.ChangeId @android.compat.annotation.EnabledSince long IME_AUTOFILL_DEFAULT_SUPPORTED_LOCALES_IS_EMPTY\npublic  void setHostInputToken(android.os.IBinder)\nprivate  boolean extrasEquals(android.os.Bundle)\nprivate  void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic  void setHostDisplayId(int)\nprivate  void onConstructed()\npublic  void filterContentTypes()\nprivate static  int defaultMaxSuggestionCount()\nprivate static  java.lang.String defaultHostPackageName()\nprivate static  android.widget.inline.InlinePresentationSpec defaultInlineTooltipPresentationSpec()\nprivate static  android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.NonNull android.os.Bundle defaultExtras()\nprivate static  boolean defaultServiceSupported()\nprivate static  boolean defaultClientSupported()\npublic  boolean isServiceSupported()\npublic  boolean isClientSupported()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
+            inputSignatures = "public static final  int SUGGESTION_COUNT_UNLIMITED\nprivate final  int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.widget.inline.InlinePresentationSpec> mInlinePresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @android.annotation.NonNull android.os.Bundle mExtras\nprivate @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate  int mHostDisplayId\nprivate @android.annotation.Nullable android.widget.inline.InlinePresentationSpec mInlineTooltipPresentationSpec\nprivate static final @android.compat.annotation.ChangeId @android.compat.annotation.EnabledSince long IME_AUTOFILL_DEFAULT_SUPPORTED_LOCALES_IS_EMPTY\npublic  void setHostInputToken(android.os.IBinder)\nprivate  boolean extrasEquals(android.os.Bundle)\nprivate  void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic  void setHostDisplayId(int)\nprivate  void onConstructed()\npublic  void filterContentTypes()\nprivate static  int defaultMaxSuggestionCount()\nprivate static  java.lang.String defaultHostPackageName()\nprivate static  android.widget.inline.InlinePresentationSpec defaultInlineTooltipPresentationSpec()\nprivate static  android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.NonNull android.os.Bundle defaultExtras()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index fd336a2..6209b46 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -414,4 +414,12 @@
         // intentionally empty
     }
 
+    /**
+     * Finish stylus handwriting session.
+     * @hide
+     */
+    default void finishStylusHandwriting() {
+        // intentionally empty
+    }
+
 }
diff --git a/core/java/android/view/translation/UiTranslationManager.java b/core/java/android/view/translation/UiTranslationManager.java
index 3012e93..01acdfe 100644
--- a/core/java/android/view/translation/UiTranslationManager.java
+++ b/core/java/android/view/translation/UiTranslationManager.java
@@ -101,33 +101,32 @@
     public static final String LOG_TAG = "UiTranslation";
 
     /**
-     * The state caller request to disable utranslation,, it is no longer need to ui translation.
+     * The state the caller requests to enable UI translation.
      *
      * @hide
      */
     public static final int STATE_UI_TRANSLATION_STARTED = 0;
     /**
-     * The state caller request to pause ui translation, it will switch back to the original text.
+     * The state caller requests to pause UI translation. It will switch back to the original text.
      *
      * @hide
      */
     public static final int STATE_UI_TRANSLATION_PAUSED = 1;
     /**
-     * The state caller request to resume the paused ui translation, it will show the translated
+     * The state caller requests to resume the paused UI translation. It will show the translated
      * text again if the text had been translated.
      *
      * @hide
      */
     public static final int STATE_UI_TRANSLATION_RESUMED = 2;
     /**
-     * The state the caller request to enable ui translation.
+     * The state caller requests to disable UI translation when it no longer needs translation.
      *
      * @hide
      */
     public static final int STATE_UI_TRANSLATION_FINISHED = 3;
-    /**
-     * @hide
-     */
+
+    /** @hide */
     @IntDef(prefix = {"STATE__TRANSLATION"}, value = {
             STATE_UI_TRANSLATION_STARTED,
             STATE_UI_TRANSLATION_PAUSED,
@@ -145,6 +144,8 @@
     public static final String EXTRA_SOURCE_LOCALE = "source_locale";
     /** @hide */
     public static final String EXTRA_TARGET_LOCALE = "target_locale";
+    /** @hide */
+    public static final String EXTRA_PACKAGE_NAME = "package_name";
 
     @NonNull
     private final Context mContext;
@@ -215,7 +216,7 @@
 
     /**
      * Request to disable the ui translation. It will destroy all the {@link Translator}s and no
-     * longer to show to show the translated text.
+     * longer to show the translated text.
      *
      * @param activityId the identifier for the Activity which needs ui translation
      * @throws NullPointerException the activityId or
@@ -362,8 +363,8 @@
     public void onTranslationFinished(boolean activityDestroyed, ActivityId activityId,
             ComponentName componentName) {
         try {
-            mService.onTranslationFinished(activityDestroyed,
-                    activityId.getToken(), componentName, mContext.getUserId());
+            mService.onTranslationFinished(activityDestroyed, activityId.getToken(), componentName,
+                    mContext.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -392,20 +393,21 @@
 
         private void onStateChange(Bundle bundle) {
             int state = bundle.getInt(EXTRA_STATE);
+            String packageName = bundle.getString(EXTRA_PACKAGE_NAME);
             switch (state) {
                 case STATE_UI_TRANSLATION_STARTED:
-                    mSourceLocale = (ULocale) bundle.getSerializable(EXTRA_SOURCE_LOCALE);
-                    mTargetLocale = (ULocale) bundle.getSerializable(EXTRA_TARGET_LOCALE);
-                    mCallback.onStarted(mSourceLocale, mTargetLocale);
+                    mSourceLocale = bundle.getSerializable(EXTRA_SOURCE_LOCALE, ULocale.class);
+                    mTargetLocale = bundle.getSerializable(EXTRA_TARGET_LOCALE, ULocale.class);
+                    mCallback.onStarted(mSourceLocale, mTargetLocale, packageName);
                     break;
                 case STATE_UI_TRANSLATION_RESUMED:
-                    mCallback.onResumed(mSourceLocale, mTargetLocale);
+                    mCallback.onResumed(mSourceLocale, mTargetLocale, packageName);
                     break;
                 case STATE_UI_TRANSLATION_PAUSED:
-                    mCallback.onPaused();
+                    mCallback.onPaused(packageName);
                     break;
                 case STATE_UI_TRANSLATION_FINISHED:
-                    mCallback.onFinished();
+                    mCallback.onFinished(packageName);
                     break;
                 default:
                     Log.wtf(TAG, "Unexpected translation state:" + state);
diff --git a/core/java/android/view/translation/UiTranslationStateCallback.java b/core/java/android/view/translation/UiTranslationStateCallback.java
index d7dc284..3ccca5f 100644
--- a/core/java/android/view/translation/UiTranslationStateCallback.java
+++ b/core/java/android/view/translation/UiTranslationStateCallback.java
@@ -24,11 +24,21 @@
 /**
  * Callback for listening to UI Translation state changes. See {@link
  * UiTranslationManager#registerUiTranslationStateCallback(Executor, UiTranslationStateCallback)}.
+ * <p>
+ * Prior to Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}, callback methods
+ * <em>without</em> {@code packageName} are invoked. Apps with minSdkVersion lower than {@link
+ * android.os.Build.VERSION_CODES#TIRAMISU} <em>must</em> implement those methods if they want to
+ * handle the events.
+ * <p>
+ * In Android version {@link android.os.Build.VERSION_CODES#TIRAMISU} and later, if both methods
+ * with and without {@code packageName} are implemented (e.g., {@link #onFinished()} and {@link
+ * #onFinished(String)}, only the one <em>with</em> {@code packageName} will be called.
  */
 public interface UiTranslationStateCallback {
 
     /**
-     * @removed use {@link #onStarted(ULocale, ULocale)} instead.
+     * @removed use {@link #onStarted(ULocale, ULocale)} or {@link #onStarted(ULocale, ULocale,
+     * String)} instead.
      */
     @Deprecated
     default void onStarted(@NonNull String sourceLocale, @NonNull String targetLocale) {
@@ -41,27 +51,122 @@
      * <p>
      * This is also called if either the requested {@code sourceLocale} or {@code targetLocale} has
      * changed.
+     * <p>
+     * Apps should implement {@link #onStarted(ULocale, ULocale, String)} instead if they need the
+     * name of the package that owns the activity being translated.
+     * <p>
+     * Apps with minSdkVersion lower than {@link android.os.Build.VERSION_CODES#TIRAMISU}
+     * <em>must</em> implement this method if they want to handle the "started" event.
+     *
+     * @param sourceLocale {@link ULocale} the UI is being translated from.
+     * @param targetLocale {@link ULocale} the UI is being translated to.
      */
     default void onStarted(@NonNull ULocale sourceLocale, @NonNull ULocale targetLocale) {
         onStarted(sourceLocale.getLanguage(), targetLocale.getLanguage());
     }
 
     /**
+     * The system is requesting translation of the UI from {@code sourceLocale} to {@code
+     * targetLocale}.
+     * <p>
+     * This is also called if either the requested {@code sourceLocale} or {@code targetLocale} has
+     * changed.
+     * <p>
+     * Apps <em>may</em> implement {@link #onStarted(ULocale, ULocale)} instead if they don't need
+     * the name of the package that owns the activity being translated.
+     * <p>
+     * Apps with minSdkVersion lower than {@link android.os.Build.VERSION_CODES#TIRAMISU}
+     * <em>must</em> implement {@link #onStarted(ULocale, ULocale)} if they want to handle the
+     * "started" event.
+     *
+     * @param sourceLocale {@link ULocale} the UI is being translated from.
+     * @param targetLocale {@link ULocale} the UI is being translated to.
+     * @param packageName  The name of the package that owns the activity being translated.
+     */
+    default void onStarted(@NonNull ULocale sourceLocale, @NonNull ULocale targetLocale,
+            @NonNull String packageName) {
+        onStarted(sourceLocale, targetLocale);
+    }
+
+    /**
      * The system is requesting that the application temporarily show the UI contents in their
      * original language.
+     * <p>
+     * Apps should implement {@link #onPaused(String)} as well if they need the name of the
+     * package that owns the activity being translated.
      */
     void onPaused();
 
     /**
-     * The system is requesting that the application restore from the temporarily paused state and
-     * show the content in translated language.
+     * The system is requesting that the application temporarily show the UI contents in their
+     * original language.
+     * <p>
+     * Apps <em>may</em> implement {@link #onPaused()} instead if they don't need the name of the
+     * package that owns the activity being translated.
+     * <p>
+     * Apps with minSdkVersion lower than {@link android.os.Build.VERSION_CODES#TIRAMISU}
+     * <em>must</em> implement {@link #onPaused()} if they want to handle the "paused" event.
      */
-    // TODO: Remove the default implementation when clients have implemented this.
+    default void onPaused(@NonNull String packageName) {
+        onPaused();
+    }
+
+    /**
+     * The system is requesting that the application restore from the temporarily paused state and
+     * show the content in the translated language.
+     * <p>
+     * Apps should implement {@link #onResumed(ULocale, ULocale, String)} instead if they need the
+     * name of the package that owns the activity being translated.
+     * <p>
+     * Apps with minSdkVersion lower than {@link android.os.Build.VERSION_CODES#TIRAMISU}
+     * <em>must</em> implement this method if they want to handle the "resumed" event.
+     *
+     * @param sourceLocale {@link ULocale} the UI is being translated from.
+     * @param targetLocale {@link ULocale} the UI is being translated to.
+     */
     default void onResumed(@NonNull ULocale sourceLocale, @NonNull ULocale targetLocale) {
     }
 
     /**
+     * The system is requesting that the application restore from the temporarily paused state and
+     * show the content in the translated language.
+     * <p>
+     * Apps <em>may</em> implement {@link #onResumed(ULocale, ULocale)} instead if they don't need
+     * the name of the package that owns the activity being translated.
+     * <p>
+     * Apps with minSdkVersion lower than {@link android.os.Build.VERSION_CODES#TIRAMISU}
+     * <em>must</em> implement {@link #onResumed(ULocale, ULocale)} if they want to handle the
+     * "resumed" event.
+     *
+     * @param sourceLocale {@link ULocale} the UI is being translated from.
+     * @param targetLocale {@link ULocale} the UI is being translated to.
+     * @param packageName  The name of the package that owns the activity being translated.
+     */
+    default void onResumed(@NonNull ULocale sourceLocale, @NonNull ULocale targetLocale,
+            @NonNull String packageName) {
+        onResumed(sourceLocale, targetLocale);
+    }
+
+    /**
      * The UI Translation session has ended.
+     * <p>
+     * Apps should implement {@link #onFinished(String)} as well if they need the name of the
+     * package that owns the activity being translated.
      */
     void onFinished();
+
+    /**
+     * The UI Translation session has ended.
+     * <p>
+     * Apps <em>may</em> implement {@link #onFinished()} instead if they don't need the name of the
+     * package that owns the activity being translated.
+     * <p>
+     * Apps with minSdkVersion lower than {@link android.os.Build.VERSION_CODES#TIRAMISU}
+     * <em>must</em> implement {@link #onFinished()} if they want to handle the "finished" event.
+     *
+     * @param packageName The name of the package that owns the activity being translated.
+     */
+    default void onFinished(@NonNull String packageName) {
+        onFinished();
+    }
 }
diff --git a/core/java/android/view/translation/ViewTranslationCallback.java b/core/java/android/view/translation/ViewTranslationCallback.java
index 66c028b..3936b63 100644
--- a/core/java/android/view/translation/ViewTranslationCallback.java
+++ b/core/java/android/view/translation/ViewTranslationCallback.java
@@ -60,7 +60,7 @@
     /**
      * Called when user wants to view the original content instead of the translated content. This
      * method will not be called before {@link View#onViewTranslationResponse} or
-     * {@link View#onViewTranslationResponse}.
+     * {@link View#onVirtualViewTranslationResponses}.
      *
      * @return {@code true} if the View handles hiding the translation.
      */
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 3a7a544..dbfcca9 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -111,6 +111,7 @@
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.ViewParent;
+import android.view.ViewRootImpl;
 import android.view.ViewTreeObserver;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -129,6 +130,9 @@
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.TextView.Drawables;
 import android.widget.TextView.OnEditorActionListener;
+import android.window.OnBackInvokedCallback;
+import android.window.OnBackInvokedDispatcher;
+import android.window.WindowOnBackInvokedDispatcher;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.inputmethod.EditableInputConnection;
@@ -235,6 +239,14 @@
     private boolean mSelectionControllerEnabled;
 
     private final boolean mHapticTextHandleEnabled;
+    /** Handles OnBackInvokedCallback back dispatch */
+    private final OnBackInvokedCallback mBackCallback = new OnBackInvokedCallback() {
+        @Override
+        public void onBackInvoked() {
+            stopTextActionMode();
+        }
+    };
+    private boolean mBackCallbackRegistered;
 
     @Nullable
     private MagnifierMotionAnimator mMagnifierAnimator;
@@ -753,6 +765,35 @@
         stopTextActionModeWithPreservingSelection();
 
         mDefaultOnReceiveContentListener.clearInputConnectionInfo();
+        unregisterOnBackInvokedCallback();
+    }
+
+    private void unregisterOnBackInvokedCallback() {
+        if (!mBackCallbackRegistered) {
+            return;
+        }
+        ViewRootImpl viewRootImpl = getTextView().getViewRootImpl();
+        if (viewRootImpl != null
+                && WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(
+                        viewRootImpl.mContext)) {
+            viewRootImpl.getOnBackInvokedDispatcher()
+                    .unregisterOnBackInvokedCallback(mBackCallback);
+            mBackCallbackRegistered = false;
+        }
+    }
+
+    private void registerOnBackInvokedCallback() {
+        if (mBackCallbackRegistered) {
+            return;
+        }
+        ViewRootImpl viewRootImpl = mTextView.getViewRootImpl();
+        if (viewRootImpl != null
+                && WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(
+                        viewRootImpl.mContext)) {
+            viewRootImpl.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
+                    OnBackInvokedDispatcher.PRIORITY_DEFAULT, mBackCallback);
+            mBackCallbackRegistered = true;
+        }
     }
 
     private void discardTextDisplayLists() {
@@ -2370,6 +2411,7 @@
                 new TextActionModeCallback(TextActionMode.INSERTION);
         mTextActionMode = mTextView.startActionMode(
                 actionModeCallback, ActionMode.TYPE_FLOATING);
+        registerOnBackInvokedCallback();
         if (mTextActionMode != null && getInsertionController() != null) {
             getInsertionController().show();
         }
@@ -2485,6 +2527,7 @@
 
         ActionMode.Callback actionModeCallback = new TextActionModeCallback(actionMode);
         mTextActionMode = mTextView.startActionMode(actionModeCallback, ActionMode.TYPE_FLOATING);
+        registerOnBackInvokedCallback();
 
         final boolean selectableText = mTextView.isTextEditable() || mTextView.isTextSelectable();
         if (actionMode == TextActionMode.TEXT_LINK && !selectableText
@@ -2660,6 +2703,7 @@
             // This will hide the mSelectionModifierCursorController
             mTextActionMode.finish();
         }
+        unregisterOnBackInvokedCallback();
     }
 
     private void stopTextActionModeWithPreservingSelection() {
@@ -4595,7 +4639,7 @@
 
             if (includeEditorBounds) {
                 final RectF bounds = new RectF();
-                mTextView.getBoundsOnScreen(bounds, false /* clipToParent */);
+                bounds.set(0 /* left */, 0 /* top */, mTextView.getWidth(), mTextView.getHeight());
                 EditorBoundsInfo.Builder boundsBuilder = new EditorBoundsInfo.Builder();
                 //TODO(b/210039666): add Handwriting bounds once they're available.
                 builder.setEditorBoundsInfo(
@@ -6309,7 +6353,8 @@
             }
             switch (event.getActionMasked()) {
                 case MotionEvent.ACTION_MOVE:
-                    if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
+                    if (event.isFromSource(InputDevice.SOURCE_MOUSE)
+                            || (mTextView.isAutoHandwritingEnabled() && isFromStylus(event))) {
                         break;
                     }
                     if (mIsDraggingCursor) {
@@ -6332,6 +6377,11 @@
             }
         }
 
+        private boolean isFromStylus(MotionEvent motionEvent) {
+            final int pointerIndex = motionEvent.getActionIndex();
+            return motionEvent.getToolType(pointerIndex) == MotionEvent.TOOL_TYPE_STYLUS;
+        }
+
         private void positionCursorDuringDrag(MotionEvent event) {
             mPrevLineDuringDrag = getLineDuringDrag(event);
             int offset = mTextView.getOffsetAtCoordinate(mPrevLineDuringDrag, event.getX());
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index 9c9baf3..f1dc5e7 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import android.annotation.NonNull;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Resources;
@@ -30,10 +31,14 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewRootImpl;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
 import android.widget.SeekBar.OnSeekBarChangeListener;
+import android.window.OnBackInvokedCallback;
+import android.window.OnBackInvokedDispatcher;
+import android.window.WindowOnBackInvokedDispatcher;
 
 import com.android.internal.policy.PhoneWindow;
 
@@ -115,6 +120,27 @@
     private CharSequence mPlayDescription;
     private CharSequence mPauseDescription;
     private final AccessibilityManager mAccessibilityManager;
+    private boolean mBackCallbackRegistered;
+    /** Handles back invocation */
+    private final OnBackInvokedCallback mBackCallback = new OnBackInvokedCallback() {
+        @Override
+        public void onBackInvoked() {
+            hide();
+        }
+    };
+    /** Handles decor view attach state change */
+    private final OnAttachStateChangeListener mAttachStateListener =
+            new OnAttachStateChangeListener() {
+        @Override
+        public void onViewAttachedToWindow(@NonNull View v) {
+            registerOnBackInvokedCallback();
+        }
+
+        @Override
+        public void onViewDetachedFromWindow(@NonNull View v) {
+            unregisterOnBackInvokedCallback();
+        }
+    };
 
     public MediaController(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -151,6 +177,7 @@
         mWindow.requestFeature(Window.FEATURE_NO_TITLE);
         mDecor = mWindow.getDecorView();
         mDecor.setOnTouchListener(mTouchListener);
+        mDecor.addOnAttachStateChangeListener(mAttachStateListener);
         mWindow.setContentView(this);
         mWindow.setBackgroundDrawableResource(android.R.color.transparent);
 
@@ -395,6 +422,7 @@
             removeCallbacks(mFadeOut);
             postDelayed(mFadeOut, timeout);
         }
+        registerOnBackInvokedCallback();
     }
 
     public boolean isShowing() {
@@ -416,6 +444,7 @@
                 Log.w("MediaController", "already removed");
             }
             mShowing = false;
+            unregisterOnBackInvokedCallback();
         }
     }
 
@@ -718,6 +747,35 @@
         }
     }
 
+    private void unregisterOnBackInvokedCallback() {
+        if (!mBackCallbackRegistered) {
+            return;
+        }
+        ViewRootImpl viewRootImpl = mDecor.getViewRootImpl();
+        if (viewRootImpl != null
+                && WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(
+                viewRootImpl.mContext)) {
+            viewRootImpl.getOnBackInvokedDispatcher()
+                    .unregisterOnBackInvokedCallback(mBackCallback);
+        }
+        mBackCallbackRegistered = false;
+    }
+
+    private void registerOnBackInvokedCallback() {
+        if (mBackCallbackRegistered) {
+            return;
+        }
+
+        ViewRootImpl viewRootImpl = mDecor.getViewRootImpl();
+        if (viewRootImpl != null
+                && WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(
+                viewRootImpl.mContext)) {
+            viewRootImpl.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
+                    OnBackInvokedDispatcher.PRIORITY_DEFAULT, mBackCallback);
+            mBackCallbackRegistered = true;
+        }
+    }
+
     public interface MediaPlayerControl {
         void    start();
         void    pause();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index b076d39..6f83a45 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -788,7 +788,8 @@
     private Layout mLayout;
     private boolean mLocalesChanged = false;
     private int mTextSizeUnit = -1;
-    private LineBreakConfig mLineBreakConfig = new LineBreakConfig();
+    private int mLineBreakStyle = DEFAULT_LINE_BREAK_STYLE;
+    private int mLineBreakWordStyle = DEFAULT_LINE_BREAK_WORD_STYLE;
 
     // This is used to reflect the current user preference for changing font weight and making text
     // more bold.
@@ -1457,13 +1458,12 @@
                     break;
 
                 case com.android.internal.R.styleable.TextView_lineBreakStyle:
-                    mLineBreakConfig.setLineBreakStyle(
-                            a.getInt(attr, LineBreakConfig.LINE_BREAK_STYLE_NONE));
+                    mLineBreakStyle = a.getInt(attr, LineBreakConfig.LINE_BREAK_STYLE_NONE);
                     break;
 
                 case com.android.internal.R.styleable.TextView_lineBreakWordStyle:
-                    mLineBreakConfig.setLineBreakWordStyle(
-                            a.getInt(attr, LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE));
+                    mLineBreakWordStyle = a.getInt(attr,
+                            LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE);
                     break;
 
                 case com.android.internal.R.styleable.TextView_autoSizeTextType:
@@ -4301,13 +4301,12 @@
             @LineBreakConfig.LineBreakStyle int lineBreakStyle,
             @LineBreakConfig.LineBreakWordStyle int lineBreakWordStyle) {
         boolean updated = false;
-        if (isLineBreakStyleSpecified && mLineBreakConfig.getLineBreakStyle() != lineBreakStyle) {
-            mLineBreakConfig.setLineBreakStyle(lineBreakStyle);
+        if (isLineBreakStyleSpecified && mLineBreakStyle != lineBreakStyle) {
+            mLineBreakStyle = lineBreakStyle;
             updated = true;
         }
-        if (isLineBreakWordStyleSpecified
-                && mLineBreakConfig.getLineBreakWordStyle() != lineBreakWordStyle) {
-            mLineBreakConfig.setLineBreakWordStyle(lineBreakWordStyle);
+        if (isLineBreakWordStyleSpecified && mLineBreakWordStyle != lineBreakWordStyle) {
+            mLineBreakWordStyle = lineBreakWordStyle;
             updated = true;
         }
         if (updated && mLayout != null) {
@@ -4871,50 +4870,72 @@
     }
 
     /**
-     * Sets line break configuration indicates which strategy needs to be used when calculating the
-     * text wrapping.
-     * <P>
-     * There are two types of line break rules that can be configured at the same time. One is
-     * line break style(lb) and the other is line break word style(lw). The line break style
-     * affects rule-based breaking. The line break word style affects dictionary-based breaking
-     * and provide phrase-based breaking opportunities. There are several types for the
-     * line break style:
+     * Set the line break style for text wrapping.
+     *
+     * The line break style to indicates the line break strategies can be used when
+     * calculating the text wrapping. The line break style affects rule-based breaking. It
+     * specifies the strictness of line-breaking rules.
+     * There are several types for the line break style:
      * {@link LineBreakConfig#LINE_BREAK_STYLE_LOOSE},
      * {@link LineBreakConfig#LINE_BREAK_STYLE_NORMAL} and
-     * {@link LineBreakConfig#LINE_BREAK_STYLE_STRICT}.
-     * The type for the line break word style is
-     * {@link LineBreakConfig#LINE_BREAK_WORD_STYLE_PHRASE}.
-     * The default values of the line break style and the line break word style are
-     * {@link LineBreakConfig#LINE_BREAK_STYLE_NONE} and
-     * {@link LineBreakConfig#LINE_BREAK_WORD_STYLE_NONE} respectively, indicating that no line
-     * breaking rules are specified.
-     * See <a href="https://drafts.csswg.org/css-text/#line-break-property">
+     * {@link LineBreakConfig#LINE_BREAK_STYLE_STRICT}. The default values of the line break style
+     * is {@link LineBreakConfig#LINE_BREAK_STYLE_NONE}, indicating no breaking rule is specified.
+     * See <a href="https://www.w3.org/TR/css-text-3/#line-break-property">
      *         the line-break property</a>
      *
-     * @param lineBreakConfig the line break config for text wrapping.
+     * @param lineBreakStyle the line break style for the text.
      */
-    public void setLineBreakConfig(@NonNull LineBreakConfig lineBreakConfig) {
-        Objects.requireNonNull(lineBreakConfig);
-        if (mLineBreakConfig.equals(lineBreakConfig)) {
-            return;
-        }
-        mLineBreakConfig.set(lineBreakConfig);
-        if (mLayout != null) {
-            nullLayouts();
-            requestLayout();
-            invalidate();
+    public void setLineBreakStyle(@LineBreakConfig.LineBreakStyle int lineBreakStyle) {
+        if (mLineBreakStyle != lineBreakStyle) {
+            mLineBreakStyle = lineBreakStyle;
+            if (mLayout != null) {
+                nullLayouts();
+                requestLayout();
+                invalidate();
+            }
         }
     }
 
     /**
-     * Get the current line break configuration for text wrapping.
+     * Set the line break word style for text wrapping.
      *
-     * @return the current line break configuration to be used for text wrapping.
+     * The line break word style affects dictionary-based breaking and provide phrase-based
+     * breaking opportunities. The type for the line break word style is
+     * {@link LineBreakConfig#LINE_BREAK_WORD_STYLE_PHRASE}. The default values of the line break
+     * word style is {@link LineBreakConfig#LINE_BREAK_WORD_STYLE_NONE}, indicating no breaking rule
+     * is specified.
+     * See <a href="https://www.w3.org/TR/css-text-3/#word-break-property">
+     *         the word-break property</a>
+     *
+     * @param lineBreakWordStyle the line break word style for the tet
      */
-    public @NonNull LineBreakConfig getLineBreakConfig() {
-        LineBreakConfig lbConfig = new LineBreakConfig();
-        lbConfig.set(mLineBreakConfig);
-        return lbConfig;
+    public void setLineBreakWordStyle(@LineBreakConfig.LineBreakWordStyle int lineBreakWordStyle) {
+        if (mLineBreakWordStyle != lineBreakWordStyle) {
+            mLineBreakWordStyle = lineBreakWordStyle;
+            if (mLayout != null) {
+                nullLayouts();
+                requestLayout();
+                invalidate();
+            }
+        }
+    }
+
+    /**
+     * Get the current line break style for text wrapping.
+     *
+     * @return the current line break style to be used for text wrapping.
+     */
+    public @LineBreakConfig.LineBreakStyle int getLineBreakStyle() {
+        return mLineBreakStyle;
+    }
+
+    /**
+     * Get the current line word break style for text wrapping.
+     *
+     * @return the current line break word style to be used for text wrapping.
+     */
+    public @LineBreakConfig.LineBreakWordStyle int getLineBreakWordStyle() {
+        return mLineBreakWordStyle;
     }
 
     /**
@@ -4924,7 +4945,8 @@
      * @see PrecomputedText
      */
     public @NonNull PrecomputedText.Params getTextMetricsParams() {
-        return new PrecomputedText.Params(new TextPaint(mTextPaint), mLineBreakConfig,
+        return new PrecomputedText.Params(new TextPaint(mTextPaint),
+                LineBreakConfig.getLineBreakConfig(mLineBreakStyle, mLineBreakWordStyle),
                 getTextDirectionHeuristic(),
                 mBreakStrategy, mHyphenationFrequency);
     }
@@ -4941,13 +4963,9 @@
         mTextDir = params.getTextDirection();
         mBreakStrategy = params.getBreakStrategy();
         mHyphenationFrequency = params.getHyphenationFrequency();
-        if (params.getLineBreakConfig() != null) {
-            mLineBreakConfig.set(params.getLineBreakConfig());
-        } else {
-            // Set default value if the line break config in the PrecomputedText.Params is null.
-            mLineBreakConfig.setLineBreakStyle(DEFAULT_LINE_BREAK_STYLE);
-            mLineBreakConfig.setLineBreakWordStyle(DEFAULT_LINE_BREAK_WORD_STYLE);
-        }
+        LineBreakConfig lineBreakConfig = params.getLineBreakConfig();
+        mLineBreakStyle = lineBreakConfig.getLineBreakStyle();
+        mLineBreakWordStyle = lineBreakConfig.getLineBreakWordStyle();
         if (mLayout != null) {
             nullLayouts();
             requestLayout();
@@ -6486,7 +6504,8 @@
             }
             final @PrecomputedText.Params.CheckResultUsableResult int checkResult =
                     precomputed.getParams().checkResultUsable(getPaint(), mTextDir, mBreakStrategy,
-                            mHyphenationFrequency, mLineBreakConfig);
+                            mHyphenationFrequency, LineBreakConfig.getLineBreakConfig(
+                                    mLineBreakStyle, mLineBreakWordStyle));
             switch (checkResult) {
                 case PrecomputedText.Params.UNUSABLE:
                     throw new IllegalArgumentException(
@@ -9383,7 +9402,8 @@
                         .setHyphenationFrequency(mHyphenationFrequency)
                         .setJustificationMode(mJustificationMode)
                         .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE)
-                        .setLineBreakConfig(mLineBreakConfig);
+                        .setLineBreakConfig(LineBreakConfig.getLineBreakConfig(
+                                mLineBreakStyle, mLineBreakWordStyle));
                 if (shouldEllipsize) {
                     builder.setEllipsize(mEllipsize)
                             .setEllipsizedWidth(ellipsisWidth);
@@ -9498,7 +9518,8 @@
                     .setHyphenationFrequency(mHyphenationFrequency)
                     .setJustificationMode(mJustificationMode)
                     .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE)
-                    .setLineBreakConfig(mLineBreakConfig);
+                    .setLineBreakConfig(LineBreakConfig.getLineBreakConfig(
+                            mLineBreakStyle, mLineBreakWordStyle));
             if (shouldEllipsize) {
                 builder.setEllipsize(effectiveEllipsize)
                         .setEllipsizedWidth(ellipsisWidth);
@@ -9866,7 +9887,8 @@
                 .setJustificationMode(getJustificationMode())
                 .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE)
                 .setTextDirection(getTextDirectionHeuristic())
-                .setLineBreakConfig(mLineBreakConfig);
+                .setLineBreakConfig(LineBreakConfig.getLineBreakConfig(
+                        mLineBreakStyle, mLineBreakWordStyle));
 
         final StaticLayout layout = layoutBuilder.build();
 
@@ -12341,9 +12363,10 @@
         }
 
         // A view should not be exposed as clickable/long-clickable to a service because of a
-        // LinkMovementMethod.
+        // LinkMovementMethod or because it has selectable and non-editable text.
         if ((info.isClickable() || info.isLongClickable())
-                && mMovement instanceof LinkMovementMethod) {
+                && (mMovement instanceof LinkMovementMethod
+                || (isTextSelectable() && !isTextEditable()))) {
             if (!hasOnClickListeners()) {
                 info.setClickable(false);
                 info.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK);
@@ -12575,11 +12598,9 @@
                         return true;
                     }
                     if (start >= 0 && start <= end && end <= text.length()) {
+                        requestFocusOnNonEditableSelectableText();
                         Selection.setSelection((Spannable) text, start, end);
-                        // Make sure selection mode is engaged.
-                        if (mEditor != null) {
-                            mEditor.startSelectionActionModeAsync(false);
-                        }
+                        hideAccessibilitySelectionControllers();
                         return true;
                     }
                 }
@@ -12673,6 +12694,18 @@
         return handled;
     }
 
+    private void requestFocusOnNonEditableSelectableText() {
+        if (!isTextEditable() && isTextSelectable()) {
+            if (!isEnabled()) {
+                return;
+            }
+
+            if (isFocusable() && !isFocused()) {
+                requestFocus();
+            }
+        }
+    }
+
     private boolean hasSpannableText() {
         return mText != null && mText instanceof Spannable;
     }
@@ -12701,9 +12734,7 @@
     /**
      * Returns the text that should be exposed to accessibility services.
      * <p>
-     * This approximates what is displayed visually. If the user has specified
-     * that accessibility services should speak passwords, this method will
-     * bypass any password transformation method and return unobscured text.
+     * This approximates what is displayed visually.
      *
      * @return the text that should be exposed to accessibility services, may
      *         be {@code null} if no text is set
@@ -13684,6 +13715,13 @@
     /**
      * @hide
      */
+    public void prepareForExtendedAccessibilitySelection() {
+        requestFocusOnNonEditableSelectableText();
+    }
+
+    /**
+     * @hide
+     */
     @Override
     public int getAccessibilitySelectionEnd() {
         return getSelectionEnd();
@@ -13705,8 +13743,12 @@
             Selection.removeSelection((Spannable) text);
         }
         // Hide all selection controllers used for adjusting selection
-        // since we are doing so explicitlty by other means and these
+        // since we are doing so explicitly by other means and these
         // controllers interact with how selection behaves.
+        hideAccessibilitySelectionControllers();
+    }
+
+    private void hideAccessibilitySelectionControllers() {
         if (mEditor != null) {
             mEditor.hideCursorAndSpanControllers();
             mEditor.stopTextActionMode();
diff --git a/core/java/android/widget/TextViewTranslationCallback.java b/core/java/android/widget/TextViewTranslationCallback.java
index 942be21..1713d84 100644
--- a/core/java/android/widget/TextViewTranslationCallback.java
+++ b/core/java/android/widget/TextViewTranslationCallback.java
@@ -89,7 +89,7 @@
                     originalTranslationMethod);
         }
         final TransformationMethod transformation = mTranslationTransformation;
-        runWithAnimation(
+        runChangeTextWithAnimationIfNeeded(
                 (TextView) view,
                 () -> {
                     mIsShowingTranslation = true;
@@ -122,7 +122,7 @@
         if (mTranslationTransformation != null) {
             final TransformationMethod transformation =
                     mTranslationTransformation.getOriginalTransformationMethod();
-            runWithAnimation(
+            runChangeTextWithAnimationIfNeeded(
                     (TextView) view,
                     () -> {
                         mIsShowingTranslation = false;
@@ -232,10 +232,16 @@
      * Applies a simple text alpha animation when toggling between original and translated text. The
      * text is fully faded out, then swapped to the new text, then the fading is reversed.
      *
-     * @param runnable the operation to run on the view after the text is faded out, to change to
-     * displaying the original or translated text.
+     * @param changeTextRunnable the operation to run on the view after the text is faded out, to
+     * change to displaying the original or translated text.
      */
-    private void runWithAnimation(TextView view, Runnable runnable) {
+    private void runChangeTextWithAnimationIfNeeded(TextView view, Runnable changeTextRunnable) {
+        boolean areAnimatorsEnabled = ValueAnimator.areAnimatorsEnabled();
+        if (!areAnimatorsEnabled) {
+            // The animation is disabled, just change display text
+            changeTextRunnable.run();
+            return;
+        }
         if (mAnimator != null) {
             mAnimator.end();
             // Note: mAnimator is now null; do not use again here.
@@ -269,7 +275,7 @@
 
             @Override
             public void onAnimationRepeat(Animator animation) {
-                runnable.run();
+                changeTextRunnable.run();
             }
         });
         mAnimator.start();
diff --git a/core/java/android/window/ClientWindowFrames.java b/core/java/android/window/ClientWindowFrames.java
index acf9882..51f3fe2 100644
--- a/core/java/android/window/ClientWindowFrames.java
+++ b/core/java/android/window/ClientWindowFrames.java
@@ -27,47 +27,49 @@
  */
 public class ClientWindowFrames implements Parcelable {
     /** The actual window bounds. */
-    public final @NonNull Rect frame;
+    public final @NonNull Rect frame = new Rect();
 
     /**
      * The container frame that is usually the same as display size. It may exclude the area of
      * insets if the window layout parameter has specified fit-insets-sides.
      */
-    public final @NonNull Rect displayFrame;
+    public final @NonNull Rect displayFrame = new Rect();
 
-    /** The background area while the window is resizing. */
-    public final @NonNull Rect backdropFrame;
+    /**
+     * The frame to be referenced while applying gravity and MATCH_PARENT.
+     */
+    public final @NonNull Rect parentFrame = new Rect();
+
+    public boolean isParentFrameClippedByDisplayCutout;
 
     public ClientWindowFrames() {
-        frame = new Rect();
-        displayFrame = new Rect();
-        backdropFrame = new Rect();
     }
 
     public ClientWindowFrames(ClientWindowFrames other) {
-        frame = new Rect(other.frame);
-        displayFrame = new Rect(other.displayFrame);
-        backdropFrame = new Rect(other.backdropFrame);
+        frame.set(other.frame);
+        displayFrame.set(other.displayFrame);
+        parentFrame.set(other.parentFrame);
+        isParentFrameClippedByDisplayCutout = other.isParentFrameClippedByDisplayCutout;
     }
 
     private ClientWindowFrames(Parcel in) {
-        frame = Rect.CREATOR.createFromParcel(in);
-        displayFrame = Rect.CREATOR.createFromParcel(in);
-        backdropFrame = Rect.CREATOR.createFromParcel(in);
+        readFromParcel(in);
     }
 
     /** Needed for AIDL out parameters. */
     public void readFromParcel(Parcel in) {
         frame.readFromParcel(in);
         displayFrame.readFromParcel(in);
-        backdropFrame.readFromParcel(in);
+        parentFrame.readFromParcel(in);
+        isParentFrameClippedByDisplayCutout = in.readBoolean();
     }
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         frame.writeToParcel(dest, flags);
         displayFrame.writeToParcel(dest, flags);
-        backdropFrame.writeToParcel(dest, flags);
+        parentFrame.writeToParcel(dest, flags);
+        dest.writeBoolean(isParentFrameClippedByDisplayCutout);
     }
 
     @Override
@@ -75,7 +77,8 @@
         final StringBuilder sb = new StringBuilder(32);
         return "ClientWindowFrames{frame=" + frame.toShortString(sb)
                 + " display=" + displayFrame.toShortString(sb)
-                + " backdrop=" + backdropFrame.toShortString(sb) + "}";
+                + " parentFrame=" + parentFrame.toShortString(sb)
+                + " parentClippedByDisplayCutout=" + isParentFrameClippedByDisplayCutout + "}";
     }
 
     @Override
diff --git a/core/java/android/window/DisplayWindowPolicyController.java b/core/java/android/window/DisplayWindowPolicyController.java
index 3359a41..1270d87 100644
--- a/core/java/android/window/DisplayWindowPolicyController.java
+++ b/core/java/android/window/DisplayWindowPolicyController.java
@@ -17,12 +17,14 @@
 package android.window;
 
 import android.annotation.NonNull;
+import android.app.WindowConfiguration;
 import android.content.ComponentName;
 import android.content.pm.ActivityInfo;
 import android.util.ArraySet;
 
 import java.io.PrintWriter;
 import java.util.List;
+import java.util.Set;
 
 /**
  * Abstract class to control the policies of the windows that can be displayed on the virtual
@@ -46,6 +48,22 @@
     private int mSystemWindowFlags;
 
     /**
+     * The set of windowing mode that are supported in this display.
+     * @see android.app.WindowConfiguration.WindowingMode
+     */
+    private final Set<Integer> mSupportedWindowingModes = new ArraySet<>();
+
+    /**
+     * A controller to control the policies of the windows that can be displayed on the virtual
+     * display.
+     */
+    public DisplayWindowPolicyController() {
+        synchronized (mSupportedWindowingModes) {
+            mSupportedWindowingModes.add(WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
+        }
+    }
+
+    /**
      * Returns {@code true} if the given window flags contain the flags that we're interested in.
      */
     public final boolean isInterestedWindowFlags(int windowFlags, int systemWindowFlags) {
@@ -62,9 +80,34 @@
     }
 
     /**
-     * Returns {@code true} if the given activities can be displayed on this virtual display.
+     * Returns {@code true} if the given windowing mode is supported in this display.
      */
-    public abstract boolean canContainActivities(@NonNull List<ActivityInfo> activities);
+    public final boolean isWindowingModeSupported(
+            @WindowConfiguration.WindowingMode int windowingMode) {
+        synchronized (mSupportedWindowingModes) {
+            return mSupportedWindowingModes.contains(windowingMode);
+        }
+    }
+
+    /**
+     * Sets the windowing modes are supported in this display.
+     *
+     * @param supportedWindowingModes The set of
+     * {@link android.app.WindowConfiguration.WindowingMode}.
+     */
+    public final void setSupportedWindowingModes(Set<Integer> supportedWindowingModes) {
+        synchronized (mSupportedWindowingModes) {
+            mSupportedWindowingModes.clear();
+            mSupportedWindowingModes.addAll(supportedWindowingModes);
+        }
+    }
+
+    /**
+     * Returns {@code true} if the given activities can be displayed on this virtual display and
+     * the windowing mode is supported.
+     */
+    public abstract boolean canContainActivities(@NonNull List<ActivityInfo> activities,
+            @WindowConfiguration.WindowingMode int windowingMode);
 
     /**
      * Called when an Activity window is layouted with the new changes where contains the
diff --git a/core/java/android/window/OnBackInvokedCallback.java b/core/java/android/window/OnBackInvokedCallback.java
index dcd80fd..400a56f 100644
--- a/core/java/android/window/OnBackInvokedCallback.java
+++ b/core/java/android/window/OnBackInvokedCallback.java
@@ -33,7 +33,7 @@
  * within the same priority. Between different pirorities, callbacks with higher priority
  * are invoked first.
  *
- * See {@link OnBackInvokedDispatcher#registerOnBackInvokedCallback(OnBackInvokedCallback, int)}
+ * See {@link OnBackInvokedDispatcher#registerOnBackInvokedCallback(int, OnBackInvokedCallback)}
  * for specifying callback priority.
  */
 public interface OnBackInvokedCallback {
diff --git a/core/java/android/window/OnBackInvokedDispatcher.java b/core/java/android/window/OnBackInvokedDispatcher.java
index 63e6d30..5eed8cd 100644
--- a/core/java/android/window/OnBackInvokedDispatcher.java
+++ b/core/java/android/window/OnBackInvokedDispatcher.java
@@ -94,15 +94,15 @@
      * Within the same priority level, callbacks are invoked in the reverse order in which
      * they are registered. Higher priority callbacks are invoked before lower priority ones.
      *
+     * @param priority The priority of the callback.
      * @param callback The callback to be registered. If the callback instance has been already
      *                 registered, the existing instance (no matter its priority) will be
      *                 unregistered and registered again.
-     * @param priority The priority of the callback.
      * @throws {@link IllegalArgumentException} if the priority is negative.
      */
-    @SuppressLint({"SamShouldBeLast", "ExecutorRegistration"})
+    @SuppressLint({"ExecutorRegistration"})
     void registerOnBackInvokedCallback(
-            @NonNull OnBackInvokedCallback callback, @Priority @IntRange(from = 0) int priority);
+            @Priority @IntRange(from = 0) int priority, @NonNull OnBackInvokedCallback callback);
 
     /**
      * Unregisters a {@link OnBackInvokedCallback}.
diff --git a/core/java/android/window/ProxyOnBackInvokedDispatcher.java b/core/java/android/window/ProxyOnBackInvokedDispatcher.java
index cf17a21..2b2f5e9 100644
--- a/core/java/android/window/ProxyOnBackInvokedDispatcher.java
+++ b/core/java/android/window/ProxyOnBackInvokedDispatcher.java
@@ -44,7 +44,7 @@
     /**
      * List of pair representing an {@link OnBackInvokedCallback} and its associated priority.
      *
-     * @see OnBackInvokedDispatcher#registerOnBackInvokedCallback(OnBackInvokedCallback, int)
+     * @see OnBackInvokedDispatcher#registerOnBackInvokedCallback(int, OnBackInvokedCallback)
      */
     private final List<Pair<OnBackInvokedCallback, Integer>> mCallbacks = new ArrayList<>();
     private final Object mLock = new Object();
@@ -52,7 +52,7 @@
 
     @Override
     public void registerOnBackInvokedCallback(
-            @NonNull OnBackInvokedCallback callback, int priority) {
+            int priority, @NonNull OnBackInvokedCallback callback) {
         if (DEBUG) {
             Log.v(TAG, String.format("Pending register %s. Actual=%s", callback,
                     mActualDispatcherOwner));
@@ -91,7 +91,7 @@
             mCallbacks.add(Pair.create(callback, priority));
             if (mActualDispatcherOwner != null) {
                 mActualDispatcherOwner.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
-                        callback, priority);
+                        priority, callback);
             }
         }
     }
@@ -115,7 +115,7 @@
         for (Pair<OnBackInvokedCallback, Integer> callbackPair : mCallbacks) {
             int priority = callbackPair.second;
             if (priority >= 0) {
-                dispatcher.registerOnBackInvokedCallback(callbackPair.first, priority);
+                dispatcher.registerOnBackInvokedCallback(priority, callbackPair.first);
             } else {
                 dispatcher.registerSystemOnBackInvokedCallback(callbackPair.first);
             }
diff --git a/core/java/android/window/SplashScreen.java b/core/java/android/window/SplashScreen.java
index fab180d..f1c0d8d 100644
--- a/core/java/android/window/SplashScreen.java
+++ b/core/java/android/window/SplashScreen.java
@@ -100,8 +100,12 @@
      * <p>
      * To reset to the default theme, set this the themeId to {@link Resources#ID_NULL}.
      * <p>
-     * <b>Note:</b> The theme name must be stable across versions, otherwise it won't be found
-     * after your application is updated.
+     * <b>Note:</b> Internally, the theme name is resolved and persisted. This means that the theme
+     * name must be stable across versions, otherwise it won't be found after your application is
+     * updated.
+     *
+     * @param themeId The ID of the splashscreen theme to be used in place of the one defined in
+     *                the manifest.
      */
     void setSplashScreenTheme(@StyleRes int themeId);
 
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index 10d7eca..19ee1d0 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -233,14 +233,6 @@
         }
 
         /**
-         * Set the animation duration if icon is animatable.
-         */
-        public Builder setAnimationDurationMillis(long duration) {
-            mIconAnimationDuration = Duration.ofMillis(duration);
-            return this;
-        }
-
-        /**
          * Set the Runnable that can receive the task which should be executed on UI thread.
          * @param uiThreadInitTask
          */
@@ -294,8 +286,7 @@
                 } else {
                     view.mIconView = createSurfaceView(view);
                 }
-                view.initIconAnimation(mIconDrawable,
-                        mIconAnimationDuration != null ? mIconAnimationDuration.toMillis() : 0);
+                view.initIconAnimation(mIconDrawable);
                 view.mIconAnimationStart = mIconAnimationStart;
                 view.mIconAnimationDuration = mIconAnimationDuration;
             } else if (mIconSize != 0) {
@@ -463,6 +454,11 @@
     /**
      * Returns the duration of the icon animation if icon is animatable.
      *
+     * Note the return value can be null or 0 if the
+     * {@link android.R.attr#windowSplashScreenAnimatedIcon} is not
+     * {@link android.graphics.drawable.AnimationDrawable} or
+     * {@link android.graphics.drawable.AnimatedVectorDrawable}.
+     *
      * @see android.R.attr#windowSplashScreenAnimatedIcon
      * @see android.R.attr#windowSplashScreenAnimationDuration
      */
@@ -497,12 +493,12 @@
         mSurfaceView.setChildSurfacePackage(mSurfacePackage);
     }
 
-    void initIconAnimation(Drawable iconDrawable, long duration) {
+    void initIconAnimation(Drawable iconDrawable) {
         if (!(iconDrawable instanceof IconAnimateListener)) {
             return;
         }
         IconAnimateListener aniDrawable = (IconAnimateListener) iconDrawable;
-        aniDrawable.prepareAnimate(duration, this::animationStartCallback);
+        aniDrawable.prepareAnimate(this::animationStartCallback);
         aniDrawable.setAnimationJankMonitoring(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationCancel(Animator animation) {
@@ -524,7 +520,7 @@
 
     private void animationStartCallback(long animDuration) {
         mIconAnimationStart = Instant.now();
-        if (animDuration > 0) {
+        if (animDuration >= 0) {
             mIconAnimationDuration = Duration.ofMillis(animDuration);
         }
     }
@@ -695,10 +691,9 @@
     public interface IconAnimateListener {
         /**
          * Prepare the animation if this drawable also be animatable.
-         * @param duration The animation duration.
          * @param startListener The callback listener used to receive the start of the animation.
          */
-        void prepareAnimate(long duration, LongConsumer startListener);
+        void prepareAnimate(LongConsumer startListener);
 
         /**
          * Stop animation.
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 7718a3b..51da61f 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -344,7 +344,7 @@
             if (parentChg.getMode() != TRANSIT_CHANGE) return false;
 
             // If there are no more parents left, then all the parents, so far, have not been
-            // visibility changes which means this change is indpendent.
+            // visibility changes which means this change is independent.
             if (parentChg.getParent() == null) return true;
 
             parentChg = info.getChange(parentChg.getParent());
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 35c9594..f2db564 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -269,6 +269,20 @@
     }
 
     /**
+     * Used in conjunction with a shell-transition call (usually finishTransition). This is
+     * basically a message to the transition system that a particular task should NOT go into
+     * PIP even though it normally would. This is to deal with some edge-case situations where
+     * Recents will "commit" the transition to go home, but then not actually go-home.
+     * @hide
+     */
+    @NonNull
+    public WindowContainerTransaction setDoNotPip(@NonNull WindowContainerToken container) {
+        Change chg = getOrCreateChange(container.asBinder());
+        chg.mChangeMask |= Change.CHANGE_FORCE_NO_PIP;
+        return this;
+    }
+
+    /**
      * Reparents a container into another one. The effect of a {@code null} parent can vary. For
      * example, reparenting a stack to {@code null} will reparent it to its display.
      *
@@ -790,6 +804,7 @@
         public static final int CHANGE_HIDDEN = 1 << 3;
         public static final int CHANGE_BOUNDS_TRANSACTION_RECT = 1 << 4;
         public static final int CHANGE_IGNORE_ORIENTATION_REQUEST = 1 << 5;
+        public static final int CHANGE_FORCE_NO_PIP = 1 << 6;
 
         private final Configuration mConfiguration = new Configuration();
         private boolean mFocusable = true;
diff --git a/core/java/android/window/WindowInfosListener.java b/core/java/android/window/WindowInfosListener.java
index 9d4545c..8db5a5e 100644
--- a/core/java/android/window/WindowInfosListener.java
+++ b/core/java/android/window/WindowInfosListener.java
@@ -17,6 +17,7 @@
 package android.window;
 
 import android.graphics.Matrix;
+import android.util.Pair;
 import android.util.Size;
 import android.view.InputWindowHandle;
 
@@ -47,9 +48,13 @@
 
     /**
      * Register the WindowInfosListener.
+     *
+     * @return The cached values for InputWindowHandles and DisplayInfos. This is the last updated
+     * value that was sent from SurfaceFlinger to this particular process. If there was nothing
+     * registered previously, then the data can be empty.
      */
-    public void register() {
-        nativeRegister(mNativeListener);
+    public Pair<InputWindowHandle[], DisplayInfo[]> register() {
+        return nativeRegister(mNativeListener);
     }
 
     /**
@@ -60,7 +65,7 @@
     }
 
     private static native long nativeCreate(WindowInfosListener thiz);
-    private static native void nativeRegister(long ptr);
+    private static native Pair<InputWindowHandle[], DisplayInfo[]> nativeRegister(long ptr);
     private static native void nativeUnregister(long ptr);
     private static native long nativeGetFinalizer();
 
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 5dbb551..97573c2 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -53,7 +53,7 @@
     private static final String TAG = "WindowOnBackDispatcher";
     private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability";
     private static final boolean IS_BACK_PREDICTABILITY_ENABLED = SystemProperties
-            .getInt(BACK_PREDICTABILITY_PROP, 0) > 0;
+            .getInt(BACK_PREDICTABILITY_PROP, 1) > 0;
 
     /** Convenience hashmap to quickly decide if a callback has been added. */
     private final HashMap<OnBackInvokedCallback, Integer> mAllCallbacks = new HashMap<>();
@@ -83,7 +83,7 @@
     // TODO: Take an Executor for the callback to run on.
     @Override
     public void registerOnBackInvokedCallback(
-            @NonNull OnBackInvokedCallback callback, @Priority int priority) {
+            @Priority int priority, @NonNull OnBackInvokedCallback callback) {
         if (priority < 0) {
             throw new IllegalArgumentException("Application registered OnBackInvokedCallback "
                     + "cannot have negative priority. Priority: " + priority);
diff --git a/core/java/com/android/internal/app/AppLocaleStore.java b/core/java/com/android/internal/app/AppLocaleStore.java
new file mode 100644
index 0000000..76e5898
--- /dev/null
+++ b/core/java/com/android/internal/app/AppLocaleStore.java
@@ -0,0 +1,85 @@
+/*
+ * 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.internal.app;
+
+import android.app.LocaleConfig;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.LocaleList;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Locale;
+
+public class AppLocaleStore {
+    private static final String TAG = AppLocaleStore.class.getSimpleName();
+
+    public static ArrayList<Locale> getAppSupportedLocales(Context context, String packageName) {
+        ArrayList<Locale> appSupportedLocales = new ArrayList<>();
+        LocaleList packageLocaleList = getPackageLocales(context, packageName);
+
+        if (packageLocaleList != null && packageLocaleList.size() > 0) {
+            for (int i = 0; i < packageLocaleList.size(); i++) {
+                appSupportedLocales.add(packageLocaleList.get(i));
+            }
+            Log.d(TAG, "getAppSupportedLocales from LocaleConfig. Size: "
+                    + appSupportedLocales.size());
+        } else {
+            String[] languages = getAssetLocales(context, packageName);
+            for (String language : languages) {
+                appSupportedLocales.add(Locale.forLanguageTag(language));
+            }
+            Log.d(TAG, "getAppSupportedLocales from asset. Size: "
+                    + appSupportedLocales.size());
+        }
+        return appSupportedLocales;
+    }
+
+    private static LocaleList getPackageLocales(Context context, String packageName) {
+        try {
+            LocaleConfig localeConfig =
+                    new LocaleConfig(context.createPackageContext(packageName, 0));
+            if (localeConfig.getStatus() == LocaleConfig.STATUS_SUCCESS) {
+                return localeConfig.getSupportedLocales();
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.w(TAG, "Can not found the package name : " + packageName + " / " + e);
+        }
+        return null;
+    }
+
+    private static String[] getAssetLocales(Context context, String packageName) {
+        try {
+            PackageManager packageManager = context.getPackageManager();
+            String[] locales = packageManager.getResourcesForApplication(
+                    packageManager.getPackageInfo(packageName, PackageManager.MATCH_ALL)
+                            .applicationInfo).getAssets().getNonSystemLocales();
+            if (locales == null) {
+                Log.i(TAG, "[" + packageName + "] locales are null.");
+                return new String[0];
+            } else if (locales.length <= 0) {
+                Log.i(TAG, "[" + packageName + "] locales length is 0.");
+                return new String[0];
+            }
+            return locales;
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.w(TAG, "Can not found the package name : " + packageName + " / " + e);
+        }
+        return new String[0];
+    }
+
+}
diff --git a/core/java/com/android/internal/app/BlockedAppStreamingActivity.java b/core/java/com/android/internal/app/BlockedAppStreamingActivity.java
index 31c3822..2d6c77f 100644
--- a/core/java/com/android/internal/app/BlockedAppStreamingActivity.java
+++ b/core/java/com/android/internal/app/BlockedAppStreamingActivity.java
@@ -56,7 +56,11 @@
 
         CharSequence streamedDeviceName = intent.getCharSequenceExtra(EXTRA_STREAMED_DEVICE);
         if (!TextUtils.isEmpty(streamedDeviceName)) {
-            mAlertParams.mTitle = getString(R.string.app_streaming_blocked_title, appLabel);
+            mAlertParams.mTitle =
+                    TextUtils.equals(activityInfo.packageName,
+                        getPackageManager().getPermissionControllerPackageName())
+                            ? getString(R.string.app_streaming_blocked_title_for_permission_dialog)
+                            : getString(R.string.app_streaming_blocked_title, appLabel);
             mAlertParams.mMessage =
                     getString(R.string.app_streaming_blocked_message, streamedDeviceName);
         } else {
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 70506cc..96728ed 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -28,7 +28,6 @@
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
 import android.app.SharedElementCallback;
 import android.app.prediction.AppPredictionContext;
 import android.app.prediction.AppPredictionManager;
@@ -71,11 +70,9 @@
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
-import android.os.IBinder;
 import android.os.Message;
 import android.os.Parcelable;
 import android.os.PatternMatcher;
-import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -107,7 +104,6 @@
 import android.widget.ImageView;
 import android.widget.Space;
 import android.widget.TextView;
-import android.widget.Toast;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
@@ -762,25 +758,17 @@
             return false;
         }
 
-        try {
-            Intent delegationIntent = new Intent();
-            final ComponentName delegateActivity = ComponentName.unflattenFromString(
-                    Resources.getSystem().getString(R.string.config_chooserActivity));
-            IBinder permissionToken = ActivityTaskManager.getService()
-                    .requestStartActivityPermissionToken(delegateActivity);
-            delegationIntent.setComponent(delegateActivity);
-            delegationIntent.putExtra(Intent.EXTRA_INTENT, getIntent());
-            delegationIntent.putExtra(ActivityTaskManager.EXTRA_PERMISSION_TOKEN, permissionToken);
-            delegationIntent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
+        Intent delegationIntent = new Intent();
+        final ComponentName delegateActivity = ComponentName.unflattenFromString(
+                Resources.getSystem().getString(R.string.config_chooserActivity));
+        delegationIntent.setComponent(delegateActivity);
+        delegationIntent.putExtra(Intent.EXTRA_INTENT, getIntent());
+        delegationIntent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
 
-            // Don't close until the delegate finishes, or the token will be invalidated.
-            mAwaitingDelegateResponse = true;
-            startActivityForResult(delegationIntent, REQUEST_CODE_RETURN_FROM_DELEGATE_CHOOSER);
-            return true;
-        } catch (RemoteException e) {
-            Log.e(TAG, e.toString());
-        }
-        return false;
+        // Don't close until the delegate finishes, or the token will be invalidated.
+        mAwaitingDelegateResponse = true;
+        startActivityForResult(delegationIntent, REQUEST_CODE_RETURN_FROM_DELEGATE_CHOOSER);
+        return true;
     }
 
     @Override
@@ -1054,7 +1042,6 @@
             ClipboardManager clipboardManager = (ClipboardManager) getSystemService(
                     Context.CLIPBOARD_SERVICE);
             clipboardManager.setPrimaryClipAsPackage(clipData, getReferrerPackageName());
-            Toast.makeText(getApplicationContext(), R.string.copied, Toast.LENGTH_SHORT).show();
 
             // Log share completion via copy
             LogMaker targetLogMaker = new LogMaker(
diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
index 393bff4..9164089 100644
--- a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
@@ -247,54 +247,54 @@
     }
 
     private String getWorkAppPausedTitle() {
-        return getContext().getSystemService(DevicePolicyManager.class).getString(
+        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
                 RESOLVER_WORK_PAUSED_TITLE,
                 () -> getContext().getString(R.string.resolver_turn_on_work_apps));
     }
 
     private String getCrossProfileBlockedTitle() {
-        return getContext().getSystemService(DevicePolicyManager.class).getString(
+        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
                 RESOLVER_CROSS_PROFILE_BLOCKED_TITLE,
                 () -> getContext().getString(R.string.resolver_cross_profile_blocked));
     }
 
     private String getCantShareWithWorkMessage() {
-        return getContext().getSystemService(DevicePolicyManager.class).getString(
+        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
                 RESOLVER_CANT_SHARE_WITH_WORK,
                 () -> getContext().getString(
                         R.string.resolver_cant_share_with_work_apps_explanation));
     }
 
     private String getCantShareWithPersonalMessage() {
-        return getContext().getSystemService(DevicePolicyManager.class).getString(
+        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
                 RESOLVER_CANT_SHARE_WITH_PERSONAL,
                 () -> getContext().getString(
                         R.string.resolver_cant_share_with_personal_apps_explanation));
     }
 
     private String getCantAccessWorkMessage() {
-        return getContext().getSystemService(DevicePolicyManager.class).getString(
+        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
                 RESOLVER_CANT_ACCESS_WORK,
                 () -> getContext().getString(
                         R.string.resolver_cant_access_work_apps_explanation));
     }
 
     private String getCantAccessPersonalMessage() {
-        return getContext().getSystemService(DevicePolicyManager.class).getString(
+        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
                 RESOLVER_CANT_ACCESS_PERSONAL,
                 () -> getContext().getString(
                         R.string.resolver_cant_access_personal_apps_explanation));
     }
 
     private String getNoWorkAppsAvailableMessage() {
-        return getContext().getSystemService(DevicePolicyManager.class).getString(
+        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
                 RESOLVER_NO_WORK_APPS,
                 () -> getContext().getString(
                         R.string.resolver_no_work_apps_available));
     }
 
     private String getNoPersonalAppsAvailableMessage() {
-        return getContext().getSystemService(DevicePolicyManager.class).getString(
+        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
                 RESOLVER_NO_PERSONAL_APPS,
                 () -> getContext().getString(
                         R.string.resolver_no_personal_apps_available));
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index 25b8dba..070d8ff 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -163,13 +163,13 @@
     }
 
     private String getForwardToPersonalMessage() {
-        return getSystemService(DevicePolicyManager.class).getString(
+        return getSystemService(DevicePolicyManager.class).getResources().getString(
                 FORWARD_INTENT_TO_PERSONAL,
                 () -> getString(com.android.internal.R.string.forward_intent_to_owner));
     }
 
     private String getForwardToWorkMessage() {
-        return getSystemService(DevicePolicyManager.class).getString(
+        return getSystemService(DevicePolicyManager.class).getResources().getString(
                 FORWARD_INTENT_TO_WORK,
                 () -> getString(com.android.internal.R.string.forward_intent_to_work));
     }
@@ -207,7 +207,6 @@
             startActivityAsCaller(
                     newIntent,
                     /* options= */ null,
-                    /* permissionToken= */ null,
                     /* ignoreTargetSecurity= */ false,
                     userId);
         } catch (RuntimeException e) {
@@ -231,7 +230,7 @@
             return;
         }
         sanitizeIntent(innerIntent);
-        startActivityAsCaller(intentReceived, null, null, false, getUserId());
+        startActivityAsCaller(intentReceived, null, false, getUserId());
         finish();
     }
 
@@ -251,7 +250,7 @@
         sanitizeIntent(intentReceived);
         intentReceived.putExtra(EXTRA_SELECTED_PROFILE, selectedProfile);
         intentReceived.putExtra(EXTRA_CALLING_USER, UserHandle.of(callingUserId));
-        startActivityAsCaller(intentReceived, null, null, false, userId);
+        startActivityAsCaller(intentReceived, null, false, userId);
         finish();
     }
 
diff --git a/core/java/com/android/internal/app/LocaleHelper.java b/core/java/com/android/internal/app/LocaleHelper.java
index 707286e..57bd3f9 100644
--- a/core/java/com/android/internal/app/LocaleHelper.java
+++ b/core/java/com/android/internal/app/LocaleHelper.java
@@ -234,7 +234,11 @@
         public int compare(LocaleStore.LocaleInfo lhs, LocaleStore.LocaleInfo rhs) {
             // We don't care about the various suggestion types, just "suggested" (!= 0)
             // and "all others" (== 0)
-            if (lhs.isSuggested() == rhs.isSuggested()) {
+            if (lhs.isAppCurrentLocale() || rhs.isAppCurrentLocale()) {
+                return lhs.isAppCurrentLocale() ? -1 : 1;
+            } else if (lhs.isSystemLocale() || rhs.isSystemLocale()) {
+                    return lhs.isSystemLocale() ? -1 : 1;
+            } else if (lhs.isSuggested() == rhs.isSuggested()) {
                 // They are in the same "bucket" (suggested / others), so we compare the text
                 return mCollator.compare(
                         removePrefixForCompare(lhs.getLocale(), lhs.getLabel(mCountryMode)),
diff --git a/core/java/com/android/internal/app/LocalePickerWithRegion.java b/core/java/com/android/internal/app/LocalePickerWithRegion.java
index b4ae56f..e7cb43e 100644
--- a/core/java/com/android/internal/app/LocalePickerWithRegion.java
+++ b/core/java/com/android/internal/app/LocalePickerWithRegion.java
@@ -23,6 +23,7 @@
 import android.os.Bundle;
 import android.os.LocaleList;
 import android.text.TextUtils;
+import android.util.Log;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
@@ -32,6 +33,7 @@
 
 import com.android.internal.R;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Locale;
@@ -45,6 +47,7 @@
  * default locale.</p>
  */
 public class LocalePickerWithRegion extends ListFragment implements SearchView.OnQueryTextListener {
+    private static final String TAG = LocalePickerWithRegion.class.getSimpleName();
     private static final String PARENT_FRAGMENT_NAME = "localeListEditor";
 
     private SuggestedLocaleAdapter mAdapter;
@@ -57,6 +60,7 @@
     private boolean mPreviousSearchHadFocus = false;
     private int mFirstVisiblePosition = 0;
     private int mTopDistance = 0;
+    private String mAppPackageName;
 
     /**
      * Other classes can register to be notified when a locale was selected.
@@ -73,17 +77,25 @@
 
     private static LocalePickerWithRegion createCountryPicker(Context context,
             LocaleSelectedListener listener, LocaleStore.LocaleInfo parent,
-            boolean translatedOnly) {
+            boolean translatedOnly, String appPackageName) {
         LocalePickerWithRegion localePicker = new LocalePickerWithRegion();
         boolean shouldShowTheList = localePicker.setListener(context, listener, parent,
-                translatedOnly);
+                translatedOnly, appPackageName);
         return shouldShowTheList ? localePicker : null;
     }
 
     public static LocalePickerWithRegion createLanguagePicker(Context context,
             LocaleSelectedListener listener, boolean translatedOnly) {
         LocalePickerWithRegion localePicker = new LocalePickerWithRegion();
-        localePicker.setListener(context, listener, /* parent */ null, translatedOnly);
+        localePicker.setListener(context, listener, /* parent */ null, translatedOnly, null);
+        return localePicker;
+    }
+
+    public static LocalePickerWithRegion createLanguagePicker(Context context,
+            LocaleSelectedListener listener, boolean translatedOnly, String appPackageName) {
+        LocalePickerWithRegion localePicker = new LocalePickerWithRegion();
+        localePicker.setListener(
+                context, listener, /* parent */ null, translatedOnly, appPackageName);
         return localePicker;
     }
 
@@ -101,20 +113,32 @@
      * "pretending" it was selected, and return false.</p>
      */
     private boolean setListener(Context context, LocaleSelectedListener listener,
-            LocaleStore.LocaleInfo parent, boolean translatedOnly) {
+            LocaleStore.LocaleInfo parent, boolean translatedOnly, String appPackageName) {
         this.mParentLocale = parent;
         this.mListener = listener;
         this.mTranslatedOnly = translatedOnly;
+        this.mAppPackageName = appPackageName;
         setRetainInstance(true);
 
         final HashSet<String> langTagsToIgnore = new HashSet<>();
-        if (!translatedOnly) {
+        LocaleStore.LocaleInfo appCurrentLocale =
+                LocaleStore.getAppCurrentLocaleInfo(context, appPackageName);
+        boolean isForCountryMode = parent != null;
+
+        if (!TextUtils.isEmpty(appPackageName) && !isForCountryMode) {
+            if (appCurrentLocale != null) {
+                Log.d(TAG, "appCurrentLocale: " + appCurrentLocale.getLocale().toLanguageTag());
+                langTagsToIgnore.add(appCurrentLocale.getLocale().toLanguageTag());
+            } else {
+                Log.d(TAG, "appCurrentLocale is null");
+            }
+        } else if (!translatedOnly) {
             final LocaleList userLocales = LocalePicker.getLocales();
             final String[] langTags = userLocales.toLanguageTags().split(",");
             Collections.addAll(langTagsToIgnore, langTags);
         }
 
-        if (parent != null) {
+        if (isForCountryMode) {
             mLocaleList = LocaleStore.getLevelLocales(context,
                     langTagsToIgnore, parent, translatedOnly);
             if (mLocaleList.size() <= 1) {
@@ -127,10 +151,39 @@
             mLocaleList = LocaleStore.getLevelLocales(context, langTagsToIgnore,
                     null /* no parent */, translatedOnly);
         }
+        Log.d(TAG, "mLocaleList size:  " + mLocaleList.size());
 
+        // Adding current locale and system default option into suggestion list
+        if(!TextUtils.isEmpty(appPackageName)) {
+            if (appCurrentLocale != null && !isForCountryMode) {
+                mLocaleList.add(appCurrentLocale);
+            }
+            filterTheLanguagesNotSupportedInApp(context, appPackageName);
+
+            if (!isForCountryMode) {
+                mLocaleList.add(LocaleStore.getSystemDefaultLocaleInfo());
+            }
+        }
         return true;
     }
 
+    private void filterTheLanguagesNotSupportedInApp(Context context, String appPackageName) {
+        ArrayList<Locale> supportedLocales =
+                AppLocaleStore.getAppSupportedLocales(context, appPackageName);
+
+        Set<LocaleStore.LocaleInfo> filteredList = new HashSet<>();
+        for(LocaleStore.LocaleInfo li: mLocaleList) {
+            for(Locale l: supportedLocales) {
+                if(LocaleList.matchesLanguageAndScript(li.getLocale(), l)) {
+                    filteredList.add(li);
+                }
+            }
+        }
+        Log.d(TAG, "mLocaleList after app-supported filter:  " + filteredList.size());
+
+        mLocaleList = filteredList;
+    }
+
     private void returnToParentFrame() {
         getFragmentManager().popBackStack(PARENT_FRAGMENT_NAME,
                 FragmentManager.POP_BACK_STACK_INCLUSIVE);
@@ -151,7 +204,7 @@
 
         final boolean countryMode = mParentLocale != null;
         final Locale sortingLocale = countryMode ? mParentLocale.getLocale() : Locale.getDefault();
-        mAdapter = new SuggestedLocaleAdapter(mLocaleList, countryMode);
+        mAdapter = new SuggestedLocaleAdapter(mLocaleList, countryMode, mAppPackageName);
         final LocaleHelper.LocaleInfoComparator comp =
                 new LocaleHelper.LocaleInfoComparator(sortingLocale, countryMode);
         mAdapter.sort(comp);
@@ -212,17 +265,22 @@
 
     @Override
     public void onListItemClick(ListView l, View v, int position, long id) {
+        SuggestedLocaleAdapter adapter = (SuggestedLocaleAdapter) getListAdapter();
         final LocaleStore.LocaleInfo locale =
-                (LocaleStore.LocaleInfo) getListAdapter().getItem(position);
+                (LocaleStore.LocaleInfo) adapter.getItem(position);
+        // Special case for resetting the app locale to equal the system locale.
+        boolean isSystemLocale = locale.isSystemLocale();
+        boolean isRegionLocale = locale.getParent() != null;
 
-        if (locale.getParent() != null) {
+        if (isSystemLocale || isRegionLocale) {
             if (mListener != null) {
                 mListener.onLocaleSelected(locale);
             }
             returnToParentFrame();
         } else {
             LocalePickerWithRegion selector = LocalePickerWithRegion.createCountryPicker(
-                    getContext(), mListener, locale, mTranslatedOnly /* translate only */);
+                    getContext(), mListener, locale, mTranslatedOnly /* translate only */,
+                    adapter.getAppPackageName());
             if (selector != null) {
                 getFragmentManager().beginTransaction()
                         .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java
index 1c5ca59..cea8eaa 100644
--- a/core/java/com/android/internal/app/LocaleStore.java
+++ b/core/java/com/android/internal/app/LocaleStore.java
@@ -16,11 +16,13 @@
 
 package com.android.internal.app;
 
+import android.app.LocaleManager;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.LocaleList;
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
+import android.util.Log;
 
 import java.io.Serializable;
 import java.util.HashMap;
@@ -31,12 +33,17 @@
 
 public class LocaleStore {
     private static final HashMap<String, LocaleInfo> sLocaleCache = new HashMap<>();
+    private static final String TAG = LocaleStore.class.getSimpleName();
     private static boolean sFullyInitialized = false;
 
     public static class LocaleInfo implements Serializable {
         private static final int SUGGESTION_TYPE_NONE = 0;
         private static final int SUGGESTION_TYPE_SIM = 1 << 0;
         private static final int SUGGESTION_TYPE_CFG = 1 << 1;
+        // Only for per-app language picker
+        private static final int SUGGESTION_TYPE_CURRENT = 1 << 2;
+        // Only for per-app language picker
+        private static final int SUGGESTION_TYPE_SYSTEM_LANGUAGE = 1 << 3;
 
         private final Locale mLocale;
         private final Locale mParent;
@@ -189,6 +196,14 @@
         public void setChecked(boolean checked) {
             mIsChecked = checked;
         }
+
+        public boolean isAppCurrentLocale() {
+            return (mSuggestionFlags & SUGGESTION_TYPE_CURRENT) > 0;
+        }
+
+        public boolean isSystemLocale() {
+            return (mSuggestionFlags & SUGGESTION_TYPE_SYSTEM_LANGUAGE) > 0;
+        }
     }
 
     private static Set<String> getSimCountries(Context context) {
@@ -239,6 +254,40 @@
         }
     }
 
+    public static LocaleInfo getAppCurrentLocaleInfo(Context context, String appPackageName) {
+        if (appPackageName == null) {
+            return null;
+        }
+
+        LocaleManager localeManager = context.getSystemService(LocaleManager.class);
+        try {
+            LocaleList localeList = (localeManager == null)
+                    ? null : localeManager.getApplicationLocales(appPackageName);
+            Locale locale = localeList == null ? null : localeList.get(0);
+
+            if (locale != null) {
+                LocaleInfo localeInfo = new LocaleInfo(locale);
+                localeInfo.mSuggestionFlags |= LocaleInfo.SUGGESTION_TYPE_CURRENT;
+                localeInfo.mIsTranslated = true;
+                return localeInfo;
+            }
+        } catch (IllegalArgumentException e) {
+            Log.d(TAG, "IllegalArgumentException ", e);
+        }
+        return null;
+    }
+
+    /**
+     * The "system default" is special case for per-app picker. Intentionally keep the locale
+     * empty to let activity know "system default" been selected.
+     */
+    public static LocaleInfo getSystemDefaultLocaleInfo() {
+        LocaleInfo systemDefaultInfo = new LocaleInfo("");
+        systemDefaultInfo.mSuggestionFlags |= LocaleInfo.SUGGESTION_TYPE_SYSTEM_LANGUAGE;
+        systemDefaultInfo.mIsTranslated = true;
+        return systemDefaultInfo;
+    }
+
     /*
      * Show all the languages supported for a country in the suggested list.
      * This is also handy for devices without SIM (tablets).
diff --git a/core/java/com/android/internal/app/OWNERS b/core/java/com/android/internal/app/OWNERS
index e6c911e..3833976 100644
--- a/core/java/com/android/internal/app/OWNERS
+++ b/core/java/com/android/internal/app/OWNERS
@@ -9,3 +9,6 @@
 per-file *Assist* = file:/core/java/android/service/voice/OWNERS
 per-file *Hotword* = file:/core/java/android/service/voice/OWNERS
 per-file *Voice* = file:/core/java/android/service/voice/OWNERS
+
+# System language settings
+per-file *Locale* = file:platform/packages/apps/Settings:/src/com/android/settings/localepicker/OWNERS
\ No newline at end of file
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index fd5eac8..dc68e16 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -850,13 +850,13 @@
     }
 
     private String getForwardToPersonalMsg() {
-        return getSystemService(DevicePolicyManager.class).getString(
+        return getSystemService(DevicePolicyManager.class).getResources().getString(
                 FORWARD_INTENT_TO_PERSONAL,
                 () -> getString(com.android.internal.R.string.forward_intent_to_owner));
     }
 
     private String getForwardToWorkMsg() {
-        return getSystemService(DevicePolicyManager.class).getString(
+        return getSystemService(DevicePolicyManager.class).getResources().getString(
                 FORWARD_INTENT_TO_WORK,
                 () -> getString(com.android.internal.R.string.forward_intent_to_work));
     }
@@ -1150,7 +1150,7 @@
     }
 
     private String getWorkProfileNotSupportedMsg(String launcherName) {
-        return getSystemService(DevicePolicyManager.class).getString(
+        return getSystemService(DevicePolicyManager.class).getResources().getString(
                 RESOLVER_WORK_PROFILE_NOT_SUPPORTED,
                 () -> getString(
                         com.android.internal.R.string.activity_resolver_work_profiles_support,
@@ -1463,7 +1463,7 @@
             int userId) {
         // Note: this method will be overridden in the delegate implementation to use the passed-in
         // permission token.
-        startActivityAsCaller(intent, options, null, false, userId);
+        startActivityAsCaller(intent, options, false, userId);
         return true;
     }
 
@@ -1879,12 +1879,12 @@
     }
 
     private String getPersonalTabLabel() {
-        return getSystemService(DevicePolicyManager.class).getString(
+        return getSystemService(DevicePolicyManager.class).getResources().getString(
                 RESOLVER_PERSONAL_TAB, () -> getString(R.string.resolver_personal_tab));
     }
 
     private String getWorkTabLabel() {
-        return getSystemService(DevicePolicyManager.class).getString(
+        return getSystemService(DevicePolicyManager.class).getResources().getString(
                 RESOLVER_WORK_TAB, () -> getString(R.string.resolver_work_tab));
     }
 
@@ -1935,13 +1935,13 @@
     }
 
     private String getPersonalTabAccessibilityLabel() {
-        return getSystemService(DevicePolicyManager.class).getString(
+        return getSystemService(DevicePolicyManager.class).getResources().getString(
                 RESOLVER_PERSONAL_TAB_ACCESSIBILITY,
                 () -> getString(R.string.resolver_personal_tab_accessibility));
     }
 
     private String getWorkTabAccessibilityLabel() {
-        return getSystemService(DevicePolicyManager.class).getString(
+        return getSystemService(DevicePolicyManager.class).getResources().getString(
                 RESOLVER_WORK_TAB_ACCESSIBILITY,
                 () -> getString(R.string.resolver_work_tab_accessibility));
     }
diff --git a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
index 4da59a3..f4e568b 100644
--- a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
@@ -242,40 +242,40 @@
     }
 
     private String getWorkAppPausedTitle() {
-        return getContext().getSystemService(DevicePolicyManager.class).getString(
+        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
                 RESOLVER_WORK_PAUSED_TITLE,
                 () -> getContext().getString(R.string.resolver_turn_on_work_apps));
     }
 
     private String getCrossProfileBlockedTitle() {
-        return getContext().getSystemService(DevicePolicyManager.class).getString(
+        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
                 RESOLVER_CROSS_PROFILE_BLOCKED_TITLE,
                 () -> getContext().getString(R.string.resolver_cross_profile_blocked));
     }
 
     private String getCantAccessWorkMessage() {
-        return getContext().getSystemService(DevicePolicyManager.class).getString(
+        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
                 RESOLVER_CANT_ACCESS_WORK,
                 () -> getContext().getString(
                         R.string.resolver_cant_access_work_apps_explanation));
     }
 
     private String getCantAccessPersonalMessage() {
-        return getContext().getSystemService(DevicePolicyManager.class).getString(
+        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
                 RESOLVER_CANT_ACCESS_PERSONAL,
                 () -> getContext().getString(
                         R.string.resolver_cant_access_personal_apps_explanation));
     }
 
     private String getNoWorkAppsAvailableMessage() {
-        return getContext().getSystemService(DevicePolicyManager.class).getString(
+        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
                 RESOLVER_NO_WORK_APPS,
                 () -> getContext().getString(
                         R.string.resolver_no_work_apps_available));
     }
 
     private String getNoPersonalAppsAvailableMessage() {
-        return getContext().getSystemService(DevicePolicyManager.class).getString(
+        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
                 RESOLVER_NO_PERSONAL_APPS,
                 () -> getContext().getString(
                         R.string.resolver_no_personal_apps_available));
diff --git a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
index 46f47a3..c3e7920 100644
--- a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
+++ b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
@@ -53,6 +53,7 @@
     private static final int TYPE_HEADER_SUGGESTED = 0;
     private static final int TYPE_HEADER_ALL_OTHERS = 1;
     private static final int TYPE_LOCALE = 2;
+    private static final int TYPE_SYSTEM_LANGUAGE_FOR_APP_LANGUAGE_PICKER = 3;
     private static final int MIN_REGIONS_FOR_SUGGESTIONS = 6;
 
     private ArrayList<LocaleStore.LocaleInfo> mLocaleOptions;
@@ -64,10 +65,18 @@
     private Locale mDisplayLocale = null;
     // used to potentially cache a modified Context that uses mDisplayLocale
     private Context mContextOverride = null;
+    private String mAppPackageName;
 
     public SuggestedLocaleAdapter(Set<LocaleStore.LocaleInfo> localeOptions, boolean countryMode) {
+        this(localeOptions, countryMode, null);
+    }
+
+    public SuggestedLocaleAdapter(Set<LocaleStore.LocaleInfo> localeOptions, boolean countryMode,
+            String appPackageName) {
         mCountryMode = countryMode;
         mLocaleOptions = new ArrayList<>(localeOptions.size());
+        mAppPackageName = appPackageName;
+
         for (LocaleStore.LocaleInfo li : localeOptions) {
             if (li.isSuggested()) {
                 mSuggestionCount++;
@@ -83,7 +92,8 @@
 
     @Override
     public boolean isEnabled(int position) {
-        return getItemViewType(position) == TYPE_LOCALE;
+        return getItemViewType(position) == TYPE_LOCALE
+                || getItemViewType(position) == TYPE_SYSTEM_LANGUAGE_FOR_APP_LANGUAGE_PICKER;
     }
 
     @Override
@@ -97,13 +107,20 @@
             if (position == mSuggestionCount + 1) {
                 return TYPE_HEADER_ALL_OTHERS;
             }
+
+            LocaleStore.LocaleInfo item = (LocaleStore.LocaleInfo) getItem(position);
+            if (item.isSystemLocale()) {
+                return TYPE_SYSTEM_LANGUAGE_FOR_APP_LANGUAGE_PICKER;
+            }
             return TYPE_LOCALE;
         }
     }
 
     @Override
     public int getViewTypeCount() {
-        if (showHeaders()) {
+        if (!TextUtils.isEmpty(mAppPackageName) && showHeaders()) {
+            return 4; // Two headers and 1 for "System language"
+        } else if (showHeaders()) {
             return 3; // Two headers in addition to the locales
         } else {
             return 1; // Locales items only
@@ -187,6 +204,21 @@
                 textView.setTextLocale(
                         mDisplayLocale != null ? mDisplayLocale : Locale.getDefault());
                 break;
+
+            case TYPE_SYSTEM_LANGUAGE_FOR_APP_LANGUAGE_PICKER:
+                if (!(convertView instanceof ViewGroup)) {
+                    convertView = mInflater.inflate(
+                            R.layout.app_language_picker_system_default, parent, false);
+                }
+
+                Locale defaultLocale = Locale.getDefault();
+                TextView title = convertView.findViewById(R.id.locale);
+                title.setText(R.string.system_locale_title);
+                title.setTextLocale(defaultLocale);
+                TextView subtitle = convertView.findViewById(R.id.system_locale_subtitle);
+                subtitle.setText(defaultLocale.getDisplayName());
+                subtitle.setTextLocale(defaultLocale);
+                break;
             default:
                 // Covers both null, and "reusing" a wrong kind of view
                 if (!(convertView instanceof ViewGroup)) {
@@ -316,4 +348,8 @@
     public Filter getFilter() {
         return new FilterByNativeAndUiNames();
     }
+
+    public String getAppPackageName() {
+        return mAppPackageName;
+    }
 }
diff --git a/core/java/com/android/internal/app/UnlaunchableAppActivity.java b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
index 3531fad..957a636 100644
--- a/core/java/com/android/internal/app/UnlaunchableAppActivity.java
+++ b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
@@ -95,12 +95,12 @@
     }
 
     private String getDialogTitle() {
-        return getSystemService(DevicePolicyManager.class).getString(
+        return getSystemService(DevicePolicyManager.class).getResources().getString(
                 UNLAUNCHABLE_APP_WORK_PAUSED_TITLE, () -> getString(R.string.work_mode_off_title));
     }
 
     private String getDialogMessage() {
-        return getSystemService(DevicePolicyManager.class).getString(
+        return getSystemService(DevicePolicyManager.class).getResources().getString(
                 UNLAUNCHABLE_APP_WORK_PAUSED_MESSAGE,
                 () -> getString(R.string.work_mode_off_message));
     }
diff --git a/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java b/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java
index 45555bf..dbbe4b9 100644
--- a/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java
+++ b/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java
@@ -24,6 +24,7 @@
  *
  * @hide
  */
+// TODO(b/222698397): remove getSfInstance/this class usage and use vsyncId for transactions
 public final class SfVsyncFrameCallbackProvider implements AnimationFrameCallbackProvider {
 
     private final Choreographer mChoreographer;
diff --git a/core/java/com/android/internal/infra/ServiceConnector.java b/core/java/com/android/internal/infra/ServiceConnector.java
index 9e07f97..cb16267 100644
--- a/core/java/com/android/internal/infra/ServiceConnector.java
+++ b/core/java/com/android/internal/infra/ServiceConnector.java
@@ -31,6 +31,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.Log;
+import android.util.Slog;
 
 import java.io.PrintWriter;
 import java.util.ArrayDeque;
@@ -562,10 +563,21 @@
         void unbindJobThread() {
             cancelTimeout();
             I service = mService;
+            // TODO(b/224695239): This is actually checking wasConnected. Rename and/or fix
+            // implementation based on what this should actually be checking. At least the first
+            // check for calling unbind is the correct behavior, though.
             boolean wasBound = service != null;
+            if (wasBound || mBinding) {
+                try {
+                    mContext.unbindService(mServiceConnection);
+                } catch (IllegalArgumentException e) {  // TODO(b/224697137): Fix the race condition
+                                                        // that requires catching this (crashes if
+                                                        // service isn't currently bound).
+                    Slog.e(LOG_TAG, "Failed to unbind: " + e);
+                }
+            }
             if (wasBound) {
                 dispatchOnServiceConnectionStatusChanged(service, false);
-                mContext.unbindService(mServiceConnection);
                 service.asBinder().unlinkToDeath(this, 0);
                 mService = null;
             }
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
index b18c98b..2ee47b6 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
@@ -43,5 +43,5 @@
     void notifyUserActionAsync();
     void applyImeVisibilityAsync(IBinder showOrHideInputToken, boolean setVisible);
     void onStylusHandwritingReady(int requestId, int pid);
-    void finishStylusHandwriting(int requestId);
+    void resetStylusHandwriting(int requestId);
 }
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
index e8a2d81..15d7acf 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -416,13 +416,13 @@
      * @param requestId
      */
     @AnyThread
-    public void finishStylusHandwriting(int requestId) {
+    public void resetStylusHandwriting(int requestId) {
         final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
         if (ops == null) {
             return;
         }
         try {
-            ops.finishStylusHandwriting(requestId);
+            ops.resetStylusHandwriting(requestId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index 34c47ed..06bc4b5 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -33,6 +33,7 @@
 import android.graphics.HardwareRendererObserver;
 import android.os.Handler;
 import android.os.Trace;
+import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.Choreographer;
@@ -188,6 +189,7 @@
                             if (mBeginVsyncId != INVALID_ID) {
                                 mSurfaceControlWrapper.addJankStatsListener(
                                         FrameTracker.this, mSurfaceControl);
+                                markEvent("FT#deferMonitoring");
                                 postTraceStartMarker();
                             }
                         }
@@ -241,8 +243,9 @@
             }
             if (mSurfaceControl != null) {
                 if (mDeferMonitoring) {
+                    markEvent("FT#deferMonitoring");
                     // Normal case, we begin the instrument from the very beginning,
-                    // except the first frame.
+                    // will exclude the first frame.
                     postTraceStartMarker();
                 } else {
                     // If we don't begin the instrument from the very beginning,
@@ -272,6 +275,7 @@
                 return;
             }
             mTracingStarted = true;
+            markEvent("FT#begin");
             Trace.beginAsyncSection(mSession.getName(), (int) mBeginVsyncId);
         }
     }
@@ -295,6 +299,7 @@
                     Log.d(TAG, "end: " + mSession.getName()
                             + ", end=" + mEndVsyncId + ", reason=" + reason);
                 }
+                markEvent("FT#end#" + reason);
                 Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId);
                 mSession.setReason(reason);
 
@@ -322,6 +327,7 @@
                     reason == REASON_CANCEL_NOT_BEGUN || reason == REASON_CANCEL_SAME_VSYNC;
             if (mCancelled || (mEndVsyncId != INVALID_ID && !cancelFromEnd)) return false;
             mCancelled = true;
+            markEvent("FT#cancel#" + reason);
             // We don't need to end the trace section if it never begun.
             if (mTracingStarted) {
                 Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId);
@@ -343,6 +349,11 @@
         }
     }
 
+    private void markEvent(String desc) {
+        Trace.beginSection(TextUtils.formatSimple("%s#%s", mSession.getName(), desc));
+        Trace.endSection();
+    }
+
     private void notifyCujEvent(String action) {
         if (mListener == null) return;
         mListener.onCujEvents(mSession, action);
diff --git a/core/java/com/android/internal/logging/InstanceId.java b/core/java/com/android/internal/logging/InstanceId.java
deleted file mode 100644
index c90d8512..0000000
--- a/core/java/com/android/internal/logging/InstanceId.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.logging;
-
-import static java.lang.Math.max;
-import static java.lang.Math.min;
-
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * An opaque identifier used to disambiguate which logs refer to a particular instance of some
- * UI element. Useful when there might be multiple instances simultaneously active.
- * Obtain from InstanceIdSequence.  Clipped to range [0, INSTANCE_ID_MAX].
- */
-public final class InstanceId implements Parcelable {
-    // At most 20 bits: ~1m possibilities, ~0.5% probability of collision in 100 values
-    static final int INSTANCE_ID_MAX = 1 << 20;
-
-    private final int mId;
-    InstanceId(int id) {
-        mId = min(max(0, id), INSTANCE_ID_MAX);
-    }
-
-    private InstanceId(Parcel in) {
-        this(in.readInt());
-    }
-
-    @VisibleForTesting
-    public int getId() {
-        return mId;
-    }
-
-    /**
-     * Create a fake instance ID for testing purposes.  Not for production use. See also
-     * InstanceIdSequenceFake, which is a testing replacement for InstanceIdSequence.
-     * @param id The ID you want to assign.
-     * @return new InstanceId.
-     */
-    @VisibleForTesting
-    public static InstanceId fakeInstanceId(int id) {
-        return new InstanceId(id);
-    }
-
-    @Override
-    public int hashCode() {
-        return mId;
-    }
-
-    @Override
-    public boolean equals(@Nullable Object obj) {
-        if (!(obj instanceof InstanceId)) {
-            return false;
-        }
-        return mId == ((InstanceId) obj).mId;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeInt(mId);
-    }
-
-    public static final Parcelable.Creator<InstanceId> CREATOR =
-            new Parcelable.Creator<InstanceId>() {
-        @Override
-        public InstanceId createFromParcel(Parcel in) {
-            return new InstanceId(in);
-        }
-
-        @Override
-        public InstanceId[] newArray(int size) {
-            return new InstanceId[size];
-        }
-    };
-
-}
diff --git a/core/java/com/android/internal/logging/InstanceIdSequence.java b/core/java/com/android/internal/logging/InstanceIdSequence.java
deleted file mode 100644
index 3464310..0000000
--- a/core/java/com/android/internal/logging/InstanceIdSequence.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.logging;
-
-import static java.lang.Math.max;
-import static java.lang.Math.min;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.security.SecureRandom;
-import java.util.Random;
-
-/**
- * Generates random InstanceIds in range [1, instanceIdMax] for passing to
- * UiEventLogger.logWithInstanceId(). Holds a SecureRandom, which self-seeds on
- * first use; try to give it a long lifetime. Safe for concurrent use.
- */
-public class InstanceIdSequence {
-    protected final int mInstanceIdMax;
-    private final Random mRandom = new SecureRandom();
-
-    /**
-     * Constructs a sequence with identifiers [1, instanceIdMax].  Capped at INSTANCE_ID_MAX.
-     * @param instanceIdMax Limiting value of identifiers. Normally positive: otherwise you get
-     *                      an all-1 sequence.
-     */
-    public InstanceIdSequence(int instanceIdMax) {
-        mInstanceIdMax = min(max(1, instanceIdMax), InstanceId.INSTANCE_ID_MAX);
-    }
-
-    /**
-     * Gets the next instance from the sequence.  Safe for concurrent use.
-     * @return new InstanceId
-     */
-    public InstanceId newInstanceId() {
-        return newInstanceIdInternal(1 + mRandom.nextInt(mInstanceIdMax));
-    }
-
-    /**
-     * Factory function for instance IDs, used for testing.
-     * @param id
-     * @return new InstanceId(id)
-     */
-    @VisibleForTesting
-    protected InstanceId newInstanceIdInternal(int id) {
-        return new InstanceId(id);
-    }
-}
diff --git a/core/java/com/android/internal/logging/UiEvent.java b/core/java/com/android/internal/logging/UiEvent.java
deleted file mode 100644
index 0407b07..0000000
--- a/core/java/com/android/internal/logging/UiEvent.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.logging;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-@Retention(SOURCE)
-@Target(FIELD)
-public @interface UiEvent {
-    /** An explanation, suitable for Android analysts, of the UI event that this log represents. */
-    String doc();
-}
diff --git a/core/java/com/android/internal/logging/UiEventLogger.java b/core/java/com/android/internal/logging/UiEventLogger.java
deleted file mode 100644
index 5378b03..0000000
--- a/core/java/com/android/internal/logging/UiEventLogger.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.logging;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-
-/**
- * Logging interface for UI events. Normal implementation is UiEventLoggerImpl.
- * For testing, use fake implementation UiEventLoggerFake.
- *
- * See go/sysui-event-logs and UiEventReported atom in atoms.proto.
- */
-public interface UiEventLogger {
-    /** Put your Event IDs in enums that implement this interface, and document them using the
-     * UiEventEnum annotation.
-     * Event IDs must be globally unique. This will be enforced by tooling (forthcoming).
-     * OEMs should use event IDs above 100000 and below 1000000 (1 million).
-     */
-    interface UiEventEnum {
-
-        /**
-         * Tag used to request new UI Event IDs via presubmit analysis.
-         *
-         * <p>Use RESERVE_NEW_UI_EVENT_ID as the constructor parameter for a new {@link EventEnum}
-         * to signal the presubmit analyzer to reserve a new ID for the event. The new ID will be
-         * returned as a Gerrit presubmit finding.  Do not submit {@code RESERVE_NEW_UI_EVENT_ID} as
-         * the constructor parameter for any event.
-         *
-         * <pre>
-         * &#064;UiEvent(doc = "Briefly describe the interaction when this event will be logged")
-         * UNIQUE_EVENT_NAME(RESERVE_NEW_UI_EVENT_ID);
-         * </pre>
-         */
-        int RESERVE_NEW_UI_EVENT_ID = Integer.MIN_VALUE; // Negative IDs are ignored by the logger.
-
-        int getId();
-    }
-
-    /**
-     * Log a simple event, with no package information. Does nothing if event.getId() <= 0.
-     * @param event an enum implementing UiEventEnum interface.
-     */
-    void log(@NonNull UiEventEnum event);
-
-    /**
-     * Log a simple event with an instance id, without package information.
-     * Does nothing if event.getId() <= 0.
-     * @param event an enum implementing UiEventEnum interface.
-     * @param instance An identifier obtained from an InstanceIdSequence. If null, reduces to log().
-     */
-    void log(@NonNull UiEventEnum event, @Nullable InstanceId instance);
-
-    /**
-     * Log an event with package information. Does nothing if event.getId() <= 0.
-     * Give both uid and packageName if both are known, but one may be omitted if unknown.
-     * @param event an enum implementing UiEventEnum interface.
-     * @param uid the uid of the relevant app, if known (0 otherwise).
-     * @param packageName the package name of the relevant app, if known (null otherwise).
-     */
-    void log(@NonNull UiEventEnum event, int uid, @Nullable String packageName);
-
-    /**
-     * Log an event with package information and an instance ID.
-     * Does nothing if event.getId() <= 0.
-     * @param event an enum implementing UiEventEnum interface.
-     * @param uid the uid of the relevant app, if known (0 otherwise).
-     * @param packageName the package name of the relevant app, if known (null otherwise).
-     * @param instance An identifier obtained from an InstanceIdSequence. If null, reduces to log().
-     */
-    void logWithInstanceId(@NonNull UiEventEnum event, int uid, @Nullable String packageName,
-            @Nullable InstanceId instance);
-
-    /**
-     * Log an event with ranked-choice information along with package.
-     * Does nothing if event.getId() <= 0.
-     * @param event an enum implementing UiEventEnum interface.
-     * @param uid the uid of the relevant app, if known (0 otherwise).
-     * @param packageName the package name of the relevant app, if known (null otherwise).
-     * @param position the position picked.
-     */
-    void logWithPosition(@NonNull UiEventEnum event, int uid, @Nullable String packageName,
-            int position);
-
-    /**
-     * Log an event with ranked-choice information along with package and instance ID.
-     * Does nothing if event.getId() <= 0.
-     * @param event an enum implementing UiEventEnum interface.
-     * @param uid the uid of the relevant app, if known (0 otherwise).
-     * @param packageName the package name of the relevant app, if known (null otherwise).
-     * @param instance An identifier obtained from an InstanceIdSequence. If null, reduces to
-     *                 logWithPosition().
-     * @param position the position picked.
-     */
-    void logWithInstanceIdAndPosition(@NonNull UiEventEnum event, int uid,
-            @Nullable String packageName, @Nullable InstanceId instance, int position);
-}
diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java
index b79c0be..a93c487 100644
--- a/core/java/com/android/internal/notification/SystemNotificationChannels.java
+++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java
@@ -221,7 +221,7 @@
 
     private static String getDeviceAdminNotificationChannelName(Context context) {
         DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
-        return dpm.getString(NOTIFICATION_CHANNEL_DEVICE_ADMIN,
+        return dpm.getResources().getString(NOTIFICATION_CHANNEL_DEVICE_ADMIN,
                 () -> context.getString(R.string.notification_channel_device_admin));
     }
 
diff --git a/core/java/com/android/internal/os/AudioPowerCalculator.java b/core/java/com/android/internal/os/AudioPowerCalculator.java
index f9310b0..ebf0ca2 100644
--- a/core/java/com/android/internal/os/AudioPowerCalculator.java
+++ b/core/java/com/android/internal/os/AudioPowerCalculator.java
@@ -78,7 +78,9 @@
         final double powerMah = mPowerEstimator.calculatePower(durationMs);
         app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO, durationMs)
                 .setConsumedPower(BatteryConsumer.POWER_COMPONENT_AUDIO, powerMah);
-        total.durationMs += durationMs;
-        total.powerMah += powerMah;
+        if (!app.isVirtualUid()) {
+            total.durationMs += durationMs;
+            total.powerMah += powerMah;
+        }
     }
 }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 70b9639..4b20347 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -69,6 +69,7 @@
 import android.os.connectivity.WifiActivityEnergyInfo;
 import android.os.connectivity.WifiBatteryStats;
 import android.provider.Settings;
+import android.telephony.AccessNetworkConstants;
 import android.telephony.Annotation.NetworkType;
 import android.telephony.CellSignalStrength;
 import android.telephony.CellSignalStrengthLte;
@@ -166,7 +167,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    static final int VERSION = 206;
+    static final int VERSION = 207;
 
     // The maximum number of names wakelocks we will keep track of
     // per uid; once the limit is reached, we batch the remaining wakelocks
@@ -546,9 +547,9 @@
                 final LongArrayMultiStateCounter onBatteryScreenOffCounter =
                         u.getProcStateScreenOffTimeCounter().getCounter();
 
-                if (uid == parentUid) {
-                    mKernelSingleUidTimeReader.addDelta(uid, onBatteryCounter, timestampMs);
-                    mKernelSingleUidTimeReader.addDelta(uid, onBatteryScreenOffCounter,
+                if (uid == parentUid || Process.isSdkSandboxUid(uid)) {
+                    mKernelSingleUidTimeReader.addDelta(parentUid, onBatteryCounter, timestampMs);
+                    mKernelSingleUidTimeReader.addDelta(parentUid, onBatteryScreenOffCounter,
                             timestampMs);
                 } else {
                     Uid.ChildUid childUid = u.getChildUid(uid);
@@ -964,6 +965,16 @@
          * Timers for each combination of frequency range and signal strength.
          */
         public final StopwatchTimer[][] perStateTimers;
+        /**
+         * Counters tracking the time (in milliseconds) spent transmitting data in a given state.
+         */
+        @Nullable
+        private LongSamplingCounter[][] mPerStateTxDurationMs = null;
+        /**
+         * Counters tracking the time (in milliseconds) spent receiving data in at given frequency.
+         */
+        @Nullable
+        private LongSamplingCounter[] mPerFrequencyRxDurationMs = null;
 
         RadioAccessTechnologyBatteryStats(int freqCount, Clock clock, TimeBase timeBase) {
             perStateTimers =
@@ -1024,15 +1035,198 @@
         }
 
         /**
-         * Reset display timers.
+         * Returns the duration in milliseconds spent in a given state since the last mark.
+         */
+        public long getTimeSinceMark(@ServiceState.FrequencyRange int frequencyRange,
+                int signalStrength, long elapsedRealtimeMs) {
+            return perStateTimers[frequencyRange][signalStrength].getTimeSinceMarkLocked(
+                    elapsedRealtimeMs * 1000) / 1000;
+        }
+
+        /**
+         * Set mark for all timers.
+         */
+        public void setMark(long elapsedRealtimeMs) {
+            final int size = perStateTimers.length;
+            for (int i = 0; i < size; i++) {
+                for (int j = 0; j < CellSignalStrength.NUM_SIGNAL_STRENGTH_BINS; j++) {
+                    perStateTimers[i][j].setMark(elapsedRealtimeMs);
+                }
+            }
+        }
+
+        /**
+         * Returns numbers of frequencies tracked for this RAT.
+         */
+        public int getFrequencyRangeCount() {
+            return perStateTimers.length;
+        }
+
+        /**
+         * Add TX time for a given state.
+         */
+        public void incrementTxDuration(@ServiceState.FrequencyRange int frequencyRange,
+                int signalStrength, long durationMs) {
+            getTxDurationCounter(frequencyRange, signalStrength, true).addCountLocked(durationMs);
+        }
+
+        /**
+         * Add TX time for a given frequency.
+         */
+        public void incrementRxDuration(@ServiceState.FrequencyRange int frequencyRange,
+                long durationMs) {
+            getRxDurationCounter(frequencyRange, true).addCountLocked(durationMs);
+        }
+
+        /**
+         * Reset radio access technology timers and counts.
          */
         public void reset(long elapsedRealtimeUs) {
             final int size = perStateTimers.length;
             for (int i = 0; i < size; i++) {
                 for (int j = 0; j < CellSignalStrength.NUM_SIGNAL_STRENGTH_BINS; j++) {
                     perStateTimers[i][j].reset(false, elapsedRealtimeUs);
+                    if (mPerStateTxDurationMs == null) continue;
+                    mPerStateTxDurationMs[i][j].reset(false, elapsedRealtimeUs);
+                }
+                if (mPerFrequencyRxDurationMs == null) continue;
+                mPerFrequencyRxDurationMs[i].reset(false, elapsedRealtimeUs);
+            }
+        }
+
+        /**
+         * Write data to summary parcel
+         */
+        public void writeSummaryToParcel(Parcel out, long elapsedRealtimeUs) {
+            final int freqCount = perStateTimers.length;
+            out.writeInt(freqCount);
+            out.writeInt(CellSignalStrength.NUM_SIGNAL_STRENGTH_BINS);
+            for (int i = 0; i < freqCount; i++) {
+                for (int j = 0; j < CellSignalStrength.NUM_SIGNAL_STRENGTH_BINS; j++) {
+                    perStateTimers[i][j].writeSummaryFromParcelLocked(out, elapsedRealtimeUs);
                 }
             }
+
+            if (mPerStateTxDurationMs == null) {
+                out.writeInt(0);
+            } else {
+                out.writeInt(1);
+                for (int i = 0; i < freqCount; i++) {
+                    for (int j = 0; j < CellSignalStrength.NUM_SIGNAL_STRENGTH_BINS; j++) {
+                        mPerStateTxDurationMs[i][j].writeSummaryFromParcelLocked(out);
+                    }
+                }
+            }
+
+            if (mPerFrequencyRxDurationMs == null) {
+                out.writeInt(0);
+            } else {
+                out.writeInt(1);
+                for (int i = 0; i < freqCount; i++) {
+                    mPerFrequencyRxDurationMs[i].writeSummaryFromParcelLocked(out);
+                }
+            }
+        }
+
+        /**
+         * Read data from summary parcel
+         */
+        public void readSummaryFromParcel(Parcel in) {
+            final int oldFreqCount = in.readInt();
+            final int oldSignalStrengthCount = in.readInt();
+            final int currFreqCount = perStateTimers.length;
+            final int currSignalStrengthCount = CellSignalStrength.NUM_SIGNAL_STRENGTH_BINS;
+
+            for (int freq = 0; freq < oldFreqCount; freq++) {
+                for (int strength = 0; strength < oldSignalStrengthCount; strength++) {
+                    if (freq >= currFreqCount || strength >= currSignalStrengthCount) {
+                        // Mismatch with the summary parcel. Consume the data but don't use it.
+                        final StopwatchTimer temp = new StopwatchTimer(null, null, -1, null,
+                                new TimeBase());
+                        // Consume perStateTimers data.
+                        temp.readSummaryFromParcelLocked(in);
+                    } else {
+                        perStateTimers[freq][strength].readSummaryFromParcelLocked(in);
+                    }
+                }
+            }
+
+            if (in.readInt() == 1) {
+                for (int freq = 0; freq < oldFreqCount; freq++) {
+                    for (int strength = 0; strength < oldSignalStrengthCount; strength++) {
+                        if (freq >= currFreqCount || strength >= currSignalStrengthCount) {
+                            // Mismatch with the summary parcel. Consume the data but don't use it.
+                            final StopwatchTimer temp = new StopwatchTimer(null, null, -1, null,
+                                    new TimeBase());
+                            // Consume mPerStateTxDurationMs data.
+                            temp.readSummaryFromParcelLocked(in);
+                        }
+                        getTxDurationCounter(freq, strength, true).readSummaryFromParcelLocked(in);
+                    }
+                }
+            }
+
+            if (in.readInt() == 1) {
+                for (int freq = 0; freq < oldFreqCount; freq++) {
+                    if (freq >= currFreqCount) {
+                        // Mismatch with the summary parcel. Consume the data but don't use it.
+                        final StopwatchTimer
+                                temp = new StopwatchTimer(null, null, -1, null, new TimeBase());
+                        // Consume mPerFrequencyRxDurationMs data.
+                        temp.readSummaryFromParcelLocked(in);
+                        continue;
+                    }
+                    getRxDurationCounter(freq, true).readSummaryFromParcelLocked(in);
+                }
+            }
+        }
+
+        private LongSamplingCounter getTxDurationCounter(
+                @ServiceState.FrequencyRange int frequencyRange, int signalStrength, boolean make) {
+            if (mPerStateTxDurationMs == null) {
+                if (!make) return null;
+
+                final int freqCount = getFrequencyRangeCount();
+                final int signalStrengthCount = perStateTimers[0].length;
+                final TimeBase timeBase = perStateTimers[0][0].mTimeBase;
+                mPerStateTxDurationMs = new LongSamplingCounter[freqCount][signalStrengthCount];
+                for (int freq = 0; freq < freqCount; freq++) {
+                    for (int strength = 0; strength < signalStrengthCount; strength++) {
+                        mPerStateTxDurationMs[freq][strength] = new LongSamplingCounter(timeBase);
+                    }
+                }
+            }
+            if (frequencyRange < 0 || frequencyRange >= getFrequencyRangeCount()) {
+                Slog.w(TAG, "Unexpected frequency range (" + frequencyRange
+                        + ") requested in getTxDurationCounter");
+                return null;
+            }
+            if (signalStrength < 0 || signalStrength >= perStateTimers[0].length) {
+                Slog.w(TAG, "Unexpected signal strength (" + signalStrength
+                        + ") requested in getTxDurationCounter");
+                return null;
+            }
+            return mPerStateTxDurationMs[frequencyRange][signalStrength];
+        }
+
+        private LongSamplingCounter getRxDurationCounter(
+                @ServiceState.FrequencyRange int frequencyRange, boolean make) {
+            if (mPerFrequencyRxDurationMs == null) {
+                if (!make) return null;
+
+                final int freqCount = getFrequencyRangeCount();
+                final TimeBase timeBase = perStateTimers[0][0].mTimeBase;
+                mPerFrequencyRxDurationMs = new LongSamplingCounter[freqCount];
+                for (int freq = 0; freq < freqCount; freq++) {
+                    mPerFrequencyRxDurationMs[freq] = new LongSamplingCounter(timeBase);
+                }
+            }
+            if (frequencyRange < 0 || frequencyRange >= getFrequencyRangeCount()) {
+                Slog.w(TAG, "Unexpected frequency range (" + frequencyRange
+                        + ") requested in getRxDurationCounter");
+                return null;
+            }
+            return mPerFrequencyRxDurationMs[frequencyRange];
         }
     }
 
@@ -1929,18 +2123,26 @@
         private final TimeBase mTimeBase;
         private final LongMultiStateCounter mCounter;
 
-        private TimeMultiStateCounter(TimeBase timeBase, Parcel in, long timestampMs) {
+        private TimeMultiStateCounter(TimeBase timeBase, int stateCount, long timestampMs) {
+            this(timeBase, new LongMultiStateCounter(stateCount), timestampMs);
+        }
+
+        private TimeMultiStateCounter(TimeBase timeBase, LongMultiStateCounter counter,
+                long timestampMs) {
             mTimeBase = timeBase;
-            mCounter = LongMultiStateCounter.CREATOR.createFromParcel(in);
+            mCounter = counter;
             mCounter.setEnabled(mTimeBase.isRunning(), timestampMs);
             timeBase.add(this);
         }
 
-        private TimeMultiStateCounter(TimeBase timeBase, int stateCount, long timestampMs) {
-            mTimeBase = timeBase;
-            mCounter = new LongMultiStateCounter(stateCount);
-            mCounter.setEnabled(mTimeBase.isRunning(), timestampMs);
-            timeBase.add(this);
+        @Nullable
+        private static TimeMultiStateCounter readFromParcel(Parcel in, TimeBase timeBase,
+                int stateCount, long timestampMs) {
+            LongMultiStateCounter counter = LongMultiStateCounter.CREATOR.createFromParcel(in);
+            if (counter.getStateCount() != stateCount) {
+                return null;
+            }
+            return new TimeMultiStateCounter(timeBase, counter, timestampMs);
         }
 
         private void writeToParcel(Parcel out) {
@@ -3510,11 +3712,8 @@
 
         private TimeMultiStateCounter readTimeMultiStateCounter(Parcel in, TimeBase timeBase) {
             if (in.readBoolean()) {
-                final TimeMultiStateCounter counter =
-                        new TimeMultiStateCounter(timeBase, in, mClock.elapsedRealtime());
-                if (counter.getStateCount() == BatteryConsumer.PROCESS_STATE_COUNT) {
-                    return counter;
-                }
+                return TimeMultiStateCounter.readFromParcel(in, timeBase,
+                        BatteryConsumer.PROCESS_STATE_COUNT, mClock.elapsedRealtime());
             }
             return null;
         }
@@ -3537,9 +3736,10 @@
                 // invalid.
                 TimeMultiStateCounter[] counters = new TimeMultiStateCounter[numCounters];
                 for (int i = 0; i < numCounters; i++) {
-                    final TimeMultiStateCounter counter =
-                            new TimeMultiStateCounter(timeBase, in, mClock.elapsedRealtime());
-                    if (counter.getStateCount() == BatteryConsumer.PROCESS_STATE_COUNT) {
+                    final TimeMultiStateCounter counter = TimeMultiStateCounter.readFromParcel(in,
+                            timeBase, BatteryConsumer.PROCESS_STATE_COUNT,
+                            mClock.elapsedRealtime());
+                    if (counter != null) {
                         counters[i] = counter;
                     } else {
                         valid = false;
@@ -4560,9 +4760,15 @@
         mIsolatedUidRefCounts.put(uid, refCount + 1);
     }
 
-    public int mapUid(int uid) {
-        int isolated = mIsolatedUids.get(uid, -1);
-        return isolated > 0 ? isolated : uid;
+    private int mapUid(int uid) {
+        if (Process.isSdkSandboxUid(uid)) {
+            return Process.getAppUidForSdkSandboxUid(uid);
+        }
+        return mapIsolatedUid(uid);
+    }
+
+    private int mapIsolatedUid(int uid) {
+        return mIsolatedUids.get(/*key=*/uid, /*valueIfKeyNotFound=*/uid);
     }
 
     @GuardedBy("this")
@@ -4656,16 +4862,18 @@
             long elapsedRealtimeMs, long uptimeMs) {
         int parentUid = mapUid(uid);
         if (uid != parentUid) {
-            // Isolated UIDs process state is already rolled up into parent, so no need to track
-            // Otherwise the parent's process state will get downgraded incorrectly
-            return;
+            if (Process.isIsolated(uid)) {
+                // Isolated UIDs process state is already rolled up into parent, so no need to track
+                // Otherwise the parent's process state will get downgraded incorrectly
+                return;
+            }
         }
         // TODO(b/155216561): It is possible for isolated uids to be in a higher
         // state than its parent uid. We should track the highest state within the union of host
         // and isolated uids rather than only the parent uid.
         FrameworkStatsLog.write(FrameworkStatsLog.UID_PROCESS_STATE_CHANGED, uid,
                 ActivityManager.processStateAmToProto(state));
-        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+        getUidStatsLocked(parentUid, elapsedRealtimeMs, uptimeMs)
                 .updateUidProcessStateLocked(state, elapsedRealtimeMs, uptimeMs);
     }
 
@@ -5011,7 +5219,7 @@
                         FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
             } else {
                 FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED,
-                        mappedUid, null, getPowerManagerWakeLockLevel(type), name,
+                        mapIsolatedUid(uid), null, getPowerManagerWakeLockLevel(type), name,
                         FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
             }
         }
@@ -5065,7 +5273,7 @@
                         FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
             } else {
                 FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED,
-                        mappedUid, null, getPowerManagerWakeLockLevel(type), name,
+                        mapIsolatedUid(uid), null, getPowerManagerWakeLockLevel(type), name,
                         FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
             }
 
@@ -5225,7 +5433,6 @@
     @GuardedBy("this")
     public void noteLongPartialWakelockStart(String name, String historyName, int uid,
             long elapsedRealtimeMs, long uptimeMs) {
-        uid = mapUid(uid);
         noteLongPartialWakeLockStartInternal(name, historyName, uid, elapsedRealtimeMs, uptimeMs);
     }
 
@@ -5260,15 +5467,21 @@
     @GuardedBy("this")
     private void noteLongPartialWakeLockStartInternal(String name, String historyName, int uid,
             long elapsedRealtimeMs, long uptimeMs) {
+        final int mappedUid = mapUid(uid);
         if (historyName == null) {
             historyName = name;
         }
-        if (!mActiveEvents.updateState(HistoryItem.EVENT_LONG_WAKE_LOCK_START, historyName, uid,
-                0)) {
+        if (!mActiveEvents.updateState(HistoryItem.EVENT_LONG_WAKE_LOCK_START, historyName,
+                mappedUid, 0)) {
             return;
         }
         addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_LONG_WAKE_LOCK_START,
-                historyName, uid);
+                historyName, mappedUid);
+        if (mappedUid != uid) {
+            // Prevent the isolated uid mapping from being removed while the wakelock is
+            // being held.
+            incrementIsolatedUidRefCount(uid);
+        }
     }
 
     @GuardedBy("this")
@@ -5280,7 +5493,6 @@
     @GuardedBy("this")
     public void noteLongPartialWakelockFinish(String name, String historyName, int uid,
             long elapsedRealtimeMs, long uptimeMs) {
-        uid = mapUid(uid);
         noteLongPartialWakeLockFinishInternal(name, historyName, uid, elapsedRealtimeMs, uptimeMs);
     }
 
@@ -5315,15 +5527,20 @@
     @GuardedBy("this")
     private void noteLongPartialWakeLockFinishInternal(String name, String historyName, int uid,
             long elapsedRealtimeMs, long uptimeMs) {
+        final int mappedUid = mapUid(uid);
         if (historyName == null) {
             historyName = name;
         }
-        if (!mActiveEvents.updateState(HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH, historyName, uid,
-                0)) {
+        if (!mActiveEvents.updateState(HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH, historyName,
+                mappedUid, 0)) {
             return;
         }
         addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH,
-                historyName, uid);
+                historyName, mappedUid);
+        if (mappedUid != uid) {
+            // Decrement the ref count for the isolated uid and delete the mapping if uneeded.
+            maybeRemoveIsolatedUidLocked(uid, elapsedRealtimeMs, uptimeMs);
+        }
     }
 
     @GuardedBy("this")
@@ -5489,7 +5706,10 @@
     @GuardedBy("this")
     private void noteStartGpsLocked(int uid, WorkChain workChain,
             long elapsedRealtimeMs, long uptimeMs) {
-        uid = getAttributionUid(uid, workChain);
+        if (workChain != null) {
+            uid = workChain.getAttributionUid();
+        }
+        final int mappedUid = mapUid(uid);
         if (mGpsNesting == 0) {
             mHistoryCur.states |= HistoryItem.STATE_GPS_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Start GPS to: "
@@ -5499,21 +5719,24 @@
         mGpsNesting++;
 
         if (workChain == null) {
-            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED, uid, null,
-                    FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__ON);
+            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED,
+                    mapIsolatedUid(uid), null, FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__ON);
         } else {
             FrameworkStatsLog.write(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED,
                     workChain.getUids(), workChain.getTags(),
                     FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__ON);
         }
 
-        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs).noteStartGps(elapsedRealtimeMs);
+        getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs).noteStartGps(elapsedRealtimeMs);
     }
 
     @GuardedBy("this")
     private void noteStopGpsLocked(int uid, WorkChain workChain,
             long elapsedRealtimeMs, long uptimeMs) {
-        uid = getAttributionUid(uid, workChain);
+        if (workChain != null) {
+            uid = workChain.getAttributionUid();
+        }
+        final int mappedUid = mapUid(uid);
         mGpsNesting--;
         if (mGpsNesting == 0) {
             mHistoryCur.states &= ~HistoryItem.STATE_GPS_ON_FLAG;
@@ -5525,14 +5748,15 @@
         }
 
         if (workChain == null) {
-            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED, uid, null,
+            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED,
+                    mapIsolatedUid(uid), null,
                     FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF);
         } else {
             FrameworkStatsLog.write(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED, workChain.getUids(),
                     workChain.getTags(), FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF);
         }
 
-        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs).noteStopGps(elapsedRealtimeMs);
+        getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs).noteStopGps(elapsedRealtimeMs);
     }
 
     @GuardedBy("this")
@@ -6607,6 +6831,27 @@
         }
     }
 
+    @RadioAccessTechnology
+    private static int mapRadioAccessNetworkTypeToRadioAccessTechnology(
+            @AccessNetworkConstants.RadioAccessNetworkType int dataType) {
+        switch (dataType) {
+            case AccessNetworkConstants.AccessNetworkType.NGRAN:
+                return RADIO_ACCESS_TECHNOLOGY_NR;
+            case AccessNetworkConstants.AccessNetworkType.EUTRAN:
+                return RADIO_ACCESS_TECHNOLOGY_LTE;
+            case AccessNetworkConstants.AccessNetworkType.UNKNOWN: //fallthrough
+            case AccessNetworkConstants.AccessNetworkType.GERAN: //fallthrough
+            case AccessNetworkConstants.AccessNetworkType.UTRAN: //fallthrough
+            case AccessNetworkConstants.AccessNetworkType.CDMA2000: //fallthrough
+            case AccessNetworkConstants.AccessNetworkType.IWLAN:
+                return RADIO_ACCESS_TECHNOLOGY_OTHER;
+            default:
+                Slog.w(TAG,
+                        "Unhandled RadioAccessNetworkType (" + dataType + "), mapping to OTHER");
+                return RADIO_ACCESS_TECHNOLOGY_OTHER;
+        }
+    }
+
     @GuardedBy("this")
     public void noteWifiOnLocked() {
         noteWifiOnLocked(mClock.elapsedRealtime(), mClock.uptimeMillis());
@@ -6950,7 +7195,10 @@
     @GuardedBy("this")
     private void noteBluetoothScanStartedLocked(WorkChain workChain, int uid,
             boolean isUnoptimized, long elapsedRealtimeMs, long uptimeMs) {
-        uid = getAttributionUid(uid, workChain);
+        if (workChain != null) {
+            uid = workChain.getAttributionUid();
+        }
+        uid = mapUid(uid);
         if (mBluetoothScanNesting == 0) {
             mHistoryCur.states2 |= HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "BLE scan started for: "
@@ -6990,7 +7238,10 @@
     @GuardedBy("this")
     private void noteBluetoothScanStoppedLocked(WorkChain workChain, int uid,
             boolean isUnoptimized, long elapsedRealtimeMs, long uptimeMs) {
-        uid = getAttributionUid(uid, workChain);
+        if (workChain != null) {
+            uid = workChain.getAttributionUid();
+        }
+        uid = mapUid(uid);
         mBluetoothScanNesting--;
         if (mBluetoothScanNesting == 0) {
             mHistoryCur.states2 &= ~HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG;
@@ -7003,14 +7254,6 @@
                 .noteBluetoothScanStoppedLocked(elapsedRealtimeMs, isUnoptimized);
     }
 
-    private int getAttributionUid(int uid, WorkChain workChain) {
-        if (workChain != null) {
-            return mapUid(workChain.getAttributionUid());
-        }
-
-        return mapUid(uid);
-    }
-
     @GuardedBy("this")
     public void noteBluetoothScanStoppedFromSourceLocked(WorkSource ws, boolean isUnoptimized) {
         noteBluetoothScanStoppedFromSourceLocked(ws, isUnoptimized,
@@ -7995,6 +8238,32 @@
                 elapsedRealtimeMs * 1000, STATS_SINCE_CHARGED) / 1000;
     }
 
+    @Override
+    public long getActiveTxRadioDurationMs(@RadioAccessTechnology int rat,
+            @ServiceState.FrequencyRange int frequencyRange, int signalStrength,
+            long elapsedRealtimeMs) {
+        final RadioAccessTechnologyBatteryStats stats = mPerRatBatteryStats[rat];
+        if (stats == null) return DURATION_UNAVAILABLE;
+
+        final LongSamplingCounter counter = stats.getTxDurationCounter(frequencyRange,
+                signalStrength, false);
+        if (counter == null) return DURATION_UNAVAILABLE;
+
+        return counter.getCountLocked(STATS_SINCE_CHARGED);
+    }
+
+    @Override
+    public long getActiveRxRadioDurationMs(@RadioAccessTechnology int rat,
+            @ServiceState.FrequencyRange int frequencyRange, long elapsedRealtimeMs) {
+        final RadioAccessTechnologyBatteryStats stats = mPerRatBatteryStats[rat];
+        if (stats == null) return DURATION_UNAVAILABLE;
+
+        final LongSamplingCounter counter = stats.getRxDurationCounter(frequencyRange, false);
+        if (counter == null) return DURATION_UNAVAILABLE;
+
+        return counter.getCountLocked(STATS_SINCE_CHARGED);
+    }
+
     @UnsupportedAppUsage
     @Override public long getMobileRadioActiveTime(long elapsedRealtimeUs, int which) {
         return mMobileRadioActiveTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
@@ -10739,11 +11008,9 @@
                             = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
                 }
                 if (in.readBoolean()) {
-                    final TimeMultiStateCounter counter =
-                            new TimeMultiStateCounter(mBsi.mOnBatteryTimeBase, in, timestampMs);
-                    if (counter.getStateCount() == BatteryConsumer.PROCESS_STATE_COUNT) {
-                        mMobileRadioActiveTime = counter;
-                    }
+                    mMobileRadioActiveTime = TimeMultiStateCounter.readFromParcel(in,
+                            mBsi.mOnBatteryTimeBase, BatteryConsumer.PROCESS_STATE_COUNT,
+                            timestampMs);
                 }
 
                 mMobileRadioActiveCount = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
@@ -10789,11 +11056,9 @@
 
             int stateCount = in.readInt();
             if (stateCount != 0) {
-                final TimeMultiStateCounter counter = new TimeMultiStateCounter(
-                        mBsi.mOnBatteryTimeBase, in, timestampMs);
-                if (stateCount == BatteryConsumer.PROCESS_STATE_COUNT) {
-                    mCpuActiveTimeMs = counter;
-                }
+                mCpuActiveTimeMs = TimeMultiStateCounter.readFromParcel(in,
+                        mBsi.mOnBatteryTimeBase, BatteryConsumer.PROCESS_STATE_COUNT,
+                        timestampMs);
             }
             mCpuClusterTimesMs = new LongSamplingCounterArray(mBsi.mOnBatteryTimeBase, in);
 
@@ -13477,6 +13742,8 @@
                     addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
                     mTmpRailStats.resetCellularTotalEnergyUsed();
                 }
+
+                incrementPerRatDataLocked(deltaInfo, elapsedRealtimeMs);
             }
             long totalAppRadioTimeUs = mMobileRadioActivePerAppTimer.getTimeSinceMarkLocked(
                     elapsedRealtimeMs * 1000);
@@ -13627,6 +13894,100 @@
         }
     }
 
+    @GuardedBy("this")
+    private void incrementPerRatDataLocked(ModemActivityInfo deltaInfo, long elapsedRealtimeMs) {
+        final int infoSize = deltaInfo.getSpecificInfoLength();
+        if (infoSize == 1 && deltaInfo.getSpecificInfoRat(0)
+                == AccessNetworkConstants.AccessNetworkType.UNKNOWN
+                && deltaInfo.getSpecificInfoFrequencyRange(0)
+                == ServiceState.FREQUENCY_RANGE_UNKNOWN) {
+            // Specific info data unavailable. Proportionally smear Rx and Tx times across each RAT.
+            final int levelCount = CellSignalStrength.getNumSignalStrengthLevels();
+            long[] perSignalStrengthActiveTimeMs = new long[levelCount];
+            long totalActiveTimeMs = 0;
+
+            for (int rat = 0; rat < RADIO_ACCESS_TECHNOLOGY_COUNT; rat++) {
+                final RadioAccessTechnologyBatteryStats ratStats = mPerRatBatteryStats[rat];
+                if (ratStats == null) continue;
+
+                final int freqCount = ratStats.getFrequencyRangeCount();
+                for (int freq = 0; freq < freqCount; freq++) {
+                    for (int level = 0; level < levelCount; level++) {
+                        final long durationMs = ratStats.getTimeSinceMark(freq, level,
+                                elapsedRealtimeMs);
+                        perSignalStrengthActiveTimeMs[level] += durationMs;
+                        totalActiveTimeMs += durationMs;
+                    }
+                }
+            }
+            if (totalActiveTimeMs != 0) {
+                // Smear the provided Tx/Rx durations across each RAT, frequency, and signal
+                // strength.
+                for (int rat = 0; rat < RADIO_ACCESS_TECHNOLOGY_COUNT; rat++) {
+                    final RadioAccessTechnologyBatteryStats ratStats = mPerRatBatteryStats[rat];
+                    if (ratStats == null) continue;
+
+                    final int freqCount = ratStats.getFrequencyRangeCount();
+                    for (int freq = 0; freq < freqCount; freq++) {
+                        long frequencyDurationMs = 0;
+                        for (int level = 0; level < levelCount; level++) {
+                            final long durationMs = ratStats.getTimeSinceMark(freq, level,
+                                    elapsedRealtimeMs);
+                            final long totalLvlDurationMs =
+                                    perSignalStrengthActiveTimeMs[level];
+                            if (totalLvlDurationMs == 0) continue;
+                            final long totalTxLvlDurations =
+                                    deltaInfo.getTransmitDurationMillisAtPowerLevel(level);
+                            // Smear HAL provided Tx power level duration based on active modem
+                            // duration in a given state. (Add totalLvlDurationMs / 2 before
+                            // the integer division with totalLvlDurationMs for rounding.)
+                            final long proportionalTxDurationMs =
+                                    (durationMs * totalTxLvlDurations
+                                            + (totalLvlDurationMs / 2)) / totalLvlDurationMs;
+                            ratStats.incrementTxDuration(freq, level, proportionalTxDurationMs);
+                            frequencyDurationMs += durationMs;
+                        }
+                        final long totalRxDuration = deltaInfo.getReceiveTimeMillis();
+                        // Smear HAL provided Rx power duration based on active modem
+                        // duration in a given state.  (Add totalActiveTimeMs / 2 before the
+                        // integer division with totalActiveTimeMs for rounding.)
+                        final long proportionalRxDurationMs =
+                                (frequencyDurationMs * totalRxDuration + (totalActiveTimeMs
+                                        / 2)) / totalActiveTimeMs;
+                        ratStats.incrementRxDuration(freq, proportionalRxDurationMs);
+                    }
+
+                }
+            }
+        } else {
+            // Specific data available.
+            for (int index = 0; index < infoSize; index++) {
+                final int rat = deltaInfo.getSpecificInfoRat(index);
+                final int freq = deltaInfo.getSpecificInfoFrequencyRange(index);
+
+                // Map RadioAccessNetworkType to course grain RadioAccessTechnology.
+                final int ratBucket = mapRadioAccessNetworkTypeToRadioAccessTechnology(rat);
+                final RadioAccessTechnologyBatteryStats ratStats = getRatBatteryStatsLocked(
+                        ratBucket);
+
+                final long rxTimeMs = deltaInfo.getReceiveTimeMillis(rat, freq);
+                final int[] txTimesMs = deltaInfo.getTransmitTimeMillis(rat, freq);
+
+                ratStats.incrementRxDuration(freq, rxTimeMs);
+                final int numTxLvl = txTimesMs.length;
+                for (int lvl = 0; lvl < numTxLvl; lvl++) {
+                    ratStats.incrementTxDuration(freq, lvl, txTimesMs[lvl]);
+                }
+            }
+        }
+
+        for (int rat = 0; rat < RADIO_ACCESS_TECHNOLOGY_COUNT; rat++) {
+            final RadioAccessTechnologyBatteryStats ratStats = mPerRatBatteryStats[rat];
+            if (ratStats == null) continue;
+            ratStats.setMark(elapsedRealtimeMs);
+        }
+    }
+
     /**
      * Add modem tx power to history
      * Device is said to be in high cellular transmit power when it has spent most of the transmit
@@ -15970,6 +16331,9 @@
     public Uid getUidStatsLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
         Uid u = mUidStats.get(uid);
         if (u == null) {
+            if (Process.isSdkSandboxUid(uid)) {
+                Log.wtf(TAG, "Tracking an SDK Sandbox UID");
+            }
             u = new Uid(this, uid, elapsedRealtimeMs, uptimeMs);
             mUidStats.put(uid, u);
         }
@@ -16879,14 +17243,18 @@
         mNextMaxDailyDeadlineMs = in.readLong();
         mBatteryTimeToFullSeconds = in.readLong();
 
-        mMeasuredEnergyStatsConfig = MeasuredEnergyStats.Config.createFromParcel(in);
-
-        /**
-         * WARNING: Supported buckets may have changed across boots. Bucket mismatch is handled
-         *          later when {@link #initMeasuredEnergyStatsLocked} is called.
-         */
-        mGlobalMeasuredEnergyStats = MeasuredEnergyStats.createAndReadSummaryFromParcel(
-                mMeasuredEnergyStatsConfig, in);
+        final MeasuredEnergyStats.Config config = MeasuredEnergyStats.Config.createFromParcel(in);
+        final MeasuredEnergyStats measuredEnergyStats =
+                MeasuredEnergyStats.createAndReadSummaryFromParcel(mMeasuredEnergyStatsConfig, in);
+        if (config != null && Arrays.equals(config.getStateNames(),
+                getBatteryConsumerProcessStateNames())) {
+            /**
+             * WARNING: Supported buckets may have changed across boots. Bucket mismatch is handled
+             *          later when {@link #initMeasuredEnergyStatsLocked} is called.
+             */
+            mMeasuredEnergyStatsConfig = config;
+            mGlobalMeasuredEnergyStats = measuredEnergyStats;
+        }
 
         mStartCount++;
 
@@ -16918,6 +17286,13 @@
             mNetworkByteActivityCounters[i].readSummaryFromParcelLocked(in);
             mNetworkPacketActivityCounters[i].readSummaryFromParcelLocked(in);
         }
+
+        final int numRat = in.readInt();
+        for (int i = 0; i < numRat; i++) {
+            if (in.readInt() == 0) continue;
+            getRatBatteryStatsLocked(i).readSummaryFromParcel(in);
+        }
+
         mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
         mMobileRadioActiveTimer.readSummaryFromParcelLocked(in);
         mMobileRadioActivePerAppTimer.readSummaryFromParcelLocked(in);
@@ -16978,7 +17353,6 @@
                 getScreenOffRpmTimerLocked(rpmName).readSummaryFromParcelLocked(in);
             }
         }
-
         int NKW = in.readInt();
         if (NKW > 10000) {
             throw new ParcelFormatException("File corrupt: too many kernel wake locks " + NKW);
@@ -17106,11 +17480,9 @@
                     u.mNetworkPacketActivityCounters[i].readSummaryFromParcelLocked(in);
                 }
                 if (in.readBoolean()) {
-                    TimeMultiStateCounter counter = new TimeMultiStateCounter(
-                            mOnBatteryTimeBase, in, elapsedRealtimeMs);
-                    if (counter.getStateCount() == BatteryConsumer.PROCESS_STATE_COUNT) {
-                        u.mMobileRadioActiveTime = counter;
-                    }
+                    u.mMobileRadioActiveTime = TimeMultiStateCounter.readFromParcel(in,
+                            mOnBatteryTimeBase, BatteryConsumer.PROCESS_STATE_COUNT,
+                            elapsedRealtimeMs);
                 }
                 u.mMobileRadioActiveCount.readSummaryFromParcelLocked(in);
             }
@@ -17160,11 +17532,9 @@
 
             int stateCount = in.readInt();
             if (stateCount != 0) {
-                final TimeMultiStateCounter counter = new TimeMultiStateCounter(
-                        mOnBatteryTimeBase, in, mClock.elapsedRealtime());
-                if (stateCount == BatteryConsumer.PROCESS_STATE_COUNT) {
-                    u.mCpuActiveTimeMs = counter;
-                }
+                u.mCpuActiveTimeMs = TimeMultiStateCounter.readFromParcel(in,
+                        mOnBatteryTimeBase, BatteryConsumer.PROCESS_STATE_COUNT,
+                        mClock.elapsedRealtime());
             }
             u.mCpuClusterTimesMs.readSummaryFromParcelLocked(in);
 
@@ -17423,6 +17793,17 @@
             mNetworkByteActivityCounters[i].writeSummaryFromParcelLocked(out);
             mNetworkPacketActivityCounters[i].writeSummaryFromParcelLocked(out);
         }
+        final int numRat = mPerRatBatteryStats.length;
+        out.writeInt(numRat);
+        for (int i = 0; i < numRat; i++) {
+            final RadioAccessTechnologyBatteryStats ratStat = mPerRatBatteryStats[i];
+            if (ratStat == null) {
+                out.writeInt(0);
+                continue;
+            }
+            out.writeInt(1);
+            ratStat.writeSummaryToParcel(out, nowRealtime);
+        }
         mMobileRadioActiveTimer.writeSummaryFromParcelLocked(out, nowRealtime);
         mMobileRadioActivePerAppTimer.writeSummaryFromParcelLocked(out, nowRealtime);
         mMobileRadioActiveAdjustedTime.writeSummaryFromParcelLocked(out);
@@ -17999,9 +18380,15 @@
         mLastWriteTimeMs = in.readLong();
         mBatteryTimeToFullSeconds = in.readLong();
 
-        mMeasuredEnergyStatsConfig = MeasuredEnergyStats.Config.createFromParcel(in);
-        mGlobalMeasuredEnergyStats =
+
+        final MeasuredEnergyStats.Config config = MeasuredEnergyStats.Config.createFromParcel(in);
+        final MeasuredEnergyStats measuredEnergyStats =
                 MeasuredEnergyStats.createFromParcel(mMeasuredEnergyStatsConfig, in);
+        if (config != null && Arrays.equals(config.getStateNames(),
+                getBatteryConsumerProcessStateNames())) {
+            mMeasuredEnergyStatsConfig = config;
+            mGlobalMeasuredEnergyStats = measuredEnergyStats;
+        }
 
         mRpmStats.clear();
         int NRPMS = in.readInt();
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index a1c1917..81c6ee7 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -22,6 +22,7 @@
 import android.os.BatteryUsageStats;
 import android.os.BatteryUsageStatsQuery;
 import android.os.Parcel;
+import android.os.Process;
 import android.os.SystemClock;
 import android.os.UidBatteryConsumer;
 import android.util.Log;
@@ -162,6 +163,8 @@
         final boolean includeProcessStateData = ((query.getFlags()
                 & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA) != 0)
                 && mStats.isProcessStateDataAvailable();
+        final boolean includeVirtualUids =  ((query.getFlags()
+                & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_VIRTUAL_UIDS) != 0);
 
         final BatteryUsageStats.Builder batteryUsageStatsBuilder = new BatteryUsageStats.Builder(
                 mStats.getCustomEnergyConsumerNames(), includePowerModels,
@@ -174,6 +177,10 @@
         SparseArray<? extends BatteryStats.Uid> uidStats = mStats.getUidStats();
         for (int i = uidStats.size() - 1; i >= 0; i--) {
             final BatteryStats.Uid uid = uidStats.valueAt(i);
+            if (!includeVirtualUids && uid.getUid() == Process.SDK_SANDBOX_VIRTUAL_UID) {
+                continue;
+            }
+
             batteryUsageStatsBuilder.getOrCreateUidBatteryConsumerBuilder(uid)
                     .setTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND,
                             getProcessBackgroundTimeMs(uid, realtimeUs))
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsStore.java b/core/java/com/android/internal/os/BatteryUsageStatsStore.java
index af82f40..09c9cfc 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsStore.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsStore.java
@@ -22,6 +22,7 @@
 import android.os.BatteryUsageStatsQuery;
 import android.os.Handler;
 import android.util.AtomicFile;
+import android.util.Log;
 import android.util.LongArray;
 import android.util.Slog;
 import android.util.TypedXmlPullParser;
@@ -47,6 +48,7 @@
 import java.util.Map;
 import java.util.Properties;
 import java.util.TreeMap;
+import java.util.concurrent.locks.ReentrantLock;
 
 /**
  * A storage mechanism for BatteryUsageStats snapshots.
@@ -73,6 +75,8 @@
     private boolean mSystemReady;
     private final File mStoreDir;
     private final File mLockFile;
+    private final ReentrantLock mFileLock = new ReentrantLock();
+    private FileLock mJvmLock;
     private final AtomicFile mConfigFile;
     private final long mMaxStorageBytes;
     private final Handler mHandler;
@@ -120,11 +124,11 @@
     }
 
     private void storeBatteryUsageStats(BatteryUsageStats stats) {
-        try (FileLock lock = lockSnapshotDirectory()) {
+        lockSnapshotDirectory();
+        try {
             if (!mStoreDir.exists()) {
                 if (!mStoreDir.mkdirs()) {
-                    Slog.e(TAG,
-                            "Could not create a directory for battery usage stats snapshots");
+                    Slog.e(TAG, "Could not create a directory for battery usage stats snapshots");
                     return;
                 }
             }
@@ -136,8 +140,8 @@
             }
 
             removeOldSnapshotsLocked();
-        } catch (IOException e) {
-            Slog.e(TAG, "Cannot lock battery usage stats directory", e);
+        } finally {
+            unlockSnapshotDirectory();
         }
     }
 
@@ -147,7 +151,8 @@
      */
     public long[] listBatteryUsageStatsTimestamps() {
         LongArray timestamps = new LongArray(100);
-        try (FileLock lock = lockSnapshotDirectory()) {
+        lockSnapshotDirectory();
+        try {
             for (File file : mStoreDir.listFiles()) {
                 String fileName = file.getName();
                 if (fileName.endsWith(SNAPSHOT_FILE_EXTENSION)) {
@@ -161,8 +166,8 @@
                     }
                 }
             }
-        } catch (IOException e) {
-            Slog.e(TAG, "Cannot lock battery usage stats directory", e);
+        } finally {
+            unlockSnapshotDirectory();
         }
         return timestamps.toArray();
     }
@@ -173,15 +178,16 @@
      */
     @Nullable
     public BatteryUsageStats loadBatteryUsageStats(long timestamp) {
-        try (FileLock lock = lockSnapshotDirectory()) {
+        lockSnapshotDirectory();
+        try {
             File file = makeSnapshotFilename(timestamp);
             try {
                 return readXmlFileLocked(file);
             } catch (Exception e) {
                 Slog.e(TAG, "Cannot read battery usage stats", e);
             }
-        } catch (IOException e) {
-            Slog.e(TAG, "Cannot lock battery usage stats directory", e);
+        } finally {
+            unlockSnapshotDirectory();
         }
         return null;
     }
@@ -192,7 +198,8 @@
      */
     public void setLastBatteryUsageStatsBeforeResetAtomPullTimestamp(long timestamp) {
         Properties props = new Properties();
-        try (FileLock lock = lockSnapshotDirectory()) {
+        lockSnapshotDirectory();
+        try {
             try (InputStream in = mConfigFile.openRead()) {
                 props.load(in);
             } catch (IOException e) {
@@ -209,8 +216,8 @@
                 mConfigFile.failWrite(out);
                 Slog.e(TAG, "Cannot save config file " + mConfigFile, e);
             }
-        } catch (IOException e) {
-            Slog.e(TAG, "Cannot lock battery usage stats directory", e);
+        } finally {
+            unlockSnapshotDirectory();
         }
     }
 
@@ -220,23 +227,41 @@
      */
     public long getLastBatteryUsageStatsBeforeResetAtomPullTimestamp() {
         Properties props = new Properties();
-        try (FileLock lock = lockSnapshotDirectory()) {
+        lockSnapshotDirectory();
+        try {
             try (InputStream in = mConfigFile.openRead()) {
                 props.load(in);
             } catch (IOException e) {
                 Slog.e(TAG, "Cannot load config file " + mConfigFile, e);
             }
-        } catch (IOException e) {
-            Slog.e(TAG, "Cannot lock battery usage stats directory", e);
+        } finally {
+            unlockSnapshotDirectory();
         }
         return Long.parseLong(
                 props.getProperty(BATTERY_USAGE_STATS_BEFORE_RESET_TIMESTAMP_PROPERTY, "0"));
     }
 
-    private FileLock lockSnapshotDirectory() throws IOException {
-        mLockFile.getParentFile().mkdirs();
-        mLockFile.createNewFile();
-        return FileChannel.open(mLockFile.toPath(), StandardOpenOption.WRITE).lock();
+    private void lockSnapshotDirectory() {
+        mFileLock.lock();
+
+        // Lock the directory from access by other JVMs
+        try {
+            mLockFile.getParentFile().mkdirs();
+            mLockFile.createNewFile();
+            mJvmLock = FileChannel.open(mLockFile.toPath(), StandardOpenOption.WRITE).lock();
+        } catch (IOException e) {
+            Log.e(TAG, "Cannot lock snapshot directory", e);
+        }
+    }
+
+    private void unlockSnapshotDirectory() {
+        try {
+            mJvmLock.close();
+        } catch (IOException e) {
+            Log.e(TAG, "Cannot unlock snapshot directory", e);
+        } finally {
+            mFileLock.unlock();
+        }
     }
 
     /**
diff --git a/core/java/com/android/internal/os/BluetoothPowerCalculator.java b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
index 2ebf689..e52c8a3 100644
--- a/core/java/com/android/internal/os/BluetoothPowerCalculator.java
+++ b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
@@ -139,8 +139,10 @@
                         BatteryConsumer.POWER_COMPONENT_BLUETOOTH, powerAndDuration.powerMah,
                         powerModel);
 
-        powerAndDuration.totalDurationMs += powerAndDuration.durationMs;
-        powerAndDuration.totalPowerMah += powerAndDuration.powerMah;
+        if (!app.isVirtualUid()) {
+            powerAndDuration.totalDurationMs += powerAndDuration.durationMs;
+            powerAndDuration.totalPowerMah += powerAndDuration.powerMah;
+        }
 
         if (query.isProcessStateDataNeeded() && powerAndDuration.keys != null) {
             for (int j = 0; j < powerAndDuration.keys.length; j++) {
diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java
index 1fc2baf..8704e93 100644
--- a/core/java/com/android/internal/os/CpuPowerCalculator.java
+++ b/core/java/com/android/internal/os/CpuPowerCalculator.java
@@ -117,7 +117,9 @@
                 }
             }
             calculateApp(app, app.getBatteryStatsUid(), query, result, keys);
-            totalPowerMah += result.powerMah;
+            if (!app.isVirtualUid()) {
+                totalPowerMah += result.powerMah;
+            }
         }
 
         final long consumptionUC = batteryStats.getCpuMeasuredBatteryConsumptionUC();
diff --git a/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java b/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java
index cbbb526..0853bd8 100644
--- a/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java
+++ b/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java
@@ -96,7 +96,9 @@
                 app.setConsumedPowerForCustomComponent(
                         BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + i,
                         customMeasuredPowerMah[i]);
-                newTotalPowerMah[i] += customMeasuredPowerMah[i];
+                if (!app.isVirtualUid()) {
+                    newTotalPowerMah[i] += customMeasuredPowerMah[i];
+                }
             }
         }
         return newTotalPowerMah;
diff --git a/core/java/com/android/internal/os/GnssPowerCalculator.java b/core/java/com/android/internal/os/GnssPowerCalculator.java
index 0f78306..070783a 100644
--- a/core/java/com/android/internal/os/GnssPowerCalculator.java
+++ b/core/java/com/android/internal/os/GnssPowerCalculator.java
@@ -58,8 +58,11 @@
             final long consumptionUC =
                     app.getBatteryStatsUid().getGnssMeasuredBatteryConsumptionUC();
             final int powerModel = getPowerModel(consumptionUC, query);
-            appsPowerMah += calculateApp(app, app.getBatteryStatsUid(), powerModel,
+            final double powerMah = calculateApp(app, app.getBatteryStatsUid(), powerModel,
                     rawRealtimeUs, averageGnssPowerMa, consumptionUC);
+            if (!app.isVirtualUid()) {
+                appsPowerMah += powerMah;
+            }
         }
 
         final long consumptionUC = batteryStats.getGnssMeasuredBatteryConsumptionUC();
diff --git a/core/java/com/android/internal/os/KernelAllocationStats.java b/core/java/com/android/internal/os/KernelAllocationStats.java
index 1c3f8b0..58d51e3 100644
--- a/core/java/com/android/internal/os/KernelAllocationStats.java
+++ b/core/java/com/android/internal/os/KernelAllocationStats.java
@@ -24,21 +24,29 @@
 
     /** Process dma-buf stats. */
     public static final class ProcessDmabuf {
+        public final int uid;
+        public final String processName;
+        public final int oomScore;
+
         /** Size of buffers retained by the process. */
         public final int retainedSizeKb;
         /** Number of buffers retained by the process. */
         public final int retainedBuffersCount;
-        /** Size of buffers mapped to the address space. */
-        public final int mappedSizeKb;
-        /** Count of buffers mapped to the address space. */
-        public final int mappedBuffersCount;
+        /** Size of buffers shared with Surface Flinger. */
+        public final int surfaceFlingerSizeKb;
+        /** Count of buffers shared with Surface Flinger. */
+        public final int surfaceFlingerCount;
 
-        ProcessDmabuf(int retainedSizeKb, int retainedBuffersCount,
-                int mappedSizeKb, int mappedBuffersCount) {
+        ProcessDmabuf(int uid, String processName, int oomScore, int retainedSizeKb,
+                int retainedBuffersCount, int surfaceFlingerSizeKb,
+                int surfaceFlingerCount) {
+            this.uid = uid;
+            this.processName = processName;
+            this.oomScore = oomScore;
             this.retainedSizeKb = retainedSizeKb;
             this.retainedBuffersCount = retainedBuffersCount;
-            this.mappedSizeKb = mappedSizeKb;
-            this.mappedBuffersCount = mappedBuffersCount;
+            this.surfaceFlingerSizeKb = surfaceFlingerSizeKb;
+            this.surfaceFlingerCount = surfaceFlingerCount;
         }
     }
 
@@ -47,7 +55,7 @@
      * stats could not be read.
      */
     @Nullable
-    public static native ProcessDmabuf getDmabufAllocations(int pid);
+    public static native ProcessDmabuf[] getDmabufAllocations();
 
     /** Pid to gpu memory size. */
     public static final class ProcessGpuMem {
diff --git a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
index f4624de..d0df45c 100644
--- a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
+++ b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
@@ -136,12 +136,14 @@
             PowerAndDuration total,
             BatteryUsageStatsQuery query, BatteryConsumer.Key[] keys) {
         final long radioActiveDurationMs = calculateDuration(u, BatteryStats.STATS_SINCE_CHARGED);
-        total.totalAppDurationMs += radioActiveDurationMs;
-
         final long consumptionUC = u.getMobileRadioMeasuredBatteryConsumptionUC();
         final int powerModel = getPowerModel(consumptionUC, query);
         final double powerMah = calculatePower(u, powerModel, radioActiveDurationMs, consumptionUC);
-        total.totalAppPowerMah += powerMah;
+
+        if (!app.isVirtualUid()) {
+            total.totalAppDurationMs += radioActiveDurationMs;
+            total.totalAppPowerMah += powerMah;
+        }
 
         app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO,
                         radioActiveDurationMs)
diff --git a/core/java/com/android/internal/os/ScreenPowerCalculator.java b/core/java/com/android/internal/os/ScreenPowerCalculator.java
index 67d3d6e..5ca1a85 100644
--- a/core/java/com/android/internal/os/ScreenPowerCalculator.java
+++ b/core/java/com/android/internal/os/ScreenPowerCalculator.java
@@ -96,8 +96,10 @@
                                     appPowerAndDuration.durationMs)
                             .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN,
                                     appPowerAndDuration.powerMah, powerModel);
-                    totalAppPower += appPowerAndDuration.powerMah;
-                    totalAppDuration += appPowerAndDuration.durationMs;
+                    if (!app.isVirtualUid()) {
+                        totalAppPower += appPowerAndDuration.powerMah;
+                        totalAppDuration += appPowerAndDuration.durationMs;
+                    }
                 }
                 break;
             case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
@@ -192,10 +194,13 @@
         long totalActivityTimeMs = 0;
         final SparseLongArray activityTimeArray = new SparseLongArray();
         for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
-            final BatteryStats.Uid uid = uidBatteryConsumerBuilders.valueAt(i).getBatteryStatsUid();
+            final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
+            final BatteryStats.Uid uid = app.getBatteryStatsUid();
             final long timeMs = getProcessForegroundTimeMs(uid, rawRealtimeUs);
             activityTimeArray.put(uid.getUid(), timeMs);
-            totalActivityTimeMs += timeMs;
+            if (!app.isVirtualUid()) {
+                totalActivityTimeMs += timeMs;
+            }
         }
 
         if (totalActivityTimeMs >= MIN_ACTIVE_TIME_FOR_SMEARING) {
diff --git a/core/java/com/android/internal/os/SensorPowerCalculator.java b/core/java/com/android/internal/os/SensorPowerCalculator.java
index 4a9c91d..573692e 100644
--- a/core/java/com/android/internal/os/SensorPowerCalculator.java
+++ b/core/java/com/android/internal/os/SensorPowerCalculator.java
@@ -51,7 +51,9 @@
                 builder.getUidBatteryConsumerBuilders();
         for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
             final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
-            appsPowerMah += calculateApp(app, app.getBatteryStatsUid(), rawRealtimeUs);
+            if (!app.isVirtualUid()) {
+                appsPowerMah += calculateApp(app, app.getBatteryStatsUid(), rawRealtimeUs);
+            }
         }
 
         builder.getAggregateBatteryConsumerBuilder(
diff --git a/core/java/com/android/internal/os/UserPowerCalculator.java b/core/java/com/android/internal/os/UserPowerCalculator.java
index 22cff6e..79e3a19 100644
--- a/core/java/com/android/internal/os/UserPowerCalculator.java
+++ b/core/java/com/android/internal/os/UserPowerCalculator.java
@@ -49,7 +49,11 @@
                 builder.getUidBatteryConsumerBuilders();
 
         for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
-            UidBatteryConsumer.Builder uidBuilder = uidBatteryConsumerBuilders.valueAt(i);
+            final UidBatteryConsumer.Builder uidBuilder = uidBatteryConsumerBuilders.valueAt(i);
+            if (uidBuilder.isVirtualUid()) {
+                continue;
+            }
+
             final int uid = uidBuilder.getUid();
             if (UserHandle.getAppId(uid) < Process.FIRST_APPLICATION_UID) {
                 continue;
diff --git a/core/java/com/android/internal/os/VideoPowerCalculator.java b/core/java/com/android/internal/os/VideoPowerCalculator.java
index a222bcb..2daf15e 100644
--- a/core/java/com/android/internal/os/VideoPowerCalculator.java
+++ b/core/java/com/android/internal/os/VideoPowerCalculator.java
@@ -75,7 +75,9 @@
         final double powerMah = mPowerEstimator.calculatePower(durationMs);
         app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO, durationMs)
                 .setConsumedPower(BatteryConsumer.POWER_COMPONENT_VIDEO, powerMah);
-        total.durationMs += durationMs;
-        total.powerMah += powerMah;
+        if (!app.isVirtualUid()) {
+            total.durationMs += durationMs;
+            total.powerMah += powerMah;
+        }
     }
 }
diff --git a/core/java/com/android/internal/os/WakelockPowerCalculator.java b/core/java/com/android/internal/os/WakelockPowerCalculator.java
index 0251e1c..3ae7113 100644
--- a/core/java/com/android/internal/os/WakelockPowerCalculator.java
+++ b/core/java/com/android/internal/os/WakelockPowerCalculator.java
@@ -62,8 +62,10 @@
                     BatteryStats.STATS_SINCE_CHARGED);
             app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WAKELOCK, result.durationMs)
                     .setConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK, result.powerMah);
-            totalAppDurationMs += result.durationMs;
-            appPowerMah += result.powerMah;
+            if (!app.isVirtualUid()) {
+                totalAppDurationMs += result.durationMs;
+                appPowerMah += result.powerMah;
+            }
 
             if (app.getUid() == Process.ROOT_UID) {
                 osBatteryConsumer = app;
diff --git a/core/java/com/android/internal/os/WifiPowerCalculator.java b/core/java/com/android/internal/os/WifiPowerCalculator.java
index 8c3fb86..2181821 100644
--- a/core/java/com/android/internal/os/WifiPowerCalculator.java
+++ b/core/java/com/android/internal/os/WifiPowerCalculator.java
@@ -111,9 +111,10 @@
             calculateApp(powerDurationAndTraffic, app.getBatteryStatsUid(), powerModel,
                     rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED,
                     batteryStats.hasWifiActivityReporting(), consumptionUC);
-
-            totalAppDurationMs += powerDurationAndTraffic.durationMs;
-            totalAppPowerMah += powerDurationAndTraffic.powerMah;
+            if (!app.isVirtualUid()) {
+                totalAppDurationMs += powerDurationAndTraffic.durationMs;
+                totalAppPowerMah += powerDurationAndTraffic.powerMah;
+            }
 
             app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI,
                     powerDurationAndTraffic.durationMs);
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 40e4085..89ac722 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -30,6 +30,7 @@
 import static android.view.View.MeasureSpec.getMode;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static android.view.ViewRootImpl.CAPTION_ON_SHELL;
 import static android.view.Window.DECOR_CAPTION_SHADE_DARK;
 import static android.view.Window.DECOR_CAPTION_SHADE_LIGHT;
 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
@@ -2120,7 +2121,9 @@
      * corresponding insets change to the InsetsController.
      */
     public void notifyCaptionHeightChanged() {
-        getWindowInsetsController().setCaptionInsetsHeight(getCaptionInsetsHeight());
+        if (!CAPTION_ON_SHELL) {
+            getWindowInsetsController().setCaptionInsetsHeight(getCaptionInsetsHeight());
+        }
     }
 
     void setWindow(PhoneWindow phoneWindow) {
diff --git a/core/java/com/android/internal/policy/TransitionAnimation.java b/core/java/com/android/internal/policy/TransitionAnimation.java
index 74749cc..e2d2505 100644
--- a/core/java/com/android/internal/policy/TransitionAnimation.java
+++ b/core/java/com/android/internal/policy/TransitionAnimation.java
@@ -29,6 +29,8 @@
 import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_OPEN;
 import static android.view.WindowManager.TRANSIT_OPEN;
 
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -60,6 +62,7 @@
 import android.view.animation.TranslateAnimation;
 
 import com.android.internal.R;
+import com.android.internal.protolog.common.ProtoLog;
 
 import java.util.List;
 
@@ -320,9 +323,9 @@
     @Nullable
     private AttributeCache.Entry getCachedAnimations(LayoutParams lp) {
         if (mDebug) {
-            Slog.v(mTag, "Loading animations: layout params pkg="
-                    + (lp != null ? lp.packageName : null)
-                    + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null));
+            ProtoLog.v(WM_DEBUG_ANIM, "Loading animations: layout params pkg=%s resId=0x%x",
+                    lp != null ? lp.packageName : null,
+                    lp != null ? lp.windowAnimations : 0);
         }
         if (lp != null && lp.windowAnimations != 0) {
             // If this is a system resource, don't try to load it from the
@@ -334,7 +337,7 @@
                 packageName = DEFAULT_PACKAGE;
             }
             if (mDebug) {
-                Slog.v(mTag, "Loading animations: picked package=" + packageName);
+                ProtoLog.v(WM_DEBUG_ANIM, "Loading animations: picked package=%s", packageName);
             }
             return AttributeCache.instance().get(packageName, resId,
                     com.android.internal.R.styleable.WindowAnimation);
@@ -345,16 +348,16 @@
     @Nullable
     private AttributeCache.Entry getCachedAnimations(String packageName, int resId) {
         if (mDebug) {
-            Slog.v(mTag, "Loading animations: package="
-                    + packageName + " resId=0x" + Integer.toHexString(resId));
+            ProtoLog.v(WM_DEBUG_ANIM, "Loading animations: package=%s resId=0x%x",
+                    packageName, resId);
         }
         if (packageName != null) {
             if ((resId & 0xFF000000) == 0x01000000) {
                 packageName = DEFAULT_PACKAGE;
             }
             if (mDebug) {
-                Slog.v(mTag, "Loading animations: picked package="
-                        + packageName);
+                ProtoLog.v(WM_DEBUG_ANIM, "Loading animations: picked package=%s",
+                        packageName);
             }
             return AttributeCache.instance().get(packageName, resId,
                     com.android.internal.R.styleable.WindowAnimation);
diff --git a/core/java/com/android/internal/power/MeasuredEnergyStats.java b/core/java/com/android/internal/power/MeasuredEnergyStats.java
index 7262e84..7fb8696 100644
--- a/core/java/com/android/internal/power/MeasuredEnergyStats.java
+++ b/core/java/com/android/internal/power/MeasuredEnergyStats.java
@@ -194,6 +194,7 @@
             return mSupportedMultiStateBuckets[index];
         }
 
+        @NonNull
         public String[] getStateNames() {
             return mStateNames;
         }
@@ -321,6 +322,10 @@
             LongMultiStateCounter multiStateCounter = null;
             if (in.readBoolean()) {
                 multiStateCounter = LongMultiStateCounter.CREATOR.createFromParcel(in);
+                if (mConfig == null
+                        || multiStateCounter.getStateCount() != mConfig.getStateNames().length) {
+                    multiStateCounter = null;
+                }
             }
 
             if (index < mAccumulatedChargeMicroCoulomb.length) {
diff --git a/core/java/com/android/internal/protolog/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java
index 45c6d5f..7f36c79 100644
--- a/core/java/com/android/internal/protolog/ProtoLogGroup.java
+++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java
@@ -60,6 +60,7 @@
             Consts.TAG_WM),
     WM_DEBUG_APP_TRANSITIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
             Consts.TAG_WM),
+    WM_DEBUG_ANIM(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM),
     WM_DEBUG_APP_TRANSITIONS_ANIM(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
             Consts.TAG_WM),
     WM_DEBUG_RECENTS_ANIMATIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index d629d66..089179d 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -297,6 +297,11 @@
      */
     void runGcForTest();
 
+    /**
+     * Send a request to SystemUI to put a given active tile in listening state
+     */
+    void requestTileServiceListeningState(in ComponentName componentName);
+
     void requestAddTile(in ComponentName componentName, in CharSequence appName, in CharSequence label, in Icon icon, in IAddTileResultCallback callback);
     void cancelRequestAddTile(in String packageName);
 
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 1d60c50..2ee5e79 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -91,7 +91,7 @@
     void onBubbleNotificationSuppressionChanged(String key, boolean isNotifSuppressed, boolean isBubbleSuppressed);
     void hideCurrentInputMethodForBubbles();
     void grantInlineReplyUriPermission(String key, in Uri uri, in UserHandle user, String packageName);
-    void clearInlineReplyUriPermissions(String key);
+    oneway void clearInlineReplyUriPermissions(String key);
     void onNotificationFeedbackReceived(String key, in Bundle feedback);
 
     void onGlobalActionsShown();
@@ -171,6 +171,11 @@
      */
     void suppressAmbientDisplay(boolean suppress);
 
+    /**
+     * Send a request to SystemUI to put a given active tile in listening state
+     */
+    void requestTileServiceListeningState(in ComponentName componentName, int userId);
+
     void requestAddTile(in ComponentName componentName, in CharSequence label, in Icon icon, int userId, in IAddTileResultCallback callback);
     void cancelRequestAddTile(in String packageName);
 
diff --git a/core/java/com/android/internal/telephony/ICarrierPrivilegesListener.aidl b/core/java/com/android/internal/telephony/ICarrierPrivilegesCallback.aidl
similarity index 84%
rename from core/java/com/android/internal/telephony/ICarrierPrivilegesListener.aidl
rename to core/java/com/android/internal/telephony/ICarrierPrivilegesCallback.aidl
index 6ca8cec..0c8e73f 100644
--- a/core/java/com/android/internal/telephony/ICarrierPrivilegesListener.aidl
+++ b/core/java/com/android/internal/telephony/ICarrierPrivilegesCallback.aidl
@@ -16,7 +16,8 @@
 
 package com.android.internal.telephony;
 
-oneway interface ICarrierPrivilegesListener {
+oneway interface ICarrierPrivilegesCallback {
     void onCarrierPrivilegesChanged(
             in List<String> privilegedPackageNames, in int[] privilegedUids);
+    void onCarrierServiceChanged(in String carrierServicePackageName, in int carrierServiceUid);
 }
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 9712d7e..c7fa757 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -32,7 +32,7 @@
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.emergency.EmergencyNumber;
-import com.android.internal.telephony.ICarrierPrivilegesListener;
+import com.android.internal.telephony.ICarrierPrivilegesCallback;
 import com.android.internal.telephony.IPhoneStateListener;
 import com.android.internal.telephony.IOnSubscriptionsChangedListener;
 
@@ -102,9 +102,11 @@
     void notifyLinkCapacityEstimateChanged(in int phoneId, in int subId,
             in List<LinkCapacityEstimate> linkCapacityEstimateList);
 
-    void addCarrierPrivilegesListener(
-            int phoneId, ICarrierPrivilegesListener callback, String pkg, String featureId);
-    void removeCarrierPrivilegesListener(ICarrierPrivilegesListener callback, String pkg);
+    void addCarrierPrivilegesCallback(
+            int phoneId, ICarrierPrivilegesCallback callback, String pkg, String featureId);
+    void removeCarrierPrivilegesCallback(ICarrierPrivilegesCallback callback, String pkg);
     void notifyCarrierPrivilegesChanged(
             int phoneId, in List<String> privilegedPackageNames, in int[] privilegedUids);
+    void notifyCarrierServiceChanged(int phoneId, in String packageName, int uid);
+
 }
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index 1cd758c..3f7c4d5 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -132,6 +132,11 @@
      */
     public static final int ACTION_UDFPS_ILLUMINATE = 14;
 
+    /**
+     * Time it takes for the gesture back affordance arrow to show up.
+     */
+    public static final int ACTION_SHOW_BACK_ARROW = 15;
+
     private static final int[] ACTIONS_ALL = {
         ACTION_EXPAND_PANEL,
         ACTION_TOGGLE_RECENTS,
@@ -147,7 +152,8 @@
         ACTION_LOCKSCREEN_UNLOCK,
         ACTION_USER_SWITCH,
         ACTION_SWITCH_DISPLAY_UNFOLD,
-        ACTION_UDFPS_ILLUMINATE
+        ACTION_UDFPS_ILLUMINATE,
+        ACTION_SHOW_BACK_ARROW,
     };
 
     /** @hide */
@@ -166,7 +172,8 @@
         ACTION_LOCKSCREEN_UNLOCK,
         ACTION_USER_SWITCH,
         ACTION_SWITCH_DISPLAY_UNFOLD,
-        ACTION_UDFPS_ILLUMINATE
+        ACTION_UDFPS_ILLUMINATE,
+        ACTION_SHOW_BACK_ARROW
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Action {
@@ -187,7 +194,8 @@
             FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOCKSCREEN_UNLOCK,
             FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_USER_SWITCH,
             FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SWITCH_DISPLAY_UNFOLD,
-            FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_UDFPS_ILLUMINATE
+            FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_UDFPS_ILLUMINATE,
+            FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_BACK_ARROW,
     };
 
     private static LatencyTracker sLatencyTracker;
@@ -277,6 +285,8 @@
                 return "ACTION_SWITCH_DISPLAY_UNFOLD";
             case 15:
                 return "ACTION_UDFPS_ILLUMINATE";
+            case 16:
+                return "ACTION_SHOW_BACK_ARROW";
             default:
                 throw new IllegalArgumentException("Invalid action");
         }
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 6673f67..52f0fb5 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -51,10 +51,10 @@
     @Override
     public void resized(ClientWindowFrames frames, boolean reportDraw,
             MergedConfiguration mergedConfiguration, boolean forceLayout,
-            boolean alwaysConsumeSystemBars, int displayId) {
+            boolean alwaysConsumeSystemBars, int displayId, int seqId, int resizeMode) {
         if (reportDraw) {
             try {
-                mSession.finishDrawing(this, null /* postDrawTransaction */);
+                mSession.finishDrawing(this, null /* postDrawTransaction */, seqId);
             } catch (RemoteException e) {
             }
         }
diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
index 273c5f1..40d89db 100644
--- a/core/java/com/android/internal/view/IInputMethod.aidl
+++ b/core/java/com/android/internal/view/IInputMethod.aidl
@@ -67,4 +67,6 @@
             in List<MotionEvent> events);
 
     void initInkWindow();
+
+    void finishStylusHandwriting();
 }
diff --git a/core/java/com/android/internal/widget/CachingIconView.java b/core/java/com/android/internal/widget/CachingIconView.java
index 299cbe1..d115697 100644
--- a/core/java/com/android/internal/widget/CachingIconView.java
+++ b/core/java/com/android/internal/widget/CachingIconView.java
@@ -23,6 +23,7 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Configuration;
+import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
@@ -35,6 +36,8 @@
 import android.widget.ImageView;
 import android.widget.RemoteViews;
 
+import com.android.internal.R;
+
 import java.util.Objects;
 import java.util.function.Consumer;
 
@@ -55,9 +58,42 @@
     private int mBackgroundColor;
     private boolean mWillBeForceHidden;
 
+    private int mMaxDrawableWidth = -1;
+    private int mMaxDrawableHeight = -1;
+
+    public CachingIconView(Context context) {
+        this(context, null, 0, 0);
+    }
+
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public CachingIconView(Context context, @Nullable AttributeSet attrs) {
-        super(context, attrs);
+        this(context, attrs, 0, 0);
+    }
+
+    public CachingIconView(Context context, @Nullable AttributeSet attrs,
+            int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public CachingIconView(Context context, @Nullable AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    private void init(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        if (attrs == null) {
+            return;
+        }
+
+        TypedArray ta = context.obtainStyledAttributes(attrs,
+                R.styleable.CachingIconView, defStyleAttr, defStyleRes);
+        mMaxDrawableWidth = ta.getDimensionPixelSize(R.styleable
+                .CachingIconView_maxDrawableWidth, -1);
+        mMaxDrawableHeight = ta.getDimensionPixelSize(R.styleable
+                .CachingIconView_maxDrawableHeight, -1);
+        ta.recycle();
     }
 
     @Override
@@ -66,15 +102,27 @@
         if (!testAndSetCache(icon)) {
             mInternalSetDrawable = true;
             // This calls back to setImageDrawable, make sure we don't clear the cache there.
-            super.setImageIcon(icon);
+            Drawable drawable = loadSizeRestrictedIcon(icon);
+            if (drawable == null) {
+                super.setImageIcon(icon);
+            } else {
+                super.setImageDrawable(drawable);
+            }
             mInternalSetDrawable = false;
         }
     }
 
+    @Nullable
+    private Drawable loadSizeRestrictedIcon(@Nullable Icon icon) {
+        return LocalImageResolver.resolveImage(icon, getContext(), mMaxDrawableWidth,
+                mMaxDrawableHeight);
+    }
+
     @Override
-    public Runnable setImageIconAsync(@Nullable Icon icon) {
+    public Runnable setImageIconAsync(@Nullable final Icon icon) {
         resetCache();
-        return super.setImageIconAsync(icon);
+        Drawable drawable = loadSizeRestrictedIcon(icon);
+        return () -> setImageDrawable(drawable);
     }
 
     @Override
@@ -83,14 +131,30 @@
         if (!testAndSetCache(resId)) {
             mInternalSetDrawable = true;
             // This calls back to setImageDrawable, make sure we don't clear the cache there.
-            super.setImageResource(resId);
+            Drawable drawable = loadSizeRestrictedDrawable(resId);
+            if (drawable == null) {
+                super.setImageResource(resId);
+            } else {
+                super.setImageDrawable(drawable);
+            }
             mInternalSetDrawable = false;
         }
     }
 
+    @Nullable
+    private Drawable loadSizeRestrictedDrawable(@DrawableRes int resId) {
+        return LocalImageResolver.resolveImage(resId, getContext(), mMaxDrawableWidth,
+                mMaxDrawableHeight);
+    }
+
     @Override
     public Runnable setImageResourceAsync(@DrawableRes int resId) {
         resetCache();
+        Drawable drawable = loadSizeRestrictedDrawable(resId);
+        if (drawable != null) {
+            return () -> setImageDrawable(drawable);
+        }
+
         return super.setImageResourceAsync(resId);
     }
 
@@ -98,13 +162,31 @@
     @RemotableViewMethod(asyncImpl="setImageURIAsync")
     public void setImageURI(@Nullable Uri uri) {
         resetCache();
-        super.setImageURI(uri);
+        Drawable drawable = loadSizeRestrictedUri(uri);
+        if (drawable == null) {
+            super.setImageURI(uri);
+        } else {
+            mInternalSetDrawable = true;
+            super.setImageDrawable(drawable);
+            mInternalSetDrawable = false;
+        }
+    }
+
+    @Nullable
+    private Drawable loadSizeRestrictedUri(@Nullable Uri uri) {
+        return LocalImageResolver.resolveImage(uri, getContext(), mMaxDrawableWidth,
+                mMaxDrawableHeight);
     }
 
     @Override
     public Runnable setImageURIAsync(@Nullable Uri uri) {
         resetCache();
-        return super.setImageURIAsync(uri);
+        Drawable drawable = loadSizeRestrictedUri(uri);
+        if (drawable == null) {
+            return super.setImageURIAsync(uri);
+        } else {
+            return () -> setImageDrawable(drawable);
+        }
     }
 
     @Override
@@ -307,4 +389,18 @@
     public void setWillBeForceHidden(boolean forceHidden) {
         mWillBeForceHidden = forceHidden;
     }
+
+    /**
+     * Returns the set maximum width of drawable in pixels. -1 if not set.
+     */
+    public int getMaxDrawableWidth() {
+        return mMaxDrawableWidth;
+    }
+
+    /**
+     * Returns the set maximum height of drawable in pixels. -1 if not set.
+     */
+    public int getMaxDrawableHeight() {
+        return mMaxDrawableHeight;
+    }
 }
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 5fa4a65..4706aff 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -66,7 +66,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.function.Consumer;
 
 /**
  * A custom-built layout for the Notification.MessagingStyle allows dynamic addition and removal
@@ -76,8 +75,6 @@
 public class ConversationLayout extends FrameLayout
         implements ImageMessageConsumer, IMessagingLayout {
 
-    private static final Consumer<MessagingMessage> REMOVE_MESSAGE
-            = MessagingMessage::removeMessage;
     public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f);
     public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
     public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
@@ -150,7 +147,7 @@
     private Icon mShortcutIcon;
     private View mAppNameDivider;
     private TouchDelegateComposite mTouchDelegate = new TouchDelegateComposite(this);
-    private ArrayList<MessagingGroup> mToRecycle = new ArrayList<>();
+    private ArrayList<MessagingLinearLayout.MessagingChild> mToRecycle = new ArrayList<>();
 
     public ConversationLayout(@NonNull Context context) {
         super(context);
@@ -463,8 +460,12 @@
         removeGroups(oldGroups);
 
         // Let's remove the remaining messages
-        mMessages.forEach(REMOVE_MESSAGE);
-        mHistoricMessages.forEach(REMOVE_MESSAGE);
+        for (MessagingMessage message : mMessages) {
+            message.removeMessage(mToRecycle);
+        }
+        for (MessagingMessage historicMessage : mHistoricMessages) {
+            historicMessage.removeMessage(mToRecycle);
+        }
 
         mMessages = messages;
         mHistoricMessages = historicMessages;
@@ -475,8 +476,8 @@
         updateConversationLayout();
 
         // Recycle everything at the end of the update, now that we know it's no longer needed.
-        for (MessagingGroup group : mToRecycle) {
-            group.recycle();
+        for (MessagingLinearLayout.MessagingChild child : mToRecycle) {
+            child.recycle();
         }
         mToRecycle.clear();
     }
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 851e8e0..3494c9e 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -53,7 +53,6 @@
     VerifyCredentialResponse verifyTiedProfileChallenge(in LockscreenCredential credential, int userId, int flags);
     VerifyCredentialResponse verifyGatekeeperPasswordHandle(long gatekeeperPasswordHandle, long challenge, int userId);
     void removeGatekeeperPasswordHandle(long gatekeeperPasswordHandle);
-    boolean checkVoldPassword(int userId);
     int getCredentialType(int userId);
     byte[] getHashFactor(in LockscreenCredential currentCredential, int userId);
     void setSeparateProfileChallengeEnabled(int userId, boolean enabled, in LockscreenCredential managedUserPassword);
diff --git a/core/java/com/android/internal/widget/LocalImageResolver.java b/core/java/com/android/internal/widget/LocalImageResolver.java
index 616b699..ce27b34 100644
--- a/core/java/com/android/internal/widget/LocalImageResolver.java
+++ b/core/java/com/android/internal/widget/LocalImageResolver.java
@@ -16,70 +16,195 @@
 
 package com.android.internal.widget;
 
+import android.annotation.DrawableRes;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
 import android.graphics.ImageDecoder;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
+import android.util.Log;
 import android.util.Size;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.io.IOException;
 
 /** A class to extract Drawables from a MessagingStyle/ConversationStyle message. */
 public class LocalImageResolver {
-    private static final String TAG = LocalImageResolver.class.getSimpleName();
 
-    private static final int MAX_SAFE_ICON_SIZE_PX = 480;
+    private static final String TAG = "LocalImageResolver";
+
+    @VisibleForTesting
+    static final int DEFAULT_MAX_SAFE_ICON_SIZE_PX = 480;
 
     /**
-     * Resolve an image from the given Uri using {@link ImageDecoder}
+     * Resolve an image from the given Uri using {@link ImageDecoder} if it contains a
+     * bitmap reference.
      */
+    @Nullable
     public static Drawable resolveImage(Uri uri, Context context) throws IOException {
-        final ImageDecoder.Source source =
-                ImageDecoder.createSource(context.getContentResolver(), uri);
-        final Drawable drawable =
-                ImageDecoder.decodeDrawable(source, LocalImageResolver::onHeaderDecoded);
-        return drawable;
+        try {
+            final ImageDecoder.Source source =
+                    ImageDecoder.createSource(context.getContentResolver(), uri);
+            return ImageDecoder.decodeDrawable(source,
+                    (decoder, info, s) -> LocalImageResolver.onHeaderDecoded(decoder, info,
+                            DEFAULT_MAX_SAFE_ICON_SIZE_PX, DEFAULT_MAX_SAFE_ICON_SIZE_PX));
+        } catch (Exception e) {
+            // Invalid drawable resource can actually throw either NullPointerException or
+            // ResourceNotFoundException. This sanitizes to expected output.
+            throw new IOException(e);
+        }
     }
 
     /**
-     * Get the drawable from Icon using {@link ImageDecoder} if it contains a Uri, or
+     * Get the drawable from Icon using {@link ImageDecoder} if it contains a bitmap reference, or
      * using {@link Icon#loadDrawable(Context)} otherwise.  This will correctly apply the Icon's,
      * tint, if present, to the drawable.
+     *
+     * @return drawable or null if loading failed.
      */
-    public static Drawable resolveImage(Icon icon, Context context) throws IOException {
-        Uri uri = getResolvableUri(icon);
-        if (uri != null) {
-            Drawable result = resolveImage(uri, context);
-            if (icon.hasTint()) {
-                result.mutate();
-                result.setTintList(icon.getTintList());
-                result.setTintBlendMode(icon.getTintBlendMode());
-            }
-            return result;
+    @Nullable
+    public static Drawable resolveImage(@Nullable Icon icon, Context context) throws IOException {
+        return resolveImage(icon, context, DEFAULT_MAX_SAFE_ICON_SIZE_PX,
+                DEFAULT_MAX_SAFE_ICON_SIZE_PX);
+    }
+
+    /**
+     * Get the drawable from Icon using {@link ImageDecoder} if it contains a bitmap reference, or
+     * using {@link Icon#loadDrawable(Context)} otherwise.  This will correctly apply the Icon's,
+     * tint, if present, to the drawable.
+     *
+     * @throws IOException if the icon could not be loaded for whichever reason
+     */
+    @Nullable
+    public static Drawable resolveImage(@Nullable Icon icon, Context context, int maxWidth,
+            int maxHeight) {
+        if (icon == null) {
+            return null;
         }
+
+        switch (icon.getType()) {
+            case Icon.TYPE_URI:
+            case Icon.TYPE_URI_ADAPTIVE_BITMAP:
+                Uri uri = getResolvableUri(icon);
+                if (uri != null) {
+                    Drawable result = resolveImage(uri, context, maxWidth, maxHeight);
+                    if (result != null) {
+                        return tintDrawable(icon, result);
+                    }
+                }
+                break;
+            case Icon.TYPE_RESOURCE:
+                Drawable result = resolveImage(icon.getResId(), context, maxWidth, maxHeight);
+                if (result != null) {
+                    return tintDrawable(icon, result);
+                }
+                break;
+            case Icon.TYPE_BITMAP:
+            case Icon.TYPE_ADAPTIVE_BITMAP:
+                return resolveBitmapImage(icon, context, maxWidth, maxHeight);
+            case Icon.TYPE_DATA:    // We can't really improve on raw data images.
+            default:
+                break;
+        }
+
+        // Fallback to straight drawable load if we fail with more efficient approach.
+        try {
+            return icon.loadDrawable(context);
+        } catch (Resources.NotFoundException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Attempts to resolve the resource as a bitmap drawable constrained within max sizes.
+     */
+    @Nullable
+    public static Drawable resolveImage(Uri uri, Context context, int maxWidth, int maxHeight) {
+        final ImageDecoder.Source source =
+                ImageDecoder.createSource(context.getContentResolver(), uri);
+        return resolveImage(source, maxWidth, maxHeight);
+    }
+
+    /**
+     * Attempts to resolve the resource as a bitmap drawable constrained within max sizes.
+     *
+     * @return decoded drawable or null if the passed resource is not a straight bitmap
+     */
+    @Nullable
+    public static Drawable resolveImage(@DrawableRes int resId, Context context, int maxWidth,
+            int maxHeight) {
+        final ImageDecoder.Source source = ImageDecoder.createSource(context.getResources(), resId);
+        return resolveImage(source, maxWidth, maxHeight);
+    }
+
+    @Nullable
+    private static Drawable resolveBitmapImage(Icon icon, Context context, int maxWidth,
+            int maxHeight) {
+        Bitmap bitmap = icon.getBitmap();
+        if (bitmap == null) {
+            return null;
+        }
+
+        if (bitmap.getWidth() > maxWidth || bitmap.getHeight() > maxHeight) {
+            Icon smallerIcon = icon.getType() == Icon.TYPE_ADAPTIVE_BITMAP
+                    ? Icon.createWithAdaptiveBitmap(bitmap) : Icon.createWithBitmap(bitmap);
+            // We don't want to modify the source icon, create a copy.
+            smallerIcon.setTintList(icon.getTintList())
+                    .setTintBlendMode(icon.getTintBlendMode())
+                    .scaleDownIfNecessary(maxWidth, maxHeight);
+            return smallerIcon.loadDrawable(context);
+        }
+
         return icon.loadDrawable(context);
     }
 
-    public static Drawable resolveImage(Uri uri, Context context, int maxWidth, int maxHeight)
-            throws IOException {
-        final ImageDecoder.Source source =
-                ImageDecoder.createSource(context.getContentResolver(), uri);
-        return ImageDecoder.decodeDrawable(source, (decoder, info, unused) -> {
-            final Size size = info.getSize();
-            if (size.getWidth() > size.getHeight()) {
-                if (size.getWidth() > maxWidth) {
-                    final int targetHeight = size.getHeight() * maxWidth / size.getWidth();
-                    decoder.setTargetSize(maxWidth, targetHeight);
+    @Nullable
+    private static Drawable tintDrawable(Icon icon, @Nullable Drawable drawable) {
+        if (drawable == null) {
+            return null;
+        }
+
+        if (icon.hasTint()) {
+            drawable.mutate();
+            drawable.setTintList(icon.getTintList());
+            drawable.setTintBlendMode(icon.getTintBlendMode());
+        }
+
+        return drawable;
+    }
+
+    private static Drawable resolveImage(ImageDecoder.Source source, int maxWidth, int maxHeight) {
+        try {
+            return ImageDecoder.decodeDrawable(source, (decoder, info, unused) -> {
+                if (maxWidth <= 0 || maxHeight <= 0) {
+                    return;
                 }
-            } else {
-                if (size.getHeight() > maxHeight) {
-                    final int targetWidth = size.getWidth() * maxHeight / size.getHeight();
-                    decoder.setTargetSize(targetWidth, maxHeight);
+
+                final Size size = info.getSize();
+                if (size.getWidth() > size.getHeight()) {
+                    if (size.getWidth() > maxWidth) {
+                        final int targetHeight = size.getHeight() * maxWidth / size.getWidth();
+                        decoder.setTargetSize(maxWidth, targetHeight);
+                    }
+                } else {
+                    if (size.getHeight() > maxHeight) {
+                        final int targetWidth = size.getWidth() * maxHeight / size.getHeight();
+                        decoder.setTargetSize(targetWidth, maxHeight);
+                    }
                 }
-            }
-        });
+            });
+
+        // ImageDecoder documentation is misleading a bit - it'll throw NotFoundException
+        // in some cases despite it not saying so. Rethrow it as an IOException to keep
+        // our API contract.
+        } catch (IOException | Resources.NotFoundException e) {
+            Log.e(TAG, "Failed to load image drawable", e);
+            return null;
+        }
     }
 
     private static int getPowerOfTwoForSampleRatio(double ratio) {
@@ -88,11 +213,12 @@
     }
 
     private static void onHeaderDecoded(ImageDecoder decoder, ImageDecoder.ImageInfo info,
-            ImageDecoder.Source source) {
+            int maxWidth, int maxHeight) {
         final Size size = info.getSize();
         final int originalSize = Math.max(size.getHeight(), size.getWidth());
-        final double ratio = (originalSize > MAX_SAFE_ICON_SIZE_PX)
-                ? originalSize * 1f / MAX_SAFE_ICON_SIZE_PX
+        final int maxSize = Math.max(maxWidth, maxHeight);
+        final double ratio = (originalSize > maxSize)
+                ? originalSize * 1f / maxSize
                 : 1.0;
         decoder.setTargetSampleSize(getPowerOfTwoForSampleRatio(ratio));
     }
@@ -101,7 +227,7 @@
      * Gets the Uri for this icon, assuming the icon can be treated as a pure Uri.  Null otherwise.
      */
     @Nullable
-    public static Uri getResolvableUri(@Nullable Icon icon) {
+    private static Uri getResolvableUri(@Nullable Icon icon) {
         if (icon == null || (icon.getType() != Icon.TYPE_URI
                 && icon.getType() != Icon.TYPE_URI_ADAPTIVE_BITMAP)) {
             return null;
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 82ae424..a94b307 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -526,20 +526,6 @@
     }
 
     /**
-     * Check to see if vold already has the password.
-     * Note that this also clears vold's copy of the password.
-     * @return Whether the vold password matches or not.
-     */
-    public boolean checkVoldPassword(int userId) {
-        try {
-            return getLockSettings().checkVoldPassword(userId);
-        } catch (RemoteException re) {
-            Log.e(TAG, "failed to check vold password", re);
-            return false;
-        }
-    }
-
-    /**
      * Returns the password history hash factor, needed to check new password against password
      * history with {@link #checkPasswordHistory(byte[], byte[], int)}
      */
@@ -808,7 +794,7 @@
      */
     public void setSeparateProfileChallengeEnabled(int userHandle, boolean enabled,
             LockscreenCredential profilePassword) {
-        if (!isCredentialSharedWithParent(userHandle)) {
+        if (!isCredentialSharableWithParent(userHandle)) {
             return;
         }
         try {
@@ -824,7 +810,7 @@
      * Returns true if {@code userHandle} is a managed profile with separate challenge.
      */
     public boolean isSeparateProfileChallengeEnabled(int userHandle) {
-        return isCredentialSharedWithParent(userHandle) && hasSeparateChallenge(userHandle);
+        return isCredentialSharableWithParent(userHandle) && hasSeparateChallenge(userHandle);
     }
 
     /**
@@ -849,8 +835,8 @@
         return info != null && info.isManagedProfile();
     }
 
-    private boolean isCredentialSharedWithParent(int userHandle) {
-        return getUserManager(userHandle).isCredentialSharedWithParent();
+    private boolean isCredentialSharableWithParent(int userHandle) {
+        return getUserManager(userHandle).isCredentialSharableWithParent();
     }
 
     /**
@@ -1135,7 +1121,7 @@
     public List<ComponentName> getEnabledTrustAgents(int userId) {
         String serialized = getString(ENABLED_TRUST_AGENTS, userId);
         if (TextUtils.isEmpty(serialized)) {
-            return null;
+            return new ArrayList<ComponentName>();
         }
         String[] split = serialized.split(",");
         ArrayList<ComponentName> activeTrustAgents = new ArrayList<ComponentName>(split.length);
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 2b6b933..fc5da13 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -35,7 +35,6 @@
 import android.graphics.Rect;
 import android.graphics.Shader;
 import android.graphics.drawable.Drawable;
-import android.media.AudioManager;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.Parcel;
@@ -45,6 +44,7 @@
 import android.util.IntArray;
 import android.util.Log;
 import android.util.SparseArray;
+import android.util.TypedValue;
 import android.view.HapticFeedbackConstants;
 import android.view.MotionEvent;
 import android.view.RenderNodeAnimator;
@@ -77,16 +77,18 @@
 
     private static final boolean PROFILE_DRAWING = false;
     private static final int LINE_END_ANIMATION_DURATION_MILLIS = 50;
-    private static final int LINE_FADE_OUT_DURATION_MILLIS = 500;
-    private static final int LINE_FADE_OUT_DELAY_MILLIS = 150;
     private static final int DOT_ACTIVATION_DURATION_MILLIS = 50;
     private static final int DOT_RADIUS_INCREASE_DURATION_MILLIS = 96;
     private static final int DOT_RADIUS_DECREASE_DURATION_MILLIS = 192;
+    private static final float MIN_DOT_HIT_FACTOR = 0.2f;
     private final CellState[][] mCellStates;
 
     private final int mDotSize;
     private final int mDotSizeActivated;
+    private final float mDotHitFactor;
     private final int mPathWidth;
+    private final int mLineFadeOutAnimationDurationMs;
+    private final int mLineFadeOutAnimationDelayMs;
 
     private boolean mDrawingProfilingStarted = false;
 
@@ -143,12 +145,11 @@
     private boolean mPatternInProgress = false;
     private boolean mFadePattern = true;
 
-    private float mHitFactor = 0.6f;
-
     @UnsupportedAppUsage
     private float mSquareWidth;
     @UnsupportedAppUsage
     private float mSquareHeight;
+    private float mDotHitRadius;
     private final LinearGradient mFadeOutGradientShader;
 
     private final Path mCurrentPath = new Path();
@@ -164,8 +165,7 @@
 
     private final Interpolator mFastOutSlowInInterpolator;
     private final Interpolator mLinearOutSlowInInterpolator;
-    private PatternExploreByTouchHelper mExploreByTouchHelper;
-    private AudioManager mAudioManager;
+    private final PatternExploreByTouchHelper mExploreByTouchHelper;
 
     private Drawable mSelectedDrawable;
     private Drawable mNotSelectedDrawable;
@@ -346,9 +346,17 @@
         mPathWidth = getResources().getDimensionPixelSize(R.dimen.lock_pattern_dot_line_width);
         mPathPaint.setStrokeWidth(mPathWidth);
 
+        mLineFadeOutAnimationDurationMs =
+            getResources().getInteger(R.integer.lock_pattern_line_fade_out_duration);
+        mLineFadeOutAnimationDelayMs =
+            getResources().getInteger(R.integer.lock_pattern_line_fade_out_delay);
+
         mDotSize = getResources().getDimensionPixelSize(R.dimen.lock_pattern_dot_size);
         mDotSizeActivated = getResources().getDimensionPixelSize(
                 R.dimen.lock_pattern_dot_size_activated);
+        TypedValue outValue = new TypedValue();
+        getResources().getValue(R.dimen.lock_pattern_dot_hit_factor, outValue, true);
+        mDotHitFactor = Math.max(Math.min(outValue.getFloat(), 1f), MIN_DOT_HIT_FACTOR);
 
         mUseLockPatternDrawable = getResources().getBoolean(R.bool.use_lock_pattern_drawable);
         if (mUseLockPatternDrawable) {
@@ -375,7 +383,6 @@
                 AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in);
         mExploreByTouchHelper = new PatternExploreByTouchHelper(this);
         setAccessibilityDelegate(mExploreByTouchHelper);
-        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
 
         int fadeAwayGradientWidth = getResources().getDimensionPixelSize(
                 R.dimen.lock_pattern_fade_away_gradient_width);
@@ -679,6 +686,7 @@
         final int height = h - mPaddingTop - mPaddingBottom;
         mSquareHeight = height / 3.0f;
         mExploreByTouchHelper.invalidateRoot();
+        mDotHitRadius = Math.min(mSquareHeight / 2, mSquareWidth / 2) * mDotHitFactor;
 
         if (mUseLockPatternDrawable) {
             mNotSelectedDrawable.setBounds(mPaddingLeft, mPaddingTop, width, height);
@@ -765,8 +773,7 @@
             }
             addCellToPattern(cell);
             performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
-                    HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
-                    | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
+                    HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
             return cell;
         }
         return null;
@@ -829,7 +836,7 @@
         deactivateAnimator.setDuration(DOT_ACTIVATION_DURATION_MILLIS);
         AnimatorSet set = new AnimatorSet();
         set.play(deactivateAnimator)
-                .after(LINE_FADE_OUT_DELAY_MILLIS + LINE_FADE_OUT_DURATION_MILLIS
+                .after(mLineFadeOutAnimationDelayMs + mLineFadeOutAnimationDurationMs
                         - DOT_ACTIVATION_DURATION_MILLIS * 2)
                 .after(activateAnimator);
         return set;
@@ -860,8 +867,8 @@
     private Animator createLineDisappearingAnimation() {
         ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
         valueAnimator.addUpdateListener(animation -> invalidate());
-        valueAnimator.setStartDelay(LINE_FADE_OUT_DELAY_MILLIS);
-        valueAnimator.setDuration(LINE_FADE_OUT_DURATION_MILLIS);
+        valueAnimator.setStartDelay(mLineFadeOutAnimationDelayMs);
+        valueAnimator.setDuration(mLineFadeOutAnimationDurationMs);
         return valueAnimator;
     }
 
@@ -890,63 +897,30 @@
         return set;
     }
 
-    // helper method to find which cell a point maps to
+    @Nullable
     private Cell checkForNewHit(float x, float y) {
-
-        final int rowHit = getRowHit(y);
-        if (rowHit < 0) {
-            return null;
+        Cell cellHit = detectCellHit(x, y);
+        if (cellHit != null && !mPatternDrawLookup[cellHit.row][cellHit.column]) {
+            return cellHit;
         }
-        final int columnHit = getColumnHit(x);
-        if (columnHit < 0) {
-            return null;
-        }
-
-        if (mPatternDrawLookup[rowHit][columnHit]) {
-            return null;
-        }
-        return Cell.of(rowHit, columnHit);
+        return null;
     }
 
-    /**
-     * Helper method to find the row that y falls into.
-     * @param y The y coordinate
-     * @return The row that y falls in, or -1 if it falls in no row.
-     */
-    private int getRowHit(float y) {
-
-        final float squareHeight = mSquareHeight;
-        float hitSize = squareHeight * mHitFactor;
-
-        float offset = mPaddingTop + (squareHeight - hitSize) / 2f;
-        for (int i = 0; i < 3; i++) {
-
-            final float hitTop = offset + squareHeight * i;
-            if (y >= hitTop && y <= hitTop + hitSize) {
-                return i;
+    /** Helper method to find which cell a point maps to. */
+    @Nullable
+    private Cell detectCellHit(float x, float y) {
+        final float hitRadiusSquared = mDotHitRadius * mDotHitRadius;
+        for (int row = 0; row < 3; row++) {
+            for (int column = 0; column < 3; column++) {
+                float centerY = getCenterYForRow(row);
+                float centerX = getCenterXForColumn(column);
+                if ((x - centerX) * (x - centerX) + (y - centerY) * (y - centerY)
+                        < hitRadiusSquared) {
+                    return Cell.of(row, column);
+                }
             }
         }
-        return -1;
-    }
-
-    /**
-     * Helper method to find the column x fallis into.
-     * @param x The x coordinate.
-     * @return The column that x falls in, or -1 if it falls in no column.
-     */
-    private int getColumnHit(float x) {
-        final float squareWidth = mSquareWidth;
-        float hitSize = squareWidth * mHitFactor;
-
-        float offset = mPaddingLeft + (squareWidth - hitSize) / 2f;
-        for (int i = 0; i < 3; i++) {
-
-            final float hitLeft = offset + squareWidth * i;
-            if (x >= hitLeft && x <= hitLeft + hitSize) {
-                return i;
-            }
-        }
-        return -1;
+        return null;
     }
 
     @Override
@@ -1309,14 +1283,14 @@
         float fadeAwayProgress;
         if (mFadePattern) {
             if (elapsedRealtime - lineFadeStart
-                    >= LINE_FADE_OUT_DELAY_MILLIS + LINE_FADE_OUT_DURATION_MILLIS) {
+                    >= mLineFadeOutAnimationDelayMs + mLineFadeOutAnimationDurationMs) {
                 // Time for this segment animation is out so we don't need to draw it.
                 return;
             }
             // Set this line segment to fade away animated.
             fadeAwayProgress = Math.max(
-                    ((float) (elapsedRealtime - lineFadeStart - LINE_FADE_OUT_DELAY_MILLIS))
-                            / LINE_FADE_OUT_DURATION_MILLIS, 0f);
+                    ((float) (elapsedRealtime - lineFadeStart - mLineFadeOutAnimationDelayMs))
+                            / mLineFadeOutAnimationDurationMs, 0f);
             drawFadingAwayLineSegment(canvas, startX, startY, endX, endY, fadeAwayProgress);
         } else {
             mPathPaint.setAlpha(255);
@@ -1553,8 +1527,7 @@
         protected int getVirtualViewAt(float x, float y) {
             // This must use the same hit logic for the screen to ensure consistency whether
             // accessibility is on or off.
-            int id = getVirtualViewIdForHit(x, y);
-            return id;
+            return getVirtualViewIdForHit(x, y);
         }
 
         @Override
@@ -1670,12 +1643,11 @@
             final int col = ordinal % 3;
             float centerX = getCenterXForColumn(col);
             float centerY = getCenterYForRow(row);
-            float cellheight = mSquareHeight * mHitFactor * 0.5f;
-            float cellwidth = mSquareWidth * mHitFactor * 0.5f;
-            bounds.left = (int) (centerX - cellwidth);
-            bounds.right = (int) (centerX + cellwidth);
-            bounds.top = (int) (centerY - cellheight);
-            bounds.bottom = (int) (centerY + cellheight);
+            float cellHitRadius = mDotHitRadius;
+            bounds.left = (int) (centerX - cellHitRadius);
+            bounds.right = (int) (centerX + cellHitRadius);
+            bounds.top = (int) (centerY - cellHitRadius);
+            bounds.bottom = (int) (centerY + cellHitRadius);
             return bounds;
         }
 
@@ -1694,16 +1666,12 @@
          * @return VIRTUAL_BASE_VIEW_ID+id or 0 if no view was hit
          */
         private int getVirtualViewIdForHit(float x, float y) {
-            final int rowHit = getRowHit(y);
-            if (rowHit < 0) {
+            Cell cellHit = detectCellHit(x, y);
+            if (cellHit == null) {
                 return ExploreByTouchHelper.INVALID_ID;
             }
-            final int columnHit = getColumnHit(x);
-            if (columnHit < 0) {
-                return ExploreByTouchHelper.INVALID_ID;
-            }
-            boolean dotAvailable = mPatternDrawLookup[rowHit][columnHit];
-            int dotId = (rowHit * 3 + columnHit) + VIRTUAL_BASE_VIEW_ID;
+            boolean dotAvailable = mPatternDrawLookup[cellHit.row][cellHit.column];
+            int dotId = (cellHit.row * 3 + cellHit.column) + VIRTUAL_BASE_VIEW_ID;
             int view = dotAvailable ? dotId : ExploreByTouchHelper.INVALID_ID;
             if (DEBUG_A11Y) Log.v(TAG, "getVirtualViewIdForHit(" + x + "," + y + ") => "
                     + view + "avail =" + dotAvailable);
diff --git a/core/java/com/android/internal/widget/LockscreenCredential.java b/core/java/com/android/internal/widget/LockscreenCredential.java
index 361ba95..1074004 100644
--- a/core/java/com/android/internal/widget/LockscreenCredential.java
+++ b/core/java/com/android/internal/widget/LockscreenCredential.java
@@ -175,27 +175,6 @@
         return mCredential;
     }
 
-    /**
-     *  Returns the credential type recognized by {@link StorageManager}. Can be one of
-     *  {@link StorageManager#CRYPT_TYPE_DEFAULT}, {@link StorageManager#CRYPT_TYPE_PATTERN},
-     *  {@link StorageManager#CRYPT_TYPE_PIN} or {@link StorageManager#CRYPT_TYPE_PASSWORD}.
-     */
-    public int getStorageCryptType() {
-        if (isNone()) {
-            return StorageManager.CRYPT_TYPE_DEFAULT;
-        }
-        if (isPattern()) {
-            return StorageManager.CRYPT_TYPE_PATTERN;
-        }
-        if (isPin()) {
-            return StorageManager.CRYPT_TYPE_PIN;
-        }
-        if (isPassword()) {
-            return StorageManager.CRYPT_TYPE_PASSWORD;
-        }
-        throw new IllegalStateException("Unhandled credential type");
-    }
-
     /** Returns whether this is an empty credential */
     public boolean isNone() {
         ensureNotZeroized();
diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java
index 9e06e33..146cb3f 100644
--- a/core/java/com/android/internal/widget/MessagingGroup.java
+++ b/core/java/com/android/internal/widget/MessagingGroup.java
@@ -262,7 +262,8 @@
         return createdGroup;
     }
 
-    public void removeMessage(MessagingMessage messagingMessage) {
+    public void removeMessage(MessagingMessage messagingMessage,
+            ArrayList<MessagingLinearLayout.MessagingChild> toRecycle) {
         View view = messagingMessage.getView();
         boolean wasShown = view.isShown();
         ViewGroup messageParent = (ViewGroup) view.getParent();
@@ -270,15 +271,14 @@
             return;
         }
         messageParent.removeView(view);
-        Runnable recycleRunnable = () -> {
-            messageParent.removeTransientView(view);
-            messagingMessage.recycle();
-        };
         if (wasShown && !MessagingLinearLayout.isGone(view)) {
             messageParent.addTransientView(view, 0);
-            performRemoveAnimation(view, recycleRunnable);
+            performRemoveAnimation(view, () -> {
+                messageParent.removeTransientView(view);
+                messagingMessage.recycle();
+            });
         } else {
-            recycleRunnable.run();
+            toRecycle.add(messagingMessage);
         }
     }
 
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
index 21ca196..9ac6ef7 100644
--- a/core/java/com/android/internal/widget/MessagingLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -51,7 +51,6 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
-import java.util.function.Consumer;
 
 /**
  * A custom-built layout for the Notification.MessagingStyle allows dynamic addition and removal
@@ -62,8 +61,6 @@
         implements ImageMessageConsumer, IMessagingLayout {
 
     private static final float COLOR_SHIFT_AMOUNT = 60;
-    private static final Consumer<MessagingMessage> REMOVE_MESSAGE
-            = MessagingMessage::removeMessage;
     public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f);
     public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
     public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
@@ -89,6 +86,7 @@
     private boolean mIsCollapsed;
     private ImageResolver mImageResolver;
     private CharSequence mConversationTitle;
+    private ArrayList<MessagingLinearLayout.MessagingChild> mToRecycle = new ArrayList<>();
 
     public MessagingLayout(@NonNull Context context) {
         super(context);
@@ -212,8 +210,12 @@
         removeGroups(oldGroups);
 
         // Let's remove the remaining messages
-        mMessages.forEach(REMOVE_MESSAGE);
-        mHistoricMessages.forEach(REMOVE_MESSAGE);
+        for (MessagingMessage message : mMessages) {
+            message.removeMessage(mToRecycle);
+        }
+        for (MessagingMessage historicMessage : mHistoricMessages) {
+            historicMessage.removeMessage(mToRecycle);
+        }
 
         mMessages = messages;
         mHistoricMessages = historicMessages;
@@ -223,6 +225,12 @@
         // after groups are finalized, hide the first sender name if it's showing as the title
         mPeopleHelper.maybeHideFirstSenderName(mGroups, mIsOneToOne, mConversationTitle);
         updateImageMessages();
+
+        // Recycle everything at the end of the update, now that we know it's no longer needed.
+        for (MessagingLinearLayout.MessagingChild child : mToRecycle) {
+            child.recycle();
+        }
+        mToRecycle.clear();
     }
 
     private void updateImageMessages() {
@@ -263,18 +271,17 @@
             MessagingGroup group = oldGroups.get(i);
             if (!mGroups.contains(group)) {
                 List<MessagingMessage> messages = group.getMessages();
-                Runnable endRunnable = () -> {
-                    mMessagingLinearLayout.removeTransientView(group);
-                    group.recycle();
-                };
 
                 boolean wasShown = group.isShown();
                 mMessagingLinearLayout.removeView(group);
                 if (wasShown && !MessagingLinearLayout.isGone(group)) {
                     mMessagingLinearLayout.addTransientView(group, 0);
-                    group.removeGroupAnimated(endRunnable);
+                    group.removeGroupAnimated(() -> {
+                        mMessagingLinearLayout.removeTransientView(group);
+                        group.recycle();
+                    });
                 } else {
-                    endRunnable.run();
+                    mToRecycle.add(group);
                 }
                 mMessages.removeAll(messages);
                 mHistoricMessages.removeAll(messages);
diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java
index cb1d387..c06f5f7 100644
--- a/core/java/com/android/internal/widget/MessagingLinearLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java
@@ -365,6 +365,7 @@
         default int getExtraSpacing() {
             return 0;
         }
+        void recycle();
     }
 
     public static class LayoutParams extends MarginLayoutParams {
diff --git a/core/java/com/android/internal/widget/MessagingMessage.java b/core/java/com/android/internal/widget/MessagingMessage.java
index 8c84379..2cc0d23 100644
--- a/core/java/com/android/internal/widget/MessagingMessage.java
+++ b/core/java/com/android/internal/widget/MessagingMessage.java
@@ -20,6 +20,7 @@
 import android.app.Notification;
 import android.view.View;
 
+import java.util.ArrayList;
 import java.util.Objects;
 
 /**
@@ -96,8 +97,8 @@
         return sameAs(message.getMessage());
     }
 
-    default void removeMessage() {
-        getGroup().removeMessage(this);
+    default void removeMessage(ArrayList<MessagingLinearLayout.MessagingChild> toRecycle) {
+        getGroup().removeMessage(this, toRecycle);
     }
 
     default void setMessagingGroup(MessagingGroup group) {
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index b1846d2..db41d33 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -31,9 +31,11 @@
 import android.os.Process;
 import android.os.SystemProperties;
 import android.os.Trace;
+import android.os.VintfRuntimeInfo;
 import android.os.incremental.IncrementalManager;
 import android.os.storage.StorageManager;
 import android.permission.PermissionManager.SplitPermissionInfo;
+import android.sysprop.ApexProperties;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -56,7 +58,10 @@
 import java.io.FileNotFoundException;
 import java.io.FileReader;
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -435,15 +440,15 @@
     }
 
     /** Get privapp permission allowlist for an apk-in-apex. */
-    public ArraySet<String> getApexPrivAppPermissions(String module, String packageName) {
-        return mApexPrivAppPermissions.getOrDefault(module, EMPTY_PERMISSIONS)
-                .get(packageName);
+    public ArraySet<String> getApexPrivAppPermissions(String apexName, String apkPackageName) {
+        return mApexPrivAppPermissions.getOrDefault(apexName, EMPTY_PERMISSIONS)
+                .get(apkPackageName);
     }
 
     /** Get privapp permissions denylist for an apk-in-apex. */
-    public ArraySet<String> getApexPrivAppDenyPermissions(String module, String packageName) {
-        return mApexPrivAppDenyPermissions.getOrDefault(module, EMPTY_PERMISSIONS)
-                .get(packageName);
+    public ArraySet<String> getApexPrivAppDenyPermissions(String apexName, String apkPackageName) {
+        return mApexPrivAppDenyPermissions.getOrDefault(apexName, EMPTY_PERMISSIONS)
+                .get(apkPackageName);
     }
 
     public ArraySet<String> getVendorPrivAppPermissions(String packageName) {
@@ -1187,7 +1192,8 @@
                             boolean systemExt = permFile.toPath().startsWith(
                                     Environment.getSystemExtDirectory().toPath() + "/");
                             boolean apex = permFile.toPath().startsWith(
-                                    Environment.getApexDirectory().toPath() + "/");
+                                    Environment.getApexDirectory().toPath() + "/")
+                                    && ApexProperties.updatable().orElse(false);
                             if (vendor) {
                                 readPrivAppPermissions(parser, mVendorPrivAppPermissions,
                                         mVendorPrivAppDenyPermissions);
@@ -1445,6 +1451,14 @@
             addFeature(PackageManager.FEATURE_IPSEC_TUNNELS, 0);
         }
 
+        if (isFilesystemSupported("erofs")) {
+            if (isKernelVersionAtLeast(5, 10)) {
+                addFeature(PackageManager.FEATURE_EROFS, 0);
+            } else if (isKernelVersionAtLeast(4, 19)) {
+                addFeature(PackageManager.FEATURE_EROFS_LEGACY, 0);
+            }
+        }
+
         for (String featureName : mUnavailableFeatures) {
             removeFeature(featureName);
         }
@@ -1814,4 +1828,29 @@
     private static boolean isSystemProcess() {
         return Process.myUid() == Process.SYSTEM_UID;
     }
+
+    private static boolean isFilesystemSupported(String fs) {
+        try {
+            final byte[] fsTableData = Files.readAllBytes(Paths.get("/proc/filesystems"));
+            final String fsTable = new String(fsTableData, StandardCharsets.UTF_8);
+            return fsTable.contains("\t" + fs + "\n");
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    private static boolean isKernelVersionAtLeast(int major, int minor) {
+        final String kernelVersion = VintfRuntimeInfo.getKernelVersion();
+        final String[] parts = kernelVersion.split("\\.");
+        if (parts.length < 2) {
+            return false;
+        }
+        try {
+            final int majorVersion = Integer.parseInt(parts[0]);
+            final int minorVersion = Integer.parseInt(parts[1]);
+            return majorVersion > major || (majorVersion == major && minorVersion >= minor);
+        } catch (NumberFormatException e) {
+            return false;
+        }
+    }
 }
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 4aa00f6..a1be884 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -272,6 +272,7 @@
                 "libinput",
                 "libcamera_client",
                 "libcamera_metadata",
+                "libprocinfo",
                 "libsqlite",
                 "libEGL",
                 "libGLESv1_CM",
@@ -361,7 +362,7 @@
                 "libwuffs_mirror_release_c",
             ],
         },
-        linux_glibc: {
+        host_linux: {
             srcs: [
                 "android_content_res_ApkAssets.cpp",
                 "android_database_CursorWindow.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index eedf7fa..eba6cca 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -1567,6 +1567,7 @@
         REG_JNI(register_android_graphics_classes),
         REG_JNI(register_android_graphics_BLASTBufferQueue),
         REG_JNI(register_android_graphics_GraphicBuffer),
+        REG_JNI(register_android_graphics_GraphicsStatsService),
         REG_JNI(register_android_graphics_SurfaceTexture),
         REG_JNI(register_android_database_CursorWindow),
         REG_JNI(register_android_database_SQLiteConnection),
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 13ca133..f28e2f6 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -396,6 +396,9 @@
     {
         JNIEnv* env = javavm_to_jnienv(mVM);
 
+        LOG_ALWAYS_FATAL_IF(env == nullptr,
+                            "Binder thread started or Java binder used, but env null. Attach JVM?");
+
         ALOGV("onTransact() on %p calling object %p in env %p vm %p\n", this, mObject, env, mVM);
 
         IPCThreadState* thread_state = IPCThreadState::self();
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 19402f7..0585586 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -108,6 +108,32 @@
     DisplayEventDispatcher::dispose();
 }
 
+static jobject createJavaVsyncEventData(JNIEnv* env, VsyncEventData vsyncEventData) {
+    ScopedLocalRef<jobjectArray>
+            frameTimelineObjs(env,
+                              env->NewObjectArray(VsyncEventData::kFrameTimelinesLength,
+                                                  gDisplayEventReceiverClassInfo
+                                                          .frameTimelineClassInfo.clazz,
+                                                  /*initial element*/ NULL));
+    for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
+        VsyncEventData::FrameTimeline frameTimeline = vsyncEventData.frameTimelines[i];
+        ScopedLocalRef<jobject>
+                frameTimelineObj(env,
+                                 env->NewObject(gDisplayEventReceiverClassInfo
+                                                        .frameTimelineClassInfo.clazz,
+                                                gDisplayEventReceiverClassInfo
+                                                        .frameTimelineClassInfo.init,
+                                                frameTimeline.vsyncId,
+                                                frameTimeline.expectedPresentationTime,
+                                                frameTimeline.deadlineTimestamp));
+        env->SetObjectArrayElement(frameTimelineObjs.get(), i, frameTimelineObj.get());
+    }
+    return env->NewObject(gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
+                          gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.init,
+                          frameTimelineObjs.get(), vsyncEventData.preferredFrameTimelineIndex,
+                          vsyncEventData.frameInterval);
+}
+
 void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId,
                                                uint32_t count, VsyncEventData vsyncEventData) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
@@ -116,37 +142,9 @@
     if (receiverObj.get()) {
         ALOGV("receiver %p ~ Invoking vsync handler.", this);
 
-        ScopedLocalRef<jobjectArray>
-                frameTimelineObjs(env,
-                                  env->NewObjectArray(VsyncEventData::kFrameTimelinesLength,
-                                                      gDisplayEventReceiverClassInfo
-                                                              .frameTimelineClassInfo.clazz,
-                                                      /*initial element*/ NULL));
-        for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
-            VsyncEventData::FrameTimeline frameTimeline = vsyncEventData.frameTimelines[i];
-            ScopedLocalRef<jobject>
-                    frameTimelineObj(env,
-                                     env->NewObject(gDisplayEventReceiverClassInfo
-                                                            .frameTimelineClassInfo.clazz,
-                                                    gDisplayEventReceiverClassInfo
-                                                            .frameTimelineClassInfo.init,
-                                                    frameTimeline.vsyncId,
-                                                    frameTimeline.expectedPresentationTime,
-                                                    frameTimeline.deadlineTimestamp));
-            env->SetObjectArrayElement(frameTimelineObjs.get(), i, frameTimelineObj.get());
-        }
-        ScopedLocalRef<jobject>
-                vsyncEventDataJava(env,
-                                   env->NewObject(gDisplayEventReceiverClassInfo
-                                                          .vsyncEventDataClassInfo.clazz,
-                                                  gDisplayEventReceiverClassInfo
-                                                          .vsyncEventDataClassInfo.init,
-                                                  frameTimelineObjs.get(),
-                                                  vsyncEventData.preferredFrameTimelineIndex,
-                                                  vsyncEventData.frameInterval));
-
+        jobject javaVsyncEventData = createJavaVsyncEventData(env, vsyncEventData);
         env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync,
-                            timestamp, displayId.value, count, vsyncEventDataJava.get());
+                            timestamp, displayId.value, count, javaVsyncEventData);
         ALOGV("receiver %p ~ Returned from vsync handler.", this);
     }
 
@@ -255,19 +253,27 @@
     }
 }
 
+static jobject nativeGetLatestVsyncEventData(JNIEnv* env, jclass clazz, jlong receiverPtr) {
+    sp<NativeDisplayEventReceiver> receiver =
+            reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
+    gui::ParcelableVsyncEventData parcelableVsyncEventData;
+    status_t status = receiver->getLatestVsyncEventData(&parcelableVsyncEventData);
+    if (status) {
+        ALOGW("Failed to get latest vsync event data from surface flinger");
+        return NULL;
+    }
+    return createJavaVsyncEventData(env, parcelableVsyncEventData.vsync);
+}
 
 static const JNINativeMethod gMethods[] = {
-    /* name, signature, funcPtr */
-    { "nativeInit",
-            "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;II)J",
-            (void*)nativeInit },
-    { "nativeDispose",
-            "(J)V",
-            (void*)nativeDispose },
-    // @FastNative
-    { "nativeScheduleVsync", "(J)V",
-            (void*)nativeScheduleVsync }
-};
+        /* name, signature, funcPtr */
+        {"nativeInit", "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;II)J",
+         (void*)nativeInit},
+        {"nativeDispose", "(J)V", (void*)nativeDispose},
+        // @FastNative
+        {"nativeScheduleVsync", "(J)V", (void*)nativeScheduleVsync},
+        {"nativeGetLatestVsyncEventData", "(J)Landroid/view/DisplayEventReceiver$VsyncEventData;",
+         (void*)nativeGetLatestVsyncEventData}};
 
 int register_android_view_DisplayEventReceiver(JNIEnv* env) {
     int res = RegisterMethodsOrDie(env, "android/view/DisplayEventReceiver", gMethods,
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 68025a8..39f192b 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -253,6 +253,11 @@
     jfieldID alphaInterpretation;
 } gDisplayDecorationSupportInfo;
 
+static struct {
+    jclass clazz;
+    jmethodID invokeReleaseCallback;
+} gInvokeReleaseCallback;
+
 class JNamedColorSpace {
 public:
     // ColorSpace.Named.SRGB.ordinal() = 0;
@@ -625,8 +630,59 @@
     transaction->setGeometry(ctrl, source, dst, orientation);
 }
 
+class JGlobalRefHolder {
+public:
+    JGlobalRefHolder(JavaVM* vm, jobject object) : mVm(vm), mObject(object) {}
+
+    virtual ~JGlobalRefHolder() {
+        env()->DeleteGlobalRef(mObject);
+        mObject = nullptr;
+    }
+
+    jobject object() { return mObject; }
+    JavaVM* vm() { return mVm; }
+
+    JNIEnv* env() {
+        JNIEnv* env = nullptr;
+        if (mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+            if (mVm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) {
+                LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!");
+            }
+        }
+        return env;
+    }
+
+private:
+    JGlobalRefHolder(const JGlobalRefHolder&) = delete;
+    void operator=(const JGlobalRefHolder&) = delete;
+
+    JavaVM* mVm;
+    jobject mObject;
+};
+
+static ReleaseBufferCallback genReleaseCallback(JNIEnv* env, jobject releaseCallback) {
+    if (releaseCallback == nullptr) return nullptr;
+
+    JavaVM* vm = nullptr;
+    LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM");
+    auto globalCallbackRef =
+            std::make_shared<JGlobalRefHolder>(vm, env->NewGlobalRef(releaseCallback));
+    return [globalCallbackRef](const ReleaseCallbackId&, const sp<Fence>& releaseFence,
+                               std::optional<uint32_t> currentMaxAcquiredBufferCount) {
+        Fence* fenceCopy = releaseFence.get();
+        // We need to grab an extra ref as Java's SyncFence takes ownership
+        if (fenceCopy) {
+            fenceCopy->incStrong(0);
+        }
+        globalCallbackRef->env()->CallStaticVoidMethod(gInvokeReleaseCallback.clazz,
+                                                       gInvokeReleaseCallback.invokeReleaseCallback,
+                                                       globalCallbackRef->object(),
+                                                       reinterpret_cast<jlong>(fenceCopy));
+    };
+}
+
 static void nativeSetBuffer(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject,
-                            jobject bufferObject, jlong fencePtr) {
+                            jobject bufferObject, jlong fencePtr, jobject releaseCallback) {
     auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
     sp<GraphicBuffer> graphicBuffer(GraphicBuffer::fromAHardwareBuffer(
@@ -635,7 +691,8 @@
     if (fencePtr != 0) {
         optFence = sp<Fence>{reinterpret_cast<Fence*>(fencePtr)};
     }
-    transaction->setBuffer(ctrl, graphicBuffer, optFence);
+    transaction->setBuffer(ctrl, graphicBuffer, optFence, std::nullopt,
+                           genReleaseCallback(env, releaseCallback));
 }
 
 static void nativeSetBufferTransform(JNIEnv* env, jclass clazz, jlong transactionObj,
@@ -2155,7 +2212,7 @@
             (void*)nativeGetDisplayedContentSample },
     {"nativeSetGeometry", "(JJLandroid/graphics/Rect;Landroid/graphics/Rect;J)V",
             (void*)nativeSetGeometry },
-    {"nativeSetBuffer", "(JJLandroid/hardware/HardwareBuffer;J)V",
+    {"nativeSetBuffer", "(JJLandroid/hardware/HardwareBuffer;JLjava/util/function/Consumer;)V",
             (void*)nativeSetBuffer },
     {"nativeSetBufferTransform", "(JJI)V", (void*) nativeSetBufferTransform},
     {"nativeSetDataSpace", "(JJI)V",
@@ -2451,6 +2508,12 @@
     gDisplayDecorationSupportInfo.alphaInterpretation =
             GetFieldIDOrDie(env, displayDecorationSupportClazz, "alphaInterpretation", "I");
 
+    jclass surfaceControlClazz = FindClassOrDie(env, "android/view/SurfaceControl");
+    gInvokeReleaseCallback.clazz = MakeGlobalRefOrDie(env, surfaceControlClazz);
+    gInvokeReleaseCallback.invokeReleaseCallback =
+            GetStaticMethodIDOrDie(env, surfaceControlClazz, "invokeReleaseCallback",
+                                   "(Ljava/util/function/Consumer;J)V");
+
     return err;
 }
 
diff --git a/core/jni/android_window_WindowInfosListener.cpp b/core/jni/android_window_WindowInfosListener.cpp
index 08c9f20..aae2549 100644
--- a/core/jni/android_window_WindowInfosListener.cpp
+++ b/core/jni/android_window_WindowInfosListener.cpp
@@ -44,6 +44,11 @@
     jmethodID ctor;
 } gDisplayInfoClassInfo;
 
+static struct {
+    jclass clazz;
+    jmethodID ctor;
+} gPairClassInfo;
+
 static jclass gInputWindowHandleClass;
 
 jobject fromDisplayInfo(JNIEnv* env, gui::DisplayInfo displayInfo) {
@@ -57,6 +62,30 @@
                           displayInfo.logicalHeight, matrixObj.get());
 }
 
+static jobjectArray fromWindowInfos(JNIEnv* env, const std::vector<WindowInfo>& windowInfos) {
+    jobjectArray jWindowHandlesArray =
+            env->NewObjectArray(windowInfos.size(), gInputWindowHandleClass, nullptr);
+    for (int i = 0; i < windowInfos.size(); i++) {
+        ScopedLocalRef<jobject>
+                jWindowHandle(env,
+                              android_view_InputWindowHandle_fromWindowInfo(env, windowInfos[i]));
+        env->SetObjectArrayElement(jWindowHandlesArray, i, jWindowHandle.get());
+    }
+
+    return jWindowHandlesArray;
+}
+
+static jobjectArray fromDisplayInfos(JNIEnv* env, const std::vector<DisplayInfo>& displayInfos) {
+    jobjectArray jDisplayInfoArray =
+            env->NewObjectArray(displayInfos.size(), gDisplayInfoClassInfo.clazz, nullptr);
+    for (int i = 0; i < displayInfos.size(); i++) {
+        ScopedLocalRef<jobject> jDisplayInfo(env, fromDisplayInfo(env, displayInfos[i]));
+        env->SetObjectArrayElement(jDisplayInfoArray, i, jDisplayInfo.get());
+    }
+
+    return jDisplayInfoArray;
+}
+
 struct WindowInfosListener : public gui::WindowInfosListener {
     WindowInfosListener(JNIEnv* env, jobject listener)
           : mListener(env->NewWeakGlobalRef(listener)) {}
@@ -72,26 +101,8 @@
             return;
         }
 
-        ScopedLocalRef<jobjectArray>
-                jWindowHandlesArray(env,
-                                    env->NewObjectArray(windowInfos.size(), gInputWindowHandleClass,
-                                                        nullptr));
-        for (int i = 0; i < windowInfos.size(); i++) {
-            ScopedLocalRef<jobject>
-                    jWindowHandle(env,
-                                  android_view_InputWindowHandle_fromWindowInfo(env,
-                                                                                windowInfos[i]));
-            env->SetObjectArrayElement(jWindowHandlesArray.get(), i, jWindowHandle.get());
-        }
-
-        ScopedLocalRef<jobjectArray>
-                jDisplayInfoArray(env,
-                                  env->NewObjectArray(displayInfos.size(),
-                                                      gDisplayInfoClassInfo.clazz, nullptr));
-        for (int i = 0; i < displayInfos.size(); i++) {
-            ScopedLocalRef<jobject> jDisplayInfo(env, fromDisplayInfo(env, displayInfos[i]));
-            env->SetObjectArrayElement(jDisplayInfoArray.get(), i, jDisplayInfo.get());
-        }
+        ScopedLocalRef<jobjectArray> jWindowHandlesArray(env, fromWindowInfos(env, windowInfos));
+        ScopedLocalRef<jobjectArray> jDisplayInfoArray(env, fromDisplayInfos(env, displayInfos));
 
         env->CallVoidMethod(listener, gListenerClassInfo.onWindowInfosChanged,
                             jWindowHandlesArray.get(), jDisplayInfoArray.get());
@@ -124,9 +135,16 @@
     listener->decStrong((void*)nativeCreate);
 }
 
-void nativeRegister(JNIEnv* env, jclass clazz, jlong ptr) {
+jobject nativeRegister(JNIEnv* env, jclass clazz, jlong ptr) {
     sp<WindowInfosListener> listener = reinterpret_cast<WindowInfosListener*>(ptr);
-    SurfaceComposerClient::getDefault()->addWindowInfosListener(listener);
+    std::pair<std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>> initialInfo;
+    SurfaceComposerClient::getDefault()->addWindowInfosListener(listener, &initialInfo);
+
+    ScopedLocalRef<jobjectArray> jWindowHandlesArray(env, fromWindowInfos(env, initialInfo.first));
+    ScopedLocalRef<jobjectArray> jDisplayInfoArray(env, fromDisplayInfos(env, initialInfo.second));
+
+    return env->NewObject(gPairClassInfo.clazz, gPairClassInfo.ctor, jWindowHandlesArray.get(),
+                          jDisplayInfoArray.get());
 }
 
 void nativeUnregister(JNIEnv* env, jclass clazz, jlong ptr) {
@@ -141,7 +159,7 @@
 const JNINativeMethod gMethods[] = {
         /* name, signature, funcPtr */
         {"nativeCreate", "(Landroid/window/WindowInfosListener;)J", (void*)nativeCreate},
-        {"nativeRegister", "(J)V", (void*)nativeRegister},
+        {"nativeRegister", "(J)Landroid/util/Pair;", (void*)nativeRegister},
         {"nativeUnregister", "(J)V", (void*)nativeUnregister},
         {"nativeGetFinalizer", "()J", (void*)nativeGetFinalizer}};
 
@@ -166,6 +184,12 @@
     gDisplayInfoClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
     gDisplayInfoClassInfo.ctor = env->GetMethodID(gDisplayInfoClassInfo.clazz, "<init>",
                                                   "(IIILandroid/graphics/Matrix;)V");
+
+    clazz = env->FindClass("android/util/Pair");
+    gPairClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
+    gPairClassInfo.ctor = env->GetMethodID(gPairClassInfo.clazz, "<init>",
+                                           "(Ljava/lang/Object;Ljava/lang/Object;)V");
+
     return 0;
 }
 
diff --git a/core/jni/com_android_internal_os_KernelAllocationStats.cpp b/core/jni/com_android_internal_os_KernelAllocationStats.cpp
index e0a24430..5b10497 100644
--- a/core/jni/com_android_internal_os_KernelAllocationStats.cpp
+++ b/core/jni/com_android_internal_os_KernelAllocationStats.cpp
@@ -13,12 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
 #include <dmabufinfo/dmabufinfo.h>
 #include <jni.h>
 #include <meminfo/sysmeminfo.h>
+#include <procinfo/process.h>
 
 #include "core_jni_helpers.h"
 
+using DmaBuffer = ::android::dmabufinfo::DmaBuffer;
+using android::base::ReadFileToString;
+using android::base::StringPrintf;
+
 namespace {
 static jclass gProcessDmabufClazz;
 static jmethodID gProcessDmabufCtor;
@@ -28,30 +35,127 @@
 
 namespace android {
 
-static jobject KernelAllocationStats_getDmabufAllocations(JNIEnv *env, jobject, jint pid) {
-    std::vector<dmabufinfo::DmaBuffer> buffers;
-    if (!dmabufinfo::ReadDmaBufMapRefs(pid, &buffers)) {
+struct PidDmaInfo {
+    uid_t uid;
+    std::string cmdline;
+    int oomScoreAdj;
+};
+
+static jobjectArray KernelAllocationStats_getDmabufAllocations(JNIEnv *env, jobject) {
+    std::vector<DmaBuffer> buffers;
+
+    if (!dmabufinfo::ReadDmaBufs(&buffers)) {
         return nullptr;
     }
-    jint mappedSize = 0;
-    jint mappedCount = buffers.size();
-    for (const auto &buffer : buffers) {
-        mappedSize += buffer.size();
-    }
-    mappedSize /= 1024;
 
-    jint retainedSize = -1;
-    jint retainedCount = -1;
-    if (dmabufinfo::ReadDmaBufFdRefs(pid, &buffers)) {
-        retainedCount = buffers.size();
-        retainedSize = 0;
-        for (const auto &buffer : buffers) {
-            retainedSize += buffer.size();
+    // Create a reverse map from pid to dmabufs
+    // Store dmabuf inodes & sizes for later processing.
+    std::unordered_map<pid_t, std::set<ino_t>> pidToInodes;
+    std::unordered_map<ino_t, long> inodeToSize;
+    for (auto &buf : buffers) {
+        for (auto pid : buf.pids()) {
+            pidToInodes[pid].insert(buf.inode());
         }
-        retainedSize /= 1024;
+        inodeToSize[buf.inode()] = buf.size();
     }
-    return env->NewObject(gProcessDmabufClazz, gProcessDmabufCtor, retainedSize, retainedCount,
-                          mappedSize, mappedCount);
+
+    pid_t surfaceFlingerPid = -1;
+    // The set of all inodes that are being retained by SurfaceFlinger. Buffers
+    // shared between another process and SF will appear in this set.
+    std::set<ino_t> surfaceFlingerBufferInodes;
+    // The set of all inodes that are being retained by any process other
+    // than SurfaceFlinger. Buffers shared between another process and SF will
+    // appear in this set.
+    std::set<ino_t> otherProcessBufferInodes;
+
+    // Find SurfaceFlinger pid & get cmdlines, oomScoreAdj, etc for each pid
+    // holding any DMA buffers.
+    std::unordered_map<pid_t, PidDmaInfo> pidDmaInfos;
+    for (const auto &pidToInodeEntry : pidToInodes) {
+        pid_t pid = pidToInodeEntry.first;
+
+        android::procinfo::ProcessInfo processInfo;
+        if (!android::procinfo::GetProcessInfo(pid, &processInfo)) {
+            continue;
+        }
+
+        std::string cmdline;
+        if (!ReadFileToString(StringPrintf("/proc/%d/cmdline", pid), &cmdline)) {
+            continue;
+        }
+
+        // cmdline strings are null-delimited, so we split on \0 here
+        if (cmdline.substr(0, cmdline.find('\0')) == "/system/bin/surfaceflinger") {
+            if (surfaceFlingerPid == -1) {
+                surfaceFlingerPid = pid;
+                surfaceFlingerBufferInodes = pidToInodes[pid];
+            } else {
+                LOG(ERROR) << "getDmabufAllocations found multiple SF processes; pid1: " << pid
+                           << ", pid2:" << surfaceFlingerPid;
+                surfaceFlingerPid = -2; // Used as a sentinel value below
+            }
+        } else {
+            otherProcessBufferInodes.insert(pidToInodes[pid].begin(), pidToInodes[pid].end());
+        }
+
+        std::string oomScoreAdjStr;
+        if (!ReadFileToString(StringPrintf("/proc/%d/oom_score_adj", pid), &oomScoreAdjStr)) {
+            continue;
+        }
+
+        pidDmaInfos[pid] = PidDmaInfo{.uid = processInfo.uid,
+                                      .cmdline = cmdline,
+                                      .oomScoreAdj = atoi(oomScoreAdjStr.c_str())};
+    }
+
+    if (surfaceFlingerPid < 0) {
+        LOG(ERROR) << "getDmabufAllocations could not identify SurfaceFlinger "
+                   << "process via /proc/pid/cmdline";
+    }
+
+    jobjectArray ret = env->NewObjectArray(pidDmaInfos.size(), gProcessDmabufClazz, NULL);
+    int retArrayIndex = 0;
+    for (const auto &pidDmaInfosEntry : pidDmaInfos) {
+        pid_t pid = pidDmaInfosEntry.first;
+
+        // For all processes apart from SurfaceFlinger, this set will store the
+        // dmabuf inodes that are shared with SF. For SF, it will store the inodes
+        // that are shared with any other process.
+        std::set<ino_t> sharedBuffers;
+        if (pid == surfaceFlingerPid) {
+            set_intersection(surfaceFlingerBufferInodes.begin(), surfaceFlingerBufferInodes.end(),
+                             otherProcessBufferInodes.begin(), otherProcessBufferInodes.end(),
+                             std::inserter(sharedBuffers, sharedBuffers.end()));
+        } else if (surfaceFlingerPid > 0) {
+            set_intersection(pidToInodes[pid].begin(), pidToInodes[pid].end(),
+                             surfaceFlingerBufferInodes.begin(), surfaceFlingerBufferInodes.end(),
+                             std::inserter(sharedBuffers, sharedBuffers.begin()));
+        } // If surfaceFlingerPid < 0; it means we failed to identify it, and
+        // the SF-related fields below should be left empty.
+
+        long totalSize = 0;
+        long sharedBuffersSize = 0;
+        for (const auto &inode : pidToInodes[pid]) {
+            totalSize += inodeToSize[inode];
+            if (sharedBuffers.count(inode)) {
+                sharedBuffersSize += inodeToSize[inode];
+            }
+        }
+
+        jobject obj = env->NewObject(gProcessDmabufClazz, gProcessDmabufCtor,
+                                     /* uid */ pidDmaInfos[pid].uid,
+                                     /* process name */
+                                     env->NewStringUTF(pidDmaInfos[pid].cmdline.c_str()),
+                                     /* oomscore */ pidDmaInfos[pid].oomScoreAdj,
+                                     /* retainedSize */ totalSize / 1024,
+                                     /* retainedCount */ pidToInodes[pid].size(),
+                                     /* sharedWithSurfaceFlinger size */ sharedBuffersSize / 1024,
+                                     /* sharedWithSurfaceFlinger count */ sharedBuffers.size());
+
+        env->SetObjectArrayElement(ret, retArrayIndex++, obj);
+    }
+
+    return ret;
 }
 
 static jobject KernelAllocationStats_getGpuAllocations(JNIEnv *env) {
@@ -74,7 +178,7 @@
 }
 
 static const JNINativeMethod methods[] = {
-        {"getDmabufAllocations", "(I)Lcom/android/internal/os/KernelAllocationStats$ProcessDmabuf;",
+        {"getDmabufAllocations", "()[Lcom/android/internal/os/KernelAllocationStats$ProcessDmabuf;",
          (void *)KernelAllocationStats_getDmabufAllocations},
         {"getGpuAllocations", "()[Lcom/android/internal/os/KernelAllocationStats$ProcessGpuMem;",
          (void *)KernelAllocationStats_getGpuAllocations},
@@ -86,7 +190,8 @@
     jclass clazz =
             FindClassOrDie(env, "com/android/internal/os/KernelAllocationStats$ProcessDmabuf");
     gProcessDmabufClazz = MakeGlobalRefOrDie(env, clazz);
-    gProcessDmabufCtor = GetMethodIDOrDie(env, gProcessDmabufClazz, "<init>", "(IIII)V");
+    gProcessDmabufCtor =
+            GetMethodIDOrDie(env, gProcessDmabufClazz, "<init>", "(ILjava/lang/String;IIIII)V");
 
     clazz = FindClassOrDie(env, "com/android/internal/os/KernelAllocationStats$ProcessGpuMem");
     gProcessGpuMemClazz = MakeGlobalRefOrDie(env, clazz);
@@ -94,4 +199,4 @@
     return res;
 }
 
-} // namespace android
+} // namespace android
\ No newline at end of file
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 5b7092c..7bc6905 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -895,7 +895,7 @@
 
   // pthread_setname_np fails rather than truncating long strings.
   char buf[16];       // MAX_TASK_COMM_LEN=16 is hard-coded into bionic
-  strlcpy(buf, name_start_ptr, sizeof(buf) - 1);
+  strlcpy(buf, name_start_ptr, sizeof(buf));
   errno = pthread_setname_np(pthread_self(), buf);
   if (errno != 0) {
     ALOGW("Unable to set the name of current thread to '%s': %s", buf, strerror(errno));
diff --git a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
index 0c05da5..679a4f0 100644
--- a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
+++ b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
@@ -34,6 +34,7 @@
 #include <sys/mman.h>
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/system_properties.h>
 #include <vector>
 
 namespace android {
@@ -43,10 +44,10 @@
 using android::zygote::ZygoteFailure;
 
 // WARNING: Knows a little about the wire protocol used to communicate with Zygote.
-// TODO: Fix error handling.
 
+// Commands and nice names have large arbitrary size limits to avoid dynamic memory allocation.
 constexpr size_t MAX_COMMAND_BYTES = 32768;
-constexpr size_t NICE_NAME_BYTES = 50;
+constexpr size_t NICE_NAME_BYTES = 128;
 
 // A buffer optionally bundled with a file descriptor from which we can fill it.
 // Does not own the file descriptor; destroying a NativeCommandBuffer does not
@@ -190,6 +191,9 @@
         size_t copy_len = std::min(name_len, NICE_NAME_BYTES - 1);
         memcpy(mNiceName, arg_start + NN_LENGTH, copy_len);
         mNiceName[copy_len] = '\0';
+        if (haveWrapProperty()) {
+          return false;
+        }
         continue;
       }
       if (arg_end - arg_start == IW_LENGTH
@@ -222,6 +226,8 @@
         }
         saw_setgid = true;
       }
+      // ro.debuggable can be handled entirely in the child unless --invoke-with is also specified.
+      // Thus we do not need to check it here.
     }
     return saw_runtime_args && saw_setuid && saw_setgid;
   }
@@ -249,6 +255,14 @@
   }
 
  private:
+  bool haveWrapProperty() {
+    static const char* WRAP = "wrap.";
+    static const size_t WRAP_LENGTH = strlen(WRAP);
+    char propNameBuf[WRAP_LENGTH + NICE_NAME_BYTES];
+    strcpy(propNameBuf, WRAP);
+    strlcpy(propNameBuf + WRAP_LENGTH, mNiceName, NICE_NAME_BYTES);
+    return __system_property_find(propNameBuf) != nullptr;
+  }
   // Picky version of atoi(). No sign or unexpected characters allowed. Return -1 on failure.
   static int digitsVal(char* start, char* end) {
     int result = 0;
@@ -269,7 +283,7 @@
   uint32_t mNext;  // Index of first character past last line returned by readLine.
   int32_t mLinesLeft;  // Lines in current command that haven't yet been read.
   int mFd;  // Open file descriptor from which we can read more. -1 if none.
-  char mNiceName[NICE_NAME_BYTES];
+  char mNiceName[NICE_NAME_BYTES];  // Always null terminated.
   char mBuffer[MAX_COMMAND_BYTES];
 };
 
@@ -372,6 +386,7 @@
             jint minUid,
             jstring managed_nice_name) {
 
+  ALOGI("Entering forkRepeatedly native zygote loop");
   NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer);
   int session_socket = n_buffer->getFd();
   std::vector<int> session_socket_fds {session_socket};
@@ -400,7 +415,8 @@
   socklen_t cred_size = sizeof credentials;
   if (getsockopt(n_buffer->getFd(), SOL_SOCKET, SO_PEERCRED, &credentials, &cred_size) == -1
       || cred_size != sizeof credentials) {
-    fail_fn_1(CREATE_ERROR("ForkMany failed to get initial credentials, %s", strerror(errno)));
+    fail_fn_1(CREATE_ERROR("ForkRepeatedly failed to get initial credentials, %s",
+                           strerror(errno)));
   }
 
   bool first_time = true;
diff --git a/core/proto/android/os/appbatterystats.proto b/core/proto/android/os/appbatterystats.proto
new file mode 100644
index 0000000..8769ebb
--- /dev/null
+++ b/core/proto/android/os/appbatterystats.proto
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package android.os;
+
+option java_multiple_files = true;
+
+message AppBatteryStatsProto {
+  message UidStats {
+    optional int32 uid = 1;
+
+    message ProcessStateStats {
+      enum ProcessState {
+        UNSPECIFIED = 0;
+        FOREGROUND = 1;
+        BACKGROUND = 2;
+        FOREGROUND_SERVICE = 3;
+        CACHED = 4;
+      }
+
+      optional ProcessState process_state = 1;
+
+      // Time spent in this state in the past 24 hours
+      optional int64 duration_ms = 2;
+      // Estimated power consumed in this state in the past 24 hours
+      optional double power_mah = 3;
+    }
+
+    repeated ProcessStateStats process_state_stats = 2;
+  }
+
+  repeated UidStats uid_stats = 1;
+}
diff --git a/core/proto/android/os/batteryusagestats.proto b/core/proto/android/os/batteryusagestats.proto
index cc90e05..856bc83 100644
--- a/core/proto/android/os/batteryusagestats.proto
+++ b/core/proto/android/os/batteryusagestats.proto
@@ -76,6 +76,7 @@
                 FOREGROUND = 1;
                 BACKGROUND = 2;
                 FOREGROUND_SERVICE = 3;
+                CACHED = 4;
             }
 
             optional ProcessState process_state = 2;
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 0ade093..152d729 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -384,6 +384,7 @@
     optional float min_aspect_ratio = 33;
     optional bool provides_max_bounds = 34;
     optional bool enable_recents_screenshot = 35;
+    optional int32 last_drop_input_mode = 36;
 }
 
 /* represents WindowToken */
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 53e9045..0353e4b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -471,11 +471,9 @@
         android:name="com.android.server.connectivityservice.CONNECTED_TO_PROVISIONING_NETWORK_ACTION" />
 
     <!-- Defined in RestrictionsManager -->
-    <protected-broadcast
-        android:name="android.intent.action.PERMISSION_RESPONSE_RECEIVED" />
-    <!-- Defined in RestrictionsManager -->
+    <protected-broadcast android:name="android.content.action.PERMISSION_RESPONSE_RECEIVED" />
+    <protected-broadcast android:name="android.content.action.REQUEST_PERMISSION" />
 
-    <protected-broadcast android:name="android.intent.action.REQUEST_PERMISSION" />
     <protected-broadcast android:name="android.nfc.handover.intent.action.HANDOVER_STARTED" />
     <protected-broadcast android:name="android.nfc.handover.intent.action.TRANSFER_DONE" />
     <protected-broadcast android:name="android.nfc.handover.intent.action.TRANSFER_PROGRESS" />
@@ -528,6 +526,7 @@
     <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_ADDED" />
     <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNLOCKED" />
     <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_REMOVED" />
+    <protected-broadcast android:name="android.app.action.MANAGED_PROFILE_PROVISIONED" />
 
     <protected-broadcast android:name="android.bluetooth.adapter.action.BLE_STATE_CHANGED" />
     <protected-broadcast android:name="com.android.bluetooth.map.USER_CONFIRM_TIMEOUT" />
@@ -655,6 +654,8 @@
 
     <protected-broadcast android:name="android.intent.action.DEVICE_LOCKED_CHANGED" />
 
+    <protected-broadcast android:name="com.android.content.pm.action.CAN_INTERACT_ACROSS_PROFILES_CHANGED"/>
+
     <!-- Added in O -->
     <protected-broadcast android:name="android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED" />
     <protected-broadcast android:name="com.android.server.wm.ACTION_REVOKE_SYSTEM_ALERT_WINDOW_PERMISSION" />
@@ -718,12 +719,100 @@
     <protected-broadcast android:name="android.app.action.SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED" />
     <protected-broadcast android:name="android.app.action.SHOW_NEW_USER_DISCLAIMER" />
 
+    <!-- Moved from packages/services/Telephony in T -->
+    <protected-broadcast android:name="android.telecom.action.CURRENT_TTY_MODE_CHANGED" />
+    <protected-broadcast android:name="android.intent.action.SERVICE_STATE" />
+    <protected-broadcast android:name="android.intent.action.RADIO_TECHNOLOGY" />
+    <protected-broadcast android:name="android.intent.action.EMERGENCY_CALLBACK_MODE_CHANGED" />
+    <protected-broadcast android:name="android.intent.action.EMERGENCY_CALL_STATE_CHANGED" />
+    <protected-broadcast android:name="android.intent.action.SIG_STR" />
+    <protected-broadcast android:name="android.intent.action.ANY_DATA_STATE" />
+    <protected-broadcast android:name="android.intent.action.DATA_STALL_DETECTED" />
+    <protected-broadcast android:name="android.intent.action.SIM_STATE_CHANGED" />
+    <protected-broadcast android:name="android.intent.action.USER_ACTIVITY_NOTIFICATION" />
+    <protected-broadcast android:name="android.telephony.action.SHOW_NOTICE_ECM_BLOCK_OTHERS" />
+    <protected-broadcast android:name="android.intent.action.ACTION_MDN_STATE_CHANGED" />
+    <protected-broadcast android:name="android.telephony.action.SERVICE_PROVIDERS_UPDATED" />
+    <protected-broadcast android:name="android.provider.Telephony.SIM_FULL" />
+    <protected-broadcast android:name="com.android.internal.telephony.carrier_key_download_alarm" />
+    <protected-broadcast android:name="com.android.internal.telephony.data-restart-trysetup" />
+    <protected-broadcast android:name="com.android.internal.telephony.data-stall" />
+    <protected-broadcast android:name="com.android.internal.telephony.provisioning_apn_alarm" />
+    <protected-broadcast android:name="android.intent.action.DATA_SMS_RECEIVED" />
+    <protected-broadcast android:name="android.provider.Telephony.SMS_RECEIVED" />
+    <protected-broadcast android:name="android.provider.Telephony.SMS_DELIVER" />
+    <protected-broadcast android:name="android.provider.Telephony.SMS_REJECTED" />
+    <protected-broadcast android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
+    <protected-broadcast android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" />
+    <protected-broadcast android:name="android.provider.Telephony.SMS_CB_RECEIVED" />
+    <protected-broadcast android:name="android.provider.action.SMS_EMERGENCY_CB_RECEIVED" />
+    <protected-broadcast android:name="android.provider.Telephony.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED" />
+    <protected-broadcast android:name="android.provider.Telephony.SECRET_CODE" />
+    <protected-broadcast android:name="com.android.internal.stk.command" />
+    <protected-broadcast android:name="com.android.internal.stk.session_end" />
+    <protected-broadcast android:name="com.android.internal.stk.icc_status_change" />
+    <protected-broadcast android:name="com.android.internal.stk.alpha_notify" />
+    <protected-broadcast android:name="com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED" />
+    <protected-broadcast android:name="com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED" />
+    <protected-broadcast android:name="com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE" />
+    <protected-broadcast android:name="com.android.internal.telephony.CARRIER_SIGNAL_RESET" />
+    <protected-broadcast android:name="com.android.internal.telephony.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE" />
+    <protected-broadcast android:name="com.android.internal.telephony.PROVISION" />
+    <protected-broadcast android:name="com.android.internal.telephony.ACTION_LINE1_NUMBER_ERROR_DETECTED" />
+    <protected-broadcast android:name="com.android.internal.provider.action.VOICEMAIL_SMS_RECEIVED" />
+    <protected-broadcast android:name="com.android.intent.isim_refresh" />
+    <protected-broadcast android:name="com.android.ims.ACTION_RCS_SERVICE_AVAILABLE" />
+    <protected-broadcast android:name="com.android.ims.ACTION_RCS_SERVICE_UNAVAILABLE" />
+    <protected-broadcast android:name="com.android.ims.ACTION_RCS_SERVICE_DIED" />
+    <protected-broadcast android:name="com.android.ims.ACTION_PRESENCE_CHANGED" />
+    <protected-broadcast android:name="com.android.ims.ACTION_PUBLISH_STATUS_CHANGED" />
+    <protected-broadcast android:name="com.android.ims.IMS_SERVICE_UP" />
+    <protected-broadcast android:name="com.android.ims.IMS_SERVICE_DOWN" />
+    <protected-broadcast android:name="com.android.ims.IMS_INCOMING_CALL" />
+    <protected-broadcast android:name="com.android.ims.internal.uce.UCE_SERVICE_UP" />
+    <protected-broadcast android:name="com.android.ims.internal.uce.UCE_SERVICE_DOWN" />
+    <protected-broadcast android:name="com.android.imsconnection.DISCONNECTED" />
+    <protected-broadcast android:name="com.android.intent.action.IMS_FEATURE_CHANGED" />
+    <protected-broadcast android:name="com.android.intent.action.IMS_CONFIG_CHANGED" />
+    <protected-broadcast android:name="android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR" />
+    <protected-broadcast android:name="com.android.phone.vvm.omtp.sms.REQUEST_SENT" />
+    <protected-broadcast android:name="com.android.phone.vvm.ACTION_VISUAL_VOICEMAIL_SERVICE_EVENT" />
+    <protected-broadcast android:name="com.android.internal.telephony.CARRIER_VVM_PACKAGE_INSTALLED" />
+    <protected-broadcast android:name="com.android.cellbroadcastreceiver.GET_LATEST_CB_AREA_INFO" />
+    <protected-broadcast android:name="com.android.internal.telephony.ACTION_CARRIER_CERTIFICATE_DOWNLOAD" />
+    <protected-broadcast android:name="com.android.internal.telephony.action.COUNTRY_OVERRIDE" />
+    <protected-broadcast android:name="com.android.internal.telephony.OPEN_DEFAULT_SMS_APP" />
+    <protected-broadcast android:name="com.android.internal.telephony.ACTION_TEST_OVERRIDE_CARRIER_ID" />
+    <protected-broadcast android:name="android.telephony.action.SIM_CARD_STATE_CHANGED" />
+    <protected-broadcast android:name="android.telephony.action.SIM_APPLICATION_STATE_CHANGED" />
+    <protected-broadcast android:name="android.telephony.action.SIM_SLOT_STATUS_CHANGED" />
+    <protected-broadcast android:name="android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED" />
+    <protected-broadcast android:name="android.telephony.action.SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED" />
+    <protected-broadcast android:name="android.telephony.action.TOGGLE_PROVISION" />
+    <protected-broadcast android:name="android.telephony.action.NETWORK_COUNTRY_CHANGED" />
+    <protected-broadcast android:name="android.telephony.action.PRIMARY_SUBSCRIPTION_LIST_CHANGED" />
+    <protected-broadcast android:name="android.telephony.action.MULTI_SIM_CONFIG_CHANGED" />
+    <protected-broadcast android:name="android.telephony.action.CARRIER_SIGNAL_RESET" />
+    <protected-broadcast android:name="android.telephony.action.CARRIER_SIGNAL_PCO_VALUE" />
+    <protected-broadcast android:name="android.telephony.action.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE" />
+    <protected-broadcast android:name="android.telephony.action.CARRIER_SIGNAL_REDIRECTED" />
+    <protected-broadcast android:name="android.telephony.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED" />
+    <protected-broadcast android:name="com.android.phone.settings.CARRIER_PROVISIONING" />
+    <protected-broadcast android:name="com.android.phone.settings.TRIGGER_CARRIER_PROVISIONING" />
+    <protected-broadcast android:name="com.android.internal.telephony.ACTION_VOWIFI_ENABLED" />
+    <protected-broadcast android:name="android.telephony.action.ANOMALY_REPORTED" />
+    <protected-broadcast android:name="android.intent.action.SUBSCRIPTION_INFO_RECORD_ADDED" />
+    <protected-broadcast android:name="android.intent.action.ACTION_MANAGED_ROAMING_IND" />
+    <protected-broadcast android:name="android.telephony.ims.action.RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE" />
+
     <!-- Added in T -->
     <protected-broadcast android:name="android.safetycenter.action.REFRESH_SAFETY_SOURCES" />
+    <protected-broadcast android:name="android.safetycenter.action.SAFETY_CENTER_ENABLED_CHANGED" />
     <protected-broadcast android:name="android.app.action.DEVICE_POLICY_RESOURCE_UPDATED" />
     <protected-broadcast android:name="android.intent.action.SHOW_FOREGROUND_SERVICE_MANAGER" />
     <protected-broadcast android:name="android.service.autofill.action.DELAYED_FILL" />
     <protected-broadcast android:name="android.app.action.PROVISIONING_COMPLETED" />
+    <protected-broadcast android:name="android.app.action.LOST_MODE_LOCATION_UPDATE" />
 
     <!-- ====================================================================== -->
     <!--                          RUNTIME PERMISSIONS                           -->
@@ -991,10 +1080,12 @@
 
     <!-- Allows an application to read audio files from external storage.
       <p>This permission is enforced starting in API level
-      {@link android.os.Build.VERSION_CODES#TIRAMISU}.
+      {@link android.os.Build.VERSION_CODES#TIRAMISU}. An app which targets
+      {@link android.os.Build.VERSION_CODES#TIRAMISU} or higher and needs to read audio files from
+      external storage must hold this permission; {@link #READ_EXTERNAL_STORAGE} is not required.
       For apps with a <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
-      targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S} or lower, this permission
-      must not be used and the READ_EXTERNAL_STORAGE permission must be used instead.
+      targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S_V2} or lower, the
+      {@link #READ_EXTERNAL_STORAGE} permission is required, instead, to read audio files.
      <p>Protection level: dangerous -->
     <permission android:name="android.permission.READ_MEDIA_AUDIO"
                 android:permissionGroup="android.permission-group.UNDEFINED"
@@ -1010,12 +1101,14 @@
                       android:description="@string/permgroupdesc_readMediaVisual"
                       android:priority="1000" />
 
-    <!-- Allows an application to read audio files from external storage.
-    <p>This permission is enforced starting in API level
-    {@link android.os.Build.VERSION_CODES#TIRAMISU}.
-    For apps with a <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
-    targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S} or lower, this permission
-    must not be used and the READ_EXTERNAL_STORAGE permission must be used instead.
+    <!-- Allows an application to read video files from external storage.
+      <p>This permission is enforced starting in API level
+      {@link android.os.Build.VERSION_CODES#TIRAMISU}. An app which targets
+      {@link android.os.Build.VERSION_CODES#TIRAMISU} or higher and needs to read video files from
+      external storage must hold this permission; {@link #READ_EXTERNAL_STORAGE} is not required.
+      For apps with a <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+      targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S_V2} or lower, the
+      {@link #READ_EXTERNAL_STORAGE} permission is required, instead, to read video files.
    <p>Protection level: dangerous -->
     <permission android:name="android.permission.READ_MEDIA_VIDEO"
                 android:permissionGroup="android.permission-group.UNDEFINED"
@@ -1025,15 +1118,17 @@
 
     <!-- Allows an application to read image files from external storage.
       <p>This permission is enforced starting in API level
-      {@link android.os.Build.VERSION_CODES#TIRAMISU}.
+      {@link android.os.Build.VERSION_CODES#TIRAMISU}. An app which targets
+      {@link android.os.Build.VERSION_CODES#TIRAMISU} or higher and needs to read image files from
+      external storage must hold this permission; {@link #READ_EXTERNAL_STORAGE} is not required.
       For apps with a <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
-      targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S} or lower, this permission
-      must not be used and the READ_EXTERNAL_STORAGE permission must be used instead.
-     <p>Protection level: dangerous -->
-    <permission android:name="android.permission.READ_MEDIA_IMAGE"
+      targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S_V2} or lower, the
+      {@link #READ_EXTERNAL_STORAGE} permission is required, instead, to read image files.
+   <p>Protection level: dangerous -->
+    <permission android:name="android.permission.READ_MEDIA_IMAGES"
                 android:permissionGroup="android.permission-group.UNDEFINED"
-                android:label="@string/permlab_readMediaImage"
-                android:description="@string/permdesc_readMediaImage"
+                android:label="@string/permlab_readMediaImages"
+                android:description="@string/permdesc_readMediaImages"
                 android:protectionLevel="dangerous" />
 
     <!-- Allows an application to write to external storage.
@@ -1901,11 +1996,21 @@
     <!-- Allows applications to enable/disable wifi auto join. This permission
          is used to let OEMs grant their trusted app access to a subset of privileged wifi APIs
          to improve wifi performance.
-         <p>Not for use by third-party applications. -->
+         <p>Not for use by third-party applications.
+         @deprecated will be replaced with MANAGE_WIFI_NETWORK_SELECTION -->
     <permission android:name="android.permission.MANAGE_WIFI_AUTO_JOIN"
                 android:protectionLevel="signature|privileged|knownSigner"
                 android:knownCerts="@array/wifi_known_signers" />
 
+    <!-- This permission is used to let OEMs grant their trusted app access to a subset of
+         privileged wifi APIs to improve wifi performance. Allows applications to manage
+         Wi-Fi network selection related features such as enable or disable global auto-join,
+         modify connectivity scan intervals, and approve Wi-Fi Direct connections.
+         <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.MANAGE_WIFI_NETWORK_SELECTION"
+                android:protectionLevel="signature|privileged|knownSigner"
+                android:knownCerts="@array/wifi_known_signers" />
+
     <!-- Allows applications to get notified when a Wi-Fi interface request cannot
          be satisfied without tearing down one or more other interfaces, and provide a decision
          whether to approve the request or reject it.
@@ -3089,7 +3194,7 @@
 
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY"
-                android:protectionLevel="signature|recents|role"/>
+                android:protectionLevel="signature|recents|role|installer"/>
 
     <!-- @deprecated Use {@link android.Manifest.permission#REQUEST_COMPANION_RUN_IN_BACKGROUND}
          @hide
@@ -3717,29 +3822,6 @@
     <permission android:name="android.permission.REQUEST_INCIDENT_REPORT_APPROVAL"
         android:protectionLevel="signature|privileged" />
 
-    <!-- ========================================= -->
-    <!-- Permissions for AdServices -->
-    <!-- ========================================= -->
-    <eat-comment />
-
-    <!-- Allows an application to access AdServices Topics API. -->
-    <permission android:name="android.permission.ACCESS_ADSERVICES_TOPICS"
-        android:label="@string/permlab_accessAdServicesTopics"
-        android:description="@string/permdesc_accessAdServicesTopics"
-        android:protectionLevel="normal" />
-
-    <!-- Allows an application to access AdServices Attribution APIs. -->
-    <permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION"
-        android:label="@string/permlab_accessAdServicesAttribution"
-        android:description="@string/permdesc_accessAdServicesAttribution"
-        android:protectionLevel="normal" />
-
-    <!-- Allows an application to access AdServices Custom Audiences APIs. -->
-    <permission android:name="android.permission.ACCESS_ADSERVICES_CUSTOM_AUDIENCES"
-        android:label="@string/permlab_accessAdServicesCustomAudiences"
-        android:description="@string/permdesc_accessAdServicesCustomAudiences"
-        android:protectionLevel="normal" />
-
     <!-- ==================================== -->
     <!-- Private permissions                  -->
     <!-- ==================================== -->
@@ -4426,21 +4508,41 @@
          For more details, see <a
          href="{@docRoot}about/versions/12/behavior-changes-12#exact-alarm-permission">
          Exact alarm permission</a>.
-         <p>Apps who hold this permission and target API level 31 or above, always stay in the
+         <p>Apps need to target API {@link android.os.Build.VERSION_CODES#S} or above to be able to
+         request this permission. Note that apps targeting lower API levels do not need this
+         permission to use exact alarm APIs.
+         <p>Apps that hold this permission, always stay in the
          {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_WORKING_SET WORKING_SET} or
          lower standby bucket.
-         Applications targeting API level 30 or below do not need this permission to use
-         exact alarm APIs.
+         <p>If your app relies on exact alarms for core functionality, it can instead request
+         {@link android.Manifest.permission#USE_EXACT_ALARM} once it targets API
+         {@link android.os.Build.VERSION_CODES#TIRAMISU}. All apps using exact alarms for secondary
+         features (which should still be user facing) should continue using this permission.
      -->
     <permission android:name="android.permission.SCHEDULE_EXACT_ALARM"
         android:protectionLevel="normal|appop"/>
 
-    <!-- Allows apps to use exact alarms just like with SCHEDULE_EXACT_ALARM but without needing
-        to request this permission from the user.
-        <p><b>This is only for apps that rely on exact alarms for their core functionality.</b>
-        App stores may enforce policies to audit and review the use of this permission. Any app that
-        requests this but is found to not require exact alarms for its primary function may be
-        removed from the app store.
+    <!-- Allows apps to use exact alarms just like with {@link
+         android.Manifest.permission#SCHEDULE_EXACT_ALARM} but without needing to request this
+         permission from the user.
+         <p><b> This is only intended for use by apps that rely on exact alarms for their core
+         functionality.</b> You should continue using {@code SCHEDULE_EXACT_ALARM} if your app needs
+         exact alarms for a secondary feature that users may or may not use within your app.
+         <p> Keep in mind that this is a powerful permission and app stores may enforce policies to
+         audit and review the use of this permission. Such audits may involve removal from the app
+         store if the app is found to be misusing this permission.
+         <p> Apps need to target API {@link android.os.Build.VERSION_CODES#TIRAMISU} or above to be
+         able to request this permission. Note that only one of {@code USE_EXACT_ALARM} or
+         {@code SCHEDULE_EXACT_ALARM} should be requested on a device. If your app is already using
+         {@code SCHEDULE_EXACT_ALARM} on older SDKs but need {@code USE_EXACT_ALARM} on SDK 33 and
+         above, then {@code SCHEDULE_EXACT_ALARM} should be declared with a max-sdk attribute, like:
+         <pre>
+         &lt;uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"
+         &Tab; android:maxSdkVersion="32" /&gt;
+         </pre>
+         <p>Apps that hold this permission, always stay in the
+         {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_WORKING_SET WORKING_SET} or
+         lower standby bucket.
     -->
     <permission android:name="android.permission.USE_EXACT_ALARM"
                 android:protectionLevel="normal"/>
@@ -5133,6 +5235,14 @@
         android:protectionLevel="signature|privileged|development|appop|retailDemo" />
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
 
+    <!-- Allows an application to query broadcast response stats (see
+         {@link android.app.usage.BroadcastResponseStats}).
+         @SystemApi
+         @hide
+    -->
+    <permission android:name="android.permission.ACCESS_BROADCAST_RESPONSE_STATS"
+        android:protectionLevel="signature|privileged|development" />
+
     <!-- Allows a data loader to read a package's access logs. The access logs contain the
          set of pages referenced over time.
          <p>Declaring the permission implies intention to use the API and the user of the
@@ -5988,7 +6098,7 @@
     <!-- @SystemApi Allows an application to turn on / off quiet mode.
          @hide -->
     <permission android:name="android.permission.MODIFY_QUIET_MODE"
-                android:protectionLevel="signature|privileged|development" />
+                android:protectionLevel="signature|privileged|development|role" />
 
     <!-- Allows internal management of the camera framework
          @hide -->
@@ -6041,10 +6151,10 @@
     <permission android:name="android.permission.MANAGE_APPOPS"
                 android:protectionLevel="signature" />
 
-    <!-- @hide Permission that allows background clipboard access.
-         <p>Not for use by third-party applications. -->
+    <!-- @SystemApi Permission that allows background clipboard access.
+         @hide Not for use by third-party applications. -->
     <permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND"
-        android:protectionLevel="signature" />
+        android:protectionLevel="signature|role" />
     <!-- @hide Permission that suppresses the notification when the clipboard is accessed.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.SUPPRESS_CLIPBOARD_ACCESS_NOTIFICATION"
@@ -6150,10 +6260,10 @@
     <!-- Allows input events to be monitored. Very dangerous!  @hide -->
     <permission android:name="android.permission.MONITOR_INPUT"
                 android:protectionLevel="signature|recents" />
-    <!-- Allows the use of FLAG_SLIPPERY, which permits touch events to slip from the current
-         window to the window where the touch currently is on top of.  @hide -->
+    <!-- @SystemApi Allows the use of FLAG_SLIPPERY, which permits touch events to slip from the
+         current window to the window where the touch currently is on top of.  @hide -->
     <permission android:name="android.permission.ALLOW_SLIPPERY_TOUCHES"
-                android:protectionLevel="signature|recents" />
+                android:protectionLevel="signature|privileged|recents|role" />
     <!--  Allows the caller to change the associations between input devices and displays.
         Very dangerous! @hide -->
     <permission android:name="android.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY"
@@ -6410,6 +6520,12 @@
     <permission android:name="android.permission.WRITE_SECURITY_LOG"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Allows an UID to be visible to the application based on an interaction between the
+         two apps. This permission is not intended to be held by apps.
+         @hide @TestApi @SystemApi(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES) -->
+    <permission android:name="android.permission.MAKE_UID_VISIBLE"
+                android:protectionLevel="signature" />
+
     <!-- Attribution for Geofencing service. -->
     <attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
     <!-- Attribution for Country Detector. -->
@@ -6829,6 +6945,9 @@
             </intent-filter>
         </receiver>
 
+        <!-- Broadcast Receiver listen to sufficient verifier requests from Package Manager
+             when install new SDK, to verifier SDK code during installation time
+             and terminate install if SDK not compatible with privacy sandbox restrictions. -->
         <receiver android:name="com.android.server.sdksandbox.SdkSandboxVerifierReceiver"
                  android:exported="false">
             <intent-filter>
diff --git a/core/res/res/drawable-nodpi/stat_sys_adb.xml b/core/res/res/drawable-nodpi/stat_sys_adb.xml
index f8c0451..cb4462c 100644
--- a/core/res/res/drawable-nodpi/stat_sys_adb.xml
+++ b/core/res/res/drawable-nodpi/stat_sys_adb.xml
@@ -1,5 +1,5 @@
 <!--
-Copyright (C) 2021 The Android Open Source Project
+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.
@@ -13,11 +13,78 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp" android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-  <path android:pathData="M18 9c0-.69268-.1174-1.35795-.3333-1.97699C16.8495 4.68061 14.621 3 12 3 8.68629 3 6 5.68629 6 9v3h6M6 15c0 .6927.11738 1.3579.33333 1.977C7.15047 19.3194 9.37897 21 12 21c3.3137 0 6-2.6863 6-6v-3h-6" android:strokeColor="#000000" android:strokeWidth="2" android:fillColor="#00000000"/>
-  <path android:fillColor="#000000" android:pathData="M10 7a1 1 0 1 0 0 2 1 1 0 1 0 0-2zM14 7a1 1 0 1 0 0 2 1 1 0 1 0 0-2z"/>
-  <path android:pathData="M6 3l1.5 1.5M18 3l-1.5 1.5" android:strokeColor="#000000" android:strokeWidth="2" android:fillColor="#000000"/>
+<vector android:width="24dp" android:height="24dp"
+        android:viewportWidth="24" android:viewportHeight="24"
+        xmlns:android="http://schemas.android.com/apk/res/android">
+  <path android:pathData="
+        M22.45 11.94
+        l-.58-.21
+        a1.19 1.19 0 0 1-.26-2.12
+        l.51-.34
+        a1.2 1.2 0 0 0-.83-2.19
+        l-.61.08
+        a1.2 1.2 0 0 1-1.21-1.76
+        l.29-.54
+        A1.2 1.2 0 0 0 18 3.31
+        l-.5.36
+        a1.21 1.21 0 0 1-1.9-1
+        v-.61
+        a1.2 1.2 0 0 0-2.27-.56
+        l-.26.5
+        a1.2 1.2 0 0 1-2.14 0
+        l-.28-.54
+        a1.2 1.2 0 0 0-2.27.56
+        v.61
+        a1.21 1.21 0 0 1-1.9 1
+        L6 3.31
+        a1.2 1.2 0 0 0-1.76 1.55
+        l.29.54
+        a1.2 1.2 0 0 1-1.21 1.76
+        l-.61-.08
+        a1.2 1.2 0 0 0-.83 2.19
+        l.51.34
+        a1.19 1.19 0 0 1-.26 2.12
+        l-.58.21
+        a1.21 1.21 0 0 0 .29 2.33
+        l.61.06
+        a1.2 1.2 0 0 1 .76 2
+        l-.42.46
+        a1.2 1.2 0 0 0 1.33 1.92
+        l.57-.22
+        a1.21 1.21 0 0 1 1.61 1.42
+        l-.16.59
+        a1.2 1.2 0 0 0 2.07 1.09
+        l.4-.47
+        a1.2 1.2 0 0 1 2.08.51
+        l.14.6
+        a1.2 1.2 0 0 0 2.34 0
+        l.14-.6
+        a1.2 1.2 0 0 1 2.08-.51
+        l.4.47
+        a1.2 1.2 0 0 0 2.07-1.09
+        l-.16-.59
+        a1.21 1.21 0 0 1 1.61-1.42
+        l.57.22
+        a1.2 1.2 0 0 0 1.33-1.92
+        l-.42-.46
+        a1.2 1.2 0 0 1 .76-2
+        l.61-.06
+        a1.21 1.21 0 0 0 .29-2.33
+        z
+        M12 19
+        a7 7 0 1 1 7-7 7 7 0 0 1-7 7
+        z
+        "
+        android:fillColor="#000000" />
+  <path android:pathData="
+        M9 7.75
+        a.75.75 0 1 0 0 1.5.75.75 0 1 0 0-1.5
+        z
+        M15 7.75
+        a.75.75 0 1 0 0 1.5.75.75 0 1 0 0-1.5
+        z
+        "
+        android:fillColor="#000000" />
+  <path android:strokeColor="#000000" android:strokeMiterLimit="10" android:strokeWidth="2"
+        android:pathData="M4 12h16M12 12v8" />
 </vector>
diff --git a/core/res/res/layout/app_language_picker_system_default.xml b/core/res/res/layout/app_language_picker_system_default.xml
new file mode 100644
index 0000000..d9883bc
--- /dev/null
+++ b/core/res/res/layout/app_language_picker_system_default.xml
@@ -0,0 +1,42 @@
+<!--
+  ~ 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.
+  -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:orientation="vertical"
+    android:paddingTop="8dp">
+    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:id="@+id/locale"
+              android:gravity="center_vertical"
+              android:textAppearance="?android:attr/textAppearanceListItem"
+              android:textDirection="locale"
+              android:layoutDirection="locale"
+              android:layout_weight="1" />
+
+    <TextView
+        android:id="@+id/system_locale_subtitle"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+        android:textColor="?android:attr/textColorSecondary"
+        android:layout_weight="1" />
+</LinearLayout>
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index 81a79c5..a7f2aa7 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -49,6 +49,8 @@
         android:layout_marginStart="@dimen/notification_icon_circle_start"
         android:background="@drawable/notification_icon_circle"
         android:padding="@dimen/notification_icon_circle_padding"
+        android:maxDrawableWidth="@dimen/notification_icon_circle_size"
+        android:maxDrawableHeight="@dimen/notification_icon_circle_size"
         />
 
     <!-- extends ViewGroup -->
diff --git a/core/res/res/layout/notification_template_material_base.xml b/core/res/res/layout/notification_template_material_base.xml
index c6983ae..0756d68 100644
--- a/core/res/res/layout/notification_template_material_base.xml
+++ b/core/res/res/layout/notification_template_material_base.xml
@@ -45,6 +45,8 @@
         android:layout_marginStart="@dimen/notification_icon_circle_start"
         android:background="@drawable/notification_icon_circle"
         android:padding="@dimen/notification_icon_circle_padding"
+        android:maxDrawableWidth="@dimen/notification_icon_circle_size"
+        android:maxDrawableHeight="@dimen/notification_icon_circle_size"
         />
 
     <FrameLayout
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index da5f899..155e903 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2322,7 +2322,9 @@
         <attr name="windowSplashScreenAnimatedIcon" format="reference"/>
         <!-- The duration, in milliseconds, of the window splash screen icon animation duration
              when playing the splash screen starting window. The maximum animation duration should
-             be limited below 1000ms. -->
+             be limited below 1000ms.
+              @deprecated Not used by framework starting from API level 33. The system estimates the
+               duration of the vector animation automatically. -->
         <attr name="windowSplashScreenAnimationDuration" format="integer"/>
 
         <!-- Place an drawable image in the bottom of the starting window, it can be used to
@@ -5479,9 +5481,9 @@
             <enum name="none" value="0" />
             <!-- Use the least restrictive rule for line-breaking. -->
             <enum name="loose" value="1" />
-            <!-- Indicate breaking text with the most comment set of line-breaking rules. -->
+            <!-- Indicates breaking text with the most comment set of line-breaking rules. -->
             <enum name="normal" value="2" />
-            <!-- ndicates breaking text with the most strictest line-breaking rules. -->
+            <!-- Indicates breaking text with the most strictest line-breaking rules. -->
             <enum name="strict" value="3" />
         </attr>
         <!-- Specify the phrase-based line break can be used when calculating the text wrapping.-->
@@ -9807,4 +9809,12 @@
         of the supported locale. {@link android.app.LocaleConfig} -->
         <attr name="name" />
     </declare-styleable>
+
+    <!-- @hide -->
+    <declare-styleable name="CachingIconView">
+        <!-- Maximum width of displayed drawable. Drawables exceeding this size will be downsampled. -->
+        <attr name="maxDrawableWidth" format="dimension"/>
+        <!-- Maximum width of height drawable. Drawables exceeding this size will be downsampled. -->
+        <attr name="maxDrawableHeight" format="dimension"/>
+    </declare-styleable>
     </resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 579ef51..7562b9a 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -401,15 +401,6 @@
          and before. -->
     <attr name="sharedUserMaxSdkVersion" format="integer" />
 
-    <!-- Whether the application should inherit all AndroidKeyStore keys of its shared user
-         group in the case of leaving its shared user ID in an upgrade.  If set to false, all
-         AndroidKeyStore keys will remain in the shared user group, and the application will no
-         longer have access to those keys after the upgrade. If set to true, all AndroidKeyStore
-         keys owned by the shared user group will be transferred to the upgraded application;
-         other applications in the shared user group will no longer have access to those keys
-         after the migration. The default value is false if not explicitly set. -->
-    <attr name="inheritKeyStoreKeys" format="boolean" />
-
     <!-- Internal version code.  This is the number used to determine whether
          one version is more recent than another: it has no other meaning than
          that higher numbers are more recent.  You could use this number to
@@ -1704,7 +1695,6 @@
         <attr name="sharedUserId" />
         <attr name="sharedUserLabel" />
         <attr name="sharedUserMaxSdkVersion" />
-        <attr name="inheritKeyStoreKeys" />
         <attr name="installLocation" />
         <attr name="isolatedSplits" />
         <attr name="isFeatureSplit" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0a572be..94eb45c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2931,8 +2931,8 @@
     <!-- Apps that are authorized to access shared accounts, overridden by product overlays -->
     <string name="config_appsAuthorizedForSharedAccounts" translatable="false">;com.android.settings;</string>
 
-    <!-- Settings intelligence package name -->
-    <string name="config_settingsIntelligencePackageName" translatable="false">
+    <!-- System settings intelligence package name -->
+    <string name="config_systemSettingsIntelligence" translatable="false">
         com.android.settings.intelligence
     </string>
 
@@ -2963,6 +2963,11 @@
      the currently focused view is a text editor. -->
     <bool name="config_preventImeStartupUnlessTextEditor">false</bool>
 
+    <!-- These IMEs are known not to behave well when evicted from memory and thus are exempt
+         from the IME startup prevention behavior that is enabled by
+         config_preventImeStartupUnlessTextEditor. -->
+    <string-array name="config_nonPreemptibleInputMethods" translatable="false" />
+
     <!-- The list of classes that should be added to the notification ranking pipeline.
      See {@link com.android.server.notification.NotificationSignalExtractor}
       If you add a new extractor to this list make sure to update
@@ -2988,6 +2993,12 @@
 
     </string-array>
 
+    <!-- When migrating notification settings into the permission framework, whether all existing
+         apps should be marked as 'user-set' (true) or whether only the apps that have explicitly
+         modified notification settings should be marked as 'user-set' (false). Users will not see
+         system generated permission prompts for 'user-set' apps. -->
+    <bool name="config_notificationForceUserSetOnUpgrade">true</bool>
+
     <!-- Default Gravity setting for the system Toast view. Equivalent to: Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM -->
     <integer name="config_toastDefaultGravity">0x00000051</integer>
 
@@ -4851,6 +4862,7 @@
         <item>0.25</item>
         <item>0.5</item>
         <item>0.75</item>
+        <item>0.875</item>
     </string-array>
 
     <!-- Messages that should not be shown to the user during face auth enrollment. This should be
@@ -5735,13 +5747,13 @@
         exceeds the threshold, it'll be moved to restricted standby bucket. The value must be
         one of or combination of the definitions in AppBatteryPolicy.
     -->
-    <integer name="config_bg_current_drain_types_to_restricted_bucket">4</integer>
+    <integer name="config_bg_current_drain_types_to_restricted_bucket">20</integer>
 
     <!-- The types of battery drain we're checking on each app; if the sum of the battery drain
         exceeds the threshold, it'll be moved to background restricted level. The value must be
         one of or combination of the definitions in AppBatteryPolicy.
     -->
-    <integer name="config_bg_current_drain_types_to_bg_restricted">12</integer>
+    <integer name="config_bg_current_drain_types_to_bg_restricted">28</integer>
 
     <!-- The power usage components we're monitoring. Must one of the definition in BatteryConsumer.
     -->
@@ -5789,11 +5801,21 @@
     <!-- The types of state where we'll exempt its battery usage during that state.
          The state here must be one or a combination of STATE_TYPE_* in BaseAppStateTracker.
     -->
-    <integer name="config_bg_current_drain_exempted_types">9</integer>
+    <integer name="config_bg_current_drain_exempted_types">25</integer>
 
     <!-- The behavior when an app has the permission ACCESS_BACKGROUND_LOCATION granted,
          whether or not the system will use a higher threshold towards its background battery usage
          because of it.
     -->
     <bool name="config_bg_current_drain_high_threshold_by_bg_location">false</bool>
+
+    <!-- Start safety protection resources to be overlaid -->
+
+    <!-- Safety protection icon to be overlaid -->
+    <item name="ic_safety_protection" type="drawable">@null</item>
+
+    <!-- Display text for safety protection to be overlaid. This is translatable -->
+    <string name="safety_protection_display_text"></string>
+
+    <!-- End safety protection resources to be overlaid -->
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 1b9f7fe..323c726 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -668,8 +668,14 @@
     <dimen name="lock_pattern_dot_line_width">22dp</dimen>
     <dimen name="lock_pattern_dot_size">14dp</dimen>
     <dimen name="lock_pattern_dot_size_activated">30dp</dimen>
+    <!-- How much of the cell space is classified as hit areas [0..1] where 1 means that hit area is
+         a circle with diameter equals to cell minimum side min(width, height). -->
+    <item type="dimen" format="float" name="lock_pattern_dot_hit_factor">0.6</item>
     <!-- Width of a gradient applied to a lock pattern line while its disappearing animation. -->
     <dimen name="lock_pattern_fade_away_gradient_width">8dp</dimen>
+    <!-- Parameters applied to line disappearing animation in LockPatternView in milliseconds. -->
+    <integer name="lock_pattern_line_fade_out_duration">500</integer>
+    <integer name="lock_pattern_line_fade_out_delay">150</integer>
 
     <dimen name="text_handle_min_size">40dp</dimen>
 
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index 2dc17b8..aaf6a41 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -128,7 +128,7 @@
     <public name="localeConfig" />
     <public name="showBackground" />
     <public name="useTargetActivityForQuickAccess"/>
-    <public name="inheritKeyStoreKeys" />
+    <public name="removed_inheritKeyStoreKeys" />
     <public name="preferKeepClear" />
     <public name="autoHandwritingEnabled" />
     <public name="fromExtendLeft" />
@@ -148,6 +148,10 @@
     <public name="supportsInlineSuggestionsWithTouchExploration" />
     <public name="lineBreakStyle" />
     <public name="lineBreakWordStyle" />
+    <!-- @hide -->
+    <public name="maxDrawableWidth" />
+    <!-- @hide -->
+    <public name="maxDrawableHeight" />
   </staging-public-group>
 
   <staging-public-group type="id" first-id="0x01de0000">
@@ -175,6 +179,10 @@
     <public name="config_systemAutomotiveCalendarSyncManager" />
     <!-- @hide @SystemApi -->
     <public name="config_defaultAutomotiveNavigation" />
+    <!-- @hide @SystemApi -->
+    <public name="safety_protection_display_text" />
+    <!-- @hide @SystemApi -->
+    <public name="config_systemSettingsIntelligence" />
   </staging-public-group>
 
   <staging-public-group type="dimen" first-id="0x01db0000">
@@ -189,6 +197,8 @@
   </staging-public-group>
 
   <staging-public-group type="drawable" first-id="0x01d80000">
+    <!-- @hide @SystemApi -->
+    <public name="ic_safety_protection" />
   </staging-public-group>
 
   <staging-public-group type="layout" first-id="0x01d70000">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 602e42d..f11fd92 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1248,14 +1248,13 @@
         Malicious apps may use this to erase or modify your call log.</string>
 
     <!-- Title of the body sensors permission, listed so the user can decide whether to allow the application to access body sensor data. [CHAR LIMIT=80] -->
-    <string name="permlab_bodySensors">access body sensors (like heart rate monitors)
-    </string>
+    <string name="permlab_bodySensors">Access body sensor data, like heart rate, while in use</string>
     <!-- Description of the body sensors permission, listed so the user can decide whether to allow the application to access data from body sensors. [CHAR LIMIT=NONE] -->
-    <string name="permdesc_bodySensors" product="default">Access to data from body sensors such as heart rate, temperature, blood oxygen percentage, etc.</string>
+    <string name="permdesc_bodySensors" product="default">Allows the app to access body sensor data, such as heart rate, temperature, and blood oxygen percentage, while the app is in use.</string>
     <!-- Title of the background body sensors permission, listed so the user can decide whether to allow the application to access body sensor data in the background. [CHAR LIMIT=80] -->
-    <string name="permlab_bodySensors_background">access body sensors (like heart rate monitors) while in the background</string>
+    <string name="permlab_bodySensors_background">Access body sensor data, like heart rate, while in the background</string>
     <!-- Description of the background body sensors permission, listed so the user can decide whether to allow the application to access data from body sensors in the background. [CHAR LIMIT=NONE] -->
-    <string name="permdesc_bodySensors_background" product="default">Access to data from body sensors such as heart rate, temperature, blood oxygen percentage, etc. while in the background.</string>
+    <string name="permdesc_bodySensors_background" product="default">Allows the app to access body sensor data, such as heart rate, temperature, and blood oxygen percentage, while the app is in the background.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readCalendar">Read calendar events and details</string>
@@ -1919,9 +1918,9 @@
     <string name="permdesc_readMediaVideo">Allows the app to read video files from your shared storage.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] -->
-    <string name="permlab_readMediaImage">read image files from shared storage</string>
+    <string name="permlab_readMediaImages">read image files from shared storage</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] -->
-    <string name="permdesc_readMediaImage">Allows the app to read image files from your shared storage.</string>
+    <string name="permdesc_readMediaImages">Allows the app to read image files from your shared storage.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can write to. [CHAR LIMIT=none] -->
     <string name="permlab_sdcardWrite">modify or delete the contents of your shared storage</string>
@@ -2415,7 +2414,7 @@
     <!-- On the unlock pattern screen, shown at the top of the unlock screen to tell the user what to do. Below this text is the place for theu ser to draw the pattern. -->
     <string name="lockscreen_pattern_instructions">Draw pattern to unlock</string>
     <!-- Button at the bottom of the unlock screen to make an emergency call or access other emergency assistance functions. -->
-    <string name="lockscreen_emergency_call">Emergency call</string>
+    <string name="lockscreen_emergency_call">Emergency</string>
     <!-- Button at the bottom of the unlock screen that lets the user return to a call -->
     <string name="lockscreen_return_to_call">Return to call</string>
     <!-- Shown to confirm that the user entered their lock pattern correctly. -->
@@ -2989,9 +2988,6 @@
     <!-- Displayed to the user to confirm that they have copied text from a web page to the clipboard. -->
     <string name="text_copied">Text copied to clipboard.</string>
 
-    <!-- Displayed to the user to confirm that they have copied text/images to the clipboard [CHAR LIMIT=NONE] -->
-    <string name="copied">Copied</string>
-
     <!-- Displayed to the user to inform them that an app has accessed clipboard data (pasted as in "copy and paste") that was copied from another app [CHAR LIMIT=50] -->
     <string name="pasted_from_app"><xliff:g id="pasting_app_name" example="Gmail">%1$s</xliff:g> pasted from <xliff:g id="source_app_name" example="Chrome">%2$s</xliff:g></string>
 
@@ -4095,21 +4091,6 @@
     <!-- Description of an application permission that lets it query all other packages. [CHAR LIMIT=NONE] -->
     <string name="permdesc_queryAllPackages">Allows an app to see all installed packages.</string>
 
-    <!-- Title of an application permission that lets it access AdServices Topics API. [CHAR LIMIT=NONE] -->
-    <string name="permlab_accessAdServicesTopics">access AdServices Topics API</string>
-    <!-- Description of an application permission that lets it access AdServices Topics API. [CHAR LIMIT=NONE]-->
-    <string name="permdesc_accessAdServicesTopics">Allows an application to access AdServices Topics API.</string>
-
-    <!-- Title of an application permission that lets it access AdServices Attribution APIs. [CHAR LIMIT=NONE] -->
-    <string name="permlab_accessAdServicesAttribution">access AdServices Attribution APIs</string>
-    <!-- Description of an application permission that lets it access AdServices Attribution APIs. [CHAR LIMIT=NONE]-->
-    <string name="permdesc_accessAdServicesAttribution">Allows an application to access AdServices Attribution APIs.</string>
-
-    <!-- Title of an application permission that lets it access AdServices Custom Audiences API. [CHAR LIMIT=NONE] -->
-    <string name="permlab_accessAdServicesCustomAudiences">access AdServices Custom Audiences API</string>
-    <!-- Description of an application permission that lets it access AdServices Custom Audiences API. [CHAR LIMIT=NONE]-->
-    <string name="permdesc_accessAdServicesCustomAudiences">Allows an application to access AdServices Custom Audiences  API.</string>
-
     <!-- Shown in the tutorial for tap twice for zoom control. -->
     <string name="tutorial_double_tap_to_zoom_message_short">Tap twice for zoom control</string>
 
@@ -5483,6 +5464,8 @@
 
     <!-- Title of the dialog shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
     <string name="app_streaming_blocked_title"><xliff:g id="activity" example="Permission dialog">%1$s</xliff:g> unavailable</string>
+    <!-- Title of the dialog shown when the permissioncontroller is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
+    <string name="app_streaming_blocked_title_for_permission_dialog">Permission needed</string>
     <!-- Message shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
     <string name="app_streaming_blocked_message" product="tv">This can’t be accessed on your <xliff:g id="device" example="Chromebook">%1$s</xliff:g> at this time. Try on your Android TV device instead.</string>
     <!-- Message shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
@@ -5740,7 +5723,7 @@
 
     <!-- Content for the log access confirmation dialog. [CHAR LIMIT=NONE]-->
     <string name="log_access_confirmation_body">Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps you trust to access all device logs.
-        \n\nIf you don’t allow this app to access all device logs, it can still access its own logs, and your device manufacturer may still be able to access some logs or info on your device. Learn more
+        \n\nIf you don’t allow this app to access all device logs, it can still access its own logs and your device manufacturer may still be able to access some logs or info on your device. Learn more
     </string>
 
     <!-- Privacy notice do not show [CHAR LIMIT=20] -->
@@ -6296,5 +6279,10 @@
 
     <!-- Strings for VirtualDeviceManager -->
     <!-- Error message indicating the camera cannot be accessed when running on a virtual device. [CHAR LIMIT=NONE] -->
-    <string name="vdm_camera_access_denied">Cannot access camera from this device</string>
+    <string name="vdm_camera_access_denied" product="default">Can’t access the phone’s camera from your <xliff:g id="device" example="Chromebook">%1$s</xliff:g></string>
+    <!-- Error message indicating the camera cannot be accessed when running on a virtual device. [CHAR LIMIT=NONE] -->
+    <string name="vdm_camera_access_denied" product="tablet">Can’t access the tablet’s camera from your <xliff:g id="device" example="Chromebook">%1$s</xliff:g></string>
+
+    <!-- Title for preference of the system default locale. [CHAR LIMIT=50]-->
+    <string name="system_locale_title">System language</string>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 8f3abd6..f1a8e56 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1325,7 +1325,10 @@
   <java-symbol type="dimen" name="lock_pattern_dot_line_width" />
   <java-symbol type="dimen" name="lock_pattern_dot_size" />
   <java-symbol type="dimen" name="lock_pattern_dot_size_activated" />
+  <java-symbol type="dimen" name="lock_pattern_dot_hit_factor" />
   <java-symbol type="dimen" name="lock_pattern_fade_away_gradient_width" />
+  <java-symbol type="integer" name="lock_pattern_line_fade_out_duration" />
+  <java-symbol type="integer" name="lock_pattern_line_fade_out_delay" />
   <java-symbol type="drawable" name="clock_dial" />
   <java-symbol type="drawable" name="clock_hand_hour" />
   <java-symbol type="drawable" name="clock_hand_minute" />
@@ -2268,6 +2271,7 @@
   <java-symbol type="string" name="config_notificationAccessConfirmationActivity" />
   <java-symbol type="bool" name="config_killableInputMethods" />
   <java-symbol type="bool" name="config_preventImeStartupUnlessTextEditor" />
+  <java-symbol type="array" name="config_nonPreemptibleInputMethods" />
 
   <java-symbol type="layout" name="resolver_list" />
   <java-symbol type="id" name="resolver_list" />
@@ -3296,6 +3300,7 @@
   <java-symbol type="string" name="app_blocked_message" />
 
   <java-symbol type="string" name="app_streaming_blocked_title" />
+  <java-symbol type="string" name="app_streaming_blocked_title_for_permission_dialog" />
   <java-symbol type="string" name="app_streaming_blocked_message" />
 
   <!-- Used internally for assistant to launch activity transitions -->
@@ -4648,8 +4653,6 @@
   <java-symbol type="drawable" name="ic_accessibility_24dp" />
   <java-symbol type="string" name="view_and_control_notification_title" />
   <java-symbol type="string" name="view_and_control_notification_content" />
-  <java-symbol type="array" name="config_accessibility_allowed_install_source" />
-
   <!-- Translation -->
   <java-symbol type="string" name="ui_translation_accessibility_translated_text" />
   <java-symbol type="string" name="ui_translation_accessibility_translation_finished" />
@@ -4769,5 +4772,9 @@
   <java-symbol type="integer" name="config_bg_current_drain_exempted_types" />
   <java-symbol type="bool" name="config_bg_current_drain_high_threshold_by_bg_location" />
   <java-symbol type="drawable" name="ic_swap_horiz" />
+  <java-symbol type="bool" name="config_notificationForceUserSetOnUpgrade" />
 
+  <java-symbol type="string" name="system_locale_title" />
+  <java-symbol type="layout" name="app_language_picker_system_default" />
+  <java-symbol type="id" name="system_locale_subtitle" />
 </resources>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
index 6a53f68..19bb718 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
@@ -188,6 +188,9 @@
                 case BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE:
                     label = "FGS";
                     break;
+                case BatteryConsumer.PROCESS_STATE_CACHED:
+                    label = "cached";
+                    break;
                 default:
                     continue;
             }
diff --git a/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java b/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java
index 23b12cf..fd08e3c 100644
--- a/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java
+++ b/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java
@@ -242,13 +242,17 @@
                 BatteryConsumer.PROCESS_STATE_BACKGROUND);
         final BatteryConsumer.Key keyFgs = uidBuilder.getKey(BatteryConsumer.POWER_COMPONENT_CPU,
                 BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE);
+        final BatteryConsumer.Key keyCached = uidBuilder.getKey(BatteryConsumer.POWER_COMPONENT_CPU,
+                BatteryConsumer.PROCESS_STATE_CACHED);
 
         uidBuilder.setConsumedPower(keyFg, 9100, BatteryConsumer.POWER_MODEL_POWER_PROFILE)
                 .setUsageDurationMillis(keyFg, 8100)
                 .setConsumedPower(keyBg, 9200, BatteryConsumer.POWER_MODEL_MEASURED_ENERGY)
                 .setUsageDurationMillis(keyBg, 8200)
                 .setConsumedPower(keyFgs, 9300, BatteryConsumer.POWER_MODEL_MEASURED_ENERGY)
-                .setUsageDurationMillis(keyFgs, 8300);
+                .setUsageDurationMillis(keyFgs, 8300)
+                .setConsumedPower(keyCached, 9400, BatteryConsumer.POWER_MODEL_MEASURED_ENERGY)
+                .setUsageDurationMillis(keyFgs, 8400);
 
         builder.getOrCreateUidBatteryConsumerBuilder(batteryStatsUid1)
                 .setPackageWithHighestDrain("myPackage1")
diff --git a/core/tests/coretests/res/drawable/big_a.png b/core/tests/coretests/res/drawable/big_a.png
new file mode 100644
index 0000000..dc059a3
--- /dev/null
+++ b/core/tests/coretests/res/drawable/big_a.png
Binary files differ
diff --git a/packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml b/core/tests/coretests/res/layout/caching_icon_view_test_max_size.xml
similarity index 62%
copy from packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml
copy to core/tests/coretests/res/layout/caching_icon_view_test_max_size.xml
index f9ec5d0..9a03446 100644
--- a/packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml
+++ b/core/tests/coretests/res/layout/caching_icon_view_test_max_size.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -14,9 +15,10 @@
   ~ limitations under the License.
   -->
 
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-       android:shape="rectangle">
-    <solid android:color="@android:color/system_accent1_100"/>
-    <corners android:topLeftRadius="16dp" android:topRightRadius="16dp"
-             android:bottomLeftRadius="16dp" android:bottomRightRadius="16dp"/>
-</shape>
\ No newline at end of file
+<com.android.internal.widget.CachingIconView
+          xmlns:android="http://schemas.android.com/apk/res/android"
+          android:id="@+id/caching_icon_view"
+          android:layout_width="120dp"
+          android:layout_height="120dp"
+          android:maxDrawableWidth="80dp"
+          android:maxDrawableHeight="80dp" />
diff --git a/packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml b/core/tests/coretests/res/layout/caching_icon_view_test_no_max_size.xml
similarity index 65%
copy from packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml
copy to core/tests/coretests/res/layout/caching_icon_view_test_no_max_size.xml
index f9ec5d0..a213a97 100644
--- a/packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml
+++ b/core/tests/coretests/res/layout/caching_icon_view_test_no_max_size.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -14,9 +15,8 @@
   ~ limitations under the License.
   -->
 
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-       android:shape="rectangle">
-    <solid android:color="@android:color/system_accent1_100"/>
-    <corners android:topLeftRadius="16dp" android:topRightRadius="16dp"
-             android:bottomLeftRadius="16dp" android:bottomRightRadius="16dp"/>
-</shape>
\ No newline at end of file
+<com.android.internal.widget.CachingIconView
+          xmlns:android="http://schemas.android.com/apk/res/android"
+          android:id="@+id/caching_icon_view"
+          android:layout_width="120dp"
+          android:layout_height="120dp" />
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 5c9044c..beadc446 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -424,6 +424,7 @@
 
         @Override
         public void bindApplication(String s, ApplicationInfo applicationInfo,
+                String sdkSandboxClientAppPackage,
                 ProviderInfoList list, ComponentName componentName, ProfilerInfo profilerInfo,
                 Bundle bundle, IInstrumentationWatcher iInstrumentationWatcher,
                 IUiAutomationConnection iUiAutomationConnection, int i, boolean b, boolean b1,
diff --git a/core/tests/coretests/src/android/content/pm/CrossProfileAppsTest.java b/core/tests/coretests/src/android/content/pm/CrossProfileAppsTest.java
index fa657f7..5e07607 100644
--- a/core/tests/coretests/src/android/content/pm/CrossProfileAppsTest.java
+++ b/core/tests/coretests/src/android/content/pm/CrossProfileAppsTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.Mockito.when;
 
 import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyResourcesManager;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
@@ -66,6 +67,8 @@
     @Mock
     private DevicePolicyManager mDevicePolicyManager;
     @Mock
+    private DevicePolicyResourcesManager mDevicePolicyResourcesManager;
+    @Mock
     private ICrossProfileApps mService;
     @Mock
     private Resources mResources;
@@ -89,6 +92,7 @@
                 Context.DEVICE_POLICY_SERVICE);
         when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(
                 mDevicePolicyManager);
+        when(mDevicePolicyManager.getResources()).thenReturn(mDevicePolicyResourcesManager);
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
     }
 
@@ -113,7 +117,7 @@
         setValidTargetProfile(MANAGED_PROFILE);
 
         mCrossProfileApps.getProfileSwitchingLabel(MANAGED_PROFILE);
-        verify(mDevicePolicyManager).getString(eq(SWITCH_TO_WORK_LABEL), any());
+        verify(mDevicePolicyResourcesManager).getString(eq(SWITCH_TO_WORK_LABEL), any());
     }
 
     @Test
@@ -121,7 +125,7 @@
         setValidTargetProfile(PERSONAL_PROFILE);
 
         mCrossProfileApps.getProfileSwitchingLabel(PERSONAL_PROFILE);
-        verify(mDevicePolicyManager).getString(eq(SWITCH_TO_PERSONAL_LABEL), any());
+        verify(mDevicePolicyResourcesManager).getString(eq(SWITCH_TO_PERSONAL_LABEL), any());
     }
 
     @Test(expected = SecurityException.class)
diff --git a/core/tests/coretests/src/android/graphics/drawable/IconTest.java b/core/tests/coretests/src/android/graphics/drawable/IconTest.java
index 2bdcc28..75390a2 100644
--- a/core/tests/coretests/src/android/graphics/drawable/IconTest.java
+++ b/core/tests/coretests/src/android/graphics/drawable/IconTest.java
@@ -180,6 +180,61 @@
         }
     }
 
+    /**
+     * Icon resource test that ensures we can load and draw non-bitmaps. (In this case,
+     * stat_sys_adb is assumed, and asserted, to be a vector drawable.)
+     */
+    @SmallTest
+    public void testWithStatSysAdbResource() throws Exception {
+        // establish reference bitmap
+        final float dp = getContext().getResources().getDisplayMetrics().density;
+        final int stat_sys_adb_width = (int) (24 * dp);
+        final int stat_sys_adb_height = (int) (24 * dp);
+
+        final Drawable stat_sys_adb = getContext()
+                .getDrawable(com.android.internal.R.drawable.stat_sys_adb);
+        if (!(stat_sys_adb instanceof VectorDrawable)) {
+            fail("stat_sys_adb is a " + stat_sys_adb.toString()
+                    + ", not a VectorDrawable; stat_sys_adb malformed");
+        }
+
+        if (stat_sys_adb.getIntrinsicWidth() != stat_sys_adb_width) {
+            fail("intrinsic width of stat_sys_adb is not 24dp; stat_sys_adb malformed");
+        }
+        if (stat_sys_adb.getIntrinsicHeight() != stat_sys_adb_height) {
+            fail("intrinsic height of stat_sys_adb is not 24dp; stat_sys_adb malformed");
+        }
+        final Bitmap referenceBitmap = Bitmap.createBitmap(
+                stat_sys_adb_width,
+                stat_sys_adb_height,
+                Bitmap.Config.ARGB_8888);
+        stat_sys_adb.setBounds(0, 0, stat_sys_adb_width, stat_sys_adb_height);
+        stat_sys_adb.draw(new Canvas(referenceBitmap));
+
+        final Icon im1 = Icon.createWithResource(getContext(),
+                com.android.internal.R.drawable.stat_sys_adb);
+        final Drawable draw1 = im1.loadDrawable(getContext());
+
+        assertEquals(stat_sys_adb.getIntrinsicWidth(), draw1.getIntrinsicWidth());
+        assertEquals(stat_sys_adb.getIntrinsicHeight(), draw1.getIntrinsicHeight());
+        assertEquals(im1.getResId(), com.android.internal.R.drawable.stat_sys_adb);
+
+        final Bitmap test1 = Bitmap.createBitmap(
+                draw1.getIntrinsicWidth(),
+                draw1.getIntrinsicHeight(),
+                Bitmap.Config.ARGB_8888);
+        draw1.setBounds(0, 0, test1.getWidth(), test1.getHeight());
+        draw1.draw(new Canvas(test1));
+
+        final File dir = getContext().getExternalFilesDir(null);
+        test1.compress(Bitmap.CompressFormat.PNG, 100,
+                new FileOutputStream(new File(dir, "testWithVectorDrawableResource-test.png")));
+        if (!equalBitmaps(referenceBitmap, test1)) {
+            findBitmapDifferences(referenceBitmap, test1);
+            fail("testWithFile: file1 differs, check " + dir);
+        }
+    }
+
     @SmallTest
     public void testWithFile() throws Exception {
         final Bitmap bit1 = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape))
diff --git a/core/tests/coretests/src/android/net/SntpClientTest.java b/core/tests/coretests/src/android/net/SntpClientTest.java
index ba7df1e..267fc2b 100644
--- a/core/tests/coretests/src/android/net/SntpClientTest.java
+++ b/core/tests/coretests/src/android/net/SntpClientTest.java
@@ -295,7 +295,8 @@
 
     @Test
     public void testDnsResolutionFailure() throws Exception {
-        assertFalse(mClient.requestTime("ntp.server.doesnotexist.example", 5000, mNetwork));
+        assertFalse(mClient.requestTime("ntp.server.doesnotexist.example",
+                SntpClient.STANDARD_NTP_PORT, 5000, mNetwork));
     }
 
     @Test
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 227a8657..c504f0c 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -30,6 +30,7 @@
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
 import static android.view.InsetsState.LAST_TYPE;
+import static android.view.ViewRootImpl.CAPTION_ON_SHELL;
 import static android.view.WindowInsets.Type.ime;
 import static android.view.WindowInsets.Type.navigationBars;
 import static android.view.WindowInsets.Type.statusBars;
@@ -758,6 +759,11 @@
 
     @Test
     public void testCaptionInsetsStateAssemble() {
+        if (CAPTION_ON_SHELL) {
+            // For this case, the test is covered by WindowContainerInsetsSourceProviderTest, This
+            // test can be removed after the caption is moved to shell completely.
+            return;
+        }
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             mController.onFrameChanged(new Rect(0, 0, 100, 300));
             final InsetsState state = new InsetsState(mController.getState(), true);
@@ -769,6 +775,7 @@
             assertEquals(captionFrame, currentState.peekSource(ITYPE_CAPTION_BAR).getFrame());
             assertTrue(currentState.equals(state, true /* excludingCaptionInsets*/,
                     true /* excludeInvisibleIme */));
+            // Test update to remove the caption bar
             mController.setCaptionInsetsHeight(0);
             mController.onStateChanged(state);
             // The caption bar source should not be there at all, because we don't add empty
@@ -779,6 +786,11 @@
 
     @Test
     public void testNotifyCaptionInsetsOnlyChange() {
+        if (CAPTION_ON_SHELL) {
+            // For this case, the test is covered by WindowContainerInsetsSourceProviderTest, This
+            // test can be removed after the caption is moved to shell completely.
+            return;
+        }
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             final InsetsState state = new InsetsState(mController.getState(), true);
             reset(mTestHost);
diff --git a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
index 1ae9649..e303934 100644
--- a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
+++ b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
@@ -60,7 +60,7 @@
 @RunWith(AndroidJUnit4.class)
 public class HandwritingInitiatorTest {
     private static final int TOUCH_SLOP = 8;
-    private static final long TAP_TIMEOUT = ViewConfiguration.getTapTimeout();
+    private static final long TIMEOUT = ViewConfiguration.getLongPressTimeout();
     private static final Rect sHwArea = new Rect(100, 200, 500, 500);
 
     private HandwritingInitiator mHandwritingInitiator;
@@ -177,7 +177,7 @@
     }
 
     @Test
-    public void onTouchEvent_notStartHandwriting_when_stylusMove_afterTapTimeOut() {
+    public void onTouchEvent_notStartHandwriting_when_stylusMove_afterTimeOut() {
         mHandwritingInitiator.onInputConnectionCreated(mTestView);
         final int x1 = 10;
         final int y1 = 10;
@@ -187,7 +187,7 @@
 
         final int x2 = x1 + TOUCH_SLOP * 2;
         final int y2 = y1;
-        final long time2 = time1 + TAP_TIMEOUT + 10L;
+        final long time2 = time1 + TIMEOUT + 10L;
         MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, time2);
         mHandwritingInitiator.onTouchEvent(stylusEvent2);
 
diff --git a/core/tests/coretests/src/android/window/BackNavigationTest.java b/core/tests/coretests/src/android/window/BackNavigationTest.java
index 8fa48ef..94a149b 100644
--- a/core/tests/coretests/src/android/window/BackNavigationTest.java
+++ b/core/tests/coretests/src/android/window/BackNavigationTest.java
@@ -111,12 +111,12 @@
         CountDownLatch backRegisteredLatch = new CountDownLatch(1);
         mScenario.onActivity(activity -> {
             activity.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
-                    new OnBackInvokedCallback() {
+                    0, new OnBackInvokedCallback() {
                         @Override
                         public void onBackInvoked() {
                             backInvokedLatch.countDown();
                         }
-                    }, 0
+                    }
             );
             backRegisteredLatch.countDown();
         });
diff --git a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
index f8c9944..212f4ed 100644
--- a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
+++ b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
@@ -77,9 +77,9 @@
                 ArgumentCaptor.forClass(IOnBackInvokedCallback.class);
 
         mDispatcher.registerOnBackInvokedCallback(
-                mCallback1, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+                OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback1);
         mDispatcher.registerOnBackInvokedCallback(
-                mCallback2, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+                OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback2);
 
         verify(mWindowSession, times(2)).setOnBackInvokedCallback(
                 Mockito.eq(mWindow),
@@ -102,9 +102,9 @@
                 ArgumentCaptor.forClass(IOnBackInvokedCallback.class);
 
         mDispatcher.registerOnBackInvokedCallback(
-                mCallback1, OnBackInvokedDispatcher.PRIORITY_OVERLAY);
+                OnBackInvokedDispatcher.PRIORITY_OVERLAY, mCallback1);
         mDispatcher.registerOnBackInvokedCallback(
-                mCallback2, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+                OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback2);
 
         verify(mWindowSession).setOnBackInvokedCallback(
                 Mockito.eq(mWindow), captor.capture(),
@@ -118,9 +118,9 @@
     @Test
     public void propagatesTopCallback_withRemoval() throws RemoteException {
         mDispatcher.registerOnBackInvokedCallback(
-                mCallback1, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+                OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback1);
         mDispatcher.registerOnBackInvokedCallback(
-                mCallback2, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+                OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback2);
 
         reset(mWindowSession);
         mDispatcher.unregisterOnBackInvokedCallback(mCallback1);
@@ -139,16 +139,17 @@
         ArgumentCaptor<IOnBackInvokedCallback> captor =
                 ArgumentCaptor.forClass(IOnBackInvokedCallback.class);
 
-        mDispatcher.registerOnBackInvokedCallback(mCallback1,
-                OnBackInvokedDispatcher.PRIORITY_OVERLAY);
+        mDispatcher.registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_OVERLAY,
+                mCallback1
+        );
         mDispatcher.registerOnBackInvokedCallback(
-                mCallback2, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+                OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback2);
         mDispatcher.registerOnBackInvokedCallback(
-                mCallback1, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+                OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback1);
 
         reset(mWindowSession);
         mDispatcher.registerOnBackInvokedCallback(
-                mCallback2, OnBackInvokedDispatcher.PRIORITY_OVERLAY);
+                OnBackInvokedDispatcher.PRIORITY_OVERLAY, mCallback2);
         verify(mWindowSession).setOnBackInvokedCallback(
                 Mockito.eq(mWindow),
                 captor.capture(),
diff --git a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
index 1f6b57e..a663095 100644
--- a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
@@ -44,7 +44,6 @@
 import android.metrics.LogMaker;
 import android.net.Uri;
 import android.os.Bundle;
-import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -649,7 +648,7 @@
 
         @Override
         public void startActivityAsCaller(Intent intent, @Nullable Bundle options,
-                IBinder permissionToken, boolean ignoreTargetSecurity, int userId) {
+                boolean ignoreTargetSecurity, int userId) {
             mStartActivityIntent = intent;
             mUserIdActivityLaunchedIn = userId;
         }
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryTest.java
index cd61011..863aac35 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryTest.java
@@ -45,7 +45,13 @@
 public class BatteryStatsHistoryTest {
     private static final String TAG = "BatteryStatsHistoryTest";
     private static final int MAX_HISTORY_FILES = 32;
-    private final BatteryStatsImpl mBatteryStatsImpl = new MockBatteryStatsImpl();
+    private static final int MAX_HISTORY_BUFFER_KB = 128;
+
+    // Initializing max history files and buffer to the default values of non-low-ram device
+    // to maintain consistency in the tests
+    private final BatteryStatsImpl mBatteryStatsImpl = new MockBatteryStatsImpl()
+            .setMaxHistoryFiles(MAX_HISTORY_FILES)
+            .setMaxHistoryBuffer(MAX_HISTORY_BUFFER_KB * 1024);
     private final Parcel mHistoryBuffer = Parcel.obtain();
     private File mSystemDir;
     private File mHistoryDir;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
index f5cbffb..87c45dc 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -17,6 +17,8 @@
 package com.android.internal.os;
 
 import static android.os.BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS;
+import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE;
+import static android.os.BatteryStats.RADIO_ACCESS_TECHNOLOGY_COUNT;
 import static android.os.BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR;
 import static android.os.BatteryStats.STATS_SINCE_CHARGED;
 import static android.os.BatteryStats.WAKE_TYPE_PARTIAL;
@@ -24,16 +26,25 @@
 import static com.android.internal.os.BatteryStatsImpl.ExternalStatsSync.UPDATE_CPU;
 import static com.android.internal.os.BatteryStatsImpl.ExternalStatsSync.UPDATE_DISPLAY;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+
 import android.app.ActivityManager;
+import android.app.usage.NetworkStatsManager;
+import android.hardware.radio.V1_5.AccessNetwork;
 import android.os.BatteryStats;
 import android.os.BatteryStats.HistoryItem;
 import android.os.BatteryStats.Uid.Sensor;
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.WorkSource;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.ActivityStatsTechSpecificInfo;
 import android.telephony.Annotation;
 import android.telephony.CellSignalStrength;
 import android.telephony.DataConnectionRealTimeInfo;
+import android.telephony.ModemActivityInfo;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 import android.util.SparseIntArray;
@@ -48,8 +59,12 @@
 
 import junit.framework.TestCase;
 
+import org.mockito.Mock;
+
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.function.IntConsumer;
 
@@ -72,6 +87,13 @@
     private static final int ISOLATED_UID = UserHandle.getUid(0, ISOLATED_APP_ID);
     private static final WorkSource WS = new WorkSource(UID);
 
+    enum ModemState {
+        SLEEP, IDLE, RECEIVING, TRANSMITTING
+    }
+
+    @Mock
+    NetworkStatsManager mNetworkStatsManager;
+
     /**
      * Test BatteryStatsImpl.Uid.noteBluetoothScanResultLocked.
      */
@@ -213,6 +235,116 @@
         assertEquals(120_000, bgTime);
     }
 
+    /**
+     * Test BatteryStatsImpl.Uid.noteLongPartialWakelockStart for an isolated uid.
+     */
+    @SmallTest
+    public void testNoteLongPartialWakelockStart_isolatedUid() throws Exception {
+        final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
+        MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+
+
+        bi.setRecordAllHistoryLocked(true);
+        bi.forceRecordAllHistory();
+
+        int pid = 10;
+        String name = "name";
+        String historyName = "historyName";
+
+        WorkSource.WorkChain isolatedWorkChain = new WorkSource.WorkChain();
+        isolatedWorkChain.addNode(ISOLATED_UID, name);
+
+        // Map ISOLATED_UID to UID.
+        bi.addIsolatedUidLocked(ISOLATED_UID, UID);
+
+        bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+        bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
+        bi.noteLongPartialWakelockStart(name, historyName, ISOLATED_UID);
+
+        clocks.realtime = clocks.uptime = 100;
+        bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+
+        clocks.realtime = clocks.uptime = 220;
+        bi.noteLongPartialWakelockFinish(name, historyName, ISOLATED_UID);
+
+        final BatteryStatsHistoryIterator iterator =
+                bi.createBatteryStatsHistoryIterator();
+
+        BatteryStats.HistoryItem item = new BatteryStats.HistoryItem();
+
+        while (iterator.next(item)) {
+            if (item.eventCode == HistoryItem.EVENT_LONG_WAKE_LOCK_START) break;
+        }
+        assertThat(item.eventCode).isEqualTo(HistoryItem.EVENT_LONG_WAKE_LOCK_START);
+        assertThat(item.eventTag).isNotNull();
+        assertThat(item.eventTag.string).isEqualTo(historyName);
+        assertThat(item.eventTag.uid).isEqualTo(UID);
+
+        while (iterator.next(item)) {
+            if (item.eventCode == HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH) break;
+        }
+        assertThat(item.eventCode).isEqualTo(HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH);
+        assertThat(item.eventTag).isNotNull();
+        assertThat(item.eventTag.string).isEqualTo(historyName);
+        assertThat(item.eventTag.uid).isEqualTo(UID);
+    }
+
+    /**
+     * Test BatteryStatsImpl.Uid.noteLongPartialWakelockStart for an isolated uid.
+     */
+    @SmallTest
+    public void testNoteLongPartialWakelockStart_isolatedUidRace() throws Exception {
+        final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
+        MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+
+
+        bi.setRecordAllHistoryLocked(true);
+        bi.forceRecordAllHistory();
+
+        int pid = 10;
+        String name = "name";
+        String historyName = "historyName";
+
+        WorkSource.WorkChain isolatedWorkChain = new WorkSource.WorkChain();
+        isolatedWorkChain.addNode(ISOLATED_UID, name);
+
+        // Map ISOLATED_UID to UID.
+        bi.addIsolatedUidLocked(ISOLATED_UID, UID);
+
+        bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+        bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
+        bi.noteLongPartialWakelockStart(name, historyName, ISOLATED_UID);
+
+        clocks.realtime = clocks.uptime = 100;
+        bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+
+        clocks.realtime = clocks.uptime = 150;
+        bi.maybeRemoveIsolatedUidLocked(ISOLATED_UID, clocks.realtime, clocks.uptime);
+
+        clocks.realtime = clocks.uptime = 220;
+        bi.noteLongPartialWakelockFinish(name, historyName, ISOLATED_UID);
+
+        final BatteryStatsHistoryIterator iterator =
+                bi.createBatteryStatsHistoryIterator();
+
+        BatteryStats.HistoryItem item = new BatteryStats.HistoryItem();
+
+        while (iterator.next(item)) {
+            if (item.eventCode == HistoryItem.EVENT_LONG_WAKE_LOCK_START) break;
+        }
+        assertThat(item.eventCode).isEqualTo(HistoryItem.EVENT_LONG_WAKE_LOCK_START);
+        assertThat(item.eventTag).isNotNull();
+        assertThat(item.eventTag.string).isEqualTo(historyName);
+        assertThat(item.eventTag.uid).isEqualTo(UID);
+
+        while (iterator.next(item)) {
+            if (item.eventCode == HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH) break;
+        }
+        assertThat(item.eventCode).isEqualTo(HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH);
+        assertThat(item.eventTag).isNotNull();
+        assertThat(item.eventTag.string).isEqualTo(historyName);
+        assertThat(item.eventTag.uid).isEqualTo(UID);
+    }
 
     /**
      * Test BatteryStatsImpl.noteUidProcessStateLocked.
@@ -1173,69 +1305,29 @@
     }
 
     @SmallTest
-    public void testGetPerStateActiveRadioDurationMs() {
+    public void testGetPerStateActiveRadioDurationMs_noModemActivity() {
         final MockClock clock = new MockClock(); // holds realtime and uptime in ms
         final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clock);
-        final int ratCount = BatteryStats.RADIO_ACCESS_TECHNOLOGY_COUNT;
+        final int ratCount = RADIO_ACCESS_TECHNOLOGY_COUNT;
         final int frequencyCount = ServiceState.FREQUENCY_RANGE_MMWAVE + 1;
         final int txLevelCount = CellSignalStrength.getNumSignalStrengthLevels();
 
         final long[][][] expectedDurationsMs = new long[ratCount][frequencyCount][txLevelCount];
+        final long[][] expectedRxDurationsMs = new long[ratCount][frequencyCount];
+        final long[][][] expectedTxDurationsMs = new long[ratCount][frequencyCount][txLevelCount];
         for (int rat = 0; rat < ratCount; rat++) {
             for (int freq = 0; freq < frequencyCount; freq++) {
+                // Should have no RX data without Modem Activity Info
+                expectedRxDurationsMs[rat][freq] = POWER_DATA_UNAVAILABLE;
                 for (int txLvl = 0; txLvl < txLevelCount; txLvl++) {
                     expectedDurationsMs[rat][freq][txLvl] = 0;
+                    // Should have no TX data without Modem Activity Info
+                    expectedTxDurationsMs[rat][freq][txLvl] = POWER_DATA_UNAVAILABLE;
                 }
             }
         }
 
-        class ModemAndBatteryState {
-            public long currentTimeMs = 100;
-            public boolean onBattery = false;
-            public boolean modemActive = false;
-            @Annotation.NetworkType
-            public int currentNetworkDataType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
-            @BatteryStats.RadioAccessTechnology
-            public int currentRat = BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER;
-            @ServiceState.FrequencyRange
-            public int currentFrequencyRange = ServiceState.FREQUENCY_RANGE_UNKNOWN;
-            public SparseIntArray currentSignalStrengths = new SparseIntArray();
-
-            void setOnBattery(boolean onBattery) {
-                this.onBattery = onBattery;
-                bi.updateTimeBasesLocked(onBattery, Display.STATE_OFF, currentTimeMs * 1000,
-                        currentTimeMs * 1000);
-            }
-
-            void setModemActive(boolean active) {
-                modemActive = active;
-                final int state = active ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
-                        : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
-                bi.noteMobileRadioPowerStateLocked(state, currentTimeMs * 1000_000L, UID);
-            }
-
-            void setRatType(@Annotation.NetworkType int dataType,
-                    @BatteryStats.RadioAccessTechnology int rat) {
-                currentNetworkDataType = dataType;
-                currentRat = rat;
-                bi.notePhoneDataConnectionStateLocked(dataType, true, ServiceState.STATE_IN_SERVICE,
-                        currentFrequencyRange);
-            }
-
-            void setFrequencyRange(@ServiceState.FrequencyRange int frequency) {
-                currentFrequencyRange = frequency;
-                bi.notePhoneDataConnectionStateLocked(currentNetworkDataType, true,
-                        ServiceState.STATE_IN_SERVICE, frequency);
-            }
-
-            void setSignalStrength(@BatteryStats.RadioAccessTechnology int rat, int strength) {
-                currentSignalStrengths.put(rat, strength);
-                final int size = currentSignalStrengths.size();
-                final int newestGenSignalStrength = currentSignalStrengths.valueAt(size - 1);
-                bi.notePhoneSignalStrengthLocked(newestGenSignalStrength, currentSignalStrengths);
-            }
-        }
-        final ModemAndBatteryState state = new ModemAndBatteryState();
+        final ModemAndBatteryState state = new ModemAndBatteryState(bi, null, null);
 
         IntConsumer incrementTime = inc -> {
             state.currentTimeMs += inc;
@@ -1253,6 +1345,7 @@
             expectedDurationsMs[currentRat][currentFrequencyRange][currentSignalStrength] += inc;
         };
 
+
         state.setOnBattery(false);
         state.setModemActive(false);
         state.setRatType(TelephonyManager.NETWORK_TYPE_UNKNOWN,
@@ -1260,95 +1353,633 @@
         state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_UNKNOWN);
         state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER,
                 CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
-        checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
 
         // While not on battery, the timers should not increase.
         state.setModemActive(true);
         incrementTime.accept(100);
-        checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
 
         state.setRatType(TelephonyManager.NETWORK_TYPE_NR, BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR);
         incrementTime.accept(200);
-        checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
 
         state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR,
                 CellSignalStrength.SIGNAL_STRENGTH_GOOD);
         incrementTime.accept(500);
-        checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
 
         state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_MMWAVE);
         incrementTime.accept(300);
-        checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
 
         state.setRatType(TelephonyManager.NETWORK_TYPE_LTE,
                 BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE);
         incrementTime.accept(400);
-        checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
 
         state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
                 CellSignalStrength.SIGNAL_STRENGTH_MODERATE);
         incrementTime.accept(500);
-        checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
 
         // When set on battery, currently active state (RAT:LTE, Signal Strength:Moderate) should
         // start counting up.
         state.setOnBattery(true);
         incrementTime.accept(600);
-        checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
-
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
         // Changing LTE signal strength should be tracked.
         state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
                 CellSignalStrength.SIGNAL_STRENGTH_POOR);
         incrementTime.accept(700);
-        checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
 
         state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
                 CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
         incrementTime.accept(800);
-        checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
 
         state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
                 CellSignalStrength.SIGNAL_STRENGTH_GOOD);
         incrementTime.accept(900);
-        checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
 
         state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
                 CellSignalStrength.SIGNAL_STRENGTH_GREAT);
         incrementTime.accept(1000);
-        checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
 
         // Change in the signal strength of nonactive RAT should not affect anything.
         state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER,
                 CellSignalStrength.SIGNAL_STRENGTH_POOR);
         incrementTime.accept(1100);
-        checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
 
         // Changing to OTHER Rat should start tracking the poor signal strength.
         state.setRatType(TelephonyManager.NETWORK_TYPE_CDMA,
                 BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER);
         incrementTime.accept(1200);
-        checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
 
         // Noting frequency change should not affect non NR Rat.
         state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_HIGH);
         incrementTime.accept(1300);
-        checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
 
         // Now the NR Rat, HIGH frequency range, good signal strength should start counting.
         state.setRatType(TelephonyManager.NETWORK_TYPE_NR, BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR);
         incrementTime.accept(1400);
-        checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
 
         // Noting frequency change should not affect non NR Rat.
         state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_LOW);
         incrementTime.accept(1500);
-        checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
 
         // Modem no longer active, should not be tracking any more.
         state.setModemActive(false);
         incrementTime.accept(1500);
-        checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+    }
 
+    @SmallTest
+    public void testGetPerStateActiveRadioDurationMs_withModemActivity() {
+        final MockClock clock = new MockClock(); // holds realtime and uptime in ms
+        final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clock);
+        bi.setPowerProfile(mock(PowerProfile.class));
+        final int ratCount = RADIO_ACCESS_TECHNOLOGY_COUNT;
+        final int frequencyCount = ServiceState.FREQUENCY_RANGE_MMWAVE + 1;
+        final int txLevelCount = CellSignalStrength.getNumSignalStrengthLevels();
+
+        final long[][][] expectedDurationsMs = new long[ratCount][frequencyCount][txLevelCount];
+        final long[][] expectedRxDurationsMs = new long[ratCount][frequencyCount];
+        final long[][][] expectedTxDurationsMs = new long[ratCount][frequencyCount][txLevelCount];
+        for (int rat = 0; rat < ratCount; rat++) {
+            for (int freq = 0; freq < frequencyCount; freq++) {
+                expectedRxDurationsMs[rat][freq] = POWER_DATA_UNAVAILABLE;
+
+                for (int txLvl = 0; txLvl < txLevelCount; txLvl++) {
+                    expectedTxDurationsMs[rat][freq][txLvl] = POWER_DATA_UNAVAILABLE;
+                }
+            }
+        }
+
+        final ModemActivityInfo mai = new ModemActivityInfo(0L, 0L, 0L, new int[txLevelCount], 0L);
+        final ModemAndBatteryState state = new ModemAndBatteryState(bi, mai, null);
+
+        IntConsumer incrementTime = inc -> {
+            state.currentTimeMs += inc;
+            clock.realtime = clock.uptime = state.currentTimeMs;
+
+            // If the device is not on battery, no timers should increment.
+            if (!state.onBattery) return;
+            // If the modem is not active, no timers should increment.
+            if (!state.modemActive) return;
+
+            final int currRat = state.currentRat;
+            final int currFreqRange =
+                    currRat == RADIO_ACCESS_TECHNOLOGY_NR ? state.currentFrequencyRange : 0;
+            int currSignalStrength = state.currentSignalStrengths.get(currRat);
+
+            expectedDurationsMs[currRat][currFreqRange][currSignalStrength] += inc;
+
+            // Evaluate the HAL provided time in states.
+            switch (state.modemState) {
+                case SLEEP:
+                    long sleepMs = state.modemActivityInfo.getSleepTimeMillis();
+                    state.modemActivityInfo.setSleepTimeMillis(sleepMs + inc);
+                    break;
+                case IDLE:
+                    long idleMs = state.modemActivityInfo.getIdleTimeMillis();
+                    state.modemActivityInfo.setIdleTimeMillis(idleMs + inc);
+                    break;
+                case RECEIVING:
+                    long rxMs = state.modemActivityInfo.getReceiveTimeMillis();
+                    state.modemActivityInfo.setReceiveTimeMillis(rxMs + inc);
+                    expectedRxDurationsMs[currRat][currFreqRange] += inc;
+                    break;
+                case TRANSMITTING:
+                    int[] txMs = state.modemActivityInfo.getTransmitTimeMillis();
+                    txMs[currSignalStrength] += inc;
+                    state.modemActivityInfo.setTransmitTimeMillis(txMs);
+                    expectedTxDurationsMs[currRat][currFreqRange][currSignalStrength] += inc;
+                    break;
+            }
+        };
+
+        state.setOnBattery(false);
+        state.setModemActive(false);
+        state.setRatType(TelephonyManager.NETWORK_TYPE_UNKNOWN,
+                BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER);
+        state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_UNKNOWN);
+        state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER,
+                CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        // While not on battery, the timers should not increase.
+        state.setModemActive(true);
+        incrementTime.accept(100);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        state.setRatType(TelephonyManager.NETWORK_TYPE_NR, BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR);
+        incrementTime.accept(200);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR,
+                CellSignalStrength.SIGNAL_STRENGTH_GOOD);
+        incrementTime.accept(500);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_MMWAVE);
+        incrementTime.accept(300);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        state.setRatType(TelephonyManager.NETWORK_TYPE_LTE,
+                BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE);
+        incrementTime.accept(400);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
+                CellSignalStrength.SIGNAL_STRENGTH_MODERATE);
+        incrementTime.accept(500);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        // Data will now be available.
+        for (int rat = 0; rat < ratCount; rat++) {
+            for (int freq = 0; freq < frequencyCount; freq++) {
+                if (rat == RADIO_ACCESS_TECHNOLOGY_NR
+                        || freq == ServiceState.FREQUENCY_RANGE_UNKNOWN) {
+                    // Only the NR RAT should have per frequency data.
+                    expectedRxDurationsMs[rat][freq] = 0;
+                }
+                for (int txLvl = 0; txLvl < txLevelCount; txLvl++) {
+                    if (rat == RADIO_ACCESS_TECHNOLOGY_NR
+                            || freq == ServiceState.FREQUENCY_RANGE_UNKNOWN) {
+                        // Only the NR RAT should have per frequency data.
+                        expectedTxDurationsMs[rat][freq][txLvl] = 0;
+                    }
+                }
+            }
+        }
+
+        // When set on battery, currently active state (RAT:LTE, Signal Strength:Moderate) should
+        // start counting up.
+        state.setOnBattery(true);
+        incrementTime.accept(300);
+        state.setModemState(ModemState.RECEIVING);
+        incrementTime.accept(500);
+        state.setModemState(ModemState.TRANSMITTING);
+        incrementTime.accept(600);
+        state.noteModemControllerActivity();
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+        // Changing LTE signal strength should be tracked.
+        state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
+                CellSignalStrength.SIGNAL_STRENGTH_POOR);
+        incrementTime.accept(300);
+        state.setModemState(ModemState.SLEEP);
+        incrementTime.accept(1000);
+        state.setModemState(ModemState.RECEIVING);
+        incrementTime.accept(700);
+        state.noteModemControllerActivity();
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
+                CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
+        incrementTime.accept(800);
+        state.setModemState(ModemState.TRANSMITTING);
+        incrementTime.accept(222);
+        state.setModemState(ModemState.IDLE);
+        incrementTime.accept(111);
+        state.setModemState(ModemState.RECEIVING);
+        incrementTime.accept(7777);
+        state.noteModemControllerActivity();
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
+                CellSignalStrength.SIGNAL_STRENGTH_GOOD);
+        incrementTime.accept(88);
+        state.setModemState(ModemState.TRANSMITTING);
+        incrementTime.accept(900);
+        state.noteModemControllerActivity();
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
+                CellSignalStrength.SIGNAL_STRENGTH_GREAT);
+        incrementTime.accept(123);
+        state.setModemState(ModemState.RECEIVING);
+        incrementTime.accept(333);
+        state.setModemState(ModemState.TRANSMITTING);
+        incrementTime.accept(1000);
+        state.setModemState(ModemState.RECEIVING);
+        incrementTime.accept(555);
+        state.noteModemControllerActivity();
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        // Change in the signal strength of nonactive RAT should not affect anything.
+        state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER,
+                CellSignalStrength.SIGNAL_STRENGTH_POOR);
+        incrementTime.accept(631);
+        state.setModemState(ModemState.TRANSMITTING);
+        incrementTime.accept(321);
+        state.setModemState(ModemState.RECEIVING);
+        incrementTime.accept(99);
+        state.noteModemControllerActivity();
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        // Changing to OTHER Rat should start tracking the poor signal strength.
+        state.setRatType(TelephonyManager.NETWORK_TYPE_CDMA,
+                BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER);
+        incrementTime.accept(1200);
+        state.noteModemControllerActivity();
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        // Noting frequency change should not affect non NR Rat.
+        state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_HIGH);
+        incrementTime.accept(444);
+        state.setModemState(ModemState.TRANSMITTING);
+        incrementTime.accept(1300);
+        state.noteModemControllerActivity();
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        // Now the NR Rat, HIGH frequency range, good signal strength should start counting.
+        state.setRatType(TelephonyManager.NETWORK_TYPE_NR, BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR);
+        incrementTime.accept(1400);
+        state.noteModemControllerActivity();
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        // Frequency changed to low.
+        state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_LOW);
+        incrementTime.accept(852);
+        state.setModemState(ModemState.RECEIVING);
+        incrementTime.accept(157);
+        state.setModemState(ModemState.TRANSMITTING);
+        incrementTime.accept(1500);
+        state.noteModemControllerActivity();
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        // Modem no longer active, should not be tracking any more.
+        state.setModemActive(false);
+        incrementTime.accept(1500);
+        state.noteModemControllerActivity();
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+    }
+
+    @SmallTest
+    public void testGetPerStateActiveRadioDurationMs_withSpecificInfoModemActivity() {
+        final MockClock clock = new MockClock(); // holds realtime and uptime in ms
+        final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clock);
+        bi.setPowerProfile(mock(PowerProfile.class));
+        final int ratCount = RADIO_ACCESS_TECHNOLOGY_COUNT;
+        final int frequencyCount = ServiceState.FREQUENCY_RANGE_MMWAVE + 1;
+        final int txLevelCount = CellSignalStrength.getNumSignalStrengthLevels();
+
+        List<ActivityStatsTechSpecificInfo> specificInfoList = new ArrayList();
+
+        final long[][][] expectedDurationsMs = new long[ratCount][frequencyCount][txLevelCount];
+        final long[][] expectedRxDurationsMs = new long[ratCount][frequencyCount];
+        final long[][][] expectedTxDurationsMs = new long[ratCount][frequencyCount][txLevelCount];
+        for (int rat = 0; rat < ratCount; rat++) {
+            for (int freq = 0; freq < frequencyCount; freq++) {
+                if (rat == RADIO_ACCESS_TECHNOLOGY_NR
+                        || freq == ServiceState.FREQUENCY_RANGE_UNKNOWN) {
+                    // Initialize available specific Modem info
+                    specificInfoList.add(
+                            new ActivityStatsTechSpecificInfo(rat, freq, new int[txLevelCount], 0));
+                }
+                expectedRxDurationsMs[rat][freq] = POWER_DATA_UNAVAILABLE;
+
+                for (int txLvl = 0; txLvl < txLevelCount; txLvl++) {
+                    expectedTxDurationsMs[rat][freq][txLvl] = POWER_DATA_UNAVAILABLE;
+                }
+            }
+        }
+
+        specificInfoList.add(new ActivityStatsTechSpecificInfo(AccessNetwork.UNKNOWN,
+                ServiceState.FREQUENCY_RANGE_UNKNOWN, new int[txLevelCount], 0));
+        specificInfoList.add(new ActivityStatsTechSpecificInfo(AccessNetwork.GERAN,
+                ServiceState.FREQUENCY_RANGE_UNKNOWN, new int[txLevelCount], 0));
+        specificInfoList.add(new ActivityStatsTechSpecificInfo(AccessNetwork.UTRAN,
+                ServiceState.FREQUENCY_RANGE_UNKNOWN, new int[txLevelCount], 0));
+        specificInfoList.add(new ActivityStatsTechSpecificInfo(AccessNetwork.EUTRAN,
+                ServiceState.FREQUENCY_RANGE_UNKNOWN, new int[txLevelCount], 0));
+        specificInfoList.add(new ActivityStatsTechSpecificInfo(AccessNetwork.CDMA2000,
+                ServiceState.FREQUENCY_RANGE_UNKNOWN, new int[txLevelCount], 0));
+        specificInfoList.add(new ActivityStatsTechSpecificInfo(AccessNetwork.IWLAN,
+                ServiceState.FREQUENCY_RANGE_UNKNOWN, new int[txLevelCount], 0));
+        specificInfoList.add(new ActivityStatsTechSpecificInfo(AccessNetwork.NGRAN,
+                ServiceState.FREQUENCY_RANGE_UNKNOWN, new int[txLevelCount], 0));
+        specificInfoList.add(new ActivityStatsTechSpecificInfo(AccessNetwork.NGRAN,
+                ServiceState.FREQUENCY_RANGE_LOW, new int[txLevelCount], 0));
+        specificInfoList.add(new ActivityStatsTechSpecificInfo(AccessNetwork.NGRAN,
+                ServiceState.FREQUENCY_RANGE_MID, new int[txLevelCount], 0));
+        specificInfoList.add(new ActivityStatsTechSpecificInfo(AccessNetwork.NGRAN,
+                ServiceState.FREQUENCY_RANGE_HIGH, new int[txLevelCount], 0));
+        specificInfoList.add(new ActivityStatsTechSpecificInfo(AccessNetwork.NGRAN,
+                ServiceState.FREQUENCY_RANGE_MMWAVE, new int[txLevelCount], 0));
+
+        final ActivityStatsTechSpecificInfo[] specificInfos = specificInfoList.toArray(
+                new ActivityStatsTechSpecificInfo[specificInfoList.size()]);
+        final ModemActivityInfo mai = new ModemActivityInfo(0L, 0L, 0L, specificInfos);
+        final ModemAndBatteryState state = new ModemAndBatteryState(bi, mai, specificInfos);
+
+        IntConsumer incrementTime = inc -> {
+            state.currentTimeMs += inc;
+            clock.realtime = clock.uptime = state.currentTimeMs;
+
+            // If the device is not on battery, no timers should increment.
+            if (!state.onBattery) return;
+            // If the modem is not active, no timers should increment.
+            if (!state.modemActive) return;
+
+            final int currRat = state.currentRat;
+            final int currRant = state.currentRadioAccessNetworkType;
+            final int currFreqRange =
+                    currRat == RADIO_ACCESS_TECHNOLOGY_NR ? state.currentFrequencyRange : 0;
+            int currSignalStrength = state.currentSignalStrengths.get(currRat);
+
+            expectedDurationsMs[currRat][currFreqRange][currSignalStrength] += inc;
+
+            // Evaluate the HAL provided time in states.
+            final ActivityStatsTechSpecificInfo info = state.getSpecificInfo(currRant,
+                    currFreqRange);
+            switch (state.modemState) {
+                case SLEEP:
+                    long sleepMs = state.modemActivityInfo.getSleepTimeMillis();
+                    state.modemActivityInfo.setSleepTimeMillis(sleepMs + inc);
+                    break;
+                case IDLE:
+                    long idleMs = state.modemActivityInfo.getIdleTimeMillis();
+                    state.modemActivityInfo.setIdleTimeMillis(idleMs + inc);
+                    break;
+                case RECEIVING:
+                    long rxMs = info.getReceiveTimeMillis();
+                    info.setReceiveTimeMillis(rxMs + inc);
+                    expectedRxDurationsMs[currRat][currFreqRange] += inc;
+                    break;
+                case TRANSMITTING:
+                    int[] txMs = info.getTransmitTimeMillis().clone();
+                    txMs[currSignalStrength] += inc;
+                    info.setTransmitTimeMillis(txMs);
+                    expectedTxDurationsMs[currRat][currFreqRange][currSignalStrength] += inc;
+                    break;
+            }
+        };
+
+        state.setOnBattery(false);
+        state.setModemActive(false);
+        state.setRatType(TelephonyManager.NETWORK_TYPE_UNKNOWN,
+                BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER,
+                AccessNetworkConstants.AccessNetworkType.UNKNOWN);
+        state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_UNKNOWN);
+        state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER,
+                CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        // While not on battery, the timers should not increase.
+        state.setModemActive(true);
+        incrementTime.accept(100);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        state.setRatType(TelephonyManager.NETWORK_TYPE_NR, BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR,
+                AccessNetworkConstants.AccessNetworkType.NGRAN);
+        incrementTime.accept(200);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR,
+                CellSignalStrength.SIGNAL_STRENGTH_GOOD);
+        incrementTime.accept(500);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_MMWAVE);
+        incrementTime.accept(300);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        state.setRatType(TelephonyManager.NETWORK_TYPE_LTE,
+                BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
+                AccessNetworkConstants.AccessNetworkType.EUTRAN);
+        incrementTime.accept(400);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
+                CellSignalStrength.SIGNAL_STRENGTH_MODERATE);
+        incrementTime.accept(500);
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        // Data will now be available.
+        for (int rat = 0; rat < ratCount; rat++) {
+            for (int freq = 0; freq < frequencyCount; freq++) {
+                if (rat == RADIO_ACCESS_TECHNOLOGY_NR
+                        || freq == ServiceState.FREQUENCY_RANGE_UNKNOWN) {
+                    // Only the NR RAT should have per frequency data.
+                    expectedRxDurationsMs[rat][freq] = 0;
+                }
+                for (int txLvl = 0; txLvl < txLevelCount; txLvl++) {
+                    if (rat == RADIO_ACCESS_TECHNOLOGY_NR
+                            || freq == ServiceState.FREQUENCY_RANGE_UNKNOWN) {
+                        // Only the NR RAT should have per frequency data.
+                        expectedTxDurationsMs[rat][freq][txLvl] = 0;
+                    }
+                }
+            }
+        }
+
+        // When set on battery, currently active state (RAT:LTE, Signal Strength:Moderate) should
+        // start counting up.
+        state.setOnBattery(true);
+        state.noteModemControllerActivity();
+        incrementTime.accept(300);
+        state.setModemState(ModemState.RECEIVING);
+        incrementTime.accept(500);
+        state.setModemState(ModemState.TRANSMITTING);
+        incrementTime.accept(600);
+        state.noteModemControllerActivity();
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+        // Changing LTE signal strength should be tracked.
+        state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
+                CellSignalStrength.SIGNAL_STRENGTH_POOR);
+        incrementTime.accept(300);
+        state.setModemState(ModemState.SLEEP);
+        incrementTime.accept(1000);
+        state.setModemState(ModemState.RECEIVING);
+        incrementTime.accept(700);
+        state.noteModemControllerActivity();
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
+                CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
+        incrementTime.accept(800);
+        state.setModemState(ModemState.TRANSMITTING);
+        incrementTime.accept(222);
+        state.setModemState(ModemState.IDLE);
+        incrementTime.accept(111);
+        state.setModemState(ModemState.RECEIVING);
+        incrementTime.accept(7777);
+        state.noteModemControllerActivity();
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
+                CellSignalStrength.SIGNAL_STRENGTH_GOOD);
+        incrementTime.accept(88);
+        state.setModemState(ModemState.TRANSMITTING);
+        incrementTime.accept(900);
+        state.noteModemControllerActivity();
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
+                CellSignalStrength.SIGNAL_STRENGTH_GREAT);
+        incrementTime.accept(123);
+        state.setModemState(ModemState.RECEIVING);
+        incrementTime.accept(333);
+        state.setModemState(ModemState.TRANSMITTING);
+        incrementTime.accept(1000);
+        state.setModemState(ModemState.RECEIVING);
+        incrementTime.accept(555);
+        state.noteModemControllerActivity();
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        // Change in the signal strength of nonactive RAT should not affect anything.
+        state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER,
+                CellSignalStrength.SIGNAL_STRENGTH_POOR);
+        incrementTime.accept(631);
+        state.setModemState(ModemState.TRANSMITTING);
+        incrementTime.accept(321);
+        state.setModemState(ModemState.RECEIVING);
+        incrementTime.accept(99);
+        state.noteModemControllerActivity();
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        // Changing to OTHER Rat should start tracking the poor signal strength.
+        state.setRatType(TelephonyManager.NETWORK_TYPE_CDMA,
+                BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER,
+                AccessNetworkConstants.AccessNetworkType.CDMA2000);
+        incrementTime.accept(1200);
+        state.noteModemControllerActivity();
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        // Noting frequency change should not affect non NR Rat.
+        state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_HIGH);
+        incrementTime.accept(444);
+        state.setModemState(ModemState.TRANSMITTING);
+        incrementTime.accept(1300);
+        state.noteModemControllerActivity();
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        // Now the NR Rat, HIGH frequency range, good signal strength should start counting.
+        state.setRatType(TelephonyManager.NETWORK_TYPE_NR, BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR,
+                AccessNetworkConstants.AccessNetworkType.NGRAN);
+        incrementTime.accept(1400);
+        state.noteModemControllerActivity();
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        // Frequency changed to low.
+        state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_LOW);
+        incrementTime.accept(852);
+        state.setModemState(ModemState.RECEIVING);
+        incrementTime.accept(157);
+        state.setModemState(ModemState.TRANSMITTING);
+        incrementTime.accept(1500);
+        state.noteModemControllerActivity();
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
+
+        // Modem no longer active, should not be tracking any more.
+        state.setModemActive(false);
+        incrementTime.accept(1500);
+        state.noteModemControllerActivity();
+        checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+                expectedTxDurationsMs, bi, state.currentTimeMs);
     }
 
     private void setFgState(int uid, boolean fgOn, MockBatteryStatsImpl bi) {
@@ -1426,28 +2057,168 @@
     }
 
     private void checkPerStateActiveRadioDurations(long[][][] expectedDurationsMs,
+            long[][] expectedRxDurationsMs, long[][][] expectedTxDurationsMs,
             BatteryStatsImpl bi, long currentTimeMs) {
         for (int rat = 0; rat < expectedDurationsMs.length; rat++) {
             final long[][] expectedRatDurationsMs = expectedDurationsMs[rat];
             for (int freq = 0; freq < expectedRatDurationsMs.length; freq++) {
+                final long expectedRxDurationMs = expectedRxDurationsMs[rat][freq];
+
+                // Build a verbose fail message, just in case.
+                final StringBuilder rxFailSb = new StringBuilder();
+                rxFailSb.append("Wrong time in Rx state for RAT:");
+                rxFailSb.append(BatteryStats.RADIO_ACCESS_TECHNOLOGY_NAMES[rat]);
+                rxFailSb.append(", frequency:");
+                rxFailSb.append(ServiceState.frequencyRangeToString(freq));
+                assertEquals(rxFailSb.toString(), expectedRxDurationMs,
+                        bi.getActiveRxRadioDurationMs(rat, freq, currentTimeMs));
+
                 final long[] expectedFreqDurationsMs = expectedRatDurationsMs[freq];
                 for (int strength = 0; strength < expectedFreqDurationsMs.length; strength++) {
                     final long expectedSignalStrengthDurationMs = expectedFreqDurationsMs[strength];
+                    final long expectedTxDurationMs = expectedTxDurationsMs[rat][freq][strength];
                     final long actualDurationMs = bi.getActiveRadioDurationMs(rat, freq,
                             strength, currentTimeMs);
 
-                    // Build a verbose fail message, just in case.
-                    final StringBuilder sb = new StringBuilder();
-                    sb.append("Wrong time in state for RAT:");
-                    sb.append(BatteryStats.RADIO_ACCESS_TECHNOLOGY_NAMES[rat]);
-                    sb.append(", frequency:");
-                    sb.append(ServiceState.frequencyRangeToString(freq));
-                    sb.append(", strength:");
-                    sb.append(strength);
+                    final StringBuilder failSb = new StringBuilder();
+                    failSb.append("Wrong time in state for RAT:");
+                    failSb.append(BatteryStats.RADIO_ACCESS_TECHNOLOGY_NAMES[rat]);
+                    failSb.append(", frequency:");
+                    failSb.append(ServiceState.frequencyRangeToString(freq));
+                    failSb.append(", strength:");
+                    failSb.append(strength);
+                    assertEquals(failSb.toString(), expectedSignalStrengthDurationMs,
+                            actualDurationMs);
 
-                    assertEquals(sb.toString(), expectedSignalStrengthDurationMs, actualDurationMs);
+                    final StringBuilder txFailSb = new StringBuilder();
+                    txFailSb.append("Wrong time in Tx state for RAT:");
+                    txFailSb.append(BatteryStats.RADIO_ACCESS_TECHNOLOGY_NAMES[rat]);
+                    txFailSb.append(", frequency:");
+                    txFailSb.append(ServiceState.frequencyRangeToString(freq));
+                    txFailSb.append(", strength:");
+                    txFailSb.append(strength);
+                    assertEquals(txFailSb.toString(), expectedTxDurationMs,
+                            bi.getActiveTxRadioDurationMs(rat, freq, strength, currentTimeMs));
                 }
             }
         }
     }
+
+    private class ModemAndBatteryState {
+        public long currentTimeMs = 100;
+        public boolean onBattery = false;
+        public boolean modemActive = false;
+        @Annotation.NetworkType
+        public int currentNetworkDataType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+        @BatteryStats.RadioAccessTechnology
+        public int currentRat = BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER;
+        @AccessNetworkConstants.RadioAccessNetworkType
+        public int currentRadioAccessNetworkType = AccessNetworkConstants.AccessNetworkType.UNKNOWN;
+        @ServiceState.FrequencyRange
+        public int currentFrequencyRange = ServiceState.FREQUENCY_RANGE_UNKNOWN;
+        public SparseIntArray currentSignalStrengths = new SparseIntArray();
+        public ModemState modemState = ModemState.SLEEP;
+        public ModemActivityInfo modemActivityInfo;
+        public ActivityStatsTechSpecificInfo[] specificInfo;
+
+        private final MockBatteryStatsImpl mBsi;
+
+        ModemAndBatteryState(MockBatteryStatsImpl bsi, ModemActivityInfo mai,
+                ActivityStatsTechSpecificInfo[] astsi) {
+            mBsi = bsi;
+            modemActivityInfo = mai;
+            specificInfo = astsi;
+        }
+
+        void setOnBattery(boolean onBattery) {
+            this.onBattery = onBattery;
+            mBsi.updateTimeBasesLocked(onBattery, Display.STATE_OFF, currentTimeMs * 1000,
+                    currentTimeMs * 1000);
+            mBsi.setOnBatteryInternal(onBattery);
+            noteModemControllerActivity();
+        }
+
+        void setModemActive(boolean active) {
+            modemActive = active;
+            final int state = active ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
+                    : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
+            mBsi.noteMobileRadioPowerStateLocked(state, currentTimeMs * 1000_000L, UID);
+            noteModemControllerActivity();
+        }
+
+        void setRatType(@Annotation.NetworkType int dataType,
+                @BatteryStats.RadioAccessTechnology int rat,
+                @AccessNetworkConstants.RadioAccessNetworkType int halDataType) {
+            currentRadioAccessNetworkType = halDataType;
+            setRatType(dataType, rat);
+        }
+
+        void setRatType(@Annotation.NetworkType int dataType,
+                @BatteryStats.RadioAccessTechnology int rat) {
+            currentNetworkDataType = dataType;
+            currentRat = rat;
+            mBsi.notePhoneDataConnectionStateLocked(dataType, true, ServiceState.STATE_IN_SERVICE,
+                    currentFrequencyRange);
+        }
+
+        void setFrequencyRange(@ServiceState.FrequencyRange int frequency) {
+            currentFrequencyRange = frequency;
+            mBsi.notePhoneDataConnectionStateLocked(currentNetworkDataType, true,
+                    ServiceState.STATE_IN_SERVICE, frequency);
+        }
+
+        void setSignalStrength(@BatteryStats.RadioAccessTechnology int rat, int strength) {
+            currentSignalStrengths.put(rat, strength);
+            final int size = currentSignalStrengths.size();
+            final int newestGenSignalStrength = currentSignalStrengths.valueAt(size - 1);
+            mBsi.notePhoneSignalStrengthLocked(newestGenSignalStrength, currentSignalStrengths);
+        }
+
+        void setModemState(ModemState state) {
+            modemState = state;
+        }
+
+        ActivityStatsTechSpecificInfo getSpecificInfo(@BatteryStats.RadioAccessTechnology int rat,
+                @ServiceState.FrequencyRange int frequency) {
+            if (specificInfo == null) return null;
+            for (ActivityStatsTechSpecificInfo info : specificInfo) {
+                if (info.getRat() == rat && info.getFrequencyRange() == frequency) {
+                    return info;
+                }
+            }
+            return null;
+        }
+
+        void noteModemControllerActivity() {
+            if (modemActivityInfo == null) return;
+            modemActivityInfo.setTimestamp(currentTimeMs);
+            final ModemActivityInfo copy;
+            if (specificInfo == null) {
+                copy = new ModemActivityInfo(
+                        modemActivityInfo.getTimestampMillis(),
+                        modemActivityInfo.getSleepTimeMillis(),
+                        modemActivityInfo.getIdleTimeMillis(),
+                        modemActivityInfo.getTransmitTimeMillis().clone(),
+                        modemActivityInfo.getReceiveTimeMillis());
+            } else {
+                // Deep copy specificInfo
+                final ActivityStatsTechSpecificInfo[] infoCopies =
+                        new ActivityStatsTechSpecificInfo[specificInfo.length];
+                for (int i = 0; i < specificInfo.length; i++) {
+                    final ActivityStatsTechSpecificInfo info = specificInfo[i];
+                    infoCopies[i] = new ActivityStatsTechSpecificInfo(info.getRat(),
+                            info.getFrequencyRange(), info.getTransmitTimeMillis().clone(),
+                            (int) info.getReceiveTimeMillis());
+                }
+
+                copy = new ModemActivityInfo(
+                        modemActivityInfo.getTimestampMillis(),
+                        modemActivityInfo.getSleepTimeMillis(),
+                        modemActivityInfo.getIdleTimeMillis(),
+                        infoCopies);
+            }
+            mBsi.noteModemControllerActivity(copy, POWER_DATA_UNAVAILABLE,
+                    currentTimeMs, currentTimeMs, mNetworkStatsManager);
+        }
+    }
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
index 0e394c1..bfb3449 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
@@ -30,6 +30,7 @@
 public class BatteryStatsSensorTest extends TestCase {
 
     private static final int UID = 10500;
+    private static final int UID_2 = 10501; // second uid for testing pool usage
     private static final int SENSOR_ID = -10000;
 
     @SmallTest
@@ -239,7 +240,6 @@
 
     @SmallTest
     public void testPooledBackgroundUsage() throws Exception {
-        final int UID_2 = 20000; // second uid for testing pool usage
         final MockClock clocks = new MockClock();
         MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
         bi.mForceOnBattery = true;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
index 5adc9bd..483224c 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
@@ -20,6 +20,7 @@
 import static android.os.BatteryConsumer.POWER_MODEL_MEASURED_ENERGY;
 import static android.os.BatteryConsumer.POWER_MODEL_UNDEFINED;
 import static android.os.BatteryConsumer.PROCESS_STATE_BACKGROUND;
+import static android.os.BatteryConsumer.PROCESS_STATE_CACHED;
 import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND;
 import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE;
 
@@ -83,7 +84,7 @@
         final Parcel parcel = Parcel.obtain();
         parcel.writeParcelable(outBatteryUsageStats, 0);
 
-        assertThat(parcel.dataSize()).isLessThan(7000);
+        assertThat(parcel.dataSize()).isLessThan(8000);
 
         parcel.setDataPosition(0);
 
@@ -155,10 +156,11 @@
         assertThat(dump).contains("cpu(fg): 2333 apps: 1333 duration: 3s 332ms");
         assertThat(dump).contains("cpu(bg): 2444 apps: 1444 duration: 4s 442ms");
         assertThat(dump).contains("cpu(fgs): 2555 apps: 1555 duration: 5s 552ms");
+        assertThat(dump).contains("cpu(cached): 123 apps: 123 duration: 456ms");
         assertThat(dump).contains("FOO: 20200 apps: 10200 duration: 20s 400ms");
-        assertThat(dump).contains("UID 271: 1200 fg: 1777 bg: 1888 fgs: 1999 ( screen=300 "
-                + "cpu=400 (600ms) cpu:fg=1777 (7s 771ms) cpu:bg=1888 (8s 881ms) "
-                + "cpu:fgs=1999 (9s 991ms) FOO=500 )");
+        assertThat(dump).contains("UID 271: 1200 fg: 1777 bg: 1888 fgs: 1999 cached: 123 "
+                + "( screen=300 cpu=400 (600ms) cpu:fg=1777 (7s 771ms) cpu:bg=1888 (8s 881ms) "
+                + "cpu:fgs=1999 (9s 991ms) cpu:cached=123 (456ms) FOO=500 )");
         assertThat(dump).contains("User 42: 30.0 ( cpu=10.0 (30ms) FOO=20.0 )");
     }
 
@@ -193,13 +195,15 @@
                         5321, 7432, 423, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 745,
                         POWER_MODEL_UNDEFINED,
                         956, 1167, 1478,
-                        true, 3554, 3776, 3998, 3554, 15542, 3776, 17762, 3998, 19982);
+                        true, 3554, 3776, 3998, 444, 3554, 15542, 3776, 17762, 3998, 19982,
+                        444, 1110);
             } else if (uidBatteryConsumer.getUid() == APP_UID2) {
                 assertUidBatteryConsumer(uidBatteryConsumer, 1332, "bar",
                         1111, 2222, 333, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 444,
                         BatteryConsumer.POWER_MODEL_POWER_PROFILE,
                         555, 666, 777,
-                        true, 1777, 1888, 1999, 1777, 7771, 1888, 8881, 1999, 9991);
+                        true, 1777, 1888, 1999, 321, 1777, 7771, 1888, 8881, 1999, 9991,
+                        321, 654);
             } else {
                 fail("Unexpected UID " + uidBatteryConsumer.getUid());
             }
@@ -267,17 +271,17 @@
                 1000, 2000,
                 300, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 400,
                 BatteryConsumer.POWER_MODEL_POWER_PROFILE, 500, 600, 800,
-                1777, 7771, 1888, 8881, 1999, 9991);
+                1777, 7771, 1888, 8881, 1999, 9991, 123, 456);
 
         addAggregateBatteryConsumer(builder,
                 BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS, 0,
                 10100, 10200, 10300, 10400,
-                1333, 3331, 1444, 4441, 1555, 5551);
+                1333, 3331, 1444, 4441, 1555, 5551, 123, 456);
 
         addAggregateBatteryConsumer(builder,
                 BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE, 30000,
                 20100, 20200, 20300, 20400,
-                2333, 3332, 2444, 4442, 2555, 5552);
+                2333, 3332, 2444, 4442, 2555, 5552, 123, 456);
 
         if (includeUserBatteryConsumer) {
             builder.getOrCreateUserBatteryConsumerBuilder(USER_ID)
@@ -310,23 +314,23 @@
                 4321, 5432,
                 123, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 345, POWER_MODEL_MEASURED_ENERGY,
                 456, 567, 678,
-                1777, 7771, 1888, 8881, 1999, 9991);
+                1777, 7771, 1888, 8881, 1999, 9991, 321, 654);
 
         addUidBatteryConsumer(builder, batteryStats, APP_UID2, "bar",
                 1111, 2222,
                 333, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 444,
                 BatteryConsumer.POWER_MODEL_POWER_PROFILE, 555, 666, 777,
-                1777, 7771, 1888, 8881, 1999, 9991);
+                1777, 7771, 1888, 8881, 1999, 9991, 321, 654);
 
         addAggregateBatteryConsumer(builder,
                 BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS, 0,
                 10123, 10234, 10345, 10456,
-                4333, 3334, 5444, 4445, 6555, 5556);
+                4333, 3334, 5444, 4445, 6555, 5556, 321, 654);
 
         addAggregateBatteryConsumer(builder,
                 BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE, 12345,
                 20111, 20222, 20333, 20444,
-                7333, 3337, 8444, 4448, 9555, 5559);
+                7333, 3337, 8444, 4448, 9555, 5559, 123, 456);
 
         return builder;
     }
@@ -337,7 +341,7 @@
             int screenPowerModel, double cpuPower, int cpuPowerModel, double customComponentPower,
             int cpuDuration, int customComponentDuration, double cpuPowerForeground,
             int cpuDurationForeground, double cpuPowerBackground, int cpuDurationBackground,
-            double cpuPowerFgs, int cpuDurationFgs) {
+            double cpuPowerFgs, int cpuDurationFgs, double cpuPowerCached, long cpuDurationCached) {
         final BatteryStatsImpl.Uid batteryStatsUid = batteryStats.getUidStatsLocked(uid);
         final UidBatteryConsumer.Builder uidBuilder =
                 builder.getOrCreateUidBatteryConsumerBuilder(batteryStatsUid);
@@ -365,6 +369,9 @@
             final BatteryConsumer.Key cpuFgsKey = uidBuilder.getKey(
                     BatteryConsumer.POWER_COMPONENT_CPU,
                     BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE);
+            final BatteryConsumer.Key cachedKey = uidBuilder.getKey(
+                    BatteryConsumer.POWER_COMPONENT_CPU,
+                    BatteryConsumer.PROCESS_STATE_CACHED);
             uidBuilder
                     .setConsumedPower(cpuFgKey, cpuPowerForeground,
                             BatteryConsumer.POWER_MODEL_POWER_PROFILE)
@@ -374,7 +381,10 @@
                     .setUsageDurationMillis(cpuBgKey, cpuDurationBackground)
                     .setConsumedPower(cpuFgsKey, cpuPowerFgs,
                             BatteryConsumer.POWER_MODEL_POWER_PROFILE)
-                    .setUsageDurationMillis(cpuFgsKey, cpuDurationFgs);
+                    .setUsageDurationMillis(cpuFgsKey, cpuDurationFgs)
+                    .setConsumedPower(cachedKey, cpuPowerCached,
+                            BatteryConsumer.POWER_MODEL_POWER_PROFILE)
+                    .setUsageDurationMillis(cachedKey, cpuDurationCached);
         }
     }
 
@@ -382,7 +392,7 @@
             double consumedPower, int cpuPower, int customComponentPower, int cpuDuration,
             int customComponentDuration, double cpuPowerForeground, long cpuDurationForeground,
             double cpuPowerBackground, long cpuDurationBackground, double cpuPowerFgs,
-            long cpuDurationFgs) {
+            long cpuDurationFgs, double cpuPowerCached, long cpuDurationCached) {
         final AggregateBatteryConsumer.Builder aggBuilder =
                 builder.getAggregateBatteryConsumerBuilder(scope)
                         .setConsumedPower(consumedPower)
@@ -406,6 +416,9 @@
             final BatteryConsumer.Key cpuFgsKey = aggBuilder.getKey(
                     BatteryConsumer.POWER_COMPONENT_CPU,
                     BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE);
+            final BatteryConsumer.Key cpuCachedKey = aggBuilder.getKey(
+                    BatteryConsumer.POWER_COMPONENT_CPU,
+                    BatteryConsumer.PROCESS_STATE_CACHED);
             aggBuilder
                     .setConsumedPower(cpuFgKey, cpuPowerForeground,
                             BatteryConsumer.POWER_MODEL_POWER_PROFILE)
@@ -415,7 +428,10 @@
                     .setUsageDurationMillis(cpuBgKey, cpuDurationBackground)
                     .setConsumedPower(cpuFgsKey, cpuPowerFgs,
                             BatteryConsumer.POWER_MODEL_POWER_PROFILE)
-                    .setUsageDurationMillis(cpuFgsKey, cpuDurationFgs);
+                    .setUsageDurationMillis(cpuFgsKey, cpuDurationFgs)
+                    .setConsumedPower(cpuCachedKey, cpuPowerCached,
+                            BatteryConsumer.POWER_MODEL_POWER_PROFILE)
+                    .setUsageDurationMillis(cpuCachedKey, cpuDurationCached);
         }
     }
 
@@ -432,7 +448,7 @@
                         1000, 2000, 300, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 400,
                         BatteryConsumer.POWER_MODEL_POWER_PROFILE,
                         500, 600, 800,
-                        true, 1777, 1888, 1999, 1777, 7771, 1888, 8881, 1999, 9991);
+                        true, 1777, 1888, 1999, 123, 1777, 7771, 1888, 8881, 1999, 9991, 123, 456);
             } else {
                 fail("Unexpected UID " + uidBatteryConsumer.getUid());
             }
@@ -484,8 +500,10 @@
             int cpuPowerModel, double customComponentPower, int cpuDuration,
             int customComponentDuration, boolean processStateDataIncluded,
             double totalPowerForeground, double totalPowerBackground, double totalPowerFgs,
-            double cpuPowerForeground, int cpuDurationForeground, double cpuPowerBackground,
-            int cpuDurationBackground, double cpuPowerFgs, int cpuDurationFgs) {
+            double totalPowerCached, double cpuPowerForeground, int cpuDurationForeground,
+            double cpuPowerBackground,
+            int cpuDurationBackground, double cpuPowerFgs, int cpuDurationFgs,
+            int cpuPowerCached, int cpuDurationCached) {
         assertThat(uidBatteryConsumer.getConsumedPower()).isEqualTo(consumedPower);
         assertThat(uidBatteryConsumer.getPackageWithHighestDrain()).isEqualTo(
                 packageWithHighestDrain);
@@ -525,6 +543,10 @@
                     new BatteryConsumer.Dimensions(POWER_COMPONENT_ANY,
                             PROCESS_STATE_FOREGROUND_SERVICE)))
                     .isEqualTo(totalPowerFgs);
+            assertThat(uidBatteryConsumer.getConsumedPower(
+                    new BatteryConsumer.Dimensions(POWER_COMPONENT_ANY,
+                            PROCESS_STATE_CACHED)))
+                    .isEqualTo(totalPowerCached);
         }
 
         final BatteryConsumer.Key cpuFgKey = uidBatteryConsumer.getKey(
@@ -563,6 +585,19 @@
         } else {
             assertThat(cpuFgsKey).isNotNull();
         }
+
+        final BatteryConsumer.Key cachedKey = uidBatteryConsumer.getKey(
+                BatteryConsumer.POWER_COMPONENT_CPU,
+                BatteryConsumer.PROCESS_STATE_CACHED);
+        if (processStateDataIncluded) {
+            assertThat(cachedKey).isNotNull();
+            assertThat(uidBatteryConsumer.getConsumedPower(cachedKey))
+                    .isEqualTo(cpuPowerCached);
+            assertThat(uidBatteryConsumer.getUsageDurationMillis(cachedKey))
+                    .isEqualTo(cpuDurationCached);
+        } else {
+            assertThat(cpuFgsKey).isNotNull();
+        }
     }
 
     private void assertUserBatteryConsumer(UserBatteryConsumer userBatteryConsumer,
diff --git a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
index 448f666..fdbf071 100644
--- a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
@@ -145,10 +145,14 @@
         final BatteryConsumer.Key fgs = uidConsumer.getKey(
                 BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
                 BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE);
+        final BatteryConsumer.Key cached = uidConsumer.getKey(
+                BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
+                BatteryConsumer.PROCESS_STATE_CACHED);
 
         assertThat(uidConsumer.getConsumedPower(foreground)).isWithin(PRECISION).of(0.081);
         assertThat(uidConsumer.getConsumedPower(background)).isWithin(PRECISION).of(0.0416666);
         assertThat(uidConsumer.getConsumedPower(fgs)).isWithin(PRECISION).of(0);
+        assertThat(uidConsumer.getConsumedPower(cached)).isWithin(PRECISION).of(0);
     }
 
     @Test
@@ -261,10 +265,14 @@
         final BatteryConsumer.Key fgs = uidConsumer.getKey(
                 BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
                 BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE);
+        final BatteryConsumer.Key cached = uidConsumer.getKey(
+                BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
+                BatteryConsumer.PROCESS_STATE_CACHED);
 
         assertThat(uidConsumer.getConsumedPower(foreground)).isWithin(PRECISION).of(0.4965352);
         assertThat(uidConsumer.getConsumedPower(background)).isWithin(PRECISION).of(0.3255208);
         assertThat(uidConsumer.getConsumedPower(fgs)).isWithin(PRECISION).of(0);
+        assertThat(uidConsumer.getConsumedPower(cached)).isWithin(PRECISION).of(0);
     }
 
 
diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
index b89e8bc..625f52a 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -232,7 +232,7 @@
         assertThat(entry3.handlerClassName).isEqualTo(
                 "com.android.internal.os.LooperStatsTest$TestHandlerSecond");
         assertThat(entry3.messageName).startsWith(
-                "com.android.internal.os.LooperStatsTest$$ExternalSyntheticLambda4");
+                "com.android.internal.os.LooperStatsTest$$ExternalSyntheticLambda");
         assertThat(entry3.messageCount).isEqualTo(1);
         assertThat(entry3.recordedMessageCount).isEqualTo(1);
         assertThat(entry3.exceptionCount).isEqualTo(0);
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index 1bb41a8..00154a3 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -26,6 +26,7 @@
 import android.os.Handler;
 import android.os.Looper;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidActiveTimeReader;
 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeReader;
 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader;
@@ -193,6 +194,18 @@
         return this;
     }
 
+    @GuardedBy("this")
+    public MockBatteryStatsImpl setMaxHistoryFiles(int maxHistoryFiles) {
+        mConstants.MAX_HISTORY_FILES = maxHistoryFiles;
+        return this;
+    }
+
+    @GuardedBy("this")
+    public MockBatteryStatsImpl setMaxHistoryBuffer(int maxHistoryBuffer) {
+        mConstants.MAX_HISTORY_BUFFER = maxHistoryBuffer;
+        return this;
+    }
+
     public int getAndClearExternalStatsSyncFlags() {
         final int flags = mExternalStatsSync.flags;
         mExternalStatsSync.flags = 0;
diff --git a/core/tests/coretests/src/com/android/internal/widget/CachingIconViewTest.java b/core/tests/coretests/src/com/android/internal/widget/CachingIconViewTest.java
new file mode 100644
index 0000000..aa96203
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/widget/CachingIconViewTest.java
@@ -0,0 +1,259 @@
+/*
+ * 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.internal.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.graphics.drawable.InsetDrawable;
+import android.net.Uri;
+import android.util.TypedValue;
+import android.view.LayoutInflater;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.frameworks.coretests.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class CachingIconViewTest {
+
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+    }
+
+    @Test
+    public void invalidIcon_skipsLoadSuccessfully() {
+        CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
+                R.layout.caching_icon_view_test_max_size, null);
+        view.setImageIcon(Icon.createWithResource(mContext, 0x85743222));
+        Drawable drawable = view.getDrawable();
+        assertThat(drawable).isNull();
+    }
+
+    @Test
+    public void customDrawable_setImageIcon_skipsResizeSuccessfully() {
+        CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
+                R.layout.caching_icon_view_test_max_size, null);
+        view.setImageIcon(Icon.createWithResource(mContext, R.drawable.custom_drawable));
+        Drawable drawable = view.getDrawable();
+        assertThat(drawable).isInstanceOf(InsetDrawable.class);
+    }
+
+    @Test
+    public void customDrawable_setImageIconAsync_skipsResizeSuccessfully() {
+        CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
+                R.layout.caching_icon_view_test_max_size, null);
+        view.setImageIconAsync(Icon.createWithResource(mContext, R.drawable.custom_drawable)).run();
+        Drawable drawable = view.getDrawable();
+        assertThat(drawable).isInstanceOf(InsetDrawable.class);
+    }
+
+    @Test
+    public void customDrawable_setImageResource_skipsResizeSuccessfully() {
+        CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
+                R.layout.caching_icon_view_test_max_size, null);
+        view.setImageResource(R.drawable.custom_drawable);
+        Drawable drawable = view.getDrawable();
+        assertThat(drawable).isInstanceOf(InsetDrawable.class);
+    }
+
+    @Test
+    public void customDrawable_setImageResourceAsync_skipsResizeSuccessfully() {
+        CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
+                R.layout.caching_icon_view_test_max_size, null);
+        view.setImageResourceAsync(R.drawable.custom_drawable).run();
+        Drawable drawable = view.getDrawable();
+        assertThat(drawable).isInstanceOf(InsetDrawable.class);
+    }
+
+    @Test
+    public void customDrawable_setImageUri_skipsResizeSuccessfully() {
+        CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
+                R.layout.caching_icon_view_test_max_size, null);
+        view.setImageURI(Uri.parse(
+                "android.resource://com.android.frameworks.coretests/"
+                        + R.drawable.custom_drawable));
+        Drawable drawable = view.getDrawable();
+        assertThat(drawable).isInstanceOf(InsetDrawable.class);
+    }
+
+    @Test
+    public void customDrawable_setImageUriAsync_skipsResizeSuccessfully() {
+        CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
+                R.layout.caching_icon_view_test_max_size, null);
+        view.setImageURIAsync(Uri.parse(
+                "android.resource://com.android.frameworks.coretests/"
+                        + R.drawable.custom_drawable)).run();
+        Drawable drawable = view.getDrawable();
+        assertThat(drawable).isInstanceOf(InsetDrawable.class);
+    }
+
+    @Test
+    public void maxDrawableDimensionsSet_setImageIcon_resizesImageIcon() {
+        CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
+                R.layout.caching_icon_view_test_max_size, null);
+        view.setImageIcon(Icon.createWithResource(mContext, R.drawable.big_a));
+
+        assertDrawableResized(view);
+    }
+
+    @Test
+    public void maxDrawableWithNoDimensionsSet_setImageIcon_doesNotResizeImageIcon() {
+        CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
+                R.layout.caching_icon_view_test_no_max_size, null);
+        view.setImageIcon(Icon.createWithResource(mContext, R.drawable.big_a));
+
+        assertDrawableNotResized(view);
+    }
+
+    @Test
+    public void maxDrawableDimensionsSet_setImageIconAsync_resizesImageIcon() {
+        CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
+                R.layout.caching_icon_view_test_max_size, null);
+        view.setImageIconAsync(Icon.createWithResource(mContext, R.drawable.big_a)).run();
+
+        assertDrawableResized(view);
+    }
+
+    @Test
+    public void maxDrawableWithNoDimensionsSet_setImageIconAsync_doesNotResizeImageIcon() {
+        CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
+                R.layout.caching_icon_view_test_no_max_size, null);
+        view.setImageIconAsync(Icon.createWithResource(mContext, R.drawable.big_a)).run();
+
+        assertDrawableNotResized(view);
+    }
+
+    @Test
+    public void maxDrawableDimensionsSet_setImageResource_resizesImageIcon() {
+        CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
+                R.layout.caching_icon_view_test_max_size, null);
+        view.setImageResource(R.drawable.big_a);
+
+        assertDrawableResized(view);
+    }
+
+    @Test
+    public void maxDrawableWithNoDimensionsSet_setImageResource_doesNotResizeImageIcon() {
+        CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
+                R.layout.caching_icon_view_test_no_max_size, null);
+        view.setImageResource(R.drawable.big_a);
+
+        assertDrawableNotResized(view);
+    }
+
+    @Test
+    public void maxDrawableDimensionsSet_setImageResourceAsync_resizesImageIcon() {
+        CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
+                R.layout.caching_icon_view_test_max_size, null);
+        view.setImageResourceAsync(R.drawable.big_a).run();
+
+        assertDrawableResized(view);
+    }
+
+    @Test
+    public void maxDrawableWithNoDimensionsSet_setImageResourceAsync_doesNotResizeImageIcon() {
+        CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
+                R.layout.caching_icon_view_test_no_max_size, null);
+        view.setImageResourceAsync(R.drawable.big_a).run();
+
+        assertDrawableNotResized(view);
+    }
+
+    @Test
+    public void maxDrawableDimensionsSet_setImageUri_resizesImageIcon() {
+        CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
+                R.layout.caching_icon_view_test_max_size, null);
+        view.setImageURI(Uri.parse(
+                "android.resource://com.android.frameworks.coretests/" + R.drawable.big_a));
+
+        assertDrawableResized(view);
+    }
+
+    @Test
+    public void maxDrawableWithNoDimensionsSet_setImageUri_doesNotResizeImageIcon() {
+        CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
+                R.layout.caching_icon_view_test_no_max_size, null);
+        view.setImageURI(Uri.parse(
+                "android.resource://com.android.frameworks.coretests/" + R.drawable.big_a));
+
+        assertDrawableNotResized(view);
+    }
+
+    @Test
+    public void maxDrawableDimensionsSet_setImageUriAsync_resizesImageIcon() {
+        CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
+                R.layout.caching_icon_view_test_max_size, null);
+        view.setImageURIAsync(Uri.parse(
+                "android.resource://com.android.frameworks.coretests/" + R.drawable.big_a)).run();
+
+        assertDrawableResized(view);
+    }
+
+    @Test
+    public void maxDrawableWithNoDimensionsSet_setImageUriAsync_doesNotResizeImageIcon() {
+        CachingIconView view = (CachingIconView) LayoutInflater.from(mContext).inflate(
+                R.layout.caching_icon_view_test_no_max_size, null);
+        view.setImageURIAsync(Uri.parse(
+                "android.resource://com.android.frameworks.coretests/" + R.drawable.big_a)).run();
+
+        assertDrawableNotResized(view);
+    }
+
+
+    private void assertDrawableResized(@Nullable CachingIconView view) {
+        assertThat(view).isNotNull();
+        int maxSize =
+                (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 80f,
+                        mContext.getResources().getDisplayMetrics());
+        assertThat(view.getMaxDrawableHeight()).isEqualTo(maxSize);
+        assertThat(view.getMaxDrawableWidth()).isEqualTo(maxSize);
+
+        Drawable drawable = view.getDrawable();
+        assertThat(drawable).isInstanceOf(BitmapDrawable.class);
+        BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
+        assertThat(bitmapDrawable.getBitmap().getWidth()).isLessThan(maxSize + 1);
+        assertThat(bitmapDrawable.getBitmap().getHeight()).isLessThan(maxSize + 1);
+    }
+
+    private void assertDrawableNotResized(@Nullable CachingIconView view) {
+        assertThat(view).isNotNull();
+        int maxSize =
+                (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 80f,
+                        mContext.getResources().getDisplayMetrics());
+        assertThat(view.getMaxDrawableHeight()).isEqualTo(-1);
+        assertThat(view.getMaxDrawableWidth()).isEqualTo(-1);
+
+        Drawable drawable = view.getDrawable();
+        assertThat(drawable).isInstanceOf(BitmapDrawable.class);
+        BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
+        assertThat(bitmapDrawable.getBitmap().getWidth()).isGreaterThan(maxSize);
+        assertThat(bitmapDrawable.getBitmap().getHeight()).isGreaterThan(maxSize);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java b/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java
new file mode 100644
index 0000000..d8b3780
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java
@@ -0,0 +1,212 @@
+/*
+ * 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.internal.widget;
+
+import android.content.Context;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+
+import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.frameworks.coretests.R;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+
+@RunWith(AndroidJUnit4ClassRunner.class)
+public class LocalImageResolverTest {
+
+    private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
+
+    @Test
+    public void resolveImage_invalidResource_returnsNull() throws IOException {
+        // We promise IOException in case of errors - but ImageDecode will throw NotFoundException
+        // in case of wrong resource. This test verifies that we throw IOException for API users.
+        Icon icon = Icon.createWithResource(mContext, 0x85849454);
+        Drawable d = LocalImageResolver.resolveImage(icon, mContext);
+        assertThat(d).isNull();
+    }
+
+    @Test
+    public void resolveImage_invalidIconUri_returnsNull() throws IOException {
+        // We promise IOException in case of errors - but ImageDecode will throw NotFoundException
+        // in case of wrong resource. This test verifies that we throw IOException for API users.
+        Icon icon = Icon.createWithContentUri(Uri.parse("bogus://uri"));
+        Drawable d = LocalImageResolver.resolveImage(icon, mContext);
+        assertThat(d).isNull();
+    }
+
+    @Test(expected = IOException.class)
+    public void resolveImage_invalidUri_throwsException() throws IOException {
+        Drawable d = LocalImageResolver.resolveImage(Uri.parse("bogus://uri"), mContext);
+        assertThat(d).isNull();
+    }
+
+    @Test
+    public void resolveImage_nonBitmapResourceIcon_fallsBackToNonResizingLoad() throws IOException {
+        Icon icon = Icon.createWithResource(mContext, R.drawable.blue);
+        Drawable d = LocalImageResolver.resolveImage(icon, mContext);
+        assertThat(d).isInstanceOf(ColorDrawable.class);
+    }
+
+    @Test(expected = IOException.class)
+    public void resolveImage_nonBitmapResourceUri_throwsIoException() throws IOException {
+        LocalImageResolver.resolveImage(
+                Uri.parse("android.resource://com.android.frameworks.coretests/" + R.drawable.blue),
+                mContext);
+    }
+
+    @Test
+    public void resolveImageWithResId_nonBitmapResourceIcon_returnsNull() {
+        Drawable d = LocalImageResolver.resolveImage(R.drawable.blue, mContext, 480, 480);
+        assertThat(d).isNull();
+    }
+
+    @Test
+    public void resolveImage_largeBitmapIcon_defaultSize_resizeToDefaultSize() throws
+            IOException {
+        Icon icon = Icon.createWithBitmap(
+                BitmapFactory.decodeResource(mContext.getResources(), R.drawable.big_a));
+        Drawable d = LocalImageResolver.resolveImage(icon, mContext);
+
+        assertThat(d).isInstanceOf(BitmapDrawable.class);
+        BitmapDrawable bd = (BitmapDrawable) d;
+        // No isLessOrEqualThan sadly.
+        assertThat(bd.getBitmap().getWidth()).isLessThan(
+                LocalImageResolver.DEFAULT_MAX_SAFE_ICON_SIZE_PX + 1);
+        assertThat(bd.getBitmap().getHeight()).isLessThan(
+                LocalImageResolver.DEFAULT_MAX_SAFE_ICON_SIZE_PX + 1);
+    }
+
+    @Test
+    public void resolveImage_largeAdaptiveBitmapIcon_defaultSize_resizeToDefaultSize() throws
+            IOException {
+        Icon icon = Icon.createWithAdaptiveBitmap(
+                BitmapFactory.decodeResource(mContext.getResources(), R.drawable.big_a));
+        Drawable d = LocalImageResolver.resolveImage(icon, mContext);
+
+        assertThat(d).isInstanceOf(AdaptiveIconDrawable.class);
+        BitmapDrawable bd = (BitmapDrawable) ((AdaptiveIconDrawable) d).getForeground();
+        // No isLessOrEqualThan sadly.
+        assertThat(bd.getBitmap().getWidth()).isLessThan(
+                LocalImageResolver.DEFAULT_MAX_SAFE_ICON_SIZE_PX + 1);
+        assertThat(bd.getBitmap().getHeight()).isLessThan(
+                LocalImageResolver.DEFAULT_MAX_SAFE_ICON_SIZE_PX + 1);
+    }
+
+    @Test
+    public void resolveImage_largeResourceIcon_defaultSize_resizeToDefaultSize() throws
+            IOException {
+        Icon icon = Icon.createWithResource(mContext, R.drawable.big_a);
+        Drawable d = LocalImageResolver.resolveImage(icon, mContext);
+
+        assertThat(d).isInstanceOf(BitmapDrawable.class);
+        BitmapDrawable bd = (BitmapDrawable) d;
+        // No isLessOrEqualThan sadly.
+        assertThat(bd.getBitmap().getWidth()).isLessThan(
+                LocalImageResolver.DEFAULT_MAX_SAFE_ICON_SIZE_PX + 1);
+        assertThat(bd.getBitmap().getHeight()).isLessThan(
+                LocalImageResolver.DEFAULT_MAX_SAFE_ICON_SIZE_PX + 1);
+    }
+
+    @Test
+    public void resolveImage_largeResourceIcon_passedSize_resizeToDefinedSize() {
+        Icon icon = Icon.createWithResource(mContext, R.drawable.big_a);
+        Drawable d = LocalImageResolver.resolveImage(icon, mContext, 100, 50);
+
+        assertThat(d).isInstanceOf(BitmapDrawable.class);
+        BitmapDrawable bd = (BitmapDrawable) d;
+        assertThat(bd.getBitmap().getWidth()).isLessThan(101);
+        assertThat(bd.getBitmap().getHeight()).isLessThan(51);
+    }
+
+    @Test
+    public void resolveImage_largeBitmapIcon_passedSize_resizeToDefinedSize() {
+        Icon icon = Icon.createWithBitmap(
+                BitmapFactory.decodeResource(mContext.getResources(), R.drawable.big_a));
+        Drawable d = LocalImageResolver.resolveImage(icon, mContext, 100, 50);
+
+        assertThat(d).isInstanceOf(BitmapDrawable.class);
+        BitmapDrawable bd = (BitmapDrawable) d;
+        assertThat(bd.getBitmap().getWidth()).isLessThan(101);
+        assertThat(bd.getBitmap().getHeight()).isLessThan(51);
+    }
+
+    @Test
+    public void resolveImage_largeAdaptiveBitmapIcon_passedSize_resizeToDefinedSize() {
+        Icon icon = Icon.createWithAdaptiveBitmap(
+                BitmapFactory.decodeResource(mContext.getResources(), R.drawable.big_a));
+        Drawable d = LocalImageResolver.resolveImage(icon, mContext, 100, 50);
+
+        assertThat(d).isInstanceOf(AdaptiveIconDrawable.class);
+        BitmapDrawable bd = (BitmapDrawable) ((AdaptiveIconDrawable) d).getForeground();
+        assertThat(bd.getBitmap().getWidth()).isLessThan(101);
+        assertThat(bd.getBitmap().getHeight()).isLessThan(51);
+    }
+
+
+    @Test
+    public void resolveImage_smallResourceIcon_defaultSize_untouched() throws IOException {
+        Icon icon = Icon.createWithResource(mContext, R.drawable.test32x24);
+        Drawable d = LocalImageResolver.resolveImage(icon, mContext);
+
+        assertThat(d).isInstanceOf(BitmapDrawable.class);
+        BitmapDrawable bd = (BitmapDrawable) d;
+        assertThat(bd.getBitmap().getWidth()).isEqualTo(32);
+        assertThat(bd.getBitmap().getHeight()).isEqualTo(24);
+    }
+
+    @Test
+    public void resolveImage_smallBitmapIcon_defaultSize_untouched() throws IOException {
+        Icon icon = Icon.createWithBitmap(
+                BitmapFactory.decodeResource(mContext.getResources(), R.drawable.test32x24));
+        final int originalWidth = icon.getBitmap().getWidth();
+        final int originalHeight = icon.getBitmap().getHeight();
+
+        Drawable d = LocalImageResolver.resolveImage(icon, mContext);
+
+        assertThat(d).isInstanceOf(BitmapDrawable.class);
+        BitmapDrawable bd = (BitmapDrawable) d;
+        assertThat(bd.getBitmap().getWidth()).isEqualTo(originalWidth);
+        assertThat(bd.getBitmap().getHeight()).isEqualTo(originalHeight);
+    }
+
+    @Test
+    public void resolveImage_smallAdaptiveBitmapIcon_defaultSize_untouched() throws IOException {
+        Icon icon = Icon.createWithAdaptiveBitmap(
+                BitmapFactory.decodeResource(mContext.getResources(), R.drawable.test32x24));
+        final int originalWidth = icon.getBitmap().getWidth();
+        final int originalHeight = icon.getBitmap().getHeight();
+
+        Drawable d = LocalImageResolver.resolveImage(icon, mContext);
+        assertThat(d).isInstanceOf(AdaptiveIconDrawable.class);
+        BitmapDrawable bd = (BitmapDrawable) ((AdaptiveIconDrawable) d).getForeground();
+        assertThat(bd.getBitmap().getWidth()).isEqualTo(originalWidth);
+        assertThat(bd.getBitmap().getHeight()).isEqualTo(originalHeight);
+
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/widget/LockPatternViewTest.java b/core/tests/coretests/src/com/android/internal/widget/LockPatternViewTest.java
new file mode 100644
index 0000000..8ba4966
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/widget/LockPatternViewTest.java
@@ -0,0 +1,247 @@
+/*
+ * 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.internal.widget;
+
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+
+import android.content.Context;
+
+import androidx.test.annotation.UiThreadTest;
+
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Toolbar;
+
+
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.rule.UiThreadTestRule;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import com.android.internal.R;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+@RunWith(Parameterized.class)
+@SmallTest
+public class LockPatternViewTest {
+
+    @Rule
+    public UiThreadTestRule uiThreadTestRule = new UiThreadTestRule();
+
+    private final int mViewSize;
+    private final float mDefaultError;
+    private final float mDot1x;
+    private final float mDot1y;
+    private final float mDot2x;
+    private final float mDot2y;
+    private final float mDot3x;
+    private final float mDot3y;
+    private final float mDot5x;
+    private final float mDot5y;
+    private final float mDot7x;
+    private final float mDot7y;
+    private final float mDot9x;
+    private final float mDot9y;
+
+    private Context mContext;
+    private LockPatternView mLockPatternView;
+    @Mock
+    private LockPatternView.OnPatternListener mPatternListener;
+    @Captor
+    private ArgumentCaptor<List<LockPatternView.Cell>> mCellsArgumentCaptor;
+
+    public LockPatternViewTest(int viewSize) {
+        mViewSize = viewSize;
+        float cellSize = viewSize / 3f;
+        mDefaultError = cellSize * 0.2f;
+        mDot1x = cellSize / 2f;
+        mDot1y = cellSize / 2f;
+        mDot2x = cellSize + mDot1x;
+        mDot2y = mDot1y;
+        mDot3x = cellSize + mDot2x;
+        mDot3y = mDot1y;
+        // dot4 is skipped as redundant
+        mDot5x = cellSize + mDot1x;
+        mDot5y = cellSize + mDot1y;
+        // dot6 is skipped as redundant
+        mDot7x = mDot1x;
+        mDot7y = cellSize * 2 + mDot1y;
+        // dot8 is skipped as redundant
+        mDot9x = cellSize * 2 + mDot7x;
+        mDot9y = mDot7y;
+    }
+
+    @Parameterized.Parameters
+    public static Collection primeNumbers() {
+        return Arrays.asList(192, 512, 768, 1024);
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mContext = InstrumentationRegistry.getContext();
+        mLockPatternView = new LockPatternView(mContext, null);
+        int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(mViewSize,
+                View.MeasureSpec.EXACTLY);
+        int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(mViewSize,
+                View.MeasureSpec.EXACTLY);
+        mLockPatternView.measure(widthMeasureSpec, heightMeasureSpec);
+        mLockPatternView.layout(0, 0, mLockPatternView.getMeasuredWidth(),
+                mLockPatternView.getMeasuredHeight());
+    }
+
+    @UiThreadTest
+    @Test
+    public void downStartsPattern() {
+        mLockPatternView.setOnPatternListener(mPatternListener);
+        mLockPatternView.onTouchEvent(
+                MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, mDot1x, mDot1y, 1));
+        verify(mPatternListener).onPatternStart();
+    }
+
+    @UiThreadTest
+    @Test
+    public void up_completesPattern() {
+        mLockPatternView.setOnPatternListener(mPatternListener);
+        mLockPatternView.onTouchEvent(
+                MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, mDot1x, mDot1y, 1));
+        mLockPatternView.onTouchEvent(
+                MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, mDot1x, mDot1y, 1));
+        verify(mPatternListener).onPatternDetected(any());
+    }
+
+    @UiThreadTest
+    @Test
+    public void moveToDot_hitsDot() {
+        mLockPatternView.setOnPatternListener(mPatternListener);
+        mLockPatternView.onTouchEvent(
+                MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 1f, 1f, 1));
+        mLockPatternView.onTouchEvent(
+                MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, mDot1x, mDot1y, 1));
+        verify(mPatternListener).onPatternStart();
+    }
+
+    @UiThreadTest
+    @Test
+    public void moveOutside_doesNotHitsDot() {
+        mLockPatternView.setOnPatternListener(mPatternListener);
+        mLockPatternView.onTouchEvent(
+                MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 1f, 1f, 1));
+        mLockPatternView.onTouchEvent(
+                MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 2f, 2f, 1));
+        verify(mPatternListener, never()).onPatternStart();
+    }
+
+    @UiThreadTest
+    @Test
+    public void moveAlongTwoDots_hitsTwo() {
+        mLockPatternView.setOnPatternListener(mPatternListener);
+        mLockPatternView.onTouchEvent(
+                MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 1f, 1f, 1));
+        makeMove(mDot1x, mDot1y, mDot2x, mDot2y, 6);
+        mLockPatternView.onTouchEvent(
+                MotionEvent.obtain(0, 3, MotionEvent.ACTION_UP, mDot2x, mDot2y, 1));
+
+        verify(mPatternListener).onPatternDetected(mCellsArgumentCaptor.capture());
+        List<LockPatternView.Cell> patternCells = mCellsArgumentCaptor.getValue();
+        assertThat(patternCells, hasSize(2));
+        assertThat(patternCells,
+                contains(LockPatternView.Cell.of(0, 0), LockPatternView.Cell.of(0, 1)));
+    }
+
+    @UiThreadTest
+    @Test
+    public void moveAlongTwoDotsDiagonally_hitsTwo() {
+        mLockPatternView.setOnPatternListener(mPatternListener);
+        mLockPatternView.onTouchEvent(
+                MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 1f, 1f, 1));
+        makeMove(mDot1x, mDot1y, mDot5x, mDot5y, 6);
+        mLockPatternView.onTouchEvent(
+                MotionEvent.obtain(0, 3, MotionEvent.ACTION_UP, mDot5x, mDot5y, 1));
+
+        verify(mPatternListener).onPatternDetected(mCellsArgumentCaptor.capture());
+        List<LockPatternView.Cell> patternCells = mCellsArgumentCaptor.getValue();
+        assertThat(patternCells, hasSize(2));
+        assertThat(patternCells,
+                contains(LockPatternView.Cell.of(0, 0), LockPatternView.Cell.of(1, 1)));
+    }
+
+    @UiThreadTest
+    @Test
+    public void moveAlongZPattern_hitsDots() {
+        mLockPatternView.setOnPatternListener(mPatternListener);
+        mLockPatternView.onTouchEvent(
+                MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 1f, 1f, 1));
+        makeMove(mDot1x, mDot1y, mDot3x + mDefaultError, mDot3y, 10);
+        makeMove(mDot3x - mDefaultError, mDot3y, mDot7x, mDot7y, 10);
+        makeMove(mDot7x, mDot7y - mDefaultError, mDot9x, mDot9y - mDefaultError, 10);
+        mLockPatternView.onTouchEvent(
+                MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, mViewSize - mDefaultError,
+                        mViewSize - mDefaultError, 1));
+
+        verify(mPatternListener).onPatternDetected(mCellsArgumentCaptor.capture());
+        List<LockPatternView.Cell> patternCells = mCellsArgumentCaptor.getValue();
+        assertThat(patternCells, hasSize(7));
+        assertThat(patternCells,
+                contains(LockPatternView.Cell.of(0, 0),
+                        LockPatternView.Cell.of(0, 1),
+                        LockPatternView.Cell.of(0, 2),
+                        LockPatternView.Cell.of(1, 1),
+                        LockPatternView.Cell.of(2, 0),
+                        LockPatternView.Cell.of(2, 1),
+                        LockPatternView.Cell.of(2, 2)));
+    }
+
+    private void makeMove(float xFrom, float yFrom, float xTo, float yTo, int numberOfSteps) {
+        for (int i = 0; i < numberOfSteps; i++) {
+            float progress = i / (numberOfSteps - 1f);
+            float rest = 1f - progress;
+            mLockPatternView.onTouchEvent(
+                    MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,
+                            /* x= */ xFrom * rest + xTo * progress,
+                            /* y= */ yFrom * rest + yTo * progress,
+                            1));
+        }
+    }
+}
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
index f8db069..b006a16 100644
--- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -16,12 +16,15 @@
 
 package android.app.activity;
 
+import static android.app.ActivityThread.shouldReportChange;
 import static android.app.servertransaction.ActivityLifecycleItem.ON_CREATE;
 import static android.app.servertransaction.ActivityLifecycleItem.ON_DESTROY;
 import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE;
 import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME;
 import static android.app.servertransaction.ActivityLifecycleItem.ON_START;
 import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
+import static android.content.pm.ActivityInfo.CONFIG_FONT_SCALE;
+import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
@@ -31,6 +34,8 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.clearInvocations;
@@ -56,6 +61,7 @@
 import android.platform.test.annotations.Presubmit;
 import android.testing.PollingCheck;
 import android.view.WindowManagerGlobal;
+import android.window.SizeConfigurationBuckets;
 
 import androidx.test.annotation.UiThreadTest;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -195,6 +201,47 @@
         }
     }
 
+    @Test
+    public void testShouldReportChange() {
+        final Configuration newConfig = new Configuration();
+        final Configuration currentConfig = new Configuration();
+
+        assertFalse("Must not report change if no public diff",
+                shouldReportChange(0 /* publicDiff */, currentConfig, newConfig,
+                null /* sizeBuckets */, 0 /* handledConfigChanges */));
+
+        final int[] verticalThresholds = {100, 400};
+        final SizeConfigurationBuckets buckets = new SizeConfigurationBuckets(
+                null /* horizontal */,
+                verticalThresholds,
+                null /* smallest */,
+                null /* screenLayoutSize */,
+                false /* screenLayoutLongSet */);
+        currentConfig.screenHeightDp = 200;
+        newConfig.screenHeightDp = 300;
+
+        assertFalse("Must not report changes if the diff is small and not handled",
+                shouldReportChange(CONFIG_SCREEN_SIZE /* publicDiff */, currentConfig,
+                newConfig, buckets, CONFIG_FONT_SCALE /* handledConfigChanges */));
+
+        assertTrue("Must report changes if the small diff is handled",
+                shouldReportChange(CONFIG_SCREEN_SIZE /* publicDiff */, currentConfig, newConfig,
+                buckets, CONFIG_SCREEN_SIZE /* handledConfigChanges */));
+
+        currentConfig.fontScale = 0.8f;
+        newConfig.fontScale = 1.2f;
+
+        assertTrue("Must report handled changes regardless of small unhandled change",
+                shouldReportChange(CONFIG_SCREEN_SIZE | CONFIG_FONT_SCALE /* publicDiff */,
+                currentConfig, newConfig, buckets, CONFIG_FONT_SCALE /* handledConfigChanges */));
+
+        newConfig.screenHeightDp = 500;
+
+        assertFalse("Must not report changes if there's unhandled big changes",
+                shouldReportChange(CONFIG_SCREEN_SIZE | CONFIG_FONT_SCALE /* publicDiff */,
+                currentConfig, newConfig, buckets, CONFIG_FONT_SCALE /* handledConfigChanges */));
+    }
+
     private void recreateAndVerifyNoRelaunch(ActivityThread activityThread, TestActivity activity) {
         clearInvocations(activityThread);
         getInstrumentation().runOnMainSync(() -> activity.recreate());
diff --git a/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java b/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java
index 5dc44d2..8de9196 100644
--- a/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java
+++ b/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java
@@ -123,7 +123,7 @@
     public void testLogDuration() throws Exception {
         TimingsTraceLog log = new TimingsTraceLog(TAG, TRACE_TAG_APP, 10);
         log.logDuration("logro", 42);
-        verify((MockedVoidMethod) () -> Slog.d(eq(TAG), contains("logro took to complete: 42ms")));
+        verify((MockedVoidMethod) () -> Slog.v(eq(TAG), contains("logro took to complete: 42ms")));
     }
 
     @Test
@@ -134,7 +134,7 @@
 
         verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "test"));
         verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP));
-        verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("test took to complete: \\dms")));
+        verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("test took to complete: \\dms")));
     }
 
     @Test
@@ -149,8 +149,8 @@
         verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L2"));
         verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP), times(2)); // L1 and L2
 
-        verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L2 took to complete: \\d+ms")));
-        verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L1 took to complete: \\d+ms")));
+        verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L2 took to complete: \\d+ms")));
+        verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L1 took to complete: \\d+ms")));
     }
 
     @Test
@@ -170,9 +170,9 @@
         verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L3"));
         verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP), times(3));
 
-        verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L2 took to complete: \\d+ms")));
-        verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L1 took to complete: \\d+ms")));
-        verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L3 took to complete: \\d+ms")),
+        verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L2 took to complete: \\d+ms")));
+        verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L1 took to complete: \\d+ms")));
+        verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L3 took to complete: \\d+ms")),
                 never());
 
         verify((MockedVoidMethod) () -> Slog.w(TAG, "not tracing duration of 'L3' "
diff --git a/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java
index b659f37..940ca96 100644
--- a/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java
@@ -19,14 +19,20 @@
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_MANAGED;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.pm.UserInfo;
@@ -50,6 +56,7 @@
 import org.mockito.Mockito;
 
 import java.nio.charset.StandardCharsets;
+import java.util.List;
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
@@ -164,6 +171,16 @@
         verify(ils).isWeakEscrowTokenValid(eq(testHandle), eq(testToken), eq(testUserId));
     }
 
+    @Test
+    public void testGetEnabledTrustAgentsNotNull() throws RemoteException {
+        int testUserId = 10;
+        ILockSettings ils = createTestLockSettings();
+        when(ils.getString(anyString(), any(), anyInt())).thenReturn("");
+        List<ComponentName> trustAgents = mLockPatternUtils.getEnabledTrustAgents(testUserId);
+        assertNotNull(trustAgents);
+        assertEquals(0, trustAgents.size());
+    }
+
     private ILockSettings createTestLockSettings() {
         final Context context = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
         mLockPatternUtils = spy(new LockPatternUtils(context));
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 2a82d8e..df51871 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -71,14 +71,6 @@
 }
 
 prebuilt_etc {
-    name: "privapp_whitelist_com.android.cellbroadcastreceiver",
-    system_ext_specific: true,
-    sub_dir: "permissions",
-    src: "com.android.cellbroadcastreceiver.xml",
-    filename_from_src: true,
-}
-
-prebuilt_etc {
     name: "privapp_whitelist_com.android.contacts",
     product_specific: true,
     sub_dir: "permissions",
diff --git a/data/etc/com.android.cellbroadcastreceiver.xml b/data/etc/com.android.cellbroadcastreceiver.xml
deleted file mode 100644
index bc62bbc..0000000
--- a/data/etc/com.android.cellbroadcastreceiver.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2020 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
-  -->
-<permissions>
-    <privapp-permissions package="com.android.cellbroadcastreceiver">
-        <permission name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"/>
-        <permission name="android.permission.INTERACT_ACROSS_USERS"/>
-        <permission name="android.permission.MANAGE_USERS"/>
-        <permission name="android.permission.STATUS_BAR"/>
-        <permission name="android.permission.MODIFY_PHONE_STATE"/>
-        <permission name="android.permission.MODIFY_CELL_BROADCASTS"/>
-        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
-        <permission name="android.permission.RECEIVE_EMERGENCY_BROADCAST"/>
-        <permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"/>
-    </privapp-permissions>
-</permissions>
diff --git a/data/etc/com.android.launcher3.xml b/data/etc/com.android.launcher3.xml
index 598d202..36a5134 100644
--- a/data/etc/com.android.launcher3.xml
+++ b/data/etc/com.android.launcher3.xml
@@ -16,6 +16,7 @@
   -->
 <permissions>
     <privapp-permissions package="com.android.launcher3">
+        <permission name="android.permission.ALLOW_SLIPPERY_TOUCHES"/>
         <permission name="android.permission.BIND_APPWIDGET"/>
         <permission name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/>
         <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index ae350ec..2d1db71 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -17,6 +17,7 @@
 <permissions>
     <privapp-permissions package="com.android.systemui">
         <permission name="android.permission.CAPTURE_AUDIO_OUTPUT"/>
+        <permission name="android.permission.ALLOW_SLIPPERY_TOUCHES"/>
         <permission name="android.permission.BATTERY_STATS"/>
         <permission name="android.permission.BIND_APPWIDGET"/>
         <permission name="android.permission.BLUETOOTH_PRIVILEGED"/>
@@ -75,5 +76,8 @@
         <permission name="android.permission.FORCE_STOP_PACKAGES" />
         <permission name="android.permission.ACCESS_FPS_COUNTER" />
         <permission name="android.permission.CHANGE_CONFIGURATION" />
+        <permission name="android.permission.LOG_COMPAT_CHANGE" />
+        <permission name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
+        <permission name="android.permission.READ_DEVICE_CONFIG" />
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 88920c8..a829339 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -241,7 +241,7 @@
     </split-permission>
     <split-permission name="android.permission.READ_EXTERNAL_STORAGE"
                       targetSdk="33">
-        <new-permission name="android.permission.READ_MEDIA_IMAGE" />
+        <new-permission name="android.permission.READ_MEDIA_IMAGES" />
     </split-permission>
     <split-permission name="android.permission.BLUETOOTH"
                       targetSdk="31">
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index deffa3a..a973078 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -38,24 +38,6 @@
         <permission name="android.permission.CRYPT_KEEPER"/>
     </privapp-permissions>
 
-    <privapp-permissions package="com.android.cellbroadcastreceiver.module">
-        <permission name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"/>
-        <permission name="android.permission.INTERACT_ACROSS_USERS"/>
-        <permission name="android.permission.MANAGE_USERS"/>
-        <permission name="android.permission.STATUS_BAR"/>
-        <permission name="android.permission.MODIFY_PHONE_STATE"/>
-        <permission name="android.permission.MODIFY_CELL_BROADCASTS"/>
-        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
-        <permission name="android.permission.RECEIVE_EMERGENCY_BROADCAST"/>
-        <permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"/>
-    </privapp-permissions>
-
-    <privapp-permissions package="com.android.cellbroadcastservice">
-        <permission name="android.permission.MODIFY_PHONE_STATE"/>
-        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
-        <permission name="android.permission.RECEIVE_EMERGENCY_BROADCAST"/>
-    </privapp-permissions>
-
     <privapp-permissions package="com.android.externalstorage">
         <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
         <permission name="android.permission.WRITE_MEDIA_STORAGE"/>
@@ -275,6 +257,8 @@
         <!-- Needed for test only -->
         <permission name="android.permission.BATTERY_PREDICTION"/>
         <permission name="android.permission.BATTERY_STATS"/>
+        <!-- BLUETOOTH_PRIVILEGED is needed for test only -->
+        <permission name="android.permission.BLUETOOTH_PRIVILEGED"/>
         <permission name="android.permission.BIND_APPWIDGET"/>
         <permission name="android.permission.CHANGE_APP_IDLE_STATE"/>
         <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
@@ -452,10 +436,11 @@
         <permission name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" />
         <permission name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" />
         <permission name="android.permission.NEARBY_WIFI_DEVICES" />
+        <permission name="android.permission.MANAGE_WIFI_INTERFACES" />
         <permission name="android.permission.OVERRIDE_WIFI_CONFIG" />
         <!-- Permission needed for CTS test - ConcurrencyTest#testP2pExternalApprover
-             P2P external approver API sets require MANAGE_WIFI_AUTO_JOIN permission. -->
-        <permission name="android.permission.MANAGE_WIFI_AUTO_JOIN" />
+             P2P external approver API sets require MANAGE_WIFI_NETWORK_SELECTION permission. -->
+        <permission name="android.permission.MANAGE_WIFI_NETWORK_SELECTION" />
         <!-- Permission required for CTS test CarrierMessagingServiceWrapperTest -->
         <permission name="android.permission.BIND_CARRIER_SERVICES"/>
         <!-- Permission required for CTS test - MusicRecognitionManagerTest -->
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index df2b2a3..6b66fad 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -19,6 +19,12 @@
       "group": "WM_DEBUG_LOCKTASK",
       "at": "com\/android\/server\/wm\/LockTaskController.java"
     },
+    "-2111539867": {
+      "message": "remove IME snapshot, caller=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
     "-2109936758": {
       "message": "removeAppToken make exiting: %s",
       "level": "VERBOSE",
@@ -61,6 +67,12 @@
       "group": "WM_DEBUG_TASKS",
       "at": "com\/android\/server\/wm\/Task.java"
     },
+    "-2052051397": {
+      "message": "Clear animatingExit: reason=destroySurface win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
     "-2049725903": {
       "message": "Task back pressed on root taskId=%d",
       "level": "VERBOSE",
@@ -127,6 +139,12 @@
       "group": "WM_DEBUG_SYNC_ENGINE",
       "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
     },
+    "-1969928125": {
+      "message": "Animation start for %s, anim=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
+    },
     "-1963461591": {
       "message": "Removing %s from %s",
       "level": "VERBOSE",
@@ -163,6 +181,12 @@
       "group": "WM_DEBUG_STARTING_WINDOW",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "-1933723759": {
+      "message": "Clear animatingExit: reason=relayoutVisibleWindow win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
     "-1924376693": {
       "message": " Setting Ready-group to %b. group=%s from %s",
       "level": "VERBOSE",
@@ -265,6 +289,12 @@
       "group": "WM_DEBUG_RESIZE",
       "at": "com\/android\/server\/wm\/WindowState.java"
     },
+    "-1814361639": {
+      "message": "Set IME snapshot position: (%d, %d)",
+      "level": "INFO",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
     "-1810446914": {
       "message": "Trying to update display configuration for system\/invalid process.",
       "level": "WARN",
@@ -307,6 +337,12 @@
       "group": "WM_DEBUG_REMOTE_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
     },
+    "-1777010776": {
+      "message": "create IME snapshot for %s, buff width=%s, height=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
     "-1770075711": {
       "message": "Adding window client %s that is dead, aborting.",
       "level": "WARN",
@@ -613,6 +649,12 @@
       "group": "WM_DEBUG_ADD_REMOVE",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "-1471518109": {
+      "message": "Set animatingExit: reason=onAppVisibilityChanged win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
     "-1468740466": {
       "message": "Moving to PAUSED: %s (starting in paused state)",
       "level": "VERBOSE",
@@ -751,6 +793,12 @@
       "group": "WM_DEBUG_CONTENT_RECORDING",
       "at": "com\/android\/server\/wm\/ContentRecorder.java"
     },
+    "-1318478129": {
+      "message": "applyAnimation: win=%s anim=%d attr=0x%x a=%s transit=%d type=%d isEntrance=%b Callers %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
     "-1311436264": {
       "message": "Unregister task fragment organizer=%s uid=%d pid=%d",
       "level": "VERBOSE",
@@ -781,12 +829,24 @@
       "group": "WM_DEBUG_TASKS",
       "at": "com\/android\/server\/wm\/ActivityStarter.java"
     },
+    "-1303628829": {
+      "message": "**** STARTING EXIT",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/DisplayPolicy.java"
+    },
     "-1292329638": {
       "message": "Added starting %s: startingWindow=%s startingView=%s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_STARTING_WINDOW",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "-1288007399": {
+      "message": "performShowLocked: mDrawState=HAS_DRAWN in %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
     "-1270731689": {
       "message": "Attempted to set replacing window on app token with no content %s",
       "level": "WARN",
@@ -835,6 +895,12 @@
       "group": "WM_DEBUG_RECENTS_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
     },
+    "-1209252064": {
+      "message": "Clear animatingExit: reason=clearAnimatingFlags win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
     "-1207757583": {
       "message": "startAnimation(): Notify animation start: %s",
       "level": "DEBUG",
@@ -1219,6 +1285,12 @@
       "group": "WM_DEBUG_CONFIGURATION",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "-799003045": {
+      "message": "Set animatingExit: reason=remove\/replaceWindow win=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
     "-784959154": {
       "message": "Attempted to add private presentation window to a non-private display.  Aborting.",
       "level": "WARN",
@@ -1309,6 +1381,12 @@
       "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "-711194343": {
+      "message": "Setting Activity.mLauncherTaskBehind to false. Activity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
     "-706481945": {
       "message": "TaskFragment parent info changed name=%s parentTaskId=%d",
       "level": "VERBOSE",
@@ -1369,6 +1447,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/RootWindowContainer.java"
     },
+    "-658964693": {
+      "message": "onWindowAnimationFinished, wc=%s, type=%s, imeSnapshot=%s, target=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
     "-655104359": {
       "message": "Frontmost changed immersion: %s",
       "level": "DEBUG",
@@ -1669,6 +1753,12 @@
       "group": "WM_DEBUG_WINDOW_TRANSITIONS",
       "at": "com\/android\/server\/wm\/Transition.java"
     },
+    "-347866078": {
+      "message": "Setting move animation on %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
     "-344488673": {
       "message": "Finishing drawing window %s: mDrawState=%s",
       "level": "VERBOSE",
@@ -1693,6 +1783,12 @@
       "group": "WM_DEBUG_ADD_REMOVE",
       "at": "com\/android\/server\/wm\/WindowState.java"
     },
+    "-319689203": {
+      "message": "Reparenting to original parent: %s for %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
+    },
     "-317761482": {
       "message": "Create sleep token: tag=%s, displayId=%d",
       "level": "DEBUG",
@@ -1801,6 +1897,18 @@
       "group": "WM_DEBUG_APP_TRANSITIONS",
       "at": "com\/android\/server\/wm\/WindowState.java"
     },
+    "-208664771": {
+      "message": "Reparenting to leash for %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
+    },
+    "-203358733": {
+      "message": "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
     "-198463978": {
       "message": "updateRotationUnchecked: alwaysSendConfiguration=%b forceRelayout=%b",
       "level": "VERBOSE",
@@ -1897,6 +2005,12 @@
       "group": "WM_DEBUG_RECENTS_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RecentsAnimation.java"
     },
+    "-91393839": {
+      "message": "Set animatingExit: reason=remove\/applyAnimation win=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
     "-90559682": {
       "message": "Config is skipping already pausing %s",
       "level": "VERBOSE",
@@ -1921,6 +2035,12 @@
       "group": "WM_SHOW_TRANSACTIONS",
       "at": "com\/android\/server\/wm\/Session.java"
     },
+    "-81121442": {
+      "message": "ImeContainer just became organized but it doesn't have a parent or the parent doesn't have a surface control. mSurfaceControl=%s imeParentSurfaceControl=%s",
+      "level": "ERROR",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
     "-80004683": {
       "message": "Resume failed; resetting state to %s: %s",
       "level": "VERBOSE",
@@ -1933,6 +2053,12 @@
       "group": "WM_DEBUG_WINDOW_ORGANIZER",
       "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
     },
+    "-57750640": {
+      "message": "show IME snapshot, ime target=%s, callers=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
     "-55185509": {
       "message": "setFocusedTask: taskId=%d touchedActivity=%s",
       "level": "DEBUG",
@@ -1951,6 +2077,12 @@
       "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
       "at": "com\/android\/server\/wm\/WindowContainer.java"
     },
+    "-32102932": {
+      "message": "Error sending initial configuration change to WindowContainer overlay",
+      "level": "ERROR",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
     "-23020844": {
       "message": "Back: Reset surfaces",
       "level": "DEBUG",
@@ -2185,6 +2317,12 @@
       "group": "WM_DEBUG_RECENTS_ANIMATIONS",
       "at": "com\/android\/server\/wm\/Task.java"
     },
+    "215077284": {
+      "message": "Animation start delayed for %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
+    },
     "221540118": {
       "message": "mUserActivityTimeout set to %d",
       "level": "DEBUG",
@@ -2251,6 +2389,12 @@
       "group": "WM_DEBUG_WINDOW_TRANSITIONS",
       "at": "com\/android\/server\/wm\/TransitionController.java"
     },
+    "264036181": {
+      "message": "Unable to retrieve task to start recording for display %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
     "269576220": {
       "message": "Resuming rotation after drag",
       "level": "DEBUG",
@@ -2269,6 +2413,12 @@
       "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
       "at": "com\/android\/server\/wm\/AppTransition.java"
     },
+    "283489582": {
+      "message": "Clear animatingExit: reason=exitAnimationDone win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
     "288485303": {
       "message": "Attempted to set remove mode to a display that does not exist: %d",
       "level": "WARN",
@@ -2341,6 +2491,12 @@
       "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/TaskFragment.java"
     },
+    "341360111": {
+      "message": "selectAnimation in %s: transit=%d",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/DisplayPolicy.java"
+    },
     "342460966": {
       "message": "DRAG %s: pos=(%d,%d)",
       "level": "INFO",
@@ -2407,6 +2563,12 @@
       "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/TaskFragment.java"
     },
+    "385595355": {
+      "message": "Starting animation on %s: type=%d, anim=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
     "397105698": {
       "message": "grantEmbeddedWindowFocus remove request for win=%s dropped since no candidate was found",
       "level": "VERBOSE",
@@ -2419,6 +2581,12 @@
       "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "397862437": {
+      "message": "Cancelling animation restarting=%b for %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
+    },
     "399841913": {
       "message": "SURFACE RECOVER DESTROY: %s",
       "level": "INFO",
@@ -2587,6 +2755,12 @@
       "group": "WM_DEBUG_APP_TRANSITIONS",
       "at": "com\/android\/server\/wm\/WindowState.java"
     },
+    "599897753": {
+      "message": "Previous Activity is %s. Back type is %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
     "600140673": {
       "message": "checkBootAnimationComplete: Waiting for anim complete",
       "level": "INFO",
@@ -2671,12 +2845,6 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
-    "664667685": {
-      "message": "Activity %s: enableOnBackInvokedCallback=false. Returning null BackNavigationInfo.",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
     "665256544": {
       "message": "All windows drawn!",
       "level": "DEBUG",
@@ -2785,6 +2953,18 @@
       "group": "WM_DEBUG_RECENTS_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RecentsAnimation.java"
     },
+    "769218938": {
+      "message": "Loaded animation %s for %s, duration: %d, stack=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "778774915": {
+      "message": "Unable to record task since feature is disabled %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
     "781471998": {
       "message": "moveWindowTokenToDisplay: Cannot move to the original display for token: %s",
       "level": "WARN",
@@ -2887,6 +3067,12 @@
       "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/TaskFragment.java"
     },
+    "948208142": {
+      "message": "Setting Activity.mLauncherTaskBehind to true. Activity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
     "950074526": {
       "message": "setLockTaskMode: Can't lock due to auth",
       "level": "WARN",
@@ -2929,6 +3115,12 @@
       "group": "WM_DEBUG_REMOTE_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
     },
+    "975275467": {
+      "message": "Set animatingExit: reason=remove\/isAnimating win=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
     "979347997": {
       "message": "Launch on display check: disallow activity embedding without permission.",
       "level": "DEBUG",
@@ -3097,12 +3289,30 @@
       "group": "WM_DEBUG_WINDOW_ORGANIZER",
       "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
     },
+    "1164325516": {
+      "message": "onExitAnimationDone in %s: exiting=%b remove=%b selfAnimating=%b anim=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
     "1166381079": {
       "message": "Execute app transition: %s, displayId: %d Callers=%s",
       "level": "WARN",
       "group": "WM_DEBUG_APP_TRANSITIONS",
       "at": "com\/android\/server\/wm\/DisplayContent.java"
     },
+    "1172542963": {
+      "message": "onBackNavigationDone backType=%s, task=%s, prevTaskTopActivity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "1175495463": {
+      "message": "ImeContainer just became organized. Reparenting under parent. imeParentSurfaceControl=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
     "1178653181": {
       "message": "Old wallpaper still the target.",
       "level": "VERBOSE",
@@ -3223,11 +3433,11 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
-    "1333520287": {
-      "message": "Creating PendingTransition: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
+    "1335791109": {
+      "message": "createSurface %s: mDrawState=DRAW_PENDING",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
     },
     "1337596507": {
       "message": "Sending to proc %s new compat %s",
@@ -3415,11 +3625,11 @@
       "group": "WM_DEBUG_APP_TRANSITIONS",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "1554795024": {
-      "message": "Previous Activity is %s",
+    "1544805551": {
+      "message": "Skipping app transition animation. task=%s",
       "level": "DEBUG",
       "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+      "at": "com\/android\/server\/wm\/Task.java"
     },
     "1557732761": {
       "message": "For Intent %s bringing to top: %s",
@@ -3517,6 +3727,12 @@
       "group": "WM_DEBUG_IME",
       "at": "com\/android\/server\/wm\/InsetsStateController.java"
     },
+    "1667162379": {
+      "message": "Creating Pending Transition: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
+    },
     "1670933628": {
       "message": " Setting allReady override",
       "level": "VERBOSE",
@@ -3571,6 +3787,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "1730300180": {
+      "message": "PendingStartTransaction found",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+    },
     "1739298851": {
       "message": "removeWindowToken: Attempted to remove token: %s for non-exiting displayId=%d",
       "level": "WARN",
@@ -3643,6 +3865,12 @@
       "group": "WM_DEBUG_APP_TRANSITIONS",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "1810209625": {
+      "message": "Animation done in %s: exiting=%b, reportedVisible=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
     "1822314934": {
       "message": "Expected target rootTask=%s to restored behind rootTask=%s but it is behind rootTask=%s",
       "level": "WARN",
@@ -3721,6 +3949,12 @@
       "group": "WM_DEBUG_WINDOW_ORGANIZER",
       "at": "com\/android\/server\/wm\/DisplayAreaPolicyBuilder.java"
     },
+    "1878927091": {
+      "message": "prepareSurface: No changes in animation for %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
     "1891501279": {
       "message": "cancelAnimation(): reason=%s",
       "level": "DEBUG",
@@ -3823,6 +4057,12 @@
       "group": "WM_DEBUG_FOCUS_LIGHT",
       "at": "com\/android\/server\/wm\/InputMonitor.java"
     },
+    "2010476671": {
+      "message": "Animation done in %s: reportedVisible=%b okToDisplay=%b okToAnimate=%b startingDisplayed=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "2018454757": {
       "message": "WS.removeImmediately: %s Already removed...",
       "level": "VERBOSE",
@@ -3835,6 +4075,12 @@
       "group": "WM_DEBUG_STARTING_WINDOW",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "2019765997": {
+      "message": "selectRotationAnimation topFullscreen=%s rotationAnimation=%d forceJumpcut=%b",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
     "2022422429": {
       "message": "createAnimationAdapter(): container=%s",
       "level": "DEBUG",
@@ -3859,12 +4105,6 @@
       "group": "WM_DEBUG_BOOT",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
-    "2034988903": {
-      "message": "PendingStartTransaction found",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
-    },
     "2039056415": {
       "message": "Found matching affinity candidate!",
       "level": "DEBUG",
@@ -3889,6 +4129,12 @@
       "group": "WM_DEBUG_WINDOW_INSETS",
       "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
     },
+    "2075693141": {
+      "message": "Set animatingExit: reason=startExitingAnimation\/%s win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
     "2083556954": {
       "message": "Set mOrientationChanging of %s",
       "level": "VERBOSE",
@@ -3913,6 +4159,12 @@
       "group": "WM_DEBUG_KEEP_SCREEN_ON",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "2100457473": {
+      "message": "Task=%d contains embedded TaskFragment. Disabled all input during TaskFragment remote animation.",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
     "2114149926": {
       "message": "Not removing %s because app died while it's visible",
       "level": "VERBOSE",
@@ -3948,6 +4200,9 @@
     "WM_DEBUG_ADD_REMOVE": {
       "tag": "WindowManager"
     },
+    "WM_DEBUG_ANIM": {
+      "tag": "WindowManager"
+    },
     "WM_DEBUG_APP_TRANSITIONS": {
       "tag": "WindowManager"
     },
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index bd0e56a..c81473d 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -416,6 +416,8 @@
 key usage 0x0c006F BRIGHTNESS_UP
 key usage 0x0c0070 BRIGHTNESS_DOWN
 key usage 0x0c0173 MEDIA_AUDIO_TRACK
+key usage 0x0c019C PROFILE_SWITCH
+key usage 0x0c01A2 ALL_APPS
 
 # Joystick and game controller axes.
 # Axes that are not mapped will be assigned generic axis numbers by the input subsystem.
diff --git a/data/keyboards/Vendor_0957_Product_0001.kl b/data/keyboards/Vendor_0957_Product_0001.kl
index 672abef..13b4096 100644
--- a/data/keyboards/Vendor_0957_Product_0001.kl
+++ b/data/keyboards/Vendor_0957_Product_0001.kl
@@ -44,6 +44,8 @@
 key 11    0
 
 # custom keys
+key usage 0x000c019C    PROFILE_SWITCH
+key usage 0x000c01A2    ALL_APPS
 key usage 0x000c01BB    TV_INPUT
 key usage 0x000c022A    BOOKMARK
 key usage 0x000c0096    SETTINGS
@@ -53,6 +55,7 @@
 key usage 0x000c009C    CHANNEL_UP
 key usage 0x000c009D    CHANNEL_DOWN
 key usage 0x000c00CD    MEDIA_PLAY_PAUSE
+key usage 0x000c00B2    MEDIA_RECORD
 key usage 0x000c00B4    MEDIA_SKIP_BACKWARD
 key usage 0x000c00B3    MEDIA_SKIP_FORWARD
 key usage 0x000c0226    MEDIA_STOP
@@ -62,6 +65,7 @@
 key usage 0x000c0079    BUTTON_6     WAKE #Disney+
 key usage 0x000c007A    BUTTON_7     WAKE #HBOmax
 
+key usage 0x00070037    PERIOD
 key usage 0x000c01BD    INFO
 key usage 0x000c0061    CAPTIONS
 key usage 0x000c0185    TV_TELETEXT
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index fd4bed1..7cc22d7 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -849,6 +849,14 @@
         nSetContentDrawBounds(mNativeProxy, left, top, right, bottom);
     }
 
+    /**
+     * Force the new frame to draw, ensuring the UI draw request will attempt a draw this vsync.
+     * @hide
+     */
+    public void forceDrawNextFrame() {
+        nForceDrawNextFrame(mNativeProxy);
+    }
+
     /** @hide */
     public void setPictureCaptureCallback(@Nullable PictureCapturedCallback callback) {
         nSetPictureCaptureCallback(mNativeProxy, callback);
@@ -976,12 +984,12 @@
     }
 
     /**
-     * b/68769804: For low FPS experiments.
+     * b/68769804, b/66945974: For low FPS experiments.
      *
      * @hide
      */
     public static void setFPSDivisor(int divisor) {
-        nHackySetRTAnimationsEnabled(divisor <= 1);
+        nSetRtAnimationsEnabled(divisor <= 1);
     }
 
     /**
@@ -1145,6 +1153,16 @@
         nSetDrawingEnabled(drawingEnabled);
     }
 
+    /**
+     * Disable RenderThread animations that schedule draws directly from RenderThread. This is used
+     * when we don't want to de-schedule draw requests that come from the UI thread.
+     *
+     * @hide
+     */
+    public static void setRtAnimationsEnabled(boolean enabled) {
+        nSetRtAnimationsEnabled(enabled);
+    }
+
     private static final class DestroyContextRunnable implements Runnable {
         private final long mNativeInstance;
 
@@ -1423,6 +1441,8 @@
     private static native void nSetContentDrawBounds(long nativeProxy, int left,
             int top, int right, int bottom);
 
+    private static native void nForceDrawNextFrame(long nativeProxy);
+
     private static native void nSetPictureCaptureCallback(long nativeProxy,
             PictureCapturedCallback callback);
 
@@ -1451,9 +1471,6 @@
 
     private static native void nSetHighContrastText(boolean enabled);
 
-    // For temporary experimentation b/66945974
-    private static native void nHackySetRTAnimationsEnabled(boolean enabled);
-
     private static native void nSetDebuggingEnabled(boolean enabled);
 
     private static native void nSetIsolatedProcess(boolean enabled);
@@ -1472,4 +1489,6 @@
     private static native void nSetDrawingEnabled(boolean drawingEnabled);
 
     private static native boolean nIsDrawingEnabled();
+
+    private static native void nSetRtAnimationsEnabled(boolean rtAnimationsEnabled);
 }
diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java
index 7e68bc0..1a522bd 100644
--- a/graphics/java/android/graphics/Rect.java
+++ b/graphics/java/android/graphics/Rect.java
@@ -291,6 +291,14 @@
     }
 
     /**
+     * @return {@code true} if the rectangle is valid (left <= right and top <= bottom).
+     * @hide
+     */
+    public boolean isValid() {
+        return left <= right && top <= bottom;
+    }
+
+    /**
      * @return the rectangle's width. This does not check for a valid rectangle
      * (i.e. left <= right) so the result may be negative.
      */
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 61f7fac..a2f5301 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -329,7 +329,7 @@
             FontFamily.Builder familyBuilder = null;
             for (final FontFileResourceEntry fontFile : filesEntry.getEntries()) {
                 final Font.Builder fontBuilder = new Font.Builder(mgr, fontFile.getFileName(),
-                        false /* isAsset */, 0 /* cookie */)
+                        false /* isAsset */, AssetManager.COOKIE_UNKNOWN)
                         .setTtcIndex(fontFile.getTtcIndex())
                         .setFontVariationSettings(fontFile.getVariationSettings());
                 if (fontFile.getWeight() != Typeface.RESOLVE_BY_FONT_TABLE) {
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index ffaa4ea..bfa6ce5 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -1000,7 +1000,7 @@
     }
 
     private int clampAlpha(@ColorInt int color) {
-        if (Color.alpha(color) > 128) {
+        if (Color.alpha(color) < 128) {
             return  (color & 0x00FFFFFF) | 0x80000000;
         }
         return color;
@@ -1098,19 +1098,16 @@
         }
 
         // Draw the appropriate mask anchored to (0,0).
+        final int saveCount = mMaskCanvas.save();
         final int left = bounds.left;
         final int top = bounds.top;
-        if (mState.mRippleStyle == STYLE_SOLID) {
-            mMaskCanvas.translate(-left, -top);
-        }
+        mMaskCanvas.translate(-left, -top);
         if (maskType == MASK_EXPLICIT) {
             drawMask(mMaskCanvas);
         } else if (maskType == MASK_CONTENT) {
             drawContent(mMaskCanvas);
         }
-        if (mState.mRippleStyle == STYLE_SOLID) {
-            mMaskCanvas.translate(left, top);
-        }
+        mMaskCanvas.restoreToCount(saveCount);
         if (mState.mRippleStyle == STYLE_PATTERNED) {
             for (int i = 0; i < mRunningAnimations.size(); i++) {
                 mRunningAnimations.get(i).getProperties().getShader().setShader(mMaskShader);
@@ -1210,9 +1207,13 @@
         updateMaskShaderIfNeeded();
 
         // Position the shader to account for canvas translation.
-        if (mMaskShader != null && mState.mRippleStyle == STYLE_SOLID) {
+        if (mMaskShader != null) {
             final Rect bounds = getBounds();
-            mMaskMatrix.setTranslate(bounds.left - x, bounds.top - y);
+            if (mState.mRippleStyle == STYLE_PATTERNED) {
+                mMaskMatrix.setTranslate(bounds.left, bounds.top);
+            } else {
+                mMaskMatrix.setTranslate(bounds.left - x, bounds.top - y);
+            }
             mMaskShader.setLocalMatrix(mMaskMatrix);
         }
 
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index cd7936d..abd0be9 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -179,7 +179,7 @@
          */
         public Builder(@NonNull AssetManager am, @NonNull String path) {
             try {
-                mBuffer = createBuffer(am, path, true /* is asset */, 0 /* cookie */);
+                mBuffer = createBuffer(am, path, true /* is asset */, AssetManager.COOKIE_UNKNOWN);
             } catch (IOException e) {
                 mException = e;
             }
diff --git a/graphics/java/android/graphics/text/LineBreakConfig.java b/graphics/java/android/graphics/text/LineBreakConfig.java
index cffdf28..d083e44 100644
--- a/graphics/java/android/graphics/text/LineBreakConfig.java
+++ b/graphics/java/android/graphics/text/LineBreakConfig.java
@@ -26,7 +26,7 @@
 /**
  * Indicates the strategies can be used when calculating the text wrapping.
  *
- * See <a href="https://drafts.csswg.org/css-text/#line-break-property">the line-break property</a>
+ * See <a href="https://www.w3.org/TR/css-text-3/#line-break-property">the line-break property</a>
  */
 public final class LineBreakConfig {
 
@@ -78,21 +78,87 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface LineBreakWordStyle {}
 
-    private @LineBreakStyle int mLineBreakStyle = LINE_BREAK_STYLE_NONE;
-    private @LineBreakWordStyle int mLineBreakWordStyle = LINE_BREAK_WORD_STYLE_NONE;
+    /**
+     * A builder for creating {@link LineBreakConfig}.
+     */
+    public static final class Builder {
+        // The line break style for the LineBreakConfig.
+        private @LineBreakStyle int mLineBreakStyle = LineBreakConfig.LINE_BREAK_STYLE_NONE;
 
-    public LineBreakConfig() {
+        // The line break word style for the LineBreakConfig.
+        private @LineBreakWordStyle int mLineBreakWordStyle =
+                LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE;
+
+        /**
+         * Builder constructor with line break parameters.
+         */
+        public Builder() {
+        }
+
+        /**
+         * Set the line break style.
+         *
+         * @param lineBreakStyle the new line break style.
+         * @return this Builder
+         */
+        public @NonNull Builder setLineBreakStyle(@LineBreakStyle int lineBreakStyle) {
+            mLineBreakStyle = lineBreakStyle;
+            return this;
+        }
+
+        /**
+         * Set the line break word style.
+         *
+         * @param lineBreakWordStyle the new line break word style.
+         * @return this Builder
+         */
+        public @NonNull Builder setLineBreakWordStyle(@LineBreakWordStyle int lineBreakWordStyle) {
+            mLineBreakWordStyle = lineBreakWordStyle;
+            return this;
+        }
+
+        /**
+         * Build the {@link LineBreakConfig}
+         *
+         * @return the LineBreakConfig instance.
+         */
+        public @NonNull LineBreakConfig build() {
+            return new LineBreakConfig(mLineBreakStyle, mLineBreakWordStyle);
+        }
     }
 
     /**
-     * Set the line break configuration.
+     * Create the LineBreakConfig instance.
      *
-     * @param lineBreakConfig the new line break configuration.
+     * @param lineBreakStyle the line break style for text wrapping.
+     * @param lineBreakWordStyle the line break word style for text wrapping.
+     * @return the {@link LineBreakConfig} instance.
+     * @hide
      */
-    public void set(@NonNull LineBreakConfig lineBreakConfig) {
-        Objects.requireNonNull(lineBreakConfig);
-        mLineBreakStyle = lineBreakConfig.getLineBreakStyle();
-        mLineBreakWordStyle = lineBreakConfig.getLineBreakWordStyle();
+    public static @NonNull LineBreakConfig getLineBreakConfig(@LineBreakStyle int lineBreakStyle,
+            @LineBreakWordStyle int lineBreakWordStyle) {
+        LineBreakConfig.Builder builder = new LineBreakConfig.Builder();
+        return builder.setLineBreakStyle(lineBreakStyle)
+                .setLineBreakWordStyle(lineBreakWordStyle)
+                .build();
+    }
+
+    /** @hide */
+    public static final LineBreakConfig NONE =
+            new Builder().setLineBreakStyle(LINE_BREAK_STYLE_NONE)
+                    .setLineBreakWordStyle(LINE_BREAK_WORD_STYLE_NONE).build();
+
+    private final @LineBreakStyle int mLineBreakStyle;
+    private final @LineBreakWordStyle int mLineBreakWordStyle;
+
+    /**
+     * Constructor with the line break parameters.
+     * Use the {@link LineBreakConfig.Builder} to create the LineBreakConfig instance.
+     */
+    private LineBreakConfig(@LineBreakStyle int lineBreakStyle,
+            @LineBreakWordStyle int lineBreakWordStyle) {
+        mLineBreakStyle = lineBreakStyle;
+        mLineBreakWordStyle = lineBreakWordStyle;
     }
 
     /**
@@ -105,15 +171,6 @@
     }
 
     /**
-     * Set the line break style.
-     *
-     * @param lineBreakStyle the new line break style.
-     */
-    public void setLineBreakStyle(@LineBreakStyle int lineBreakStyle) {
-        mLineBreakStyle = lineBreakStyle;
-    }
-
-    /**
      * Get the line break word style.
      *
      * @return The current line break word style to be used for the text wrapping.
@@ -122,15 +179,6 @@
         return mLineBreakWordStyle;
     }
 
-    /**
-     * Set the line break word style.
-     *
-     * @param lineBreakWordStyle the new line break word style.
-     */
-    public void setLineBreakWordStyle(@LineBreakWordStyle int lineBreakWordStyle) {
-        mLineBreakWordStyle = lineBreakWordStyle;
-    }
-
     @Override
     public boolean equals(Object o) {
         if (o == null) return false;
diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
index 05fb4c3..919a93b 100644
--- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java
+++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -20,7 +20,6 @@
 import android.annotation.Nullable;
 import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
-import android.security.keystore.KeyProperties;
 import android.security.maintenance.IKeystoreMaintenance;
 import android.system.keystore2.Domain;
 import android.system.keystore2.KeyDescriptor;
@@ -158,11 +157,6 @@
      * Migrates a key given by the source descriptor to the location designated by the destination
      * descriptor.
      *
-     * If Domain::APP is selected in either source or destination, nspace must be set to
-     * {@link KeyProperties#NAMESPACE_APPLICATION}, implying the caller's UID.
-     * If the caller has the MIGRATE_ANY_KEY permission, Domain::APP may be used with
-     * other nspace values which then indicates the UID of a different application.
-     *
      * @param source - The key to migrate may be specified by Domain.APP, Domain.SELINUX, or
      *               Domain.KEY_ID. The caller needs the permissions use, delete, and grant for the
      *               source namespace.
@@ -189,20 +183,4 @@
             return SYSTEM_ERROR;
         }
     }
-
-    /**
-     * @see IKeystoreMaintenance#listEntries(int, long)
-     */
-    @Nullable
-    public static KeyDescriptor[] listEntries(int domain, long nspace) {
-        try {
-            return getService().listEntries(domain, nspace);
-        } catch (ServiceSpecificException e) {
-            Log.e(TAG, "listEntries failed", e);
-            return null;
-        } catch (Exception e) {
-            Log.e(TAG, "Can not connect to keystore", e);
-            return null;
-        }
-    }
 }
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index 31dd10a..e7961c9 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -108,6 +108,16 @@
         }
     }
 
+    /**
+     * XDH represents Curve 25519 providers.
+     */
+    public static class XDH extends AndroidKeyStoreKeyPairGeneratorSpi {
+        // XDH is treated as EC.
+        public XDH() {
+            super(KeymasterDefs.KM_ALGORITHM_EC);
+        }
+    }
+
     /*
      * These must be kept in sync with system/security/keystore/defaults.h
      */
@@ -242,6 +252,23 @@
                 } catch (NullPointerException | IllegalArgumentException e) {
                     throw new InvalidAlgorithmParameterException(e);
                 }
+            } else if (params instanceof NamedParameterSpec) {
+                NamedParameterSpec namedSpec = (NamedParameterSpec) params;
+                // Android Keystore cannot support initialization from a NamedParameterSpec
+                // because an alias for the key is needed (a KeyGenParameterSpec cannot be
+                // constructed).
+                if (namedSpec.getName().equalsIgnoreCase(NamedParameterSpec.X25519.getName())
+                        || namedSpec.getName().equalsIgnoreCase(
+                        NamedParameterSpec.ED25519.getName())) {
+                    throw new IllegalArgumentException(
+                            "This KeyPairGenerator cannot be initialized using NamedParameterSpec."
+                                    + " use " + KeyGenParameterSpec.class.getName() + " or "
+                                    + KeyPairGeneratorSpec.class.getName());
+                } else {
+                    throw new InvalidAlgorithmParameterException(
+                            "Unsupported algorithm specified via NamedParameterSpec: "
+                            + namedSpec.getName());
+                }
             } else {
                 throw new InvalidAlgorithmParameterException(
                         "Unsupported params class: " + params.getClass().getName()
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index e5d1276..d31499e 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -83,10 +83,12 @@
         // java.security.KeyPairGenerator
         put("KeyPairGenerator.EC", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$EC");
         put("KeyPairGenerator.RSA", PACKAGE_NAME +  ".AndroidKeyStoreKeyPairGeneratorSpi$RSA");
+        put("KeyPairGenerator.XDH", PACKAGE_NAME +  ".AndroidKeyStoreKeyPairGeneratorSpi$XDH");
 
         // java.security.KeyFactory
         putKeyFactoryImpl("EC");
         putKeyFactoryImpl("RSA");
+        putKeyFactoryImpl("XDH");
 
         // javax.crypto.KeyGenerator
         put("KeyGenerator.AES", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$AES");
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java b/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java
index 1c49881..921552b 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java
@@ -236,7 +236,8 @@
     }
 
     private static void assertValidState(@Nullable Integer state) {
-        if (state != null && state != COMMON_STATE_FLAT && state != COMMON_STATE_HALF_OPENED) {
+        if (state != null && state != COMMON_STATE_FLAT
+                && state != COMMON_STATE_HALF_OPENED && state != COMMON_STATE_UNKNOWN) {
             throw new IllegalArgumentException("Invalid state: " + state
                     + "must be either COMMON_STATE_FLAT or COMMON_STATE_HALF_OPENED");
         }
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/SettingsDisplayFeatureProducer.java b/libs/WindowManager/Jetpack/src/androidx/window/common/SettingsDisplayFeatureProducer.java
index e9d213e..0e696eb 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/common/SettingsDisplayFeatureProducer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/common/SettingsDisplayFeatureProducer.java
@@ -16,6 +16,8 @@
 
 package androidx.window.common;
 
+import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_FLAT;
+import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_HALF_OPENED;
 import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_UNKNOWN;
 import static androidx.window.common.CommonFoldingFeature.parseListFromString;
 
@@ -42,7 +44,10 @@
 public final class SettingsDisplayFeatureProducer
         extends BaseDataProducer<List<CommonFoldingFeature>> {
     private static final String DISPLAY_FEATURES = "display_features";
+    private static final String DEVICE_POSTURE = "device_posture";
 
+    private final Uri mDevicePostureUri =
+            Settings.Global.getUriFor(DEVICE_POSTURE);
     private final Uri mDisplayFeaturesUri =
             Settings.Global.getUriFor(DISPLAY_FEATURES);
 
@@ -55,6 +60,15 @@
         mObserver = new SettingsObserver();
     }
 
+    private int getPosture() {
+        int posture = Settings.Global.getInt(mResolver, DEVICE_POSTURE, COMMON_STATE_UNKNOWN);
+        if (posture == COMMON_STATE_HALF_OPENED || posture == COMMON_STATE_FLAT) {
+            return posture;
+        } else {
+            return COMMON_STATE_UNKNOWN;
+        }
+    }
+
     @Override
     @NonNull
     public Optional<List<CommonFoldingFeature>> getData() {
@@ -66,7 +80,7 @@
         if (TextUtils.isEmpty(displayFeaturesString)) {
             return Optional.of(Collections.emptyList());
         }
-        return Optional.of(parseListFromString(displayFeaturesString, COMMON_STATE_UNKNOWN));
+        return Optional.of(parseListFromString(displayFeaturesString, getPosture()));
     }
 
     /**
@@ -80,6 +94,7 @@
         mRegisteredObservers = true;
         mResolver.registerContentObserver(mDisplayFeaturesUri, false /* notifyForDescendants */,
                 mObserver /* ContentObserver */);
+        mResolver.registerContentObserver(mDevicePostureUri, false, mObserver);
     }
 
     /**
@@ -101,7 +116,7 @@
 
         @Override
         public void onChange(boolean selfChange, Uri uri) {
-            if (mDisplayFeaturesUri.equals(uri)) {
+            if (mDisplayFeaturesUri.equals(uri) || mDevicePostureUri.equals(uri)) {
                 notifyDataChanged();
             }
         }
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 1d2b938..418ff0e 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -37,6 +37,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
+import android.util.SparseArray;
 import android.window.TaskFragmentInfo;
 import android.window.WindowContainerTransaction;
 
@@ -58,14 +59,20 @@
 
     // Currently applied split configuration.
     private final List<EmbeddingRule> mSplitRules = new ArrayList<>();
-    private final List<TaskFragmentContainer> mContainers = new ArrayList<>();
-    private final List<SplitContainer> mSplitContainers = new ArrayList<>();
+    /**
+     * Map from Task id to {@link TaskContainer} which contains all TaskFragment and split pair info
+     * below it.
+     * When the app is host of multiple Tasks, there can be multiple splits controlled by the same
+     * organizer.
+     */
+    private final SparseArray<TaskContainer> mTaskContainers = new SparseArray<>();
 
     // Callback to Jetpack to notify about changes to split states.
     private @NonNull Consumer<List<SplitInfo>> mEmbeddingCallback;
     private final List<SplitInfo> mLastReportedSplitStates = new ArrayList<>();
 
     // We currently only support split activity embedding within the one root Task.
+    // TODO(b/207720388): move to TaskContainer
     private final Rect mParentBounds = new Rect();
 
     public SplitController() {
@@ -244,7 +251,8 @@
                 mPresenter.expandTaskFragment(currentContainer.getTaskFragmentToken());
             } else {
                 // Put activity into a new expanded container
-                final TaskFragmentContainer newContainer = newContainer(launchedActivity);
+                final TaskFragmentContainer newContainer = newContainer(launchedActivity,
+                        launchedActivity.getTaskId());
                 mPresenter.expandActivity(newContainer.getTaskFragmentToken(),
                         launchedActivity);
             }
@@ -327,12 +335,14 @@
      */
     @Nullable
     TaskFragmentContainer getContainerWithActivity(@NonNull IBinder activityToken) {
-        for (TaskFragmentContainer container : mContainers) {
-            if (container.hasActivity(activityToken)) {
-                return container;
+        for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
+            final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i).mContainers;
+            for (TaskFragmentContainer container : containers) {
+                if (container.hasActivity(activityToken)) {
+                    return container;
+                }
             }
         }
-
         return null;
     }
 
@@ -340,9 +350,12 @@
      * Creates and registers a new organized container with an optional activity that will be
      * re-parented to it in a WCT.
      */
-    TaskFragmentContainer newContainer(@Nullable Activity activity) {
-        TaskFragmentContainer container = new TaskFragmentContainer(activity);
-        mContainers.add(container);
+    TaskFragmentContainer newContainer(@Nullable Activity activity, int taskId) {
+        final TaskFragmentContainer container = new TaskFragmentContainer(activity, taskId);
+        if (!mTaskContainers.contains(taskId)) {
+            mTaskContainers.put(taskId, new TaskContainer());
+        }
+        mTaskContainers.get(taskId).mContainers.add(container);
         return container;
     }
 
@@ -354,13 +367,13 @@
             @NonNull TaskFragmentContainer primaryContainer, @NonNull Activity primaryActivity,
             @NonNull TaskFragmentContainer secondaryContainer,
             @NonNull SplitRule splitRule) {
-        SplitContainer splitContainer = new SplitContainer(primaryContainer, primaryActivity,
+        final SplitContainer splitContainer = new SplitContainer(primaryContainer, primaryActivity,
                 secondaryContainer, splitRule);
         // Remove container later to prevent pinning escaping toast showing in lock task mode.
         if (splitRule instanceof SplitPairRule && ((SplitPairRule) splitRule).shouldClearTop()) {
             removeExistingSecondaryContainers(wct, primaryContainer);
         }
-        mSplitContainers.add(splitContainer);
+        mTaskContainers.get(primaryContainer.getTaskId()).mSplitContainers.add(splitContainer);
     }
 
     /**
@@ -368,15 +381,26 @@
      */
     void removeContainer(@NonNull TaskFragmentContainer container) {
         // Remove all split containers that included this one
-        mContainers.remove(container);
-        List<SplitContainer> containersToRemove = new ArrayList<>();
-        for (SplitContainer splitContainer : mSplitContainers) {
+        final int taskId = container.getTaskId();
+        final TaskContainer taskContainer = mTaskContainers.get(taskId);
+        if (taskContainer == null) {
+            return;
+        }
+        taskContainer.mContainers.remove(container);
+        if (taskContainer.mContainers.isEmpty()) {
+            mTaskContainers.remove(taskId);
+            // No more TaskFragment in this Task, so no need to check split container.
+            return;
+        }
+
+        final List<SplitContainer> containersToRemove = new ArrayList<>();
+        for (SplitContainer splitContainer : taskContainer.mSplitContainers) {
             if (container.equals(splitContainer.getSecondaryContainer())
                     || container.equals(splitContainer.getPrimaryContainer())) {
                 containersToRemove.add(splitContainer);
             }
         }
-        mSplitContainers.removeAll(containersToRemove);
+        taskContainer.mSplitContainers.removeAll(containersToRemove);
     }
 
     /**
@@ -399,12 +423,16 @@
     }
 
     /**
-     * Returns the topmost not finished container.
+     * Returns the topmost not finished container in Task of given task id.
      */
     @Nullable
-    TaskFragmentContainer getTopActiveContainer() {
-        for (int i = mContainers.size() - 1; i >= 0; i--) {
-            TaskFragmentContainer container = mContainers.get(i);
+    TaskFragmentContainer getTopActiveContainer(int taskId) {
+        final TaskContainer taskContainer = mTaskContainers.get(taskId);
+        if (taskContainer == null) {
+            return null;
+        }
+        for (int i = taskContainer.mContainers.size() - 1; i >= 0; i--) {
+            final TaskFragmentContainer container = taskContainer.mContainers.get(i);
             if (!container.isFinished() && container.getRunningActivityCount() > 0) {
                 return container;
             }
@@ -434,7 +462,10 @@
         if (splitContainer == null) {
             return;
         }
-        if (splitContainer != mSplitContainers.get(mSplitContainers.size() - 1)) {
+        final List<SplitContainer> splitContainers = mTaskContainers.get(container.getTaskId())
+                .mSplitContainers;
+        if (splitContainers == null
+                || splitContainer != splitContainers.get(splitContainers.size() - 1)) {
             // Skip position update - it isn't the topmost split.
             return;
         }
@@ -455,8 +486,13 @@
      */
     @Nullable
     private SplitContainer getActiveSplitForContainer(@NonNull TaskFragmentContainer container) {
-        for (int i = mSplitContainers.size() - 1; i >= 0; i--) {
-            SplitContainer splitContainer = mSplitContainers.get(i);
+        final List<SplitContainer> splitContainers = mTaskContainers.get(container.getTaskId())
+                .mSplitContainers;
+        if (splitContainers == null) {
+            return null;
+        }
+        for (int i = splitContainers.size() - 1; i >= 0; i--) {
+            final SplitContainer splitContainer = splitContainers.get(i);
             if (container.equals(splitContainer.getSecondaryContainer())
                     || container.equals(splitContainer.getPrimaryContainer())) {
                 return splitContainer;
@@ -473,8 +509,13 @@
     private SplitContainer getActiveSplitForContainers(
             @NonNull TaskFragmentContainer firstContainer,
             @NonNull TaskFragmentContainer secondContainer) {
-        for (int i = mSplitContainers.size() - 1; i >= 0; i--) {
-            SplitContainer splitContainer = mSplitContainers.get(i);
+        final List<SplitContainer> splitContainers = mTaskContainers.get(firstContainer.getTaskId())
+                .mSplitContainers;
+        if (splitContainers == null) {
+            return null;
+        }
+        for (int i = splitContainers.size() - 1; i >= 0; i--) {
+            final SplitContainer splitContainer = splitContainers.get(i);
             final TaskFragmentContainer primary = splitContainer.getPrimaryContainer();
             final TaskFragmentContainer secondary = splitContainer.getSecondaryContainer();
             if ((firstContainer == secondary && secondContainer == primary)
@@ -501,7 +542,7 @@
         final  TaskFragmentContainer container = getContainerWithActivity(
                 activity.getActivityToken());
         // Don't launch placeholder if the container is occluded.
-        if (container != getTopActiveContainer()) {
+        if (container != null && container != getTopActiveContainer(container.getTaskId())) {
             return false;
         }
 
@@ -588,24 +629,30 @@
     @Nullable
     private List<SplitInfo> getActiveSplitStates() {
         List<SplitInfo> splitStates = new ArrayList<>();
-        for (SplitContainer container : mSplitContainers) {
-            if (container.getPrimaryContainer().isEmpty()
-                    || container.getSecondaryContainer().isEmpty()) {
-                // We are in an intermediate state because either the split container is about to be
-                // removed or the primary or secondary container are about to receive an activity.
-                return null;
+        for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
+            final List<SplitContainer> splitContainers = mTaskContainers.valueAt(i)
+                    .mSplitContainers;
+            for (SplitContainer container : splitContainers) {
+                if (container.getPrimaryContainer().isEmpty()
+                        || container.getSecondaryContainer().isEmpty()) {
+                    // We are in an intermediate state because either the split container is about
+                    // to be removed or the primary or secondary container are about to receive an
+                    // activity.
+                    return null;
+                }
+                final ActivityStack primaryContainer = container.getPrimaryContainer()
+                        .toActivityStack();
+                final ActivityStack secondaryContainer = container.getSecondaryContainer()
+                        .toActivityStack();
+                final SplitInfo splitState = new SplitInfo(primaryContainer, secondaryContainer,
+                        // Splits that are not showing side-by-side are reported as having 0 split
+                        // ratio, since by definition in the API the primary container occupies no
+                        // width of the split when covered by the secondary.
+                        mPresenter.shouldShowSideBySide(container)
+                                ? container.getSplitRule().getSplitRatio()
+                                : 0.0f);
+                splitStates.add(splitState);
             }
-            ActivityStack primaryContainer = container.getPrimaryContainer().toActivityStack();
-            ActivityStack secondaryContainer = container.getSecondaryContainer().toActivityStack();
-            SplitInfo splitState = new SplitInfo(primaryContainer,
-                    secondaryContainer,
-                    // Splits that are not showing side-by-side are reported as having 0 split
-                    // ratio, since by definition in the API the primary container occupies no
-                    // width of the split when covered by the secondary.
-                    mPresenter.shouldShowSideBySide(container)
-                            ? container.getSplitRule().getSplitRatio()
-                            : 0.0f);
-            splitStates.add(splitState);
         }
         return splitStates;
     }
@@ -615,11 +662,14 @@
      * the client.
      */
     private boolean allActivitiesCreated() {
-        for (TaskFragmentContainer container : mContainers) {
-            if (container.getInfo() == null
-                    || container.getInfo().getActivities().size()
-                    != container.collectActivities().size()) {
-                return false;
+        for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
+            final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i).mContainers;
+            for (TaskFragmentContainer container : containers) {
+                if (container.getInfo() == null
+                        || container.getInfo().getActivities().size()
+                        != container.collectActivities().size()) {
+                    return false;
+                }
             }
         }
         return true;
@@ -633,7 +683,12 @@
         if (container == null) {
             return false;
         }
-        for (SplitContainer splitContainer : mSplitContainers) {
+        final List<SplitContainer> splitContainers = mTaskContainers.get(container.getTaskId())
+                .mSplitContainers;
+        if (splitContainers == null) {
+            return true;
+        }
+        for (SplitContainer splitContainer : splitContainers) {
             if (container.equals(splitContainer.getPrimaryContainer())
                     || container.equals(splitContainer.getSecondaryContainer())) {
                 return false;
@@ -684,9 +739,12 @@
 
     @Nullable
     TaskFragmentContainer getContainer(@NonNull IBinder fragmentToken) {
-        for (TaskFragmentContainer container : mContainers) {
-            if (container.getTaskFragmentToken().equals(fragmentToken)) {
-                return container;
+        for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
+            final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i).mContainers;
+            for (TaskFragmentContainer container : containers) {
+                if (container.getTaskFragmentToken().equals(fragmentToken)) {
+                    return container;
+                }
             }
         }
         return null;
@@ -969,4 +1027,10 @@
         // Not reuse if it needs to destroy the existing.
         return !pairRule.shouldClearTop();
     }
+
+    /** Represents TaskFragments and split pairs below a Task. */
+    private static class TaskContainer {
+        final List<TaskFragmentContainer> mContainers = new ArrayList<>();
+        final List<SplitContainer> mSplitContainers = new ArrayList<>();
+    }
 }
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index ade5731..e7552ff 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -80,7 +80,8 @@
 
         container.finish(shouldFinishDependent, this, wct, mController);
 
-        final TaskFragmentContainer newTopContainer = mController.getTopActiveContainer();
+        final TaskFragmentContainer newTopContainer = mController.getTopActiveContainer(
+                container.getTaskId());
         if (newTopContainer != null) {
             mController.updateContainer(wct, newTopContainer);
         }
@@ -103,7 +104,8 @@
                 primaryActivity, primaryRectBounds, null);
 
         // Create new empty task fragment
-        final TaskFragmentContainer secondaryContainer = mController.newContainer(null);
+        final TaskFragmentContainer secondaryContainer = mController.newContainer(null,
+                primaryContainer.getTaskId());
         final Rect secondaryRectBounds = getBoundsForPosition(POSITION_END, parentBounds,
                 rule, isLtr(primaryActivity, rule));
         createTaskFragment(wct, secondaryContainer.getTaskFragmentToken(),
@@ -159,7 +161,8 @@
      * Creates a new expanded container.
      */
     TaskFragmentContainer createNewExpandedContainer(@NonNull Activity launchingActivity) {
-        final TaskFragmentContainer newContainer = mController.newContainer(null);
+        final TaskFragmentContainer newContainer = mController.newContainer(null,
+                launchingActivity.getTaskId());
 
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         createTaskFragment(wct, newContainer.getTaskFragmentToken(),
@@ -180,7 +183,7 @@
         TaskFragmentContainer container = mController.getContainerWithActivity(
                 activity.getActivityToken());
         if (container == null || container == containerToAvoid) {
-            container = mController.newContainer(activity);
+            container = mController.newContainer(activity, activity.getTaskId());
 
             final TaskFragmentCreationParams fragmentOptions =
                     createFragmentOptions(
@@ -222,10 +225,12 @@
         TaskFragmentContainer primaryContainer = mController.getContainerWithActivity(
                 launchingActivity.getActivityToken());
         if (primaryContainer == null) {
-            primaryContainer = mController.newContainer(launchingActivity);
+            primaryContainer = mController.newContainer(launchingActivity,
+                    launchingActivity.getTaskId());
         }
 
-        TaskFragmentContainer secondaryContainer = mController.newContainer(null);
+        TaskFragmentContainer secondaryContainer = mController.newContainer(null,
+                primaryContainer.getTaskId());
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         mController.registerSplit(wct, primaryContainer, launchingActivity, secondaryContainer,
                 rule);
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
index 89d7a40..b3becad 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
@@ -33,6 +33,12 @@
  * The base adapter can be used for {@link RemoteAnimationTarget} that is simple open/close.
  */
 class TaskFragmentAnimationAdapter {
+
+    /**
+     * If {@link #mOverrideLayer} is set to this value, we don't want to override the surface layer.
+     */
+    private static final int LAYER_NO_OVERRIDE = -1;
+
     final Animation mAnimation;
     final RemoteAnimationTarget mTarget;
     final SurfaceControl mLeash;
@@ -42,6 +48,7 @@
     final float[] mVecs = new float[4];
     final Rect mRect = new Rect();
     private boolean mIsFirstFrame = true;
+    private int mOverrideLayer = LAYER_NO_OVERRIDE;
 
     TaskFragmentAnimationAdapter(@NonNull Animation animation,
             @NonNull RemoteAnimationTarget target) {
@@ -58,10 +65,21 @@
         mLeash = leash;
     }
 
+    /**
+     * Surface layer to be set at the first frame of the animation. We will not set the layer if it
+     * is set to {@link #LAYER_NO_OVERRIDE}.
+     */
+    final void overrideLayer(int layer) {
+        mOverrideLayer = layer;
+    }
+
     /** Called on frame update. */
     final void onAnimationUpdate(@NonNull SurfaceControl.Transaction t, long currentPlayTime) {
         if (mIsFirstFrame) {
             t.show(mLeash);
+            if (mOverrideLayer != LAYER_NO_OVERRIDE) {
+                t.setLayer(mLeash, mOverrideLayer);
+            }
             mIsFirstFrame = false;
         }
 
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
index 46bdf6d..1ac3317 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
@@ -25,6 +25,7 @@
 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
+import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
 
 import android.animation.Animator;
 import android.animation.ValueAnimator;
@@ -181,18 +182,22 @@
 
     private List<TaskFragmentAnimationAdapter> createOpenAnimationAdapters(
             @NonNull RemoteAnimationTarget[] targets) {
-        return createOpenCloseAnimationAdapters(targets,
+        return createOpenCloseAnimationAdapters(targets, true /* isOpening */,
                 mAnimationSpec::loadOpenAnimation);
     }
 
     private List<TaskFragmentAnimationAdapter> createCloseAnimationAdapters(
             @NonNull RemoteAnimationTarget[] targets) {
-        return createOpenCloseAnimationAdapters(targets,
+        return createOpenCloseAnimationAdapters(targets, false /* isOpening */,
                 mAnimationSpec::loadCloseAnimation);
     }
 
+    /**
+     * Creates {@link TaskFragmentAnimationAdapter} for OPEN and CLOSE types of transition.
+     * @param isOpening {@code true} for OPEN type, {@code false} for CLOSE type.
+     */
     private List<TaskFragmentAnimationAdapter> createOpenCloseAnimationAdapters(
-            @NonNull RemoteAnimationTarget[] targets,
+            @NonNull RemoteAnimationTarget[] targets, boolean isOpening,
             @NonNull BiFunction<RemoteAnimationTarget, Rect, Animation> animationProvider) {
         // We need to know if the target window is only a partial of the whole animation screen.
         // If so, we will need to adjust it to make the whole animation screen looks like one.
@@ -210,14 +215,25 @@
             }
         }
 
+        // For OPEN transition, open windows should be above close windows.
+        // For CLOSE transition, open windows should be below close windows.
+        int offsetLayer = TYPE_LAYER_OFFSET;
         final List<TaskFragmentAnimationAdapter> adapters = new ArrayList<>();
         for (RemoteAnimationTarget target : openingTargets) {
-            adapters.add(createOpenCloseAnimationAdapter(target, animationProvider,
-                    openingWholeScreenBounds));
+            final TaskFragmentAnimationAdapter adapter = createOpenCloseAnimationAdapter(target,
+                    animationProvider, openingWholeScreenBounds);
+            if (isOpening) {
+                adapter.overrideLayer(offsetLayer++);
+            }
+            adapters.add(adapter);
         }
         for (RemoteAnimationTarget target : closingTargets) {
-            adapters.add(createOpenCloseAnimationAdapter(target, animationProvider,
-                    closingWholeScreenBounds));
+            final TaskFragmentAnimationAdapter adapter = createOpenCloseAnimationAdapter(target,
+                    animationProvider, closingWholeScreenBounds);
+            if (!isOpening) {
+                adapter.overrideLayer(offsetLayer++);
+            }
+            adapters.add(adapter);
         }
         return adapters;
     }
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index 4d2d055..e49af41 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -16,6 +16,8 @@
 
 package androidx.window.extensions.embedding;
 
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Activity;
@@ -41,6 +43,9 @@
     @NonNull
     private final IBinder mToken;
 
+    /** Parent leaf Task id. */
+    private final int mTaskId;
+
     /**
      * Server-provided task fragment information.
      */
@@ -71,8 +76,12 @@
      * Creates a container with an existing activity that will be re-parented to it in a window
      * container transaction.
      */
-    TaskFragmentContainer(@Nullable Activity activity) {
+    TaskFragmentContainer(@Nullable Activity activity, int taskId) {
         mToken = new Binder("TaskFragmentContainer");
+        if (taskId == INVALID_TASK_ID) {
+            throw new IllegalArgumentException("Invalid Task id");
+        }
+        mTaskId = taskId;
         if (activity != null) {
             addPendingAppearedActivity(activity);
         }
@@ -275,6 +284,11 @@
         }
     }
 
+    /** Gets the parent leaf Task id. */
+    int getTaskId() {
+        return mTaskId;
+    }
+
     @Override
     public String toString() {
         return toString(true /* includeContainersToFinishOnExit */);
diff --git a/libs/WindowManager/Jetpack/tests/OWNERS b/libs/WindowManager/Jetpack/tests/OWNERS
new file mode 100644
index 0000000..f2c3388
--- /dev/null
+++ b/libs/WindowManager/Jetpack/tests/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 909476
+# includes OWNERS from parent directories
+charlesccchen@google.com
+diegovela@google.com
diff --git a/libs/WindowManager/Jetpack/tests/unittest/Android.bp b/libs/WindowManager/Jetpack/tests/unittest/Android.bp
new file mode 100644
index 0000000..62e8128
--- /dev/null
+++ b/libs/WindowManager/Jetpack/tests/unittest/Android.bp
@@ -0,0 +1,52 @@
+// 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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+    name: "WMJetpackUnitTests",
+
+    srcs: [
+        "**/*.java",
+    ],
+
+    static_libs: [
+        "androidx.window.extensions",
+        "junit",
+        "androidx.test.runner",
+        "androidx.test.rules",
+        "androidx.test.ext.junit",
+        "mockito-target-extended-minus-junit4",
+        "truth-prebuilt",
+        "testables",
+        "platform-test-annotations",
+    ],
+
+    libs: [
+        "android.test.mock",
+        "android.test.base",
+        "android.test.runner",
+    ],
+
+    optimize: {
+        enabled: false,
+    },
+}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/AndroidManifest.xml b/libs/WindowManager/Jetpack/tests/unittest/AndroidManifest.xml
new file mode 100644
index 0000000..b12b6f6
--- /dev/null
+++ b/libs/WindowManager/Jetpack/tests/unittest/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="androidx.window.tests">
+
+    <application android:debuggable="true" android:largeHeap="true">
+        <uses-library android:name="android.test.mock" />
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:label="Tests for WindowManager Jetpack library"
+        android:targetPackage="androidx.window.tests">
+    </instrumentation>
+</manifest>
diff --git a/libs/WindowManager/Jetpack/tests/unittest/AndroidTest.xml b/libs/WindowManager/Jetpack/tests/unittest/AndroidTest.xml
new file mode 100644
index 0000000..56d8c33
--- /dev/null
+++ b/libs/WindowManager/Jetpack/tests/unittest/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs Tests for WindowManager Jetpack library">
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="install-arg" value="-t" />
+        <option name="test-file-name" value="WMJetpackUnitTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="framework-base-presubmit" />
+    <option name="test-tag" value="WMJetpackUnitTests" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="androidx.window.tests" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+</configuration>
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java
new file mode 100644
index 0000000..b6df876
--- /dev/null
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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 androidx.window.extensions;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class WindowExtensionsTest {
+    private WindowExtensions mExtensions;
+
+    @Before
+    public void setUp() {
+        mExtensions = WindowExtensionsProvider.getWindowExtensions();
+    }
+
+    @Test
+    public void testGetWindowLayoutComponent() {
+        assertThat(mExtensions.getWindowLayoutComponent()).isNotNull();
+    }
+
+    @Test
+    public void testGetActivityEmbeddingComponent() {
+        assertThat(mExtensions.getActivityEmbeddingComponent()).isNotNull();
+    }
+}
diff --git a/libs/WindowManager/OWNERS b/libs/WindowManager/OWNERS
index 2c61df9..780e4c1 100644
--- a/libs/WindowManager/OWNERS
+++ b/libs/WindowManager/OWNERS
@@ -1,3 +1,6 @@
 set noparent
 
 include /services/core/java/com/android/server/wm/OWNERS
+
+# Give submodule owners in shell resource approval
+per-file Shell/res*/*/*.xml = hwwang@google.com, lbill@google.com, madym@google.com
diff --git a/packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml b/libs/WindowManager/Shell/res/color/tv_pip_menu_close_icon.xml
similarity index 65%
copy from packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml
copy to libs/WindowManager/Shell/res/color/tv_pip_menu_close_icon.xml
index f9ec5d0..ce8640d 100644
--- a/packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml
+++ b/libs/WindowManager/Shell/res/color/tv_pip_menu_close_icon.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -13,10 +14,6 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-       android:shape="rectangle">
-    <solid android:color="@android:color/system_accent1_100"/>
-    <corners android:topLeftRadius="16dp" android:topRightRadius="16dp"
-             android:bottomLeftRadius="16dp" android:bottomRightRadius="16dp"/>
-</shape>
\ No newline at end of file
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@color/tv_pip_menu_icon_unfocused" />
+</selector>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml b/libs/WindowManager/Shell/res/color/tv_pip_menu_close_icon_bg.xml
similarity index 65%
copy from packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml
copy to libs/WindowManager/Shell/res/color/tv_pip_menu_close_icon_bg.xml
index f9ec5d0..6cbf66f 100644
--- a/packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml
+++ b/libs/WindowManager/Shell/res/color/tv_pip_menu_close_icon_bg.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -13,10 +14,8 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-       android:shape="rectangle">
-    <solid android:color="@android:color/system_accent1_100"/>
-    <corners android:topLeftRadius="16dp" android:topRightRadius="16dp"
-             android:bottomLeftRadius="16dp" android:bottomRightRadius="16dp"/>
-</shape>
\ No newline at end of file
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_focused="true"
+          android:color="@color/tv_pip_menu_close_icon_bg_focused" />
+    <item android:color="@color/tv_pip_menu_close_icon_bg_unfocused" />
+</selector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml b/libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml
index 87deb8b..5c8c84c 100644
--- a/libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml
@@ -21,8 +21,8 @@
     android:layout_width="wrap_content"
     android:paddingTop="48dp"
     android:paddingBottom="48dp"
-    android:paddingEnd="16dp"
-    android:layout_marginEnd="24dp"
+    android:paddingEnd="@dimen/bubble_user_education_padding_end"
+    android:layout_marginEnd="@dimen/bubble_user_education_margin_end"
     android:orientation="vertical"
     android:background="@drawable/bubble_stack_user_education_bg"
     >
diff --git a/libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml b/libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml
index fafe40e..b28f58f 100644
--- a/libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml
+++ b/libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml
@@ -23,8 +23,8 @@
     android:clickable="true"
     android:paddingTop="28dp"
     android:paddingBottom="16dp"
-    android:paddingEnd="48dp"
-    android:layout_marginEnd="24dp"
+    android:paddingEnd="@dimen/bubble_user_education_padding_end"
+    android:layout_marginEnd="@dimen/bubble_user_education_margin_end"
     android:orientation="vertical"
     android:background="@drawable/bubble_stack_user_education_bg"
     >
diff --git a/libs/WindowManager/Shell/res/values-af/strings_tv.xml b/libs/WindowManager/Shell/res/values-af/strings_tv.xml
index f552b81..c87bec0 100644
--- a/libs/WindowManager/Shell/res/values-af/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Skuif PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Vou PIP uit"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Vou PIP in"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Dubbeldruk "<annotation icon="home_icon">" TUIS "</annotation>" vir kontroles"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-am/strings_tv.xml b/libs/WindowManager/Shell/res/values-am/strings_tv.xml
index 6b6fe9f..d2335385 100644
--- a/libs/WindowManager/Shell/res/values-am/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"ፒአይፒ ውሰድ"</string>
     <string name="pip_expand" msgid="7605396312689038178">"ፒአይፒን ዘርጋ"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"ፒአይፒን ሰብስብ"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" ለመቆጣጠሪያዎች "<annotation icon="home_icon">"መነሻ"</annotation>"ን ሁለቴ ይጫኑ"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings_tv.xml b/libs/WindowManager/Shell/res/values-ar/strings_tv.xml
index a85d7b1..a1ceda5 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"‏نقل نافذة داخل النافذة (PIP)"</string>
     <string name="pip_expand" msgid="7605396312689038178">"‏توسيع نافذة داخل النافذة (PIP)"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"‏تصغير نافذة داخل النافذة (PIP)"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" انقر مرتين على "<annotation icon="home_icon">" الصفحة الرئيسية "</annotation>" للوصول لعناصر التحكم."</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-as/strings_tv.xml b/libs/WindowManager/Shell/res/values-as/strings_tv.xml
index 9e2f550..8d7bd9f 100644
--- a/libs/WindowManager/Shell/res/values-as/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"পিপ স্থানান্তৰ কৰক"</string>
     <string name="pip_expand" msgid="7605396312689038178">"পিপ বিস্তাৰ কৰক"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"পিপ সংকোচন কৰক"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" নিয়ন্ত্ৰণৰ বাবে "<annotation icon="home_icon">" গৃহপৃষ্ঠা "</annotation>" বুটামত দুবাৰ হেঁচক"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-az/strings_tv.xml b/libs/WindowManager/Shell/res/values-az/strings_tv.xml
index 670b02f..87c46fa 100644
--- a/libs/WindowManager/Shell/res/values-az/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"PIP tətbiq edin"</string>
     <string name="pip_expand" msgid="7605396312689038178">"PIP-ni genişləndirin"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"PIP-ni yığcamlaşdırın"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Nizamlayıcılar üçün "<annotation icon="home_icon">" ƏSAS SƏHİFƏ "</annotation>" süçimini iki dəfə basın"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings_tv.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings_tv.xml
index de23d71..c87f306 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Premesti sliku u slici"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Proširi sliku u slici"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Skupi sliku u slici"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Dvaput pritisnite "<annotation icon="home_icon">" HOME "</annotation>" za kontrole"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-be/strings_tv.xml b/libs/WindowManager/Shell/res/values-be/strings_tv.xml
index 03de88c..3566bc3 100644
--- a/libs/WindowManager/Shell/res/values-be/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Перамясціць PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Разгарнуць відарыс у відарысе"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Згарнуць відарыс у відарысе"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Двойчы націсніце "<annotation icon="home_icon">" ГАЛОЎНЫ ЭКРАН "</annotation>" для пераходу ў налады"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings_tv.xml b/libs/WindowManager/Shell/res/values-bg/strings_tv.xml
index 38e1ef8..91049fd 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"„Картина в картина“: Преместв."</string>
     <string name="pip_expand" msgid="7605396312689038178">"Разгъване на прозореца за PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Свиване на прозореца за PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" За достъп до контролите натиснете 2 пъти "<annotation icon="home_icon">"НАЧАЛО"</annotation></string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings_tv.xml b/libs/WindowManager/Shell/res/values-bn/strings_tv.xml
index 0b24328..792708d 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"PIP সরান"</string>
     <string name="pip_expand" msgid="7605396312689038178">"PIP বড় করুন"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"PIP আড়াল করুন"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" কন্ট্রোলের জন্য "<annotation icon="home_icon">" হোম "</annotation>" বোতামে ডবল প্রেস করুন"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings_tv.xml b/libs/WindowManager/Shell/res/values-bs/strings_tv.xml
index 63e23c2..b7f0dca 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Pokreni sliku u slici"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Proširi sliku u slici"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Suzi sliku u slici"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Dvaput pritisnite "<annotation icon="home_icon">" POČETNI EKRAN "</annotation>" za kontrole"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index 2ec1db4..8a522b3 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -27,7 +27,7 @@
     <string name="pip_play" msgid="3496151081459417097">"Reprodueix"</string>
     <string name="pip_pause" msgid="690688849510295232">"Posa en pausa"</string>
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Ves al següent"</string>
-    <string name="pip_skip_to_prev" msgid="7172158111196394092">"Torna a l\'anterior"</string>
+    <string name="pip_skip_to_prev" msgid="7172158111196394092">"Ves a l\'anterior"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Canvia la mida"</string>
     <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Amaga"</string>
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Deixa d\'amagar"</string>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings_tv.xml b/libs/WindowManager/Shell/res/values-ca/strings_tv.xml
index e35390a..1c560c7 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Mou pantalla en pantalla"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Desplega pantalla en pantalla"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Replega pantalla en pantalla"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Prem dos cops "<annotation icon="home_icon">" INICI "</annotation>" per accedir als controls"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings_tv.xml b/libs/WindowManager/Shell/res/values-cs/strings_tv.xml
index 9b38537..9a8cc2b 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Přesunout PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Rozbalit PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Sbalit PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Ovládací prvky zobrazíte dvojitým stisknutím "<annotation icon="home_icon">"tlačítka plochy"</annotation></string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-da/strings_tv.xml b/libs/WindowManager/Shell/res/values-da/strings_tv.xml
index 2f3b359..cba660a 100644
--- a/libs/WindowManager/Shell/res/values-da/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Flyt PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Udvid PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Skjul PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Tryk to gange på "<annotation icon="home_icon">" HJEM "</annotation>" for at se indstillinger"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-de/strings_tv.xml b/libs/WindowManager/Shell/res/values-de/strings_tv.xml
index 07fc28d..02a1b66 100644
--- a/libs/WindowManager/Shell/res/values-de/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"BiB verschieben"</string>
     <string name="pip_expand" msgid="7605396312689038178">"BiB maximieren"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"BiB minimieren"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Für Steuerelemente zweimal "<annotation icon="home_icon">"STARTBILDSCHIRMTASTE"</annotation>" drücken"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-el/strings_tv.xml b/libs/WindowManager/Shell/res/values-el/strings_tv.xml
index 1eba0b7..24cd030 100644
--- a/libs/WindowManager/Shell/res/values-el/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Μετακίνηση PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Ανάπτυξη PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Σύμπτυξη PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Πατήστε δύο φορές "<annotation icon="home_icon">" ΑΡΧΙΚΗ ΟΘΟΝΗ "</annotation>" για στοιχεία ελέγχου"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings_tv.xml
index 79a8b95..82257b4 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Move PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Expand PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Collapse PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Double-press "<annotation icon="home_icon">" HOME "</annotation>" for controls"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings_tv.xml
index 79a8b95..82257b4 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Move PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Expand PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Collapse PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Double-press "<annotation icon="home_icon">" HOME "</annotation>" for controls"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings_tv.xml
index 79a8b95..82257b4 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Move PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Expand PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Collapse PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Double-press "<annotation icon="home_icon">" HOME "</annotation>" for controls"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings_tv.xml
index 79a8b95..82257b4 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Move PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Expand PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Collapse PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Double-press "<annotation icon="home_icon">" HOME "</annotation>" for controls"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings_tv.xml
index 8925f18..a6e494c 100644
--- a/libs/WindowManager/Shell/res/values-en-rXC/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-en-rXC/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‏‏‎‏‏‏‎‎‎‏‏‎‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‎‏‏‎‎‎‏‎‎‏‏‎‏‏‎‎‏‏‎‏‎‎‏‎‏‏‏‏‎Move PIP‎‏‎‎‏‎"</string>
     <string name="pip_expand" msgid="7605396312689038178">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‏‎‏‏‏‏‎‎‏‎‏‏‏‎‏‎‎‏‏‎‏‎‏‏‏‎‎‏‏‏‏‎‎‏‎‏‎‏‎‏‎‎‏‏‎‏‏‎‎‎‏‎‎Expand PIP‎‏‎‎‏‎"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‎‎‏‎‎‎‎‏‎‎‏‎‏‏‎‏‏‎‏‏‏‏‎‎Collapse PIP‎‏‎‎‏‎"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‏‏‎‎‏‎‎‎‏‏‏‎‏‏‎‎‏‎‏‎‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‏‎‎‎‎‎‎‏‎‏‏‎‏‏‏‎‏‎ Double press ‎‏‎‎‏‏‎"<annotation icon="home_icon">"‎‏‎‎‏‏‏‎ HOME ‎‏‎‎‏‏‎"</annotation>"‎‏‎‎‏‏‏‎ for controls‎‏‎‎‏‎"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings_tv.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings_tv.xml
index 1b1a419..458f6b1 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Mover PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Maximizar PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Minimizar PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Presiona dos veces "<annotation icon="home_icon">"INICIO"</annotation>" para ver los controles"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-es/strings_tv.xml b/libs/WindowManager/Shell/res/values-es/strings_tv.xml
index 29ff1c6..0a69098 100644
--- a/libs/WindowManager/Shell/res/values-es/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Mover imagen en imagen"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Mostrar imagen en imagen"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Ocultar imagen en imagen"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Pulsa dos veces "<annotation icon="home_icon">"INICIO"</annotation>" para ver los controles"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-et/strings_tv.xml b/libs/WindowManager/Shell/res/values-et/strings_tv.xml
index f528bb2..dc02323 100644
--- a/libs/WindowManager/Shell/res/values-et/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Teisalda PIP-režiimi"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Laienda PIP-akent"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Ahenda PIP-aken"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Nuppude nägemiseks vajutage 2 korda nuppu "<annotation icon="home_icon">"AVAKUVA"</annotation></string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings_tv.xml b/libs/WindowManager/Shell/res/values-eu/strings_tv.xml
index 72f9980..bce06da 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Mugitu pantaila txiki gainjarria"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Zabaldu pantaila txiki gainjarria"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Tolestu pantaila txiki gainjarria"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Kontrolatzeko aukerak atzitzeko, sakatu birritan "<annotation icon="home_icon">" HASIERA "</annotation></string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings_tv.xml b/libs/WindowManager/Shell/res/values-fa/strings_tv.xml
index 5fa59be..ff9a03c 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"‏انتقال PIP (تصویر در تصویر)"</string>
     <string name="pip_expand" msgid="7605396312689038178">"گسترده کردن «تصویر در تصویر»"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"جمع کردن «تصویر در تصویر»"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" برای کنترل‌ها، دکمه "<annotation icon="home_icon">"صفحه اصلی"</annotation>" را دوبار فشار دهید"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings_tv.xml b/libs/WindowManager/Shell/res/values-fi/strings_tv.xml
index 217a85c..3e8bf90 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Siirrä PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Laajenna PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Tiivistä PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Asetukset: paina "<annotation icon="home_icon">"ALOITUSNÄYTTÖPAINIKETTA"</annotation>" kahdesti"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings_tv.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings_tv.xml
index b6f401f..66e13b8 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Déplacer l\'image incrustée"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Développer l\'image incrustée"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Réduire l\'image incrustée"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Appuyez deux fois sur "<annotation icon="home_icon">" ACCUEIL "</annotation>" pour les commandes"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings_tv.xml b/libs/WindowManager/Shell/res/values-fr/strings_tv.xml
index ffa4a22..ed9baf5b6 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Déplacer le PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Développer la fenêtre PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Réduire la fenêtre PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Menu de commandes : appuyez deux fois sur "<annotation icon="home_icon">"ACCUEIL"</annotation></string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings_tv.xml b/libs/WindowManager/Shell/res/values-gl/strings_tv.xml
index 3a7ed89..a057434 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Mover pantalla superposta"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Despregar pantalla superposta"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Contraer pantalla superposta"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Preme "<annotation icon="home_icon">"INICIO"</annotation>" dúas veces para acceder aos controis"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings_tv.xml b/libs/WindowManager/Shell/res/values-gu/strings_tv.xml
index 7a9bb25..d952591 100644
--- a/libs/WindowManager/Shell/res/values-gu/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-gu/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"PIP ખસેડો"</string>
     <string name="pip_expand" msgid="7605396312689038178">"PIP મોટી કરો"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"PIP નાની કરો"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" નિયંત્રણો માટે "<annotation icon="home_icon">" હોમ "</annotation>" બટન પર બે વાર દબાવો"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings_tv.xml b/libs/WindowManager/Shell/res/values-hi/strings_tv.xml
index 5776f81..d897ac7 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"पीआईपी को दूसरी जगह लेकर जाएं"</string>
     <string name="pip_expand" msgid="7605396312689038178">"पीआईपी विंडो को बड़ा करें"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"पीआईपी विंडो को छोटा करें"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" कंट्रोल मेन्यू पर जाने के लिए, "<annotation icon="home_icon">" होम बटन"</annotation>" दो बार दबाएं"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings_tv.xml b/libs/WindowManager/Shell/res/values-hr/strings_tv.xml
index e4d6944..8f5f316 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Premjesti PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Proširi PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Sažmi PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Dvaput pritisnite "<annotation icon="home_icon">"POČETNI ZASLON"</annotation>" za kontrole"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings_tv.xml b/libs/WindowManager/Shell/res/values-hu/strings_tv.xml
index 43beeea..fc8d795 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"PIP áthelyezése"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Kép a képben kibontása"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Kép a képben összecsukása"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Vezérlők: "<annotation icon="home_icon">" KEZDŐKÉPERNYŐ "</annotation>" gomb kétszer megnyomva"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings_tv.xml b/libs/WindowManager/Shell/res/values-hy/strings_tv.xml
index e439d5c..f5665b8 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Տեղափոխել PIP-ը"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Ծավալել PIP-ը"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Ծալել PIP-ը"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Կարգավորումների համար կրկնակի սեղմեք "<annotation icon="home_icon">"ԳԼԽԱՎՈՐ ԷԿՐԱՆ"</annotation></string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-in/strings_tv.xml b/libs/WindowManager/Shell/res/values-in/strings_tv.xml
index 25cb756..a153565 100644
--- a/libs/WindowManager/Shell/res/values-in/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Pindahkan PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Luaskan PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Ciutkan PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Tekan dua kali "<annotation icon="home_icon">" HOME "</annotation>" untuk membuka kontrol"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-is/strings_tv.xml b/libs/WindowManager/Shell/res/values-is/strings_tv.xml
index 56b9739..70ca1af 100644
--- a/libs/WindowManager/Shell/res/values-is/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Færa innfellda mynd"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Stækka innfellda mynd"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Minnka innfellda mynd"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Ýttu tvisvar á "<annotation icon="home_icon">" HEIM "</annotation>" til að opna stillingar"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-it/strings_tv.xml b/libs/WindowManager/Shell/res/values-it/strings_tv.xml
index 735c5cd..cda6275 100644
--- a/libs/WindowManager/Shell/res/values-it/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Sposta PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Espandi PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Comprimi PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Premi due volte "<annotation icon="home_icon">" HOME "</annotation>" per aprire i controlli"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings_tv.xml b/libs/WindowManager/Shell/res/values-iw/strings_tv.xml
index e4e0bf6..30ce97b 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"‏העברת תמונה בתוך תמונה (PIP)"</string>
     <string name="pip_expand" msgid="7605396312689038178">"הרחבת חלון תמונה-בתוך-תמונה"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"כיווץ של חלון תמונה-בתוך-תמונה"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" לחיצה כפולה על "<annotation icon="home_icon">" הלחצן הראשי "</annotation>" תציג את אמצעי הבקרה"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings_tv.xml b/libs/WindowManager/Shell/res/values-ja/strings_tv.xml
index c8326a6..e58e7bf6 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"PIP を移動"</string>
     <string name="pip_expand" msgid="7605396312689038178">"PIP を開く"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"PIP を閉じる"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" コントロールにアクセス: "<annotation icon="home_icon">" ホーム "</annotation>" を 2 回押します"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings_tv.xml b/libs/WindowManager/Shell/res/values-ka/strings_tv.xml
index 025e5a5..b096866 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"PIP გადატანა"</string>
     <string name="pip_expand" msgid="7605396312689038178">"PIP-ის გაშლა"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"PIP-ის ჩაკეცვა"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" მართვის საშუალებებზე წვდომისთვის ორმაგად დააჭირეთ "<annotation icon="home_icon">" მთავარ ღილაკს "</annotation></string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings_tv.xml b/libs/WindowManager/Shell/res/values-kk/strings_tv.xml
index 27afe2e..7bade0d 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"PIP клипін жылжыту"</string>
     <string name="pip_expand" msgid="7605396312689038178">"PIP терезесін жаю"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"PIP терезесін жию"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Басқару элементтері: "<annotation icon="home_icon">" НЕГІЗГІ ЭКРАН "</annotation>" түймесін екі рет басыңыз."</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-km/strings_tv.xml b/libs/WindowManager/Shell/res/values-km/strings_tv.xml
index 86bad27..721be1f 100644
--- a/libs/WindowManager/Shell/res/values-km/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"ផ្លាស់ទី PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"ពង្រីក PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"បង្រួម PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" ចុចពីរដងលើ"<annotation icon="home_icon">"ប៊ូតុងដើម"</annotation>" ដើម្បីបើកផ្ទាំងគ្រប់គ្រង"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings_tv.xml b/libs/WindowManager/Shell/res/values-kn/strings_tv.xml
index 3fbfdaa..8310c8a 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"PIP ಅನ್ನು ಸರಿಸಿ"</string>
     <string name="pip_expand" msgid="7605396312689038178">"ಚಿತ್ರದಲ್ಲಿ ಚಿತ್ರವನ್ನು ವಿಸ್ತರಿಸಿ"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"ಚಿತ್ರದಲ್ಲಿ ಚಿತ್ರವನ್ನು ಕುಗ್ಗಿಸಿ"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" ಕಂಟ್ರೋಲ್‌ಗಳಿಗಾಗಿ "<annotation icon="home_icon">" ಹೋಮ್ "</annotation>" ಅನ್ನು ಎರಡು ಬಾರಿ ಒತ್ತಿ"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings_tv.xml b/libs/WindowManager/Shell/res/values-ko/strings_tv.xml
index fa8c8980..a3e055a 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"PIP 이동"</string>
     <string name="pip_expand" msgid="7605396312689038178">"PIP 펼치기"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"PIP 접기"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" 제어 메뉴에 액세스하려면 "<annotation icon="home_icon">" 홈 "</annotation>"을 두 번 누르세요."</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings_tv.xml b/libs/WindowManager/Shell/res/values-ky/strings_tv.xml
index 6e2b810..887ac52 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"PIP\'ти жылдыруу"</string>
     <string name="pip_expand" msgid="7605396312689038178">"PIP\'ти жайып көрсөтүү"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"PIP\'ти жыйыштыруу"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Башкаруу элементтерин ачуу үчүн "<annotation icon="home_icon">" БАШКЫ БЕТ "</annotation>" баскычын эки жолу басыңыз"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-land/styles.xml b/libs/WindowManager/Shell/res/values-land/styles.xml
index 0ed9368..e89f65b 100644
--- a/libs/WindowManager/Shell/res/values-land/styles.xml
+++ b/libs/WindowManager/Shell/res/values-land/styles.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
     <style name="DockedDividerBackground">
-        <item name="android:layout_width">10dp</item>
+        <item name="android:layout_width">@dimen/split_divider_bar_width</item>
         <item name="android:layout_height">match_parent</item>
         <item name="android:layout_gravity">center_horizontal</item>
         <item name="android:background">@color/split_divider_background</item>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings_tv.xml b/libs/WindowManager/Shell/res/values-lo/strings_tv.xml
index 3d4505d..91c4a03 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"ຍ້າຍ PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"ຂະຫຍາຍ PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"ຫຍໍ້ PIP ລົງ"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" ກົດ "<annotation icon="home_icon">" HOME "</annotation>" ສອງເທື່ອສຳລັບການຄວບຄຸມ"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings_tv.xml b/libs/WindowManager/Shell/res/values-lt/strings_tv.xml
index f907055..04265ca 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Perkelti PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Iškleisti PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Sutraukti PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Jei reikia valdiklių, dukart paspauskite "<annotation icon="home_icon">"PAGRINDINIS"</annotation></string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings_tv.xml b/libs/WindowManager/Shell/res/values-lv/strings_tv.xml
index 04d9409..8c6191e 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Pārvietot attēlu attēlā"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Izvērst “Attēls attēlā” logu"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Sakļaut “Attēls attēlā” logu"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Atvērt vadīklas: divreiz nospiediet pogu "<annotation icon="home_icon">"SĀKUMS"</annotation></string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings_tv.xml b/libs/WindowManager/Shell/res/values-mk/strings_tv.xml
index e9ee1388..beef1fe 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Премести PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Прошири ја сликата во слика"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Собери ја сликата во слика"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Притиснете двапати на "<annotation icon="home_icon">" HOME "</annotation>" за контроли"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings_tv.xml b/libs/WindowManager/Shell/res/values-ml/strings_tv.xml
index 1ed6b6e..c2a532d 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"PIP നീക്കുക"</string>
     <string name="pip_expand" msgid="7605396312689038178">"PIP വികസിപ്പിക്കുക"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"PIP ചുരുക്കുക"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" നിയന്ത്രണങ്ങൾക്കായി "<annotation icon="home_icon">" ഹോം "</annotation>" രണ്ട് തവണ അമർത്തുക"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings_tv.xml b/libs/WindowManager/Shell/res/values-mn/strings_tv.xml
index d4a6942..bf8c59b 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"PIP-г зөөх"</string>
     <string name="pip_expand" msgid="7605396312689038178">"PIP-г дэлгэх"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"PIP-г хураах"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Хяналтад хандах бол "<annotation icon="home_icon">" HOME "</annotation>" дээр хоёр дарна уу"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings_tv.xml b/libs/WindowManager/Shell/res/values-mr/strings_tv.xml
index 940f983..5d519b7 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"PIP हलवा"</string>
     <string name="pip_expand" msgid="7605396312689038178">"PIP चा विस्तार करा"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"PIP कोलॅप्स करा"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" नियंत्रणांसाठी "<annotation icon="home_icon">" होम "</annotation>" दोनदा दाबा"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings_tv.xml b/libs/WindowManager/Shell/res/values-ms/strings_tv.xml
index f4b180c..08642c4 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Alihkan PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Kembangkan PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Kuncupkan PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Tekan dua kali "<annotation icon="home_icon">" LAMAN UTAMA "</annotation>" untuk mengakses kawalan"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-my/strings_tv.xml b/libs/WindowManager/Shell/res/values-my/strings_tv.xml
index 4b2a5ec..e01daee 100644
--- a/libs/WindowManager/Shell/res/values-my/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"PIP ရွှေ့ရန်"</string>
     <string name="pip_expand" msgid="7605396312689038178">"PIP ကို ချဲ့ရန်"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"PIP ကို လျှော့ပြပါ"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" ထိန်းချုပ်မှုအတွက် "<annotation icon="home_icon">" ပင်မခလုတ် "</annotation>" နှစ်ချက်နှိပ်ပါ"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings_tv.xml b/libs/WindowManager/Shell/res/values-nb/strings_tv.xml
index be74eeb..65ed0b7 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Flytt BIB"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Vis BIB"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Skjul BIB"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Dobbelttrykk på "<annotation icon="home_icon">"HJEM"</annotation>" for å åpne kontroller"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings_tv.xml b/libs/WindowManager/Shell/res/values-ne/strings_tv.xml
index a36cad6..d33fed6 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"PIP सार्नुहोस्"</string>
     <string name="pip_expand" msgid="7605396312689038178">"PIP विन्डो एक्स्पान्ड गर्नु…"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"PIP विन्डो कोल्याप्स गर्नुहोस्"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" कन्ट्रोल मेनु खोल्न "<annotation icon="home_icon">" होम "</annotation>" बटन दुई पटक थिच्नुहोस्"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings_tv.xml b/libs/WindowManager/Shell/res/values-nl/strings_tv.xml
index eb7ec60..9763c56 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"SIS verplaatsen"</string>
     <string name="pip_expand" msgid="7605396312689038178">"SIS uitvouwen"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"SIS samenvouwen"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Druk twee keer op "<annotation icon="home_icon">" HOME "</annotation>" voor bedieningselementen"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-or/strings_tv.xml b/libs/WindowManager/Shell/res/values-or/strings_tv.xml
index e48199f..e034485 100644
--- a/libs/WindowManager/Shell/res/values-or/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"PIPକୁ ମୁଭ କରନ୍ତୁ"</string>
     <string name="pip_expand" msgid="7605396312689038178">"PIPକୁ ବିସ୍ତାର କରନ୍ତୁ"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"PIPକୁ ସଙ୍କୁଚିତ କରନ୍ତୁ"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ପାଇଁ "<annotation icon="home_icon">" ହୋମ ବଟନ "</annotation>"କୁ ଦୁଇଥର ଦବାନ୍ତୁ"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings_tv.xml b/libs/WindowManager/Shell/res/values-pa/strings_tv.xml
index 891107e..9c01ac3 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"PIP ਨੂੰ ਲਿਜਾਓ"</string>
     <string name="pip_expand" msgid="7605396312689038178">"PIP ਦਾ ਵਿਸਤਾਰ ਕਰੋ"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"PIP ਨੂੰ ਸਮੇਟੋ"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" ਕੰਟਰੋਲਾਂ ਲਈ "<annotation icon="home_icon">" ਹੋਮ ਬਟਨ "</annotation>" ਨੂੰ ਦੋ ਵਾਰ ਦਬਾਓ"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings_tv.xml b/libs/WindowManager/Shell/res/values-pl/strings_tv.xml
index 7b5d08a..b922e2d 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Przenieś PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Rozwiń PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Zwiń PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Naciśnij dwukrotnie "<annotation icon="home_icon">"EKRAN GŁÓWNY"</annotation>", aby wyświetlić ustawienia"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings_tv.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings_tv.xml
index b669f16..cc4eb3c 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Mover picture-in-picture"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Abrir picture-in-picture"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Fechar picture-in-picture"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Pressione o botão "<annotation icon="home_icon">"home"</annotation>" duas vezes para acessar os controles"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings_tv.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings_tv.xml
index 6c1fa59..c4ae78d 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Mover Ecrã no ecrã"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Expandir Ecrã no ecrã"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Reduzir Ecrã no ecrã"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Prima duas vezes "<annotation icon="home_icon">" PÁGINA INICIAL "</annotation>" para controlos"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings_tv.xml b/libs/WindowManager/Shell/res/values-pt/strings_tv.xml
index b669f16..cc4eb3c 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Mover picture-in-picture"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Abrir picture-in-picture"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Fechar picture-in-picture"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Pressione o botão "<annotation icon="home_icon">"home"</annotation>" duas vezes para acessar os controles"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings_tv.xml b/libs/WindowManager/Shell/res/values-ro/strings_tv.xml
index 8ecf8c5..86a30f4 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Mutați fereastra PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Extindeți fereastra PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Restrângeți fereastra PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Apăsați de două ori "<annotation icon="home_icon">"butonul ecran de pornire"</annotation>" pentru comenzi"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings_tv.xml b/libs/WindowManager/Shell/res/values-ru/strings_tv.xml
index 19f7a00..08623e1 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Переместить PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Развернуть PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Свернуть PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Элементы управления: дважды нажмите "<annotation icon="home_icon">" кнопку главного экрана "</annotation></string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-si/strings_tv.xml b/libs/WindowManager/Shell/res/values-si/strings_tv.xml
index 7444369..fbb0ebb 100644
--- a/libs/WindowManager/Shell/res/values-si/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"PIP ගෙන යන්න"</string>
     <string name="pip_expand" msgid="7605396312689038178">"PIP දිග හරින්න"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"PIP හකුළන්න"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" පාලන සඳහා "<annotation icon="home_icon">" මුල් පිටුව "</annotation>" දෙවරක් ඔබන්න"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings_tv.xml b/libs/WindowManager/Shell/res/values-sk/strings_tv.xml
index 1a8edf1..81cb0ea 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Presunúť obraz v obraze"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Rozbaliť obraz v obraze"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Zbaliť obraz v obraze"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Ovládanie zobraz. dvoj. stlač. "<annotation icon="home_icon">" TLAČIDLA PLOCHY "</annotation></string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings_tv.xml b/libs/WindowManager/Shell/res/values-sl/strings_tv.xml
index c4c04c2..060aaa0 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Premakni sliko v sliki"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Razširi sliko v sliki"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Strni sliko v sliki"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Za kontrolnike dvakrat pritisnite gumb za "<annotation icon="home_icon">" ZAČETNI ZASLON "</annotation></string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings_tv.xml b/libs/WindowManager/Shell/res/values-sq/strings_tv.xml
index 2771b89..9bfdb6a 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Zhvendos PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Zgjero PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Palos PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Trokit dy herë "<annotation icon="home_icon">" KREU "</annotation>" për kontrollet"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings_tv.xml b/libs/WindowManager/Shell/res/values-sr/strings_tv.xml
index 3244030..6bc5c87 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Премести слику у слици"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Прошири слику у слици"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Скупи слику у слици"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Двапут притисните "<annotation icon="home_icon">" HOME "</annotation>" за контроле"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings_tv.xml b/libs/WindowManager/Shell/res/values-sv/strings_tv.xml
index 842c805..b3465ab 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Flytta BIB"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Utöka bild-i-bild"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Komprimera bild-i-bild"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Tryck snabbt två gånger på "<annotation icon="home_icon">" HEM "</annotation>" för kontroller"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings_tv.xml b/libs/WindowManager/Shell/res/values-sw/strings_tv.xml
index 8728fd9..baff49e 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Kuhamisha PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Panua PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Kunja PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Bonyeza mara mbili kitufe cha "<annotation icon="home_icon">" UKURASA WA KWANZA "</annotation>" kupata vidhibiti"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings_tv.xml b/libs/WindowManager/Shell/res/values-ta/strings_tv.xml
index e325b1a..4439e29 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"PIPபை நகர்த்து"</string>
     <string name="pip_expand" msgid="7605396312689038178">"PIPபை விரிவாக்கு"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"PIPபைச் சுருக்கு"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" கட்டுப்பாடுகள்: "<annotation icon="home_icon">" முகப்பு "</annotation>" பட்டனை இருமுறை அழுத்துக"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-te/strings_tv.xml b/libs/WindowManager/Shell/res/values-te/strings_tv.xml
index 1381e67..3557934 100644
--- a/libs/WindowManager/Shell/res/values-te/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"PIPను తరలించండి"</string>
     <string name="pip_expand" msgid="7605396312689038178">"PIPని విస్తరించండి"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"PIPని కుదించండి"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" కంట్రోల్స్ కోసం "<annotation icon="home_icon">" HOME "</annotation>" బటన్ రెండుసార్లు నొక్కండి"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-television/config.xml b/libs/WindowManager/Shell/res/values-television/config.xml
index dcb4c10..86ca655 100644
--- a/libs/WindowManager/Shell/res/values-television/config.xml
+++ b/libs/WindowManager/Shell/res/values-television/config.xml
@@ -39,4 +39,8 @@
 
     <!-- Duration (in milliseconds) the PiP stays stashed before automatically unstashing. -->
     <integer name="config_pipStashDuration">5000</integer>
+
+    <!-- Time (duration in milliseconds) that the shell waits for an app to close the PiP by itself
+    if a custom action is present before closing it. -->
+    <integer name="config_pipForceCloseDelay">5000</integer>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-th/strings_tv.xml b/libs/WindowManager/Shell/res/values-th/strings_tv.xml
index 6f00018..0a07d15 100644
--- a/libs/WindowManager/Shell/res/values-th/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"ย้าย PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"ขยาย PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"ยุบ PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" กดปุ่ม "<annotation icon="home_icon">" หน้าแรก "</annotation>" สองครั้งเพื่อเปิดการควบคุม"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings_tv.xml b/libs/WindowManager/Shell/res/values-tl/strings_tv.xml
index 868b278..9a11a38 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Ilipat ang PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"I-expand ang PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"I-collapse ang PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" I-double press ang "<annotation icon="home_icon">" HOME "</annotation>" para sa mga kontrol"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings_tv.xml b/libs/WindowManager/Shell/res/values-tr/strings_tv.xml
index 9ffad78..bf4bc6f 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"PIP\'yi taşı"</string>
     <string name="pip_expand" msgid="7605396312689038178">"PIP penceresini genişlet"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"PIP penceresini daralt"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Kontroller için "<annotation icon="home_icon">" ANA SAYFA "</annotation>"\'ya iki kez basın"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings_tv.xml b/libs/WindowManager/Shell/res/values-uk/strings_tv.xml
index 24c1698..7e9f54e 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Перемістити картинку в картинці"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Розгорнути картинку в картинці"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Згорнути картинку в картинці"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Відкрити елементи керування: двічі натисніть "<annotation icon="home_icon">"HOME"</annotation></string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings_tv.xml b/libs/WindowManager/Shell/res/values-ur/strings_tv.xml
index c05729a..c2ef69f 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"‏PIP کو منتقل کریں"</string>
     <string name="pip_expand" msgid="7605396312689038178">"‏PIP کو پھیلائیں"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"‏PIP کو سکیڑیں"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" کنٹرولز کے لیے "<annotation icon="home_icon">"ہوم "</annotation>" بٹن کو دو بار دبائیں"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings_tv.xml b/libs/WindowManager/Shell/res/values-uz/strings_tv.xml
index 43ab5ac..9ab95c8 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"PIPni siljitish"</string>
     <string name="pip_expand" msgid="7605396312689038178">"PIP funksiyasini yoyish"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"PIP funksiyasini yopish"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Boshqaruv uchun "<annotation icon="home_icon">"ASOSIY"</annotation>" tugmani ikki marta bosing"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings_tv.xml b/libs/WindowManager/Shell/res/values-vi/strings_tv.xml
index 368280c..146376d 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Di chuyển PIP (Ảnh trong ảnh)"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Mở rộng PIP (Ảnh trong ảnh)"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Thu gọn PIP (Ảnh trong ảnh)"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Nhấn đúp vào nút "<annotation icon="home_icon">" MÀN HÌNH CHÍNH "</annotation>" để mở trình đơn điều khiển"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings_tv.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings_tv.xml
index e5d879a..55407d2 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"移动画中画窗口"</string>
     <string name="pip_expand" msgid="7605396312689038178">"展开 PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"收起 PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" 按两次"<annotation icon="home_icon">"主屏幕"</annotation>"按钮可查看相关控件"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings_tv.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings_tv.xml
index 8ee5f11..15e278d 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"移動畫中畫"</string>
     <string name="pip_expand" msgid="7605396312689038178">"展開畫中畫"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"收合畫中畫"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" 按兩下"<annotation icon="home_icon">" 主畫面按鈕"</annotation>"即可顯示控制項"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings_tv.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings_tv.xml
index b23ecde..0b17b31 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"移動子母畫面"</string>
     <string name="pip_expand" msgid="7605396312689038178">"展開子母畫面"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"收合子母畫面"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" 按兩下"<annotation icon="home_icon">"主畫面按鈕"</annotation>"即可顯示控制選項"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings_tv.xml b/libs/WindowManager/Shell/res/values-zu/strings_tv.xml
index b14ee99..dad8c81 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings_tv.xml
@@ -24,4 +24,5 @@
     <string name="pip_move" msgid="1544227837964635439">"Hambisa i-PIP"</string>
     <string name="pip_expand" msgid="7605396312689038178">"Nweba i-PIP"</string>
     <string name="pip_collapse" msgid="5732233773786896094">"Goqa i-PIP"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" Chofoza kabili "<annotation icon="home_icon">" IKHAYA"</annotation>" mayelana nezilawuli"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values/colors_tv.xml b/libs/WindowManager/Shell/res/values/colors_tv.xml
index 08d3cef..64b146e 100644
--- a/libs/WindowManager/Shell/res/values/colors_tv.xml
+++ b/libs/WindowManager/Shell/res/values/colors_tv.xml
@@ -16,8 +16,10 @@
   -->
 <resources>
     <color name="tv_pip_menu_icon_focused">#0E0E0F</color>
-    <color name="tv_pip_menu_icon_unfocused">#E8EAED</color>
+    <color name="tv_pip_menu_icon_unfocused">#F8F9FA</color>
     <color name="tv_pip_menu_icon_disabled">#80868B</color>
+    <color name="tv_pip_menu_close_icon_bg_focused">#D93025</color>
+    <color name="tv_pip_menu_close_icon_bg_unfocused">#D69F261F</color>
     <color name="tv_pip_menu_icon_bg_focused">#E8EAED</color>
     <color name="tv_pip_menu_icon_bg_unfocused">#990E0E0F</color>
     <color name="tv_pip_menu_focus_border">#E8EAED</color>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index ad38975..59d03c7 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -205,8 +205,15 @@
     <dimen name="bubble_dismiss_target_padding_x">40dp</dimen>
     <dimen name="bubble_dismiss_target_padding_y">20dp</dimen>
     <dimen name="bubble_manage_menu_elevation">4dp</dimen>
-    <!-- Size of user education views on large screens (phone is just match parent). -->
-    <dimen name="bubbles_user_education_width_large_screen">400dp</dimen>
+    <!-- Size of manage user education views on large screens or in landscape. -->
+    <dimen name="bubbles_user_education_width">480dp</dimen>
+    <!-- Margin applied to the end of the user education views (really only matters for phone
+         since the width is match parent). -->
+    <dimen name="bubble_user_education_margin_end">24dp</dimen>
+    <!-- Padding applied to the end of the user education view. -->
+    <dimen name="bubble_user_education_padding_end">58dp</dimen>
+    <!-- Padding between the bubble and the user education text. -->
+    <dimen name="bubble_user_education_stack_padding">16dp</dimen>
 
     <!-- Bottom and end margin for compat buttons. -->
     <dimen name="compat_button_margin">16dp</dimen>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 8442994..31f0ef0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -165,8 +165,12 @@
     private StartingWindowController mStartingWindow;
 
     /**
-     * In charge of showing compat UI. Can be {@code null} if device doesn't support size
-     * compat.
+     * In charge of showing compat UI. Can be {@code null} if the device doesn't support size
+     * compat or if this isn't the main {@link ShellTaskOrganizer}.
+     *
+     * <p>NOTE: only the main {@link ShellTaskOrganizer} should have a {@link CompatUIController},
+     * and register itself as a {@link CompatUIController.CompatUICallback}. Subclasses should be
+     * initialized with a {@code null} {@link CompatUIController}.
      */
     @Nullable
     private final CompatUIController mCompatUI;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 8d5fdfb..08cb252 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -52,14 +52,17 @@
  */
 public class BackAnimationController implements RemoteCallable<BackAnimationController> {
 
-    private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability";
-    public static final boolean IS_ENABLED = SystemProperties
-            .getInt(BACK_PREDICTABILITY_PROP, 0) > 0;
     private static final String BACK_PREDICTABILITY_PROGRESS_THRESHOLD_PROP =
             "persist.debug.back_predictability_progress_threshold";
+    // By default, enable new back dispatching without any animations.
+    private static final int BACK_PREDICTABILITY_PROP =
+            SystemProperties.getInt("persist.debug.back_predictability", 1);
+    public static final boolean IS_ENABLED = BACK_PREDICTABILITY_PROP > 0;
     private static final int PROGRESS_THRESHOLD = SystemProperties
             .getInt(BACK_PREDICTABILITY_PROGRESS_THRESHOLD_PROP, -1);
     private static final String TAG = "BackAnimationController";
+    @VisibleForTesting
+    boolean mEnableAnimations = (BACK_PREDICTABILITY_PROP & (1 << 1)) != 0;
 
     /**
      * Location of the initial touch event of the back gesture.
@@ -255,7 +258,7 @@
                         backNavigationInfo.getTaskWindowConfiguration());
             }
             mTransaction.apply();
-        } else if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME) {
+        } else if (shouldDispatchToLauncher(backType)) {
             targetCallback = mBackToLauncherCallback;
         } else if (backType == BackNavigationInfo.TYPE_CALLBACK) {
             targetCallback = mBackNavigationInfo.getOnBackInvokedCallback();
@@ -309,7 +312,7 @@
 
         BackEvent backEvent = new BackEvent(0, 0, progress, swipeEdge, animationTarget);
         IOnBackInvokedCallback targetCallback = null;
-        if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME) {
+        if (shouldDispatchToLauncher(backType)) {
             targetCallback = mBackToLauncherCallback;
         } else if (backType == BackNavigationInfo.TYPE_CROSS_TASK
                 || backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY) {
@@ -330,8 +333,7 @@
             return;
         }
         int backType = mBackNavigationInfo.getType();
-        boolean shouldDispatchToLauncher = backType == BackNavigationInfo.TYPE_RETURN_TO_HOME
-                && mBackToLauncherCallback != null;
+        boolean shouldDispatchToLauncher = shouldDispatchToLauncher(backType);
         IOnBackInvokedCallback targetCallback = shouldDispatchToLauncher
                 ? mBackToLauncherCallback
                 : mBackNavigationInfo.getOnBackInvokedCallback();
@@ -356,6 +358,17 @@
         }
     }
 
+    private boolean shouldDispatchToLauncher(int backType) {
+        return backType == BackNavigationInfo.TYPE_RETURN_TO_HOME
+                && mBackToLauncherCallback != null
+                && mEnableAnimations;
+    }
+
+    @VisibleForTesting
+    void setEnableAnimations(boolean shouldEnable) {
+        mEnableAnimations = shouldEnable;
+    }
+
     private static void dispatchOnBackStarted(IOnBackInvokedCallback callback) {
         if (callback == null) {
             return;
@@ -468,7 +481,7 @@
             return;
         }
         RemoteAnimationTarget animationTarget = backNavigationInfo.getDepartingAnimationTarget();
-        if (animationTarget != null && mTriggerBack) {
+        if (animationTarget != null) {
             if (animationTarget.leash != null && animationTarget.leash.isValid()) {
                 mTransaction.remove(animationTarget.leash);
             }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index d0138a4..d2a1c55 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -383,23 +383,15 @@
         mTaskStackListener.addListener(new TaskStackListenerCallback() {
             @Override
             public void onTaskMovedToFront(int taskId) {
-                if (mSysuiProxy == null) {
-                    return;
-                }
-
-                mSysuiProxy.isNotificationShadeExpand((expand) -> {
-                    mMainExecutor.execute(() -> {
-                        int expandedId = INVALID_TASK_ID;
-                        if (mStackView != null && mStackView.getExpandedBubble() != null
-                                && isStackExpanded() && !mStackView.isExpansionAnimating()
-                                && !expand) {
-                            expandedId = mStackView.getExpandedBubble().getTaskId();
-                        }
-
-                        if (expandedId != INVALID_TASK_ID && expandedId != taskId) {
-                            mBubbleData.setExpanded(false);
-                        }
-                    });
+                mMainExecutor.execute(() -> {
+                    int expandedId = INVALID_TASK_ID;
+                    if (mStackView != null && mStackView.getExpandedBubble() != null
+                            && isStackExpanded() && !mStackView.isExpansionAnimating()) {
+                        expandedId = mStackView.getExpandedBubble().getTaskId();
+                    }
+                    if (expandedId != INVALID_TASK_ID && expandedId != taskId) {
+                        mBubbleData.setExpanded(false);
+                    }
                 });
             }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index da8308e..10ff2fb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -692,6 +692,7 @@
      * @param bubblePosition the x position of the bubble if showing on top, the y position of
      *                       the bubble if showing vertically.
      * @param onLeft whether the stack was on the left side of the screen when expanded.
+     * @param animate whether the pointer should animate to this position.
      */
     public void setPointerPosition(float bubblePosition, boolean onLeft, boolean animate) {
         // Pointer gets drawn in the padding
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index 8a120b9..97e5ee3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -579,11 +579,10 @@
 
         // Showing vertically: might need to translate the bubbles above the IME.
         // Subtract spacing here to provide a margin between top of IME and bottom of bubble row.
-        final float bottomInset = getImeHeight() + mInsets.bottom - (mSpacingBetweenBubbles * 2);
+        final float bottomHeight = getImeHeight() + mInsets.bottom - (mSpacingBetweenBubbles * 2);
+        final float bottomInset = mScreenRect.bottom - bottomHeight;
         final float expandedStackSize = getExpandedStackSize(numberOfBubbles);
-        final float centerPosition = showBubblesVertically()
-                ? mPositionRect.centerY()
-                : mPositionRect.centerX();
+        final float centerPosition = mPositionRect.centerY();
         final float rowBottom = centerPosition + (expandedStackSize / 2f);
         final float rowTop = centerPosition - (expandedStackSize / 2f);
         float rowTopForIme = rowTop;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 58f79f3..e4e5e3d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -899,7 +899,7 @@
                     mStackAnimationController.updateResources();
                     mBubbleOverflow.updateResources();
 
-                    if (mRelativeStackPositionBeforeRotation != null) {
+                    if (!isStackEduShowing() && mRelativeStackPositionBeforeRotation != null) {
                         mStackAnimationController.setStackPosition(
                                 mRelativeStackPositionBeforeRotation);
                         mRelativeStackPositionBeforeRotation = null;
@@ -1049,10 +1049,17 @@
 
     private final Runnable mAnimateTemporarilyInvisibleImmediate = () -> {
         if (mTemporarilyInvisible && mFlyout.getVisibility() != View.VISIBLE) {
+            // To calculate a distance, bubble stack needs to be moved to become hidden,
+            // we need to take into account that the bubble stack is positioned on the edge
+            // of the available screen rect, which can be offset by system bars and cutouts.
             if (mStackAnimationController.isStackOnLeftSide()) {
-                animate().translationX(-mBubbleSize).start();
+                int availableRectOffsetX =
+                        mPositioner.getAvailableRect().left - mPositioner.getScreenRect().left;
+                animate().translationX(-(mBubbleSize + availableRectOffsetX)).start();
             } else {
-                animate().translationX(mBubbleSize).start();
+                int availableRectOffsetX =
+                        mPositioner.getAvailableRect().right - mPositioner.getScreenRect().right;
+                animate().translationX(mBubbleSize - availableRectOffsetX).start();
             }
         } else {
             animate().translationX(0).start();
@@ -1193,6 +1200,8 @@
             addView(mStackEduView);
         }
         mBubbleContainer.bringToFront();
+        // Ensure the stack is in the correct spot
+        mStackAnimationController.setStackPosition(mPositioner.getDefaultStartPosition());
         return mStackEduView.show(mPositioner.getDefaultStartPosition());
     }
 
@@ -1207,6 +1216,8 @@
             mStackEduView = new StackEducationView(mContext, mPositioner, mBubbleController);
             addView(mStackEduView);
             mBubbleContainer.bringToFront(); // Stack appears on top of the stack education
+            // Ensure the stack is in the correct spot
+            mStackAnimationController.setStackPosition(mPositioner.getDefaultStartPosition());
             mStackEduView.show(mPositioner.getDefaultStartPosition());
         }
         if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) {
@@ -1324,10 +1335,12 @@
         mStackAnimationController.updateResources();
         mDismissView.updateResources();
         mMagneticTarget.setMagneticFieldRadiusPx(mBubbleSize * 2);
-        mStackAnimationController.setStackPosition(
-                new RelativeStackPosition(
-                        mPositioner.getRestingPosition(),
-                        mStackAnimationController.getAllowableStackPositionRegion()));
+        if (!isStackEduShowing()) {
+            mStackAnimationController.setStackPosition(
+                    new RelativeStackPosition(
+                            mPositioner.getRestingPosition(),
+                            mStackAnimationController.getAllowableStackPositionRegion()));
+        }
         if (mIsExpanded) {
             updateExpandedView();
         }
@@ -2795,7 +2808,14 @@
             mExpandedViewContainer.setVisibility(View.INVISIBLE);
             mExpandedViewContainer.setAlpha(0f);
             mExpandedViewContainer.addView(bev);
-            bev.setManageClickListener((view) -> showManageMenu(!mShowingManage));
+
+            postDelayed(() -> {
+                // Set the Manage button click handler from postDelayed. This appears to resolve
+                // a race condition with adding the BubbleExpandedView view to the expanded view
+                // container. Due to the race condition the click handler sometimes is not set up
+                // correctly and is never called.
+                bev.setManageClickListener((view) -> showManageMenu(true /* show */));
+            }, 0);
 
             if (!mIsExpansionAnimating) {
                 mSurfaceSynchronizer.syncSurfaceAndRun(() -> {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt
index eb4737a..c09d1e0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt
@@ -101,9 +101,8 @@
         bubbleExpandedView = expandedView
         expandedView.taskView?.setObscuredTouchRect(Rect(positioner.screenRect))
 
-        layoutParams.width = if (positioner.isLargeScreen)
-            context.resources.getDimensionPixelSize(
-                    R.dimen.bubbles_user_education_width_large_screen)
+        layoutParams.width = if (positioner.isLargeScreen || positioner.isLandscape)
+            context.resources.getDimensionPixelSize(R.dimen.bubbles_user_education_width)
         else ViewGroup.LayoutParams.MATCH_PARENT
 
         alpha = 0f
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt
index 3846de7..1ff4be8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt
@@ -122,28 +122,29 @@
      * If necessary, shows the user education view for the bubble stack. This appears the first
      * time a user taps on a bubble.
      *
-     * @return true if user education was shown, false otherwise.
+     * @return true if user education was shown and wasn't showing before, false otherwise.
      */
     fun show(stackPosition: PointF): Boolean {
         isHiding = false
         if (visibility == VISIBLE) return false
 
         controller.updateWindowFlagsForBackpress(true /* interceptBack */)
-        layoutParams.width = if (positioner.isLargeScreen)
-            context.resources.getDimensionPixelSize(
-                    R.dimen.bubbles_user_education_width_large_screen)
+        layoutParams.width = if (positioner.isLargeScreen || positioner.isLandscape)
+            context.resources.getDimensionPixelSize(R.dimen.bubbles_user_education_width)
         else ViewGroup.LayoutParams.MATCH_PARENT
 
+        val stackPadding = context.resources.getDimensionPixelSize(
+                R.dimen.bubble_user_education_stack_padding)
         setAlpha(0f)
         setVisibility(View.VISIBLE)
         post {
             requestFocus()
             with(view) {
                 if (resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_LTR) {
-                    setPadding(positioner.bubbleSize + paddingRight, paddingTop, paddingRight,
+                    setPadding(positioner.bubbleSize + stackPadding, paddingTop, paddingRight,
                             paddingBottom)
                 } else {
-                    setPadding(paddingLeft, paddingTop, positioner.bubbleSize + paddingLeft,
+                    setPadding(paddingLeft, paddingTop, positioner.bubbleSize + stackPadding,
                             paddingBottom)
                 }
                 translationY = stackPosition.y + positioner.bubbleSize / 2 - getHeight() / 2
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index 51067a4..8d1afa4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -344,7 +344,7 @@
         @Override
         public void resized(ClientWindowFrames frames, boolean reportDraw,
                 MergedConfiguration newMergedConfiguration, boolean forceLayout,
-                boolean alwaysConsumeSystemBars, int displayId) {}
+                boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, int resizeMode) {}
 
         @Override
         public void insetsChanged(InsetsState insetsState, boolean willMove, boolean willResize) {}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
index 36e55ba..a10ee6a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
@@ -23,6 +23,9 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 import static android.view.WindowManagerPolicyConstants.SPLIT_DIVIDER_LAYER;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -42,6 +45,8 @@
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 
+import androidx.annotation.NonNull;
+
 import com.android.launcher3.icons.IconProvider;
 import com.android.wm.shell.R;
 import com.android.wm.shell.common.SurfaceUtils;
@@ -52,6 +57,7 @@
 public class SplitDecorManager extends WindowlessWindowManager {
     private static final String TAG = SplitDecorManager.class.getSimpleName();
     private static final String RESIZING_BACKGROUND_SURFACE_NAME = "ResizingBackground";
+    private static final long FADE_DURATION = 133;
 
     private final IconProvider mIconProvider;
     private final SurfaceSession mSurfaceSession;
@@ -63,6 +69,11 @@
     private SurfaceControl mIconLeash;
     private SurfaceControl mBackgroundLeash;
 
+    private boolean mShown;
+    private boolean mIsResizing;
+    private Rect mBounds = new Rect();
+    private ValueAnimator mFadeAnimator;
+
     public SplitDecorManager(Configuration configuration, IconProvider iconProvider,
             SurfaceSession surfaceSession) {
         super(configuration, null /* rootSurface */, null /* hostInputToken */);
@@ -137,16 +148,19 @@
             return;
         }
 
+        if (!mIsResizing) {
+            mIsResizing = true;
+            mBounds.set(newBounds);
+        }
+
         if (mBackgroundLeash == null) {
             mBackgroundLeash = SurfaceUtils.makeColorLayer(mHostLeash,
                     RESIZING_BACKGROUND_SURFACE_NAME, mSurfaceSession);
             t.setColor(mBackgroundLeash, getResizingBackgroundColor(resizingTask))
-                    .setLayer(mBackgroundLeash, SPLIT_DIVIDER_LAYER - 1)
-                    .show(mBackgroundLeash);
+                    .setLayer(mBackgroundLeash, SPLIT_DIVIDER_LAYER - 1);
         }
 
         if (mIcon == null && resizingTask.topActivityInfo != null) {
-            // TODO: add fade-in animation.
             mIcon = mIconProvider.getIcon(resizingTask.topActivityInfo);
             mResizingIconView.setImageDrawable(mIcon);
             mResizingIconView.setVisibility(View.VISIBLE);
@@ -156,12 +170,20 @@
             lp.width = mIcon.getIntrinsicWidth();
             lp.height = mIcon.getIntrinsicHeight();
             mViewHost.relayout(lp);
-            t.show(mIconLeash).setLayer(mIconLeash, SPLIT_DIVIDER_LAYER);
+            t.setLayer(mIconLeash, SPLIT_DIVIDER_LAYER);
         }
-
         t.setPosition(mIconLeash,
                 newBounds.width() / 2 - mIcon.getIntrinsicWidth() / 2,
                 newBounds.height() / 2 - mIcon.getIntrinsicWidth() / 2);
+
+        boolean show = newBounds.width() > mBounds.width() || newBounds.height() > mBounds.height();
+        if (show != mShown) {
+            if (mFadeAnimator != null && mFadeAnimator.isRunning()) {
+                mFadeAnimator.cancel();
+            }
+            startFadeAnimation(show, false /* releaseLeash */);
+            mShown = show;
+        }
     }
 
     /** Stops showing resizing hint. */
@@ -170,6 +192,68 @@
             return;
         }
 
+        mIsResizing = false;
+        if (mFadeAnimator != null && mFadeAnimator.isRunning()) {
+            if (!mShown) {
+                // If fade-out animation is running, just add release callback to it.
+                SurfaceControl.Transaction finishT = new SurfaceControl.Transaction();
+                mFadeAnimator.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        releaseLeash(finishT);
+                        finishT.apply();
+                        finishT.close();
+                    }
+                });
+                return;
+            }
+
+            // If fade-in animation is running, cancel it and re-run fade-out one.
+            mFadeAnimator.cancel();
+        }
+        if (mShown) {
+            startFadeAnimation(false /* show */, true /* releaseLeash */);
+            mShown = false;
+        } else {
+            // Surface is hidden so release it directly.
+            releaseLeash(t);
+        }
+    }
+
+    private void startFadeAnimation(boolean show, boolean releaseLeash) {
+        final SurfaceControl.Transaction animT = new SurfaceControl.Transaction();
+        mFadeAnimator = ValueAnimator.ofFloat(0f, 1f);
+        mFadeAnimator.setDuration(FADE_DURATION);
+        mFadeAnimator.addUpdateListener(valueAnimator-> {
+            final float progress = (float) valueAnimator.getAnimatedValue();
+            animT.setAlpha(mBackgroundLeash, show ? progress : 1 - progress);
+            animT.setAlpha(mIconLeash, show ? progress : 1 - progress);
+            animT.apply();
+        });
+        mFadeAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(@NonNull Animator animation) {
+                if (show) {
+                    animT.show(mBackgroundLeash).show(mIconLeash).apply();
+                }
+            }
+
+            @Override
+            public void onAnimationEnd(@NonNull Animator animation) {
+                if (!show) {
+                    animT.hide(mBackgroundLeash).hide(mIconLeash).apply();
+                }
+                if (releaseLeash) {
+                    releaseLeash(animT);
+                    animT.apply();
+                }
+                animT.close();
+            }
+        });
+        mFadeAnimator.start();
+    }
+
+    private void releaseLeash(SurfaceControl.Transaction t) {
         if (mBackgroundLeash != null) {
             t.remove(mBackgroundLeash);
             mBackgroundLeash = null;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index b52c8d1..d05a4df 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -98,6 +98,7 @@
     private WindowContainerToken mWinToken2;
     private int mDividePosition;
     private boolean mInitialized = false;
+    private boolean mFreezeDividerWindow = false;
     private int mOrientation;
     private int mRotation;
 
@@ -225,11 +226,6 @@
         mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds, null);
         initDividerPosition(mTempRect);
 
-        if (mInitialized) {
-            release();
-            init();
-        }
-
         return true;
     }
 
@@ -298,20 +294,37 @@
     }
 
     /** Releases the surface holding the current {@link DividerView}. */
-    public void release() {
+    public void release(SurfaceControl.Transaction t) {
         if (!mInitialized) return;
         mInitialized = false;
-        mSplitWindowManager.release();
+        mSplitWindowManager.release(t);
         mDisplayImeController.removePositionProcessor(mImePositionProcessor);
         mImePositionProcessor.reset();
     }
 
+    public void release() {
+        release(null /* t */);
+    }
+
+    /** Releases and re-inflates {@link DividerView} on the root surface. */
+    public void update(SurfaceControl.Transaction t) {
+        if (!mInitialized) return;
+        mSplitWindowManager.release(t);
+        mImePositionProcessor.reset();
+        mSplitWindowManager.init(this, mInsetsState);
+    }
+
     @Override
     public void insetsChanged(InsetsState insetsState) {
         mInsetsState.set(insetsState);
         if (!mInitialized) {
             return;
         }
+        if (mFreezeDividerWindow) {
+            // DO NOT change its layout before transition actually run because it might cause
+            // flicker.
+            return;
+        }
         mSplitWindowManager.onInsetsChanged(insetsState);
     }
 
@@ -323,6 +336,10 @@
         }
     }
 
+    public void setFreezeDividerWindow(boolean freezeDividerWindow) {
+        mFreezeDividerWindow = freezeDividerWindow;
+    }
+
     /**
      * Updates bounds with the passing position. Usually used to update recording bounds while
      * performing animation or dragging divider bar to resize the splits.
@@ -496,10 +513,6 @@
     /** Apply recorded task layout to the {@link WindowContainerTransaction}. */
     public void applyTaskChanges(WindowContainerTransaction wct,
             ActivityManager.RunningTaskInfo task1, ActivityManager.RunningTaskInfo task2) {
-        if (mImePositionProcessor.applyTaskLayoutForIme(wct, task1.token, task2.token)) {
-            return;
-        }
-
         if (!mBounds1.equals(mWinBounds1) || !task1.token.equals(mWinToken1)) {
             wct.setBounds(task1.token, mBounds1);
             wct.setSmallestScreenWidthDp(task1.token, getSmallestWidthDp(mBounds1));
@@ -515,7 +528,9 @@
     }
 
     private int getSmallestWidthDp(Rect bounds) {
-        final int minWidth = Math.min(bounds.width(), bounds.height());
+        mTempRect.set(bounds);
+        mTempRect.inset(getDisplayInsets(mContext));
+        final int minWidth = Math.min(mTempRect.width(), mTempRect.height());
         final float density = mContext.getResources().getDisplayMetrics().density;
         return (int) (minWidth / density);
     }
@@ -739,6 +754,7 @@
 
         private final int mDisplayId;
 
+        private boolean mHasImeFocus;
         private boolean mImeShown;
         private int mYOffsetForIme;
         private float mDimValue1;
@@ -761,25 +777,32 @@
         @Override
         public int onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
                 boolean showing, boolean isFloating, SurfaceControl.Transaction t) {
-            if (displayId != mDisplayId) return 0;
+            if (displayId != mDisplayId || !mInitialized) {
+                return 0;
+            }
+
             final int imeTargetPosition = getImeTargetPosition();
-            if (!mInitialized || imeTargetPosition == SPLIT_POSITION_UNDEFINED) return 0;
+            mHasImeFocus = imeTargetPosition != SPLIT_POSITION_UNDEFINED;
+            if (!mHasImeFocus) {
+                return 0;
+            }
+
             mStartImeTop = showing ? hiddenTop : shownTop;
             mEndImeTop = showing ? shownTop : hiddenTop;
             mImeShown = showing;
 
             // Update target dim values
             mLastDim1 = mDimValue1;
-            mTargetDim1 = imeTargetPosition == SPLIT_POSITION_BOTTOM_OR_RIGHT && showing
+            mTargetDim1 = imeTargetPosition == SPLIT_POSITION_BOTTOM_OR_RIGHT && mImeShown
                     ? ADJUSTED_NONFOCUS_DIM : 0.0f;
             mLastDim2 = mDimValue2;
-            mTargetDim2 = imeTargetPosition == SPLIT_POSITION_TOP_OR_LEFT && showing
+            mTargetDim2 = imeTargetPosition == SPLIT_POSITION_TOP_OR_LEFT && mImeShown
                     ? ADJUSTED_NONFOCUS_DIM : 0.0f;
 
             // Calculate target bounds offset for IME
             mLastYOffset = mYOffsetForIme;
             final boolean needOffset = imeTargetPosition == SPLIT_POSITION_BOTTOM_OR_RIGHT
-                    && !isFloating && !isLandscape(mRootBounds) && showing;
+                    && !isFloating && !isLandscape(mRootBounds) && mImeShown;
             mTargetYOffset = needOffset ? getTargetYOffset() : 0;
 
             if (mTargetYOffset != mLastYOffset) {
@@ -798,15 +821,14 @@
             // ImePositionProcessor#onImeVisibilityChanged directly in DividerView is not enough
             // because DividerView won't receive onImeVisibilityChanged callback after it being
             // re-inflated.
-            mSplitWindowManager.setInteractive(
-                    !showing || imeTargetPosition == SPLIT_POSITION_UNDEFINED);
+            mSplitWindowManager.setInteractive(!mImeShown || !mHasImeFocus);
 
             return needOffset ? IME_ANIMATION_NO_ALPHA : 0;
         }
 
         @Override
         public void onImePositionChanged(int displayId, int imeTop, SurfaceControl.Transaction t) {
-            if (displayId != mDisplayId) return;
+            if (displayId != mDisplayId || !mHasImeFocus) return;
             onProgress(getProgress(imeTop));
             mSplitLayoutHandler.onLayoutPositionChanging(SplitLayout.this);
         }
@@ -814,7 +836,7 @@
         @Override
         public void onImeEndPositioning(int displayId, boolean cancel,
                 SurfaceControl.Transaction t) {
-            if (displayId != mDisplayId || cancel) return;
+            if (displayId != mDisplayId || !mHasImeFocus || cancel) return;
             onProgress(1.0f);
             mSplitLayoutHandler.onLayoutPositionChanging(SplitLayout.this);
         }
@@ -826,6 +848,7 @@
             if (!controlling && mImeShown) {
                 reset();
                 mSplitWindowManager.setInteractive(true);
+                mSplitLayoutHandler.setLayoutOffsetTarget(0, 0, SplitLayout.this);
                 mSplitLayoutHandler.onLayoutPositionChanging(SplitLayout.this);
             }
         }
@@ -859,6 +882,7 @@
         }
 
         void reset() {
+            mHasImeFocus = false;
             mImeShown = false;
             mYOffsetForIme = mLastYOffset = mTargetYOffset = 0;
             mDimValue1 = mLastDim1 = mTargetDim1 = 0.0f;
@@ -866,26 +890,6 @@
         }
 
         /**
-         * Applies adjusted task layout for showing IME.
-         *
-         * @return {@code false} if there's no need to adjust, otherwise {@code true}
-         */
-        boolean applyTaskLayoutForIme(WindowContainerTransaction wct,
-                WindowContainerToken token1, WindowContainerToken token2) {
-            if (mYOffsetForIme == 0) return false;
-
-            mTempRect.set(mBounds1);
-            mTempRect.offset(0, mYOffsetForIme);
-            wct.setBounds(token1, mTempRect);
-
-            mTempRect.set(mBounds2);
-            mTempRect.offset(0, mYOffsetForIme);
-            wct.setBounds(token2, mTempRect);
-
-            return true;
-        }
-
-        /**
          * Adjusts surface layout while showing IME.
          *
          * @return {@code false} if there's no need to adjust, otherwise {@code true}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
index 4903f9d..833d9d5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
@@ -58,6 +58,9 @@
     private SurfaceControl mLeash;
     private DividerView mDividerView;
 
+    // Used to "pass" a transaction to WWM.remove so that view removal can be synchronized.
+    private SurfaceControl.Transaction mSyncTransaction = null;
+
     public interface ParentContainerCallbacks {
         void attachToParentSurface(SurfaceControl.Builder b);
         void onLeashReady(SurfaceControl leash);
@@ -130,22 +133,38 @@
      * Releases the surface control of the current {@link DividerView} and tear down the view
      * hierarchy.
      */
-    void release() {
+    void release(@Nullable SurfaceControl.Transaction t) {
         if (mDividerView != null) {
             mDividerView = null;
         }
 
         if (mViewHost != null){
+            mSyncTransaction = t;
             mViewHost.release();
+            mSyncTransaction = null;
             mViewHost = null;
         }
 
         if (mLeash != null) {
-            new SurfaceControl.Transaction().remove(mLeash).apply();
+            if (t == null) {
+                new SurfaceControl.Transaction().remove(mLeash).apply();
+            } else {
+                t.remove(mLeash);
+            }
             mLeash = null;
         }
     }
 
+    @Override
+    protected void removeSurface(SurfaceControl sc) {
+        // This gets called via SurfaceControlViewHost.release()
+        if (mSyncTransaction != null) {
+            mSyncTransaction.remove(sc);
+        } else {
+            super.removeSurface(sc);
+        }
+    }
+
     void setInteractive(boolean interactive) {
         if (mDividerView == null) return;
         mDividerView.setInteractive(interactive);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
index b2bbafe..99b32a6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
@@ -42,6 +42,7 @@
 import com.android.wm.shell.common.annotations.ExternalThread;
 import com.android.wm.shell.compatui.CompatUIWindowManager.CompatUIHintsState;
 import com.android.wm.shell.compatui.letterboxedu.LetterboxEduWindowManager;
+import com.android.wm.shell.transition.Transitions;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -50,6 +51,8 @@
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 
+import dagger.Lazy;
+
 /**
  * Controller to show/update compat UI components on Tasks based on whether the foreground
  * activities are in compatibility mode.
@@ -102,6 +105,7 @@
     private final DisplayImeController mImeController;
     private final SyncTransactionQueue mSyncQueue;
     private final ShellExecutor mMainExecutor;
+    private final Lazy<Transitions> mTransitionsLazy;
     private final CompatUIImpl mImpl = new CompatUIImpl();
 
     private CompatUICallback mCallback;
@@ -118,13 +122,15 @@
             DisplayInsetsController displayInsetsController,
             DisplayImeController imeController,
             SyncTransactionQueue syncQueue,
-            ShellExecutor mainExecutor) {
+            ShellExecutor mainExecutor,
+            Lazy<Transitions> transitionsLazy) {
         mContext = context;
         mDisplayController = displayController;
         mDisplayInsetsController = displayInsetsController;
         mImeController = imeController;
         mSyncQueue = syncQueue;
         mMainExecutor = mainExecutor;
+        mTransitionsLazy = transitionsLazy;
         mDisplayController.addDisplayWindowListener(this);
         mImeController.addPositionProcessor(this);
         mCompatUIHintsState = new CompatUIHintsState();
@@ -302,6 +308,7 @@
             ShellTaskOrganizer.TaskListener taskListener) {
         return new LetterboxEduWindowManager(context, taskInfo,
                 mSyncQueue, taskListener, mDisplayController.getDisplayLayout(taskInfo.displayId),
+                mTransitionsLazy.get(),
                 this::onLetterboxEduDismissed);
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java
index 03986ee..3061eab 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java
@@ -18,6 +18,7 @@
 
 import static com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
 import static com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
+import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -42,7 +43,9 @@
 class LetterboxEduAnimationController {
     private static final String TAG = "LetterboxEduAnimation";
 
-    private static final int ENTER_ANIM_START_DELAY_MILLIS = 500;
+    // If shell transitions are enabled, startEnterAnimation will be called after all transitions
+    // have finished, and therefore the start delay should be shorter.
+    private static final int ENTER_ANIM_START_DELAY_MILLIS = ENABLE_SHELL_TRANSITIONS ? 300 : 500;
 
     private final TransitionAnimation mTransitionAnimation;
     private final String mPackageName;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java
index 8aa4d0e..2e0b09e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java
@@ -38,6 +38,7 @@
     // The alpha of a background is a number between 0 (fully transparent) to 255 (fully opaque).
     // 204 is simply 255 * 0.8.
     static final int BACKGROUND_DIM_ALPHA = 204;
+
     private View mDialogContainer;
     private TextView mDialogTitle;
     private Drawable mBackgroundDim;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java
index dda72ff..35f1038 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java
@@ -36,6 +36,7 @@
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.compatui.CompatUIWindowManagerAbstract;
+import com.android.wm.shell.transition.Transitions;
 
 /**
  * Window manager for the Letterbox Education.
@@ -50,7 +51,7 @@
 
     /**
      * The name of the {@link SharedPreferences} that holds which user has seen the Letterbox
-     * Education for specific packages and which user has seen the full dialog for any package.
+     * Education dialog.
      */
     @VisibleForTesting
     static final String HAS_SEEN_LETTERBOX_EDUCATION_PREF_NAME =
@@ -63,6 +64,15 @@
 
     private final LetterboxEduAnimationController mAnimationController;
 
+    private final Transitions mTransitions;
+
+    /**
+     * The id of the current user, to associate with a boolean in {@link
+     * #HAS_SEEN_LETTERBOX_EDUCATION_PREF_NAME}, indicating whether that user has already seen the
+     * Letterbox Education dialog.
+     */
+    private final int mUserId;
+
     // Remember the last reported state in case visibility changes due to keyguard or IME updates.
     private boolean mEligibleForLetterboxEducation;
 
@@ -80,19 +90,22 @@
 
     public LetterboxEduWindowManager(Context context, TaskInfo taskInfo,
             SyncTransactionQueue syncQueue, ShellTaskOrganizer.TaskListener taskListener,
-            DisplayLayout displayLayout, Runnable onDismissCallback) {
-        this(context, taskInfo, syncQueue, taskListener, displayLayout, onDismissCallback,
-                new LetterboxEduAnimationController(context));
+            DisplayLayout displayLayout, Transitions transitions,
+            Runnable onDismissCallback) {
+        this(context, taskInfo, syncQueue, taskListener, displayLayout, transitions,
+                onDismissCallback, new LetterboxEduAnimationController(context));
     }
 
     @VisibleForTesting
     LetterboxEduWindowManager(Context context, TaskInfo taskInfo,
             SyncTransactionQueue syncQueue, ShellTaskOrganizer.TaskListener taskListener,
-            DisplayLayout displayLayout, Runnable onDismissCallback,
+            DisplayLayout displayLayout, Transitions transitions, Runnable onDismissCallback,
             LetterboxEduAnimationController animationController) {
         super(context, taskInfo, syncQueue, taskListener, displayLayout);
+        mTransitions = transitions;
         mOnDismissCallback = onDismissCallback;
         mAnimationController = animationController;
+        mUserId = taskInfo.userId;
         mEligibleForLetterboxEducation = taskInfo.topActivityEligibleForLetterboxEducation;
         mSharedPreferences = mContext.getSharedPreferences(HAS_SEEN_LETTERBOX_EDUCATION_PREF_NAME,
                 Context.MODE_PRIVATE);
@@ -128,12 +141,11 @@
 
     @Override
     protected View createLayout() {
-        setSeenLetterboxEducation();
         mLayout = inflateLayout();
         updateDialogMargins();
 
-        mAnimationController.startEnterAnimation(mLayout, /* endCallback= */
-                this::onDialogEnterAnimationEnded);
+        // startEnterAnimation will be called immediately if shell-transitions are disabled.
+        mTransitions.runOnIdle(this::startEnterAnimation);
 
         return mLayout;
     }
@@ -158,10 +170,21 @@
                 R.layout.letterbox_education_dialog_layout, null);
     }
 
-    private void onDialogEnterAnimationEnded() {
+    private void startEnterAnimation() {
         if (mLayout == null) {
+            // Dialog has already been released.
             return;
         }
+        mAnimationController.startEnterAnimation(mLayout, /* endCallback= */
+                this::onDialogEnterAnimationEnded);
+    }
+
+    private void onDialogEnterAnimationEnded() {
+        if (mLayout == null) {
+            // Dialog has already been released.
+            return;
+        }
+        setSeenLetterboxEducation();
         mLayout.setDismissOnClickListener(this::onDismiss);
         // Focus on the dialog title for accessibility.
         mLayout.getDialogTitle().sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
@@ -226,7 +249,7 @@
     }
 
     private String getPrefKey() {
-        return String.valueOf(mContext.getUserId());
+        return String.valueOf(mUserId);
     }
 
     @VisibleForTesting
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index bf0337d..026eeb0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -96,6 +96,7 @@
 import java.util.Optional;
 
 import dagger.BindsOptionalOf;
+import dagger.Lazy;
 import dagger.Module;
 import dagger.Provides;
 
@@ -189,15 +190,13 @@
             @ShellMainThread ShellExecutor mainExecutor,
             @ShellMainThread Handler mainHandler,
             Context context,
-            CompatUIController compatUI,
             SyncTransactionQueue syncTransactionQueue,
             DisplayController displayController,
             DisplayInsetsController displayInsetsController,
             Optional<RecentTasksController> recentTasksOptional
     ) {
-        return new KidsModeTaskOrganizer(mainExecutor, mainHandler, context, compatUI,
-                syncTransactionQueue, displayController, displayInsetsController,
-                recentTasksOptional);
+        return new KidsModeTaskOrganizer(mainExecutor, mainHandler, context, syncTransactionQueue,
+                displayController, displayInsetsController, recentTasksOptional);
     }
 
     @WMSingleton
@@ -210,9 +209,9 @@
     static CompatUIController provideCompatUIController(Context context,
             DisplayController displayController, DisplayInsetsController displayInsetsController,
             DisplayImeController imeController, SyncTransactionQueue syncQueue,
-            @ShellMainThread ShellExecutor mainExecutor) {
+            @ShellMainThread ShellExecutor mainExecutor, Lazy<Transitions> transitionsLazy) {
         return new CompatUIController(context, displayController, displayInsetsController,
-                imeController, syncQueue, mainExecutor);
+                imeController, syncQueue, mainExecutor, transitionsLazy);
     }
 
     @WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
index 429eb99..003c559 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
@@ -38,7 +38,6 @@
 import android.window.WindowContainerTransaction;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.policy.ForceShowNavigationBarSettingsObserver;
@@ -48,7 +47,6 @@
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.compatui.CompatUIController;
 import com.android.wm.shell.recents.RecentTasksController;
 import com.android.wm.shell.startingsurface.StartingWindowController;
 
@@ -136,13 +134,12 @@
             ShellExecutor mainExecutor,
             Handler mainHandler,
             Context context,
-            @Nullable CompatUIController compatUI,
             SyncTransactionQueue syncTransactionQueue,
             DisplayController displayController,
             DisplayInsetsController displayInsetsController,
             Optional<RecentTasksController> recentTasks,
             ForceShowNavigationBarSettingsObserver forceShowNavigationBarSettingsObserver) {
-        super(taskOrganizerController, mainExecutor, context, compatUI, recentTasks);
+        super(taskOrganizerController, mainExecutor, context, /* compatUI= */ null, recentTasks);
         mContext = context;
         mMainHandler = mainHandler;
         mSyncQueue = syncTransactionQueue;
@@ -155,12 +152,11 @@
             ShellExecutor mainExecutor,
             Handler mainHandler,
             Context context,
-            @Nullable CompatUIController compatUI,
             SyncTransactionQueue syncTransactionQueue,
             DisplayController displayController,
             DisplayInsetsController displayInsetsController,
             Optional<RecentTasksController> recentTasks) {
-        super(mainExecutor, context, compatUI, recentTasks);
+        super(mainExecutor, context, /* compatUI= */ null, recentTasks);
         mContext = context;
         mMainHandler = mainHandler;
         mSyncQueue = syncTransactionQueue;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl
index b4c745f..ef62764 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl
@@ -32,4 +32,9 @@
      * @param cornerRadius the pixel value of the corner radius, zero means it's disabled.
      */
     void onPipCornerRadiusChanged(int cornerRadius);
+
+    /**
+     * Notifies the listener that user leaves PiP by tapping on the expand button.
+     */
+    void onExpandPip();
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java
index 3fefc4a..87eca74 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java
@@ -72,9 +72,10 @@
         }
     }
 
-    private void onActionsChanged(ParceledListSlice<RemoteAction> actions) {
+    private void onActionsChanged(ParceledListSlice<RemoteAction> actions,
+            RemoteAction closeAction) {
         for (PinnedTaskListener listener : mListeners) {
-            listener.onActionsChanged(actions);
+            listener.onActionsChanged(actions, closeAction);
         }
     }
 
@@ -113,9 +114,10 @@
         }
 
         @Override
-        public void onActionsChanged(ParceledListSlice<RemoteAction> actions) {
+        public void onActionsChanged(ParceledListSlice<RemoteAction> actions,
+                RemoteAction closeAction) {
             mMainExecutor.execute(() -> {
-                PinnedStackListenerForwarder.this.onActionsChanged(actions);
+                PinnedStackListenerForwarder.this.onActionsChanged(actions, closeAction);
             });
         }
 
@@ -152,7 +154,8 @@
 
         public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {}
 
-        public void onActionsChanged(ParceledListSlice<RemoteAction> actions) {}
+        public void onActionsChanged(ParceledListSlice<RemoteAction> actions,
+                RemoteAction closeAction) {}
 
         public void onActivityHidden(ComponentName componentName) {}
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
index c2d5823..7397e52 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
@@ -194,7 +194,7 @@
     public float getAspectRatioOrDefault(
             @android.annotation.Nullable PictureInPictureParams params) {
         return params != null && params.hasSetAspectRatio()
-                ? params.getAspectRatio()
+                ? params.getAspectRatioFloat()
                 : getDefaultAspectRatio();
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java
index caa1f01..f6ff294 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java
@@ -66,7 +66,7 @@
     /**
      * Given a set of actions, update the menu.
      */
-    void setAppActions(ParceledListSlice<RemoteAction> appActions);
+    void setAppActions(ParceledListSlice<RemoteAction> appActions, RemoteAction closeAction);
 
     /**
      * Resize the PiP menu with the given bounds. The PiP SurfaceControl is given if there is a
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index b266189..5d6b041 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -18,7 +18,6 @@
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.util.RotationUtils.deltaRotation;
 import static android.util.RotationUtils.rotateBounds;
@@ -450,11 +449,7 @@
             tx.setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height());
             // We set to fullscreen here for now, but later it will be set to UNDEFINED for
             // the proper windowing mode to take place. See #applyWindowingModeChangeOnExit.
-            wct.setActivityWindowingMode(mToken,
-                    direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
-                            && !requestEnterSplit
-                            ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
-                            : WINDOWING_MODE_FULLSCREEN);
+            wct.setActivityWindowingMode(mToken, WINDOWING_MODE_FULLSCREEN);
             wct.setBounds(mToken, destinationBounds);
             wct.setBoundsChangeTransaction(mToken, tx);
         }
@@ -1076,13 +1071,13 @@
      */
     private boolean applyPictureInPictureParams(@NonNull PictureInPictureParams params) {
         final Rational currentAspectRatio =
-                mPictureInPictureParams != null ? mPictureInPictureParams.getAspectRatioRational()
+                mPictureInPictureParams != null ? mPictureInPictureParams.getAspectRatio()
                         : null;
         final boolean aspectRatioChanged = !Objects.equals(currentAspectRatio,
-                params.getAspectRatioRational());
+                params.getAspectRatio());
         mPictureInPictureParams = params;
         if (aspectRatioChanged) {
-            mPipBoundsState.setAspectRatio(params.getAspectRatio());
+            mPipBoundsState.setAspectRatio(params.getAspectRatioFloat());
         }
         return aspectRatioChanged;
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index be713a5..48df28e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -89,6 +89,8 @@
     private final Rect mExitDestinationBounds = new Rect();
     @Nullable
     private IBinder mExitTransition;
+    private IBinder mRequestedEnterTransition;
+    private WindowContainerToken mRequestedEnterTask;
     /** The Task window that is currently in PIP windowing mode. */
     @Nullable
     private WindowContainerToken mCurrentPipTaskToken;
@@ -166,8 +168,7 @@
             mExitTransition = null;
             mHasFadeOut = false;
             if (mFinishCallback != null) {
-                mFinishCallback.onTransitionFinished(null, null);
-                mFinishCallback = null;
+                callFinishCallback(null /* wct */);
                 mFinishTransaction = null;
                 throw new RuntimeException("Previous callback not called, aborting exit PIP.");
             }
@@ -202,6 +203,9 @@
             }
             mCurrentPipTaskToken = null;
             return true;
+        } else if (transition == mRequestedEnterTransition) {
+            mRequestedEnterTransition = null;
+            mRequestedEnterTask = null;
         }
 
         // The previous PIP Task is no longer in PIP, but this is not an exit transition (This can
@@ -232,6 +236,11 @@
         return false;
     }
 
+    /** Helper to identify whether this handler is currently the one playing an animation */
+    private boolean isAnimatingLocally() {
+        return mFinishTransaction != null;
+    }
+
     @Nullable
     @Override
     public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@@ -239,6 +248,8 @@
         if (request.getType() == TRANSIT_PIP) {
             WindowContainerTransaction wct = new WindowContainerTransaction();
             if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
+                mRequestedEnterTransition = transition;
+                mRequestedEnterTask = request.getTriggerTask().token;
                 wct.setActivityWindowingMode(request.getTriggerTask().token,
                         WINDOWING_MODE_UNDEFINED);
                 final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
@@ -251,6 +262,23 @@
     }
 
     @Override
+    public boolean handleRotateDisplay(int startRotation, int endRotation,
+            WindowContainerTransaction wct) {
+        if (mRequestedEnterTransition != null && mOneShotAnimationType == ANIM_TYPE_ALPHA) {
+            // A fade-in was requested but not-yet started. In this case, just recalculate the
+            // initial state under the new rotation.
+            int rotationDelta = deltaRotation(startRotation, endRotation);
+            if (rotationDelta != Surface.ROTATION_0) {
+                mPipBoundsState.getDisplayLayout().rotateTo(mContext.getResources(), endRotation);
+                final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
+                wct.setBounds(mRequestedEnterTask, destinationBounds);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
     public void onTransitionMerged(@NonNull IBinder transition) {
         if (transition != mExitTransition) {
             return;
@@ -282,9 +310,11 @@
         if (enteringPip) {
             mPipTransitionState.setTransitionState(ENTERED_PIP);
         }
-        // If there is an expected exit transition, then the exit will be "merged" into this
-        // transition so don't fire the finish-callback in that case.
-        if (mExitTransition == null && mFinishCallback != null) {
+        // If we have an exit transition, but aren't playing a transition locally, it
+        // means we're expecting the exit transition will be "merged" into another transition
+        // (likely a remote like launcher), so don't fire the finish-callback here -- wait until
+        // the exit transition is merged.
+        if ((mExitTransition == null || isAnimatingLocally()) && mFinishCallback != null) {
             WindowContainerTransaction wct = new WindowContainerTransaction();
             prepareFinishResizeTransaction(taskInfo, destinationBounds,
                     direction, wct);
@@ -305,12 +335,19 @@
                 mSurfaceTransactionHelper.crop(mFinishTransaction, leash, finishBounds);
             }
             mFinishTransaction = null;
-            mFinishCallback.onTransitionFinished(wct, null /* callback */);
-            mFinishCallback = null;
+            callFinishCallback(wct);
         }
         finishResizeForMenu(destinationBounds);
     }
 
+    private void callFinishCallback(WindowContainerTransaction wct) {
+        // Need to unset mFinishCallback first because onTransitionFinished can re-enter this
+        // handler if there is a pending PiP animation.
+        final Transitions.TransitionFinishCallback finishCallback = mFinishCallback;
+        mFinishCallback = null;
+        finishCallback.onTransitionFinished(wct, null /* callback */);
+    }
+
     @Override
     public void forceFinishTransition() {
         if (mFinishCallback == null) return;
@@ -572,8 +609,7 @@
         mHasFadeOut = false;
 
         if (mFinishCallback != null) {
-            mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */);
-            mFinishCallback = null;
+            callFinishCallback(null /* wct */);
             mFinishTransaction = null;
             throw new RuntimeException("Previous callback not called, aborting entering PIP.");
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index 02e713d2..24993c62 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -196,6 +196,17 @@
     }
 
     /**
+     * Called when the display is going to rotate.
+     *
+     * @return {@code true} if it was handled, otherwise the existing pip logic
+     *                      will deal with rotation.
+     */
+    public boolean handleRotateDisplay(int startRotation, int endRotation,
+            WindowContainerTransaction wct) {
+        return false;
+    }
+
+    /**
      * Callback interface for PiP transitions (both from and to PiP mode)
      */
     public interface PipTransitionCallback {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index c4dadf1..5e4c12e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -474,7 +474,8 @@
      * Sets the menu actions to the actions provided by the current PiP menu.
      */
     @Override
-    public void setAppActions(ParceledListSlice<RemoteAction> appActions) {
+    public void setAppActions(ParceledListSlice<RemoteAction> appActions,
+            RemoteAction closeAction) {
         mAppActions = appActions;
         updateMenuActions();
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index e7a1c4c..ad5d85c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -89,6 +89,7 @@
 
 import java.io.PrintWriter;
 import java.util.Optional;
+import java.util.Set;
 import java.util.function.Consumer;
 
 /**
@@ -136,6 +137,11 @@
          * @param cornerRadius the pixel value of the corner radius, zero means it's disabled.
          */
         void onPipCornerRadiusChanged(int cornerRadius);
+
+        /**
+         * Notifies the listener that user leaves PiP by tapping on the expand button.
+         */
+        void onExpandPip();
     }
 
     /**
@@ -143,6 +149,9 @@
      */
     private final DisplayChangeController.OnDisplayChangingListener mRotationController = (
             int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) -> {
+        if (mPipTransitionController.handleRotateDisplay(fromRotation, toRotation, t)) {
+            return;
+        }
         if (mPipBoundsState.getDisplayLayout().rotation() == toRotation) {
             // The same rotation may have been set by auto PiP-able or fixed rotation. So notify
             // the change with fromRotation=false to apply the rotated destination bounds from
@@ -225,6 +234,14 @@
                     onDisplayChanged(mDisplayController.getDisplayLayout(displayId),
                             true /* saveRestoreSnapFraction */);
                 }
+
+                @Override
+                public void onKeepClearAreasChanged(int displayId, Set<Rect> restricted,
+                        Set<Rect> unrestricted) {
+                    if (mPipBoundsState.getDisplayId() == displayId) {
+                        mPipBoundsState.setKeepClearAreas(restricted, unrestricted);
+                    }
+                }
             };
 
     /**
@@ -246,8 +263,9 @@
         }
 
         @Override
-        public void onActionsChanged(ParceledListSlice<RemoteAction> actions) {
-            mMenuController.setAppActions(actions);
+        public void onActionsChanged(ParceledListSlice<RemoteAction> actions,
+                RemoteAction closeAction) {
+            mMenuController.setAppActions(actions, closeAction);
         }
 
         @Override
@@ -639,6 +657,9 @@
         mTouchHandler.setTouchEnabled(false);
         if (mPinnedStackAnimationRecentsCallback != null) {
             mPinnedStackAnimationRecentsCallback.onPipAnimationStarted();
+            if (direction == TRANSITION_DIRECTION_LEAVE_PIP) {
+                mPinnedStackAnimationRecentsCallback.onExpandPip();
+            }
         }
     }
 
@@ -898,6 +919,11 @@
             public void onPipCornerRadiusChanged(int cornerRadius) {
                 mListener.call(l -> l.onPipCornerRadiusChanged(cornerRadius));
             }
+
+            @Override
+            public void onExpandPip() {
+                mListener.call(l -> l.onExpandPip());
+            }
         };
 
         IPipImpl(PipController controller) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
index 3115f8a..11633a9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
@@ -253,11 +253,11 @@
     private WindowManager.LayoutParams getDismissTargetLayoutParams() {
         final Point windowSize = new Point();
         mWindowManager.getDefaultDisplay().getRealSize(windowSize);
-
+        int height = Math.min(windowSize.y, mDismissAreaHeight);
         final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                 WindowManager.LayoutParams.MATCH_PARENT,
-                mDismissAreaHeight,
-                0, windowSize.y - mDismissAreaHeight,
+                height,
+                0, windowSize.y - height,
                 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
                 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                         | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
index e57abc2..0f3ff36 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
@@ -148,6 +148,7 @@
         mMainExecutor.execute(() -> {
             // Choreographer.getSfInstance() must be called on the thread that the input event
             // receiver should be receiving events
+            // TODO(b/222697646): remove getSfInstance usage and use vsyncId for transactions
             mInputEventReceiver = new InputEventReceiver(inputChannel,
                 Looper.myLooper(), Choreographer.getSfInstance());
             if (mRegistrationListener != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
index f3789fd..fa0f092 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
@@ -95,6 +95,8 @@
                 final FrameCallbackScheduler scheduler = new FrameCallbackScheduler() {
                     @Override
                     public void postFrameCallback(@androidx.annotation.NonNull Runnable runnable) {
+                        // TODO(b/222697646): remove getSfInstance usage and use vsyncId for
+                        //  transactions
                         Choreographer.getSfInstance().postFrameCallback(t -> runnable.run());
                     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
index c816f18..abf1a95 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
@@ -625,6 +625,7 @@
 
     class PipResizeInputEventReceiver extends BatchedInputEventReceiver {
         PipResizeInputEventReceiver(InputChannel channel, Looper looper) {
+            // TODO(b/222697646): remove getSfInstance usage and use vsyncId for transactions
             super(channel, looper, Choreographer.getSfInstance());
         }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
index 72b93480..d6dacd1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
@@ -30,17 +30,18 @@
 import android.graphics.Rect;
 import android.os.SystemClock;
 import android.util.ArraySet;
-import android.util.Log;
 import android.util.Size;
 import android.view.Gravity;
 
 import androidx.annotation.NonNull;
 
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.R;
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.pip.PipSnapAlgorithm;
 import com.android.wm.shell.pip.tv.TvPipKeepClearAlgorithm.Placement;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
 
 import java.util.Set;
 
@@ -90,7 +91,10 @@
     /** Returns the destination bounds to place the PIP window on entry. */
     @Override
     public Rect getEntryDestinationBounds() {
-        if (DEBUG) Log.d(TAG, "getEntryDestinationBounds()");
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: getEntryDestinationBounds()", TAG);
+        }
         if (mTvPipBoundsState.isTvExpandedPipSupported()
                 && mTvPipBoundsState.getDesiredTvExpandedAspectRatio() != 0
                 && !mTvPipBoundsState.isTvPipManuallyCollapsed()) {
@@ -104,7 +108,10 @@
     /** Returns the current bounds adjusted to the new aspect ratio, if valid. */
     @Override
     public Rect getAdjustedDestinationBounds(Rect currentBounds, float newAspectRatio) {
-        if (DEBUG) Log.d(TAG, "getAdjustedDestinationBounds: " + newAspectRatio);
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: getAdjustedDestinationBounds: %f", TAG, newAspectRatio);
+        }
         return getTvPipBounds().getBounds();
     }
 
@@ -122,7 +129,11 @@
         Set<Rect> unrestrictedKeepClearAreas = mTvPipBoundsState.getUnrestrictedKeepClearAreas();
 
         if (mTvPipBoundsState.isImeShowing()) {
-            if (DEBUG) Log.d(TAG, "IME showing, height: " + mTvPipBoundsState.getImeHeight());
+            if (DEBUG) {
+                ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                        "%s: IME showing, height: %d",
+                        TAG, mTvPipBoundsState.getImeHeight());
+            }
 
             final Rect imeBounds = new Rect(
                     0,
@@ -145,15 +156,22 @@
                 unrestrictedKeepClearAreas);
 
         if (DEBUG) {
-            Log.d(TAG, "pipSize: " + pipSize);
-            Log.d(TAG, "screenSize: " + screenSize);
-            Log.d(TAG, "stashOffset: " + mTvPipBoundsState.getStashOffset());
-            Log.d(TAG, "insetBounds: " + insetBounds.toShortString());
-            Log.d(TAG, "pipSize: " + pipSize);
-            Log.d(TAG, "gravity: " + Gravity.toString(mTvPipBoundsState.getTvPipGravity()));
-            Log.d(TAG, "restrictedKeepClearAreas: " + restrictedKeepClearAreas);
-            Log.d(TAG, "unrestrictedKeepClearAreas: " + unrestrictedKeepClearAreas);
-            Log.d(TAG, "placement: " + placement);
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: screenSize: %s", TAG, screenSize);
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: stashOffset: %d", TAG, mTvPipBoundsState.getStashOffset());
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: insetBounds: %s", TAG, insetBounds.toShortString());
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: pipSize: %s", TAG, pipSize);
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: gravity: %s", TAG, Gravity.toString(mTvPipBoundsState.getTvPipGravity()));
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: restrictedKeepClearAreas: %s", TAG, restrictedKeepClearAreas);
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: unrestrictedKeepClearAreas: %s", TAG, unrestrictedKeepClearAreas);
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: placement: %s", TAG, placement);
         }
 
         return placement;
@@ -164,9 +182,11 @@
      */
     int updateGravityOnExpandToggled(int previousGravity, boolean expanding) {
         if (DEBUG) {
-            Log.d(TAG, "updateGravityOnExpandToggled(), expanding: " + expanding
-                    + ", mOrientation: " + mTvPipBoundsState.getTvFixedPipOrientation()
-                    + ", previous gravity: " + Gravity.toString(previousGravity));
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: updateGravityOnExpandToggled(), expanding: %b"
+                    + ", mOrientation: %d, previous gravity: %s",
+                    TAG, expanding, mTvPipBoundsState.getTvFixedPipOrientation(),
+                    Gravity.toString(previousGravity));
         }
 
         if (!mTvPipBoundsState.isTvExpandedPipSupported()) {
@@ -218,7 +238,10 @@
             }
         }
         mTvPipBoundsState.setTvPipGravity(updatedGravity);
-        if (DEBUG) Log.d(TAG, "new gravity: " + Gravity.toString(updatedGravity));
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: new gravity: %s", TAG, Gravity.toString(updatedGravity));
+        }
 
         return gravityToSave;
     }
@@ -227,7 +250,10 @@
      * @return true if gravity changed
      */
     boolean updateGravity(int keycode) {
-        if (DEBUG) Log.d(TAG, "updateGravity, keycode: " + keycode);
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: updateGravity, keycode: %d", TAG, keycode);
+        }
 
         // Check if position change is valid
         if (mTvPipBoundsState.isTvPipExpanded()) {
@@ -284,7 +310,10 @@
 
         if (updatedGravity != currentGravity) {
             mTvPipBoundsState.setTvPipGravity(updatedGravity);
-            if (DEBUG) Log.d(TAG, "new gravity: " + Gravity.toString(updatedGravity));
+            if (DEBUG) {
+                ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                        "%s: new gravity: %s", TAG, Gravity.toString(updatedGravity));
+            }
             return true;
         }
         return false;
@@ -313,7 +342,9 @@
 
         final Size expandedSize;
         if (expandedRatio == 0) {
-            Log.d(TAG, "updateExpandedPipSize(): Expanded mode aspect ratio of 0 not supported");
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                       "%s: updateExpandedPipSize(): Expanded mode aspect ratio"
+                               + " of 0 not supported", TAG);
             return;
         } else if (expandedRatio < 1) {
             // vertical
@@ -324,10 +355,16 @@
                 float aspectRatioHeight = mFixedExpandedWidthInPx / expandedRatio;
 
                 if (maxHeight > aspectRatioHeight) {
-                    if (DEBUG) Log.d(TAG, "Accommodate aspect ratio");
+                    if (DEBUG) {
+                        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                                "%s: Accommodate aspect ratio", TAG);
+                    }
                     expandedSize = new Size(mFixedExpandedWidthInPx, (int) aspectRatioHeight);
                 } else {
-                    if (DEBUG) Log.d(TAG, "Aspect ratio is too extreme, use max size");
+                    if (DEBUG) {
+                        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                                "%s: Aspect ratio is too extreme, use max size", TAG);
+                    }
                     expandedSize = new Size(mFixedExpandedWidthInPx, maxHeight);
                 }
             }
@@ -339,10 +376,16 @@
                 int maxWidth = displayLayout.width() - (2 * mScreenEdgeInsets.x);
                 float aspectRatioWidth = mFixedExpandedHeightInPx * expandedRatio;
                 if (maxWidth > aspectRatioWidth) {
-                    if (DEBUG) Log.d(TAG, "Accommodate aspect ratio");
+                    if (DEBUG) {
+                        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                                "%s: Accommodate aspect ratio", TAG);
+                    }
                     expandedSize = new Size((int) aspectRatioWidth, mFixedExpandedHeightInPx);
                 } else {
-                    if (DEBUG) Log.d(TAG, "Aspect ratio is too extreme, use max size");
+                    if (DEBUG) {
+                        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                                "%s: Aspect ratio is too extreme, use max size", TAG);
+                    }
                     expandedSize = new Size(maxWidth, mFixedExpandedHeightInPx);
                 }
             }
@@ -350,8 +393,9 @@
 
         mTvPipBoundsState.setTvExpandedSize(expandedSize);
         if (DEBUG) {
-            Log.d(TAG, "updateExpandedPipSize(): expanded size, width=" + expandedSize.getWidth()
-                    + ", height=" + expandedSize.getHeight());
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                       "%s: updateExpandedPipSize(): expanded size, width: %d, height: %d",
+                    TAG, expandedSize.getWidth(), expandedSize.getHeight());
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java
index d880f82..9865548 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java
@@ -75,7 +75,7 @@
     public void setBoundsStateForEntry(ComponentName componentName, ActivityInfo activityInfo,
             PictureInPictureParams params, PipBoundsAlgorithm pipBoundsAlgorithm) {
         super.setBoundsStateForEntry(componentName, activityInfo, params, pipBoundsAlgorithm);
-        setDesiredTvExpandedAspectRatio(params.getExpandedAspectRatio(), true);
+        setDesiredTvExpandedAspectRatio(params.getExpandedAspectRatioFloat(), true);
     }
 
     /** Resets the TV PiP state for a new activity. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
index 03c5e98..46b8e60 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
@@ -22,6 +22,7 @@
 import android.annotation.IntDef;
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
+import android.app.PendingIntent;
 import android.app.RemoteAction;
 import android.app.TaskInfo;
 import android.content.ComponentName;
@@ -32,9 +33,9 @@
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.RemoteException;
-import android.util.Log;
 import android.view.Gravity;
 
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.R;
 import com.android.wm.shell.WindowManagerShellWrapper;
 import com.android.wm.shell.common.DisplayController;
@@ -50,6 +51,7 @@
 import com.android.wm.shell.pip.PipTaskOrganizer;
 import com.android.wm.shell.pip.PipTransitionController;
 import com.android.wm.shell.pip.tv.TvPipKeepClearAlgorithm.Placement;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -68,7 +70,7 @@
     private static final int NONEXISTENT_TASK_ID = -1;
 
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = { "STATE_" }, value = {
+    @IntDef(prefix = {"STATE_"}, value = {
             STATE_NO_PIP,
             STATE_PIP,
             STATE_PIP_MENU,
@@ -108,6 +110,10 @@
     private int mPinnedTaskId = NONEXISTENT_TASK_ID;
     private Runnable mUnstashRunnable;
 
+    private RemoteAction mCloseAction;
+    // How long the shell will wait for the app to close the PiP if a custom action is set.
+    private int mPipForceCloseDelay;
+
     private int mResizeAnimationDuration;
 
     public static Pip create(
@@ -182,10 +188,16 @@
     }
 
     private void onConfigurationChanged(Configuration newConfig) {
-        if (DEBUG) Log.d(TAG, "onConfigurationChanged(), state=" + stateToName(mState));
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: onConfigurationChanged(), state=%s", TAG, stateToName(mState));
+        }
 
         if (isPipShown()) {
-            if (DEBUG) Log.d(TAG, "  > closing Pip.");
+            if (DEBUG) {
+                ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                        "%s:  > closing Pip.", TAG);
+            }
             closePip();
         }
 
@@ -208,20 +220,30 @@
      */
     @Override
     public void showPictureInPictureMenu() {
-        if (DEBUG) Log.d(TAG, "showPictureInPictureMenu(), state=" + stateToName(mState));
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: showPictureInPictureMenu(), state=%s", TAG, stateToName(mState));
+        }
 
         if (mState == STATE_NO_PIP) {
-            if (DEBUG) Log.d(TAG, "  > cannot open Menu from the current state.");
+            if (DEBUG) {
+                ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                        "%s:  > cannot open Menu from the current state.", TAG);
+            }
             return;
         }
 
         setState(STATE_PIP_MENU);
+        mTvPipMenuController.showMenu();
         updatePinnedStackBounds();
     }
 
     @Override
-    public void closeMenu() {
-        if (DEBUG) Log.d(TAG, "closeMenu(), state before=" + stateToName(mState));
+    public void onMenuClosed() {
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: closeMenu(), state before=%s", TAG, stateToName(mState));
+        }
         setState(STATE_PIP);
         mTvPipBoundsAlgorithm.keepUnstashedForCurrentKeepClearAreas();
         updatePinnedStackBounds();
@@ -237,7 +259,10 @@
      */
     @Override
     public void movePipToFullscreen() {
-        if (DEBUG) Log.d(TAG, "movePipToFullscreen(), state=" + stateToName(mState));
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: movePipToFullscreen(), state=%s", TAG, stateToName(mState));
+        }
 
         mPipTaskOrganizer.exitPip(mResizeAnimationDuration, false /* requestEnterSplit */);
         onPipDisappeared();
@@ -245,7 +270,10 @@
 
     @Override
     public void togglePipExpansion() {
-        if (DEBUG) Log.d(TAG, "togglePipExpansion()");
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: togglePipExpansion()", TAG);
+        }
         boolean expanding = !mTvPipBoundsState.isTvPipExpanded();
         int saveGravity = mTvPipBoundsAlgorithm
                 .updateGravityOnExpandToggled(mPreviousGravity, expanding);
@@ -258,13 +286,22 @@
     }
 
     @Override
+    public void enterPipMovementMenu() {
+        setState(STATE_PIP_MENU);
+        mTvPipMenuController.showMovementMenuOnly();
+    }
+
+    @Override
     public void movePip(int keycode) {
         if (mTvPipBoundsAlgorithm.updateGravity(keycode)) {
             mTvPipMenuController.updateGravity(mTvPipBoundsState.getTvPipGravity());
             mPreviousGravity = Gravity.NO_GRAVITY;
             updatePinnedStackBounds();
         } else {
-            if (DEBUG) Log.d(TAG, "Position hasn't changed");
+            if (DEBUG) {
+                ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                        "%s: Position hasn't changed", TAG);
+            }
         }
     }
 
@@ -323,10 +360,16 @@
 
     /** Animates the PiP to the given bounds. */
     private void movePinnedStackTo(Rect bounds) {
-        if (DEBUG) Log.d(TAG, "movePinnedStackTo() - new pip bounds: " + bounds.toShortString());
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: movePinnedStack() - new pip bounds: %s", TAG, bounds.toShortString());
+        }
         mPipTaskOrganizer.scheduleAnimateResizePip(bounds,
                 mResizeAnimationDuration, rect -> {
-                    if (DEBUG) Log.d(TAG, "movePinnedStack() animation done");
+                    if (DEBUG) {
+                        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                                "%s: movePinnedStack() animation done", TAG);
+                    }
                     mTvPipMenuController.updateExpansionState();
                 });
     }
@@ -336,8 +379,31 @@
      */
     @Override
     public void closePip() {
-        if (DEBUG) Log.d(TAG, "closePip(), state=" + stateToName(mState));
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: closePip(), state=%s, loseAction=%s", TAG, stateToName(mState),
+                    mCloseAction);
+        }
 
+        if (mCloseAction != null) {
+            try {
+                mCloseAction.getActionIntent().send();
+            } catch (PendingIntent.CanceledException e) {
+                ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                        "%s: Failed to send close action, %s", TAG, e);
+            }
+            mMainExecutor.executeDelayed(() -> closeCurrentPiP(mPinnedTaskId), mPipForceCloseDelay);
+        } else {
+            closeCurrentPiP(mPinnedTaskId);
+        }
+    }
+
+    private void closeCurrentPiP(int pinnedTaskId) {
+        if (mPinnedTaskId != pinnedTaskId) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: PiP has already been closed by custom close action", TAG);
+            return;
+        }
         removeTask(mPinnedTaskId);
         onPipDisappeared();
     }
@@ -348,7 +414,10 @@
 
     private void checkIfPinnedTaskAppeared() {
         final TaskInfo pinnedTask = getPinnedTaskInfo();
-        if (DEBUG) Log.d(TAG, "checkIfPinnedTaskAppeared(), task=" + pinnedTask);
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: checkIfPinnedTaskAppeared(), task=%s", TAG, pinnedTask);
+        }
         if (pinnedTask == null || pinnedTask.topActivity == null) return;
         mPinnedTaskId = pinnedTask.taskId;
 
@@ -357,19 +426,26 @@
     }
 
     private void checkIfPinnedTaskIsGone() {
-        if (DEBUG) Log.d(TAG, "onTaskStackChanged()");
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: onTaskStackChanged()", TAG);
+        }
 
         if (isPipShown() && getPinnedTaskInfo() == null) {
-            Log.w(TAG, "Pinned task is gone.");
+            ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: Pinned task is gone.", TAG);
             onPipDisappeared();
         }
     }
 
     private void onPipDisappeared() {
-        if (DEBUG) Log.d(TAG, "onPipDisappeared() state=" + stateToName(mState));
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: onPipDisappeared() state=%s", TAG, stateToName(mState));
+        }
 
         mPipNotificationController.dismiss();
-        mTvPipMenuController.hideMenu();
+        mTvPipMenuController.closeMenu();
         mTvPipBoundsState.resetTvPipState();
         setState(STATE_NO_PIP);
         mPinnedTaskId = NONEXISTENT_TASK_ID;
@@ -377,12 +453,18 @@
 
     @Override
     public void onPipTransitionStarted(int direction, Rect pipBounds) {
-        if (DEBUG) Log.d(TAG, "onPipTransition_Started(), state=" + stateToName(mState));
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: onPipTransition_Started(), state=%s", TAG, stateToName(mState));
+        }
     }
 
     @Override
     public void onPipTransitionCanceled(int direction) {
-        if (DEBUG) Log.d(TAG, "onPipTransition_Canceled(), state=" + stateToName(mState));
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: onPipTransition_Canceled(), state=%s", TAG, stateToName(mState));
+        }
     }
 
     @Override
@@ -390,27 +472,25 @@
         if (PipAnimationController.isInPipDirection(direction) && mState == STATE_NO_PIP) {
             setState(STATE_PIP);
         }
-        if (DEBUG) Log.d(TAG, "onPipTransition_Finished(), state=" + stateToName(mState));
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: onPipTransition_Finished(), state=%s", TAG, stateToName(mState));
+        }
     }
 
     private void setState(@State int state) {
         if (DEBUG) {
-            Log.d(TAG, "setState(), state=" + stateToName(state) + ", prev="
-                    + stateToName(mState));
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: setState(), state=%s, prev=%s",
+                    TAG, stateToName(state), stateToName(mState));
         }
         mState = state;
-
-        if (mState == STATE_PIP_MENU) {
-            if (DEBUG) Log.d(TAG, "  > show menu");
-            mTvPipMenuController.showMenu();
-        }
-
-        updatePinnedStackBounds();
     }
 
     private void loadConfigurations() {
         final Resources res = mContext.getResources();
         mResizeAnimationDuration = res.getInteger(R.integer.config_pipResizeAnimationDuration);
+        mPipForceCloseDelay = res.getInteger(R.integer.config_pipForceCloseDelay);
     }
 
     private void registerTaskStackListenerCallback(TaskStackListenerImpl taskStackListener) {
@@ -429,7 +509,10 @@
             public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
                     boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
                 if (task.getWindowingMode() == WINDOWING_MODE_PINNED) {
-                    if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()");
+                    if (DEBUG) {
+                        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                                "%s: onPinnedActivityRestartAttempt()", TAG);
+                    }
 
                     // If the "Pip-ed" Activity is launched again by Launcher or intent, make it
                     // fullscreen.
@@ -445,8 +528,9 @@
                 @Override
                 public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
                     if (DEBUG) {
-                        Log.d(TAG, "onImeVisibilityChanged(), visible=" + imeVisible
-                                + ", height=" + imeHeight);
+                        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                                "%s: onImeVisibilityChanged(), visible=%b, height=%d",
+                                TAG, imeVisible, imeHeight);
                     }
 
                     if (imeVisible == mTvPipBoundsState.isImeShowing()
@@ -464,7 +548,10 @@
 
                 @Override
                 public void onAspectRatioChanged(float ratio) {
-                    if (DEBUG) Log.d(TAG, "onAspectRatioChanged: " + ratio);
+                    if (DEBUG) {
+                        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                                "%s: onAspectRatioChanged: %f", TAG, ratio);
+                    }
 
                     boolean ratioChanged = mTvPipBoundsState.getAspectRatio() != ratio;
                     mTvPipBoundsState.setAspectRatio(ratio);
@@ -476,7 +563,10 @@
 
                 @Override
                 public void onExpandedAspectRatioChanged(float ratio) {
-                    if (DEBUG) Log.d(TAG, "onExpandedAspectRatioChanged: " + ratio);
+                    if (DEBUG) {
+                        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                                "%s: onExpandedAspectRatioChanged: %f", TAG, ratio);
+                    }
 
                     // 0) No update to the ratio --> don't do anything
 
@@ -525,36 +615,53 @@
                 public void onMovementBoundsChanged(boolean fromImeAdjustment) {}
 
                 @Override
-                public void onActionsChanged(ParceledListSlice<RemoteAction> actions) {
-                    if (DEBUG) Log.d(TAG, "onActionsChanged()");
+                public void onActionsChanged(ParceledListSlice<RemoteAction> actions,
+                        RemoteAction closeAction) {
+                    if (DEBUG) {
+                        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                                "%s: onActionsChanged()", TAG);
+                    }
 
-                    mTvPipMenuController.setAppActions(actions);
+                    mTvPipMenuController.setAppActions(actions, closeAction);
+                    mCloseAction = closeAction;
                 }
             });
         } catch (RemoteException e) {
-            Log.e(TAG, "Failed to register pinned stack listener", e);
+            ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: Failed to register pinned stack listener, %s", TAG, e);
         }
     }
 
     private static TaskInfo getPinnedTaskInfo() {
-        if (DEBUG) Log.d(TAG, "getPinnedTaskInfo()");
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: getPinnedTaskInfo()", TAG);
+        }
         try {
             final TaskInfo taskInfo = ActivityTaskManager.getService().getRootTaskInfo(
                     WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
-            if (DEBUG) Log.d(TAG, "  > taskInfo=" + taskInfo);
+            if (DEBUG) {
+                ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                        "%s: taskInfo=%s", TAG, taskInfo);
+            }
             return taskInfo;
         } catch (RemoteException e) {
-            Log.e(TAG, "getRootTaskInfo() failed", e);
+            ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: getRootTaskInfo() failed, %s", TAG, e);
             return null;
         }
     }
 
     private static void removeTask(int taskId) {
-        if (DEBUG) Log.d(TAG, "removeTask(), taskId=" + taskId);
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: removeTask(), taskId=%d", TAG, taskId);
+        }
         try {
             ActivityTaskManager.getService().removeTask(taskId);
         } catch (Exception e) {
-            Log.e(TAG, "Atm.removeTask() failed", e);
+            ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: Atm.removeTask() failed, %s", TAG, e);
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuActionButton.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuActionButton.java
index 4eb46d9..abbc614 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuActionButton.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuActionButton.java
@@ -126,4 +126,15 @@
     public boolean isEnabled() {
         return mButtonView.isEnabled();
     }
+
+    void setIsCustomCloseAction(boolean isCustomCloseAction) {
+        mIconImageView.setImageTintList(
+                getResources().getColorStateList(
+                        isCustomCloseAction ? R.color.tv_pip_menu_close_icon
+                                : R.color.tv_pip_menu_icon));
+        mButtonView.setBackgroundTintList(getResources()
+                .getColorStateList(isCustomCloseAction ? R.color.tv_pip_menu_close_icon_bg
+                        : R.color.tv_pip_menu_icon_bg));
+    }
+
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
index b3c2306..35c34ac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
@@ -30,20 +30,22 @@
 import android.graphics.RectF;
 import android.os.Handler;
 import android.os.RemoteException;
-import android.util.Log;
 import android.view.SurfaceControl;
 import android.view.SyncRtSurfaceTransactionApplier;
 import android.view.WindowManagerGlobal;
 
 import androidx.annotation.Nullable;
 
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.R;
 import com.android.wm.shell.common.SystemWindows;
 import com.android.wm.shell.pip.PipMediaController;
 import com.android.wm.shell.pip.PipMenuController;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Manages the visibility of the PiP Menu as user interacts with PiP.
@@ -63,9 +65,13 @@
 
     // User can actively move the PiP via the DPAD.
     private boolean mInMoveMode;
+    // Used when only showing the move menu since we want to close the menu completely when
+    // exiting the move menu instead of showing the regular button menu.
+    private boolean mCloseAfterExitMoveMenu;
 
     private final List<RemoteAction> mMediaActions = new ArrayList<>();
     private final List<RemoteAction> mAppActions = new ArrayList<>();
+    private RemoteAction mCloseAction;
 
     private SyncRtSurfaceTransactionApplier mApplier;
     RectF mTmpSourceRectF = new RectF();
@@ -99,7 +105,7 @@
         final BroadcastReceiver closeSystemDialogsBroadcastReceiver = new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
-                hideMenu();
+                closeMenu();
             }
         };
         context.registerReceiverForAllUsers(closeSystemDialogsBroadcastReceiver,
@@ -110,7 +116,10 @@
     }
 
     void setDelegate(Delegate delegate) {
-        if (DEBUG) Log.d(TAG, "setDelegate(), delegate=" + delegate);
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: setDelegate(), delegate=%s", TAG, delegate);
+        }
         if (mDelegate != null) {
             throw new IllegalStateException(
                     "The delegate has already been set and should not change.");
@@ -133,7 +142,10 @@
     }
 
     private void attachPipMenuView() {
-        if (DEBUG) Log.d(TAG, "attachPipMenuView()");
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: attachPipMenuView()", TAG);
+        }
 
         if (mPipMenuView != null) {
             detachPipMenuView();
@@ -146,26 +158,49 @@
                 0, SHELL_ROOT_LAYER_PIP);
     }
 
+    void showMovementMenuOnly() {
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: showMovementMenuOnly()", TAG);
+        }
+        mInMoveMode = true;
+        mCloseAfterExitMoveMenu = true;
+        showMenuInternal();
+    }
+
     @Override
     public void showMenu() {
-        if (DEBUG) Log.d(TAG, "showMenu()");
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: showMenu()", TAG);
+        }
+        mInMoveMode = false;
+        mCloseAfterExitMoveMenu = false;
+        showMenuInternal();
+    }
 
-        if (mPipMenuView != null) {
-            Rect menuBounds = getMenuBounds(mTvPipBoundsState.getBounds());
-            mSystemWindows.updateViewLayout(mPipMenuView, getPipMenuLayoutParams(
-                    MENU_WINDOW_TITLE, menuBounds.width(), menuBounds.height()));
-            maybeUpdateMenuViewActions();
-            updateExpansionState();
+    private void showMenuInternal() {
+        if (mPipMenuView == null) {
+            return;
+        }
+        Rect menuBounds = getMenuBounds(mTvPipBoundsState.getBounds());
+        mSystemWindows.updateViewLayout(mPipMenuView, getPipMenuLayoutParams(
+                MENU_WINDOW_TITLE, menuBounds.width(), menuBounds.height()));
+        maybeUpdateMenuViewActions();
+        updateExpansionState();
 
-            SurfaceControl menuSurfaceControl = getSurfaceControl();
-            if (menuSurfaceControl != null) {
-                SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-                t.setRelativeLayer(mPipMenuView.getWindowSurfaceControl(), mLeash, 1);
-                t.setPosition(menuSurfaceControl, menuBounds.left, menuBounds.top);
-                t.apply();
-            }
-            grantPipMenuFocus(true);
-            mPipMenuView.show(mInMoveMode, mDelegate.getPipGravity());
+        SurfaceControl menuSurfaceControl = getSurfaceControl();
+        if (menuSurfaceControl != null) {
+            SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+            t.setRelativeLayer(mPipMenuView.getWindowSurfaceControl(), mLeash, 1);
+            t.setPosition(menuSurfaceControl, menuBounds.left, menuBounds.top);
+            t.apply();
+        }
+        grantPipMenuFocus(true);
+        if (mInMoveMode) {
+            mPipMenuView.showMoveMenu(mDelegate.getPipGravity());
+        } else {
+            mPipMenuView.showButtonMenu();
         }
     }
 
@@ -187,19 +222,18 @@
         return menuBounds;
     }
 
-    void hideMenu() {
-        if (!isMenuVisible()) {
-            if (DEBUG) Log.d(TAG, "hideMenu() - Menu isn't visible, so don't hide");
+    void closeMenu() {
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: closeMenu()", TAG);
+        }
+        if (mPipMenuView == null) {
             return;
-        } else {
-            if (DEBUG) Log.d(TAG, "hideMenu()");
         }
 
-        mPipMenuView.hide();
-        if (!mInMoveMode) {
-            grantPipMenuFocus(false);
-            mDelegate.closeMenu();
-        }
+        mPipMenuView.hideAll();
+        grantPipMenuFocus(false);
+        mDelegate.onMenuClosed();
     }
 
     boolean isInMoveMode() {
@@ -208,21 +242,31 @@
 
     @Override
     public void onEnterMoveMode() {
-        if (DEBUG) Log.d(TAG, "onEnterMoveMode - " + mInMoveMode);
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: onEnterMoveMode - %b, close when exiting move menu: %b", TAG, mInMoveMode,
+                    mCloseAfterExitMoveMenu);
+        }
         mInMoveMode = true;
-        mPipMenuView.showMenuButtons(false);
-        mPipMenuView.showMovementHints(mDelegate.getPipGravity());
-        mDelegate.onInMoveModeChanged();
+        mPipMenuView.showMoveMenu(mDelegate.getPipGravity());
     }
 
     @Override
     public boolean onExitMoveMode() {
-        if (DEBUG) Log.d(TAG, "onExitMoveMode - " + mInMoveMode);
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: onExitMoveMode - %b, close when exiting move menu: %b", TAG, mInMoveMode,
+                    mCloseAfterExitMoveMenu);
+        }
+        if (mCloseAfterExitMoveMenu) {
+            mInMoveMode = false;
+            mCloseAfterExitMoveMenu = false;
+            closeMenu();
+            return true;
+        }
         if (mInMoveMode) {
             mInMoveMode = false;
-            mPipMenuView.showMenuButtons(true);
-            mPipMenuView.hideMovementHints();
-            mDelegate.onInMoveModeChanged();
+            mPipMenuView.showButtonMenu();
             return true;
         }
         return false;
@@ -230,7 +274,10 @@
 
     @Override
     public boolean onPipMovement(int keycode) {
-        if (DEBUG) Log.d(TAG, "onPipMovement - " + mInMoveMode);
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: onPipMovement - %b", TAG, mInMoveMode);
+        }
         if (mInMoveMode) {
             mDelegate.movePip(keycode);
         }
@@ -239,19 +286,25 @@
 
     @Override
     public void detach() {
-        hideMenu();
+        closeMenu();
         detachPipMenuView();
         mLeash = null;
     }
 
     @Override
-    public void setAppActions(ParceledListSlice<RemoteAction> actions) {
-        if (DEBUG) Log.d(TAG, "setAppActions()");
-        updateAdditionalActionsList(mAppActions, actions.getList());
+    public void setAppActions(ParceledListSlice<RemoteAction> actions, RemoteAction closeAction) {
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: setAppActions()", TAG);
+        }
+        updateAdditionalActionsList(mAppActions, actions.getList(), closeAction);
     }
 
     private void onMediaActionsChanged(List<RemoteAction> actions) {
-        if (DEBUG) Log.d(TAG, "onMediaActionsChanged()");
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: onMediaActionsChanged()", TAG);
+        }
 
         // Hide disabled actions.
         List<RemoteAction> enabledActions = new ArrayList<>();
@@ -260,17 +313,19 @@
                 enabledActions.add(remoteAction);
             }
         }
-        updateAdditionalActionsList(mMediaActions, enabledActions);
+        updateAdditionalActionsList(mMediaActions, enabledActions, mCloseAction);
     }
 
-    private void updateAdditionalActionsList(
-            List<RemoteAction> destination, @Nullable List<RemoteAction> source) {
+    private void updateAdditionalActionsList(List<RemoteAction> destination,
+            @Nullable List<RemoteAction> source, RemoteAction closeAction) {
         final int number = source != null ? source.size() : 0;
-        if (number == 0 && destination.isEmpty()) {
+        if (number == 0 && destination.isEmpty() && Objects.equals(closeAction, mCloseAction)) {
             // Nothing changed.
             return;
         }
 
+        mCloseAction = closeAction;
+
         destination.clear();
         if (number > 0) {
             destination.addAll(source);
@@ -283,16 +338,19 @@
             return;
         }
         if (!mAppActions.isEmpty()) {
-            mPipMenuView.setAdditionalActions(mAppActions, mMainHandler);
+            mPipMenuView.setAdditionalActions(mAppActions, mCloseAction, mMainHandler);
         } else {
-            mPipMenuView.setAdditionalActions(mMediaActions, mMainHandler);
+            mPipMenuView.setAdditionalActions(mMediaActions, mCloseAction, mMainHandler);
         }
     }
 
     @Override
     public boolean isMenuVisible() {
         boolean isVisible = mPipMenuView != null && mPipMenuView.isVisible();
-        if (DEBUG) Log.d(TAG, "isMenuVisible: " + isVisible);
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: isMenuVisible: %b", TAG, isVisible);
+        }
         return isVisible;
     }
 
@@ -303,7 +361,10 @@
     public void resizePipMenu(@android.annotation.Nullable SurfaceControl pipLeash,
             @android.annotation.Nullable SurfaceControl.Transaction t,
             Rect destinationBounds) {
-        if (DEBUG) Log.d(TAG, "resizePipMenu: " + destinationBounds.toShortString());
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: resizePipMenu: %s", TAG, destinationBounds.toShortString());
+        }
         if (destinationBounds.isEmpty()) {
             return;
         }
@@ -335,10 +396,16 @@
     @Override
     public void movePipMenu(SurfaceControl pipLeash, SurfaceControl.Transaction transaction,
             Rect pipDestBounds) {
-        if (DEBUG) Log.d(TAG, "movePipMenu: " + pipDestBounds.toShortString());
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: movePipMenu: %s", TAG, pipDestBounds.toShortString());
+        }
 
         if (pipDestBounds.isEmpty()) {
-            if (transaction == null && DEBUG) Log.d(TAG, "no transaction given");
+            if (transaction == null && DEBUG) {
+                ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                        "%s: no transaction given", TAG);
+            }
             return;
         }
         if (!maybeCreateSyncApplier()) {
@@ -351,10 +418,16 @@
         // resizing and the PiP menu is also resized. We then want to do a scale from the current
         // new menu bounds.
         if (pipLeash != null && transaction != null) {
-            if (DEBUG) Log.d(TAG, "mTmpSourceBounds based on mPipMenuView.getBoundsOnScreen()");
+            if (DEBUG) {
+                ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                        "%s: mTmpSourceBounds based on mPipMenuView.getBoundsOnScreen()", TAG);
+            }
             mPipMenuView.getBoundsOnScreen(mTmpSourceBounds);
         } else {
-            if (DEBUG) Log.d(TAG, "mTmpSourceBounds based on menu width and height");
+            if (DEBUG) {
+                ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                        "%s: mTmpSourceBounds based on menu width and height", TAG);
+            }
             mTmpSourceBounds.set(0, 0, menuDestBounds.width(), menuDestBounds.height());
         }
 
@@ -389,7 +462,8 @@
 
     private boolean maybeCreateSyncApplier() {
         if (mPipMenuView == null || mPipMenuView.getViewRootImpl() == null) {
-            Log.v(TAG, "Not going to move PiP, either menu or its parent is not created.");
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: Not going to move PiP, either menu or its parent is not created.", TAG);
             return false;
         }
 
@@ -412,7 +486,10 @@
     @Override
     public void updateMenuBounds(Rect destinationBounds) {
         Rect menuBounds = getMenuBounds(destinationBounds);
-        if (DEBUG) Log.d(TAG, "updateMenuBounds: " + menuBounds.toShortString());
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: updateMenuBounds: %s", TAG, menuBounds.toShortString());
+        }
         mSystemWindows.updateViewLayout(mPipMenuView,
                 getPipMenuLayoutParams(MENU_WINDOW_TITLE, menuBounds.width(),
                         menuBounds.height()));
@@ -423,13 +500,13 @@
 
     @Override
     public void onFocusTaskChanged(ActivityManager.RunningTaskInfo taskInfo) {
-        Log.d(TAG, "onFocusTaskChanged");
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: onFocusTaskChanged", TAG);
     }
 
     @Override
     public void onBackPress() {
         if (!onExitMoveMode()) {
-            hideMenu();
+            closeMenu();
         }
     }
 
@@ -459,19 +536,23 @@
 
         void togglePipExpansion();
 
-        void closeMenu();
+        void onMenuClosed();
 
         void closePip();
     }
 
     private void grantPipMenuFocus(boolean grantFocus) {
-        if (DEBUG) Log.d(TAG, "grantWindowFocus(" + grantFocus + ")");
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: grantWindowFocus(%b)", TAG, grantFocus);
+        }
 
         try {
             WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
                     mSystemWindows.getFocusGrantToken(mPipMenuView), grantFocus);
         } catch (Exception e) {
-            Log.e(TAG, "Unable to update focus", e);
+            ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: Unable to update focus, %s", TAG, e);
         }
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
index 3090139..ccd054a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
@@ -31,7 +31,6 @@
 import android.graphics.Rect;
 import android.os.Handler;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.SurfaceControl;
@@ -45,10 +44,13 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.R;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * A View that represents Pip Menu on TV. It's responsible for displaying 3 ever-present Pip Menu
@@ -77,6 +79,7 @@
     private Rect mCurrentBounds;
 
     private final TvPipMenuActionButton mExpandButton;
+    private final TvPipMenuActionButton mCloseButton;
 
     public TvPipMenuView(@NonNull Context context) {
         this(context, null);
@@ -99,8 +102,11 @@
         mActionButtonsContainer = findViewById(R.id.tv_pip_menu_action_buttons);
         mActionButtonsContainer.findViewById(R.id.tv_pip_menu_fullscreen_button)
                 .setOnClickListener(this);
-        mActionButtonsContainer.findViewById(R.id.tv_pip_menu_close_button)
-                .setOnClickListener(this);
+
+        mCloseButton = mActionButtonsContainer.findViewById(R.id.tv_pip_menu_close_button);
+        mCloseButton.setOnClickListener(this);
+        mCloseButton.setIsCustomCloseAction(true);
+
         mActionButtonsContainer.findViewById(R.id.tv_pip_menu_move_button)
                 .setOnClickListener(this);
         mExpandButton = findViewById(R.id.tv_pip_menu_expand_button);
@@ -118,17 +124,24 @@
     }
 
     void updateLayout(Rect updatedBounds) {
-        Log.d(TAG, "update menu layout: " + updatedBounds.toShortString());
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: update menu layout: %s", TAG, updatedBounds.toShortString());
         boolean previouslyVertical =
                 mCurrentBounds != null && mCurrentBounds.height() > mCurrentBounds.width();
         boolean vertical = updatedBounds.height() > updatedBounds.width();
 
         mCurrentBounds = updatedBounds;
         if (previouslyVertical == vertical) {
-            if (DEBUG) Log.d(TAG, "no update for menu layout");
+            if (DEBUG) {
+                ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                        "%s: no update for menu layout", TAG);
+            }
             return;
         } else {
-            if (DEBUG) Log.d(TAG, "change menu layout to vertical: " + vertical);
+            if (DEBUG) {
+                ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                        "%s: change menu layout to vertical: %b", TAG, vertical);
+            }
         }
 
         if (vertical) {
@@ -154,31 +167,53 @@
     }
 
     void setIsExpanded(boolean expanded) {
-        if (DEBUG) Log.d(TAG, "setIsExpanded, expanded: " + expanded);
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: setIsExpanded, expanded: %b", TAG, expanded);
+        }
         mExpandButton.setImageResource(
                 expanded ? R.drawable.pip_ic_collapse : R.drawable.pip_ic_expand);
         mExpandButton.setTextAndDescription(
                 expanded ? R.string.pip_collapse : R.string.pip_expand);
     }
 
-    void show(boolean inMoveMode, int gravity) {
-        if (DEBUG) Log.d(TAG, "show(), inMoveMode: " + inMoveMode);
-        if (inMoveMode) {
-            showMovementHints(gravity);
-        } else {
-            animateAlphaTo(1, mActionButtonsContainer);
+    /**
+     * @param gravity for the arrow hints
+     */
+    void showMoveMenu(int gravity) {
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: showMoveMenu()", TAG);
         }
-        animateAlphaTo(1, mMenuFrameView);
+        showMenuButtons(false);
+        showMovementHints(gravity);
+        showMenuFrame(true);
     }
 
-    void hide() {
-        if (DEBUG) Log.d(TAG, "hide()");
-        animateAlphaTo(0, mActionButtonsContainer);
-        animateAlphaTo(0, mMenuFrameView);
+    void showButtonMenu() {
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: showButtonMenu()", TAG);
+        }
+        showMenuButtons(true);
         hideMovementHints();
+        showMenuFrame(true);
+    }
+
+    /**
+     * Hides all menu views, including the menu frame.
+     */
+    void hideAll() {
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: hideAll()", TAG);
+        }
+        showMenuButtons(false);
+        hideMovementHints();
+        showMenuFrame(false);
     }
 
     private void animateAlphaTo(float alpha, View view) {
+        if (view.getAlpha() == alpha) {
+            return;
+        }
         view.animate()
                 .alpha(alpha)
                 .setInterpolator(alpha == 0f ? TvPipInterpolators.EXIT : TvPipInterpolators.ENTER)
@@ -204,8 +239,23 @@
                 || mArrowLeft.getAlpha() != 0f;
     }
 
-    void setAdditionalActions(List<RemoteAction> actions, Handler mainHandler) {
-        if (DEBUG) Log.d(TAG, "setAdditionalActions()");
+    void setAdditionalActions(List<RemoteAction> actions, RemoteAction closeAction,
+            Handler mainHandler) {
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: setAdditionalActions()", TAG);
+        }
+
+        // Replace system close action with custom close action if available
+        if (closeAction != null) {
+            setActionForButton(closeAction, mCloseButton, mainHandler);
+        } else {
+            mCloseButton.setTextAndDescription(R.string.pip_close);
+            mCloseButton.setImageResource(R.drawable.pip_ic_close_white);
+        }
+        mCloseButton.setIsCustomCloseAction(closeAction != null);
+        // Make sure the close action is always enabled
+        mCloseButton.setEnabled(true);
 
         // Make sure we exactly as many additional buttons as we have actions to display.
         final int actionsNumber = actions.size();
@@ -237,14 +287,37 @@
         for (int index = 0; index < actionsNumber; index++) {
             final RemoteAction action = actions.get(index);
             final TvPipMenuActionButton button = mAdditionalButtons.get(index);
-            button.setVisibility(View.VISIBLE); // Ensure the button is visible.
-            button.setTextAndDescription(action.getContentDescription());
-            button.setEnabled(action.isEnabled());
-            button.setTag(action);
-            action.getIcon().loadDrawableAsync(mContext, button::setImageDrawable, mainHandler);
+
+            // Remove action if it matches the custom close action.
+            if (actionsMatch(action, closeAction)) {
+                button.setVisibility(GONE);
+                continue;
+            }
+            setActionForButton(action, button, mainHandler);
         }
     }
 
+    /**
+     * Checks whether title, description and intent match.
+     * Comparing icons would be good, but using equals causes false negatives
+     */
+    private boolean actionsMatch(RemoteAction action1, RemoteAction action2) {
+        if (action1 == action2) return true;
+        if (action1 == null) return false;
+        return Objects.equals(action1.getTitle(), action2.getTitle())
+                && Objects.equals(action1.getContentDescription(), action2.getContentDescription())
+                && Objects.equals(action1.getActionIntent(), action2.getActionIntent());
+    }
+
+    private void setActionForButton(RemoteAction action, TvPipMenuActionButton button,
+            Handler mainHandler) {
+        button.setVisibility(View.VISIBLE); // Ensure the button is visible.
+        button.setTextAndDescription(action.getContentDescription());
+        button.setEnabled(action.isEnabled());
+        button.setTag(action);
+        action.getIcon().loadDrawableAsync(mContext, button::setImageDrawable, mainHandler);
+    }
+
     @Nullable
     SurfaceControl getWindowSurfaceControl() {
         final ViewRootImpl root = getViewRootImpl();
@@ -278,10 +351,12 @@
                 try {
                     action.getActionIntent().send();
                 } catch (PendingIntent.CanceledException e) {
-                    Log.w(TAG, "Failed to send action", e);
+                    ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                            "%s: Failed to send action, %s", TAG, e);
                 }
             } else {
-                Log.w(TAG, "RemoteAction is null");
+                ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                        "%s: RemoteAction is null", TAG);
             }
         }
     }
@@ -289,8 +364,9 @@
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
         if (DEBUG) {
-            Log.d(TAG, "dispatchKeyEvent, action: " + event.getAction()
-                    + ", keycode: " + event.getKeyCode());
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: dispatchKeyEvent, action: %d, keycode: %d",
+                    TAG, event.getAction(), event.getKeyCode());
         }
         if (mListener != null && event.getAction() == ACTION_UP) {
             switch (event.getKeyCode()) {
@@ -317,7 +393,10 @@
      * Shows user hints for moving the PiP, e.g. arrows.
      */
     public void showMovementHints(int gravity) {
-        if (DEBUG) Log.d(TAG, "showMovementHints(), position: " + Gravity.toString(gravity));
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: showMovementHints(), position: %s", TAG, Gravity.toString(gravity));
+        }
 
         animateAlphaTo(checkGravity(gravity, Gravity.BOTTOM) ? 1f : 0f, mArrowUp);
         animateAlphaTo(checkGravity(gravity, Gravity.TOP) ? 1f : 0f, mArrowDown);
@@ -333,7 +412,10 @@
      * Hides user hints for moving the PiP, e.g. arrows.
      */
     public void hideMovementHints() {
-        if (DEBUG) Log.d(TAG, "hideMovementHints()");
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: hideMovementHints()", TAG);
+        }
         animateAlphaTo(0, mArrowUp);
         animateAlphaTo(0, mArrowRight);
         animateAlphaTo(0, mArrowDown);
@@ -344,10 +426,17 @@
      * Show or hide the pip user actions.
      */
     public void showMenuButtons(boolean show) {
-        if (DEBUG) Log.d(TAG, "showMenuButtons: " + show);
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: showMenuButtons: %b", TAG, show);
+        }
         animateAlphaTo(show ? 1 : 0, mActionButtonsContainer);
     }
 
+    private void showMenuFrame(boolean show) {
+        animateAlphaTo(show ? 1 : 0, mMenuFrameView);
+    }
+
     interface Listener {
 
         void onBackPress();
@@ -355,7 +444,10 @@
         void onEnterMoveMode();
 
         /**
-         * @return whether move mode was exited
+         * Called when a button for exiting move mode was pressed.
+         *
+         * @return true if the event was handled or false if the key event should be handled by the
+         * next receiver.
          */
         boolean onExitMoveMode();
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java
index dd7e294..4033f03 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java
@@ -28,13 +28,13 @@
 import android.graphics.Bitmap;
 import android.media.MediaMetadata;
 import android.os.Handler;
-import android.os.UserHandle;
 import android.text.TextUtils;
-import android.util.Log;
 
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.R;
 import com.android.wm.shell.pip.PipMediaController;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
 
 import java.util.Objects;
 
@@ -56,6 +56,10 @@
             "com.android.wm.shell.pip.tv.notification.action.SHOW_PIP_MENU";
     private static final String ACTION_CLOSE_PIP =
             "com.android.wm.shell.pip.tv.notification.action.CLOSE_PIP";
+    private static final String ACTION_MOVE_PIP =
+            "com.android.wm.shell.pip.tv.notification.action.MOVE_PIP";
+    private static final String ACTION_TOGGLE_EXPANDED_PIP =
+            "com.android.wm.shell.pip.tv.notification.action.TOGGLE_EXPANDED_PIP";
 
     private final Context mContext;
     private final PackageManager mPackageManager;
@@ -98,7 +102,10 @@
     }
 
     void setDelegate(Delegate delegate) {
-        if (DEBUG) Log.d(TAG, "setDelegate(), delegate=" + delegate);
+        if (DEBUG) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: setDelegate(), delegate=%s", TAG, delegate);
+        }
         if (mDelegate != null) {
             throw new IllegalStateException(
                     "The delegate has already been set and should not change.");
@@ -219,6 +226,8 @@
             mIntentFilter = new IntentFilter();
             mIntentFilter.addAction(ACTION_CLOSE_PIP);
             mIntentFilter.addAction(ACTION_SHOW_PIP_MENU);
+            mIntentFilter.addAction(ACTION_MOVE_PIP);
+            mIntentFilter.addAction(ACTION_TOGGLE_EXPANDED_PIP);
         }
         boolean mRegistered = false;
 
@@ -240,12 +249,19 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             final String action = intent.getAction();
-            if (DEBUG) Log.d(TAG, "on(Broadcast)Receive(), action=" + action);
+            if (DEBUG) {
+                ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                        "%s: on(Broadcast)Receive(), action=%s", TAG, action);
+            }
 
             if (ACTION_SHOW_PIP_MENU.equals(action)) {
                 mDelegate.showPictureInPictureMenu();
             } else if (ACTION_CLOSE_PIP.equals(action)) {
                 mDelegate.closePip();
+            } else if (ACTION_MOVE_PIP.equals(action)) {
+                mDelegate.enterPipMovementMenu();
+            } else if (ACTION_TOGGLE_EXPANDED_PIP.equals(action)) {
+                mDelegate.togglePipExpansion();
             }
         }
     }
@@ -253,5 +269,7 @@
     interface Delegate {
         void showPictureInPictureMenu();
         void closePip();
+        void enterPipMovementMenu();
+        void togglePipExpansion();
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index e88eef9..2da5bec 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -18,12 +18,14 @@
 
 import static android.app.ActivityManager.START_SUCCESS;
 import static android.app.ActivityManager.START_TASK_TO_FRONT;
+import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.RemoteAnimationTarget.MODE_OPENING;
 
 import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
 import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
@@ -32,6 +34,7 @@
 import android.app.ActivityTaskManager;
 import android.app.PendingIntent;
 import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.LauncherApps;
@@ -68,6 +71,7 @@
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.common.annotations.ExternalThread;
+import com.android.wm.shell.common.split.SplitLayout;
 import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
 import com.android.wm.shell.draganddrop.DragAndDropPolicy;
 import com.android.wm.shell.recents.RecentTasksController;
@@ -196,11 +200,12 @@
 
     @Nullable
     public ActivityManager.RunningTaskInfo getTaskInfo(@SplitPosition int splitPosition) {
-        if (isSplitScreenVisible()) {
-            int taskId = mStageCoordinator.getTaskId(splitPosition);
-            return mTaskOrganizer.getRunningTaskInfo(taskId);
+        if (!isSplitScreenVisible() || splitPosition == SPLIT_POSITION_UNDEFINED) {
+            return null;
         }
-        return null;
+
+        final int taskId = mStageCoordinator.getTaskId(splitPosition);
+        return mTaskOrganizer.getRunningTaskInfo(taskId);
     }
 
     public boolean isTaskInSplitScreen(int taskId) {
@@ -321,8 +326,8 @@
         }
     }
 
-    public void startIntent(PendingIntent intent, Intent fillInIntent, @SplitPosition int position,
-            @Nullable Bundle options) {
+    public void startIntent(PendingIntent intent, @Nullable Intent fillInIntent,
+            @SplitPosition int position, @Nullable Bundle options) {
         if (!ENABLE_SHELL_TRANSITIONS) {
             startIntentLegacy(intent, fillInIntent, position, options);
             return;
@@ -331,6 +336,15 @@
         try {
             options = mStageCoordinator.resolveStartStage(STAGE_TYPE_UNDEFINED, position, options,
                     null /* wct */);
+
+            // Flag this as a no-user-action launch to prevent sending user leaving event to the
+            // current top activity since it's going to be put into another side of the split. This
+            // prevents the current top activity from going into pip mode due to user leaving event.
+            if (fillInIntent == null) {
+                fillInIntent = new Intent();
+            }
+            fillInIntent.addFlags(FLAG_ACTIVITY_NO_USER_ACTION);
+
             intent.send(mContext, 0, fillInIntent, null /* onFinished */, null /* handler */,
                     null /* requiredPermission */, options);
         } catch (PendingIntent.CanceledException e) {
@@ -338,7 +352,7 @@
         }
     }
 
-    private void startIntentLegacy(PendingIntent intent, Intent fillInIntent,
+    private void startIntentLegacy(PendingIntent intent, @Nullable Intent fillInIntent,
             @SplitPosition int position, @Nullable Bundle options) {
         final WindowContainerTransaction evictWct = new WindowContainerTransaction();
         mStageCoordinator.prepareEvictChildTasks(position, evictWct);
@@ -350,6 +364,18 @@
                     IRemoteAnimationFinishedCallback finishedCallback,
                     SurfaceControl.Transaction t) {
                 if (apps == null || apps.length == 0) {
+                    final ActivityManager.RunningTaskInfo pairedTaskInfo =
+                            getTaskInfo(SplitLayout.reversePosition(position));
+                    final ComponentName pairedActivity =
+                            pairedTaskInfo != null ? pairedTaskInfo.baseActivity : null;
+                    final ComponentName intentActivity =
+                            intent.getIntent() != null ? intent.getIntent().getComponent() : null;
+                    if (pairedActivity != null && pairedActivity.equals(intentActivity)) {
+                        // Switch split position if dragging the same activity to another side.
+                        setSideStagePosition(SplitLayout.reversePosition(
+                                mStageCoordinator.getSideStagePosition()));
+                    }
+
                     // Do nothing when the animation was cancelled.
                     t.apply();
                     return;
@@ -377,6 +403,15 @@
 
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         options = mStageCoordinator.resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, wct);
+
+        // Flag this as a no-user-action launch to prevent sending user leaving event to the current
+        // top activity since it's going to be put into another side of the split. This prevents the
+        // current top activity from going into pip mode due to user leaving event.
+        if (fillInIntent == null) {
+            fillInIntent = new Intent();
+        }
+        fillInIntent.addFlags(FLAG_ACTIVITY_NO_USER_ACTION);
+
         wct.sendPendingIntent(intent, fillInIntent, options);
         mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct);
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 9e53593..ec1ddf0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -29,6 +29,7 @@
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
 import static android.view.WindowManager.transitTypeToString;
 import static android.view.WindowManagerPolicyConstants.SPLIT_DIVIDER_LAYER;
+import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
 
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
@@ -1171,6 +1172,8 @@
                 updateUnfoldBounds();
                 return;
             }
+
+            mSplitLayout.update(null /* t */);
             onLayoutSizeChanged(mSplitLayout);
         }
     }
@@ -1198,7 +1201,6 @@
         if (!ENABLE_SHELL_TRANSITIONS) return;
 
         final SurfaceControl.Transaction t = mTransactionPool.acquire();
-        setDividerVisibility(false, t);
         mDisplayLayout.rotateTo(mContext.getResources(), toRotation);
         mSplitLayout.rotateTo(toRotation, mDisplayLayout.stableInsets());
         updateWindowBounds(mSplitLayout, wct);
@@ -1255,8 +1257,15 @@
             @Nullable TransitionRequestInfo request) {
         final ActivityManager.RunningTaskInfo triggerTask = request.getTriggerTask();
         if (triggerTask == null) {
-            // Still want to monitor everything while in split-screen, so return non-null.
-            return mMainStage.isActive() ? new WindowContainerTransaction() : null;
+            if (mMainStage.isActive()) {
+                if (request.getType() == TRANSIT_CHANGE && request.getDisplayChange() != null) {
+                    mSplitLayout.setFreezeDividerWindow(true);
+                }
+                // Still want to monitor everything while in split-screen, so return non-null.
+                return new WindowContainerTransaction();
+            } else {
+                return null;
+            }
         } else if (triggerTask.displayId != mDisplayId) {
             // Skip handling task on the other display.
             return null;
@@ -1329,8 +1338,11 @@
         // Once the pending enter transition got merged, make sure to bring divider bar visible and
         // clear the pending transition from cache to prevent mess-up the following state.
         if (transition == mSplitTransitions.mPendingEnter) {
-            finishEnterSplitScreen(null);
+            final SurfaceControl.Transaction t = mTransactionPool.acquire();
+            finishEnterSplitScreen(t);
             mSplitTransitions.mPendingEnter = null;
+            t.apply();
+            mTransactionPool.release(t);
         }
     }
 
@@ -1349,8 +1361,14 @@
             // If we're not in split-mode, just abort so something else can handle it.
             if (!mMainStage.isActive()) return false;
 
+            mSplitLayout.setFreezeDividerWindow(false);
             for (int iC = 0; iC < info.getChanges().size(); ++iC) {
                 final TransitionInfo.Change change = info.getChanges().get(iC);
+                if (change.getMode() == TRANSIT_CHANGE
+                        && (change.getFlags() & FLAG_IS_DISPLAY) != 0) {
+                    mSplitLayout.update(startTransaction);
+                }
+
                 final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
                 if (taskInfo == null || !taskInfo.hasParentTask()) continue;
                 final StageTaskListener stage = getStageOfTask(taskInfo);
@@ -1365,10 +1383,6 @@
                         Log.w(TAG, "Expected onTaskVanished on " + stage + " to have been called"
                                 + " with " + taskInfo.taskId + " before startAnimation().");
                     }
-                } else if (info.getType() == TRANSIT_CHANGE
-                        && change.getStartRotation() != change.getEndRotation()) {
-                    // Show the divider after transition finished.
-                    setDividerVisibility(true, finishTransaction);
                 }
             }
             if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index f0fb69f..b6c8cff 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -301,8 +301,6 @@
                 Color.TRANSPARENT);
         attrs.mSplashScreenIcon = safeReturnAttrDefault((def) -> typedArray.getDrawable(
                 R.styleable.Window_windowSplashScreenAnimatedIcon), null);
-        attrs.mAnimationDuration = safeReturnAttrDefault((def) -> typedArray.getInt(
-                R.styleable.Window_windowSplashScreenAnimationDuration, def), 0);
         attrs.mBrandingImage = safeReturnAttrDefault((def) -> typedArray.getDrawable(
                 R.styleable.Window_windowSplashScreenBrandingImage), null);
         attrs.mIconBgColor = safeReturnAttrDefault((def) -> typedArray.getColor(
@@ -310,9 +308,8 @@
                 Color.TRANSPARENT);
         typedArray.recycle();
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
-                "getWindowAttrs: window attributes color: %s, replace icon: %b, avd duration: %d",
-                Integer.toHexString(attrs.mWindowBgColor), attrs.mSplashScreenIcon != null,
-                attrs.mAnimationDuration);
+                "getWindowAttrs: window attributes color: %s, replace icon: %b",
+                Integer.toHexString(attrs.mWindowBgColor), attrs.mSplashScreenIcon != null);
     }
 
     /** Creates the wrapper with system theme to avoid unexpected styles from app. */
@@ -327,7 +324,6 @@
         private Drawable mSplashScreenIcon = null;
         private Drawable mBrandingImage = null;
         private int mIconBgColor = Color.TRANSPARENT;
-        private int mAnimationDuration = 0;
     }
 
     /**
@@ -401,16 +397,13 @@
 
         SplashScreenView build() {
             Drawable iconDrawable;
-            final long animationDuration;
             if (mSuggestType == STARTING_WINDOW_TYPE_SOLID_COLOR_SPLASH_SCREEN
                     || mSuggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) {
                 // empty or legacy splash screen case
-                animationDuration = 0;
                 mFinalIconSize = 0;
             } else if (mTmpAttrs.mSplashScreenIcon != null) {
                 // Using the windowSplashScreenAnimatedIcon attribute
                 iconDrawable = mTmpAttrs.mSplashScreenIcon;
-                animationDuration = mTmpAttrs.mAnimationDuration;
 
                 // There is no background below the icon, so scale the icon up
                 if (mTmpAttrs.mIconBgColor == Color.TRANSPARENT
@@ -440,11 +433,9 @@
                     Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                     createIconDrawable(new BitmapDrawable(bitmap), true);
                 }
-                animationDuration = 0;
             }
 
-            return fillViewWithIcon(mFinalIconSize, mFinalIconDrawables, animationDuration,
-                    mUiThreadInitTask);
+            return fillViewWithIcon(mFinalIconSize, mFinalIconDrawables, mUiThreadInitTask);
         }
 
         private class ShapeIconFactory extends BaseIconFactory {
@@ -460,7 +451,7 @@
             } else {
                 mFinalIconDrawables = SplashscreenIconDrawableFactory.makeIconDrawable(
                         mTmpAttrs.mIconBgColor, mThemeColor, iconDrawable, mDefaultIconSize,
-                        mFinalIconSize, mSplashscreenWorkerHandler, mSplashScreenExecutor);
+                        mFinalIconSize, mSplashscreenWorkerHandler);
             }
         }
 
@@ -520,7 +511,7 @@
         }
 
         private SplashScreenView fillViewWithIcon(int iconSize, @Nullable Drawable[] iconDrawable,
-                long animationDuration, Consumer<Runnable> uiThreadInitTask) {
+                Consumer<Runnable> uiThreadInitTask) {
             Drawable foreground = null;
             Drawable background = null;
             if (iconDrawable != null) {
@@ -536,7 +527,6 @@
                     .setIconSize(iconSize)
                     .setIconBackground(background)
                     .setCenterViewDrawable(foreground)
-                    .setAnimationDurationMillis(animationDuration)
                     .setUiThreadInitConsumer(uiThreadInitTask)
                     .setAllowHandleSolidColor(mAllowHandleSolidColor);
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
index fdd5a15..5f52071 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
@@ -44,7 +44,6 @@
 import android.window.SplashScreenView;
 
 import com.android.internal.R;
-import com.android.wm.shell.common.ShellExecutor;
 
 import java.util.function.LongConsumer;
 
@@ -63,15 +62,14 @@
      */
     static Drawable[] makeIconDrawable(@ColorInt int backgroundColor, @ColorInt int themeColor,
             @NonNull Drawable foregroundDrawable, int srcIconSize, int iconSize,
-            Handler splashscreenWorkerHandler, ShellExecutor splashScreenExecutor) {
+            Handler splashscreenWorkerHandler) {
         Drawable foreground;
         Drawable background = null;
         boolean drawBackground =
                 backgroundColor != Color.TRANSPARENT && backgroundColor != themeColor;
 
         if (foregroundDrawable instanceof Animatable) {
-            foreground = new AnimatableIconAnimateListener(foregroundDrawable,
-                    splashScreenExecutor);
+            foreground = new AnimatableIconAnimateListener(foregroundDrawable);
         } else if (foregroundDrawable instanceof AdaptiveIconDrawable) {
             // If the icon is Adaptive, we already use the icon background.
             drawBackground = false;
@@ -274,12 +272,9 @@
         private boolean mAnimationTriggered;
         private AnimatorListenerAdapter mJankMonitoringListener;
         private boolean mRunning;
-        private long mDuration;
         private LongConsumer mStartListener;
-        private final ShellExecutor mSplashScreenExecutor;
 
-        AnimatableIconAnimateListener(@NonNull Drawable foregroundDrawable,
-                ShellExecutor splashScreenExecutor) {
+        AnimatableIconAnimateListener(@NonNull Drawable foregroundDrawable) {
             super(foregroundDrawable);
             Callback callback = new Callback() {
                 @Override
@@ -299,7 +294,6 @@
                 }
             };
             mForegroundDrawable.setCallback(callback);
-            mSplashScreenExecutor = splashScreenExecutor;
             mAnimatableIcon = (Animatable) mForegroundDrawable;
         }
 
@@ -309,9 +303,8 @@
         }
 
         @Override
-        public void prepareAnimate(long duration, LongConsumer startListener) {
+        public void prepareAnimate(LongConsumer startListener) {
             stopAnimation();
-            mDuration = duration;
             mStartListener = startListener;
         }
 
@@ -328,11 +321,11 @@
                     mJankMonitoringListener.onAnimationCancel(null);
                 }
                 if (mStartListener != null) {
-                    mStartListener.accept(mDuration);
+                    mStartListener.accept(0);
                 }
                 return;
             }
-            long animDuration = mDuration;
+            long animDuration = 0;
             if (mAnimatableIcon instanceof AnimatedVectorDrawable
                     && ((AnimatedVectorDrawable) mAnimatableIcon).getTotalDuration() > 0) {
                 animDuration = ((AnimatedVectorDrawable) mAnimatableIcon).getTotalDuration();
@@ -341,9 +334,8 @@
                 animDuration = ((AnimationDrawable) mAnimatableIcon).getTotalDuration();
             }
             mRunning = true;
-            mSplashScreenExecutor.executeDelayed(this::stopAnimation, animDuration);
             if (mStartListener != null) {
-                mStartListener.accept(Math.max(animDuration, 0));
+                mStartListener.accept(animDuration);
             }
         }
 
@@ -359,7 +351,6 @@
         @Override
         public void stopAnimation() {
             if (mRunning) {
-                mSplashScreenExecutor.removeCallbacks(this::stopAnimation);
                 onAnimationEnd();
                 mJankMonitoringListener = null;
             }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
index 1bef552e..0d46199 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -62,6 +62,7 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.hardware.HardwareBuffer;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.Trace;
@@ -243,7 +244,7 @@
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "TaskSnapshot#relayout");
             session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0,
                     tmpFrames, tmpMergedConfiguration, surfaceControl, tmpInsetsState,
-                    tmpControls);
+                    tmpControls, new Bundle());
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         } catch (RemoteException e) {
             snapshotSurface.clearWindowSynced();
@@ -517,7 +518,7 @@
 
     private void reportDrawn() {
         try {
-            mSession.finishDrawing(mWindow, null /* postDrawTransaction */);
+            mSession.finishDrawing(mWindow, null /* postDrawTransaction */, Integer.MAX_VALUE);
         } catch (RemoteException e) {
             clearWindowSynced();
         }
@@ -534,7 +535,7 @@
         @Override
         public void resized(ClientWindowFrames frames, boolean reportDraw,
                 MergedConfiguration mergedConfiguration, boolean forceLayout,
-                boolean alwaysConsumeSystemBars, int displayId) {
+                boolean alwaysConsumeSystemBars, int displayId, int seqId, int resizeMode) {
             if (mOuter != null) {
                 mOuter.mSplashScreenExecutor.execute(() -> {
                     if (mergedConfiguration != null
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index a225f4e..b0e44a1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -189,7 +189,7 @@
     }
 
     private void updateEnterpriseThumbnailDrawable() {
-        mEnterpriseThumbnailDrawable = mDevicePolicyManager.getDrawable(
+        mEnterpriseThumbnailDrawable = mDevicePolicyManager.getResources().getDrawable(
                 WORK_PROFILE_ICON, OUTLINE, PROFILE_SWITCH_ANIMATION,
                 () -> mContext.getDrawable(R.drawable.ic_corp_badge));
     }
@@ -434,6 +434,10 @@
                         // If available use the background color provided through AnimationOptions
                         backgroundColorForTransition =
                                 info.getAnimationOptions().getBackgroundColor();
+                    } else if (a.getBackgroundColor() != 0) {
+                        // Otherwise fallback on the background color provided through the animation
+                        // definition.
+                        backgroundColorForTransition = a.getBackgroundColor();
                     } else if (change.getBackgroundColor() != 0) {
                         // Otherwise default to the window's background color if provided through
                         // the theme as the background color for the animation - the top most window
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index fb3cd87..435d670 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -109,6 +109,9 @@
     /** List of possible handlers. Ordered by specificity (eg. tapped back to front). */
     private final ArrayList<TransitionHandler> mHandlers = new ArrayList<>();
 
+    /** List of {@link Runnable} instances to run when the last active transition has finished.  */
+    private final ArrayList<Runnable> mRunWhenIdleQueue = new ArrayList<>();
+
     private float mTransitionAnimationScaleSetting = 1.0f;
 
     private static final class ActiveTransition {
@@ -224,6 +227,21 @@
         mRemoteTransitionHandler.removeFiltered(remoteTransition);
     }
 
+    /**
+     * Runs the given {@code runnable} when the last active transition has finished, or immediately
+     * if there are currently no active transitions.
+     *
+     * <p>This method should be called on the Shell main-thread, where the given {@code runnable}
+     * will be executed when the last active transition is finished.
+     */
+    public void runOnIdle(Runnable runnable) {
+        if (mActiveTransitions.isEmpty()) {
+            runnable.run();
+        } else {
+            mRunWhenIdleQueue.add(runnable);
+        }
+    }
+
     /** @return true if the transition was triggered by opening something vs closing something */
     public static boolean isOpeningType(@WindowManager.TransitionType int type) {
         return type == TRANSIT_OPEN
@@ -520,6 +538,11 @@
         if (mActiveTransitions.size() <= activeIdx) {
             ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "All active transition animations "
                     + "finished");
+            // Run all runnables from the run-when-idle queue.
+            for (int i = 0; i < mRunWhenIdleQueue.size(); i++) {
+                mRunWhenIdleQueue.get(i).run();
+            }
+            mRunWhenIdleQueue.clear();
             return;
         }
         // Start animating the next active transition
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt
index 61e27f2..fb404b9 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.bubble
 
+import android.platform.test.annotations.Presubmit
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import androidx.test.uiautomator.By
@@ -24,6 +25,8 @@
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.annotation.Group4
 import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
 import org.junit.runner.RunWith
 import org.junit.Test
 import org.junit.runners.Parameterized
@@ -69,9 +72,19 @@
             }
         }
 
-    @FlakyTest
+    @Presubmit
     @Test
     fun testAppIsVisibleAtEnd() {
+        Assume.assumeFalse(isShellTransitionsEnabled)
+        testSpec.assertLayersEnd {
+            this.isVisible(testApp.component)
+        }
+    }
+
+    @FlakyTest
+    @Test
+    fun testAppIsVisibleAtEnd_ShellTransit() {
+        Assume.assumeTrue(isShellTransitionsEnabled)
         testSpec.assertLayersEnd {
             this.isVisible(testApp.component)
         }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt
index a57d3e6..c43230e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.bubble
 
+import android.platform.test.annotations.Presubmit
 import androidx.test.filters.FlakyTest
 import android.platform.test.annotations.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -57,9 +58,19 @@
             }
         }
 
-    @FlakyTest(bugId = 218642026)
+    @Presubmit
     @Test
     open fun testAppIsAlwaysVisible() {
+        Assume.assumeFalse(isShellTransitionsEnabled)
+        testSpec.assertLayers {
+            this.isVisible(testApp.component)
+        }
+    }
+
+    @FlakyTest(bugId = 218642026)
+    @Test
+    open fun testAppIsAlwaysVisible_ShellTransit() {
+        Assume.assumeTrue(isShellTransitionsEnabled)
         testSpec.assertLayers {
             this.isVisible(testApp.component)
         }
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml
index f40aa66..bd98585 100644
--- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml
@@ -123,6 +123,7 @@
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
         <activity
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 9054685..3e7ee25 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -78,6 +78,7 @@
         MockitoAnnotations.initMocks(this);
         mController = new BackAnimationController(
                 mShellExecutor, mTransaction, mActivityTaskManager, mContext);
+        mController.setEnableAnimations(true);
     }
 
     private void createNavigationInfo(RemoteAnimationTarget topAnimationTarget,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
index 9bb54a1..2e5078d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
@@ -61,7 +61,7 @@
     public void testInitRelease() {
         mSplitWindowManager.init(mSplitLayout, new InsetsState());
         assertThat(mSplitWindowManager.getSurfaceControl()).isNotNull();
-        mSplitWindowManager.release();
+        mSplitWindowManager.release(null /* t */);
         assertThat(mSplitWindowManager.getSurfaceControl()).isNull();
     }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
index a31b287..596100d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
@@ -53,6 +53,7 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.compatui.letterboxedu.LetterboxEduWindowManager;
+import com.android.wm.shell.transition.Transitions;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -62,6 +63,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import dagger.Lazy;
+
 /**
  * Tests for {@link CompatUIController}.
  *
@@ -82,6 +85,7 @@
     private @Mock ShellTaskOrganizer.TaskListener mMockTaskListener;
     private @Mock SyncTransactionQueue mMockSyncQueue;
     private @Mock ShellExecutor mMockExecutor;
+    private @Mock Lazy<Transitions> mMockTransitionsLazy;
     private @Mock CompatUIWindowManager mMockCompatLayout;
     private @Mock LetterboxEduWindowManager mMockLetterboxEduLayout;
 
@@ -102,7 +106,8 @@
         doReturn(true).when(mMockLetterboxEduLayout).createLayout(anyBoolean());
         doReturn(true).when(mMockLetterboxEduLayout).updateCompatInfo(any(), any(), anyBoolean());
         mController = new CompatUIController(mContext, mMockDisplayController,
-                mMockDisplayInsetsController, mMockImeController, mMockSyncQueue, mMockExecutor) {
+                mMockDisplayInsetsController, mMockImeController, mMockSyncQueue, mMockExecutor,
+                mMockTransitionsLazy) {
             @Override
             CompatUIWindowManager createCompatUiWindowManager(Context context, TaskInfo taskInfo,
                     ShellTaskOrganizer.TaskListener taskListener) {
@@ -138,9 +143,7 @@
 
         // Verify that the compat controls and letterbox education are updated with new size compat
         // info.
-        clearInvocations(mMockCompatLayout);
-        clearInvocations(mMockLetterboxEduLayout);
-        clearInvocations(mController);
+        clearInvocations(mMockCompatLayout, mMockLetterboxEduLayout, mController);
         taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true,
                 CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED);
         mController.onCompatInfoChanged(taskInfo, mMockTaskListener);
@@ -151,9 +154,7 @@
                 true);
 
         // Verify that compat controls and letterbox education are removed with null task listener.
-        clearInvocations(mMockCompatLayout);
-        clearInvocations(mMockLetterboxEduLayout);
-        clearInvocations(mController);
+        clearInvocations(mMockCompatLayout, mMockLetterboxEduLayout, mController);
         mController.onCompatInfoChanged(createTaskInfo(DISPLAY_ID, TASK_ID,
                 /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN),
                 /* taskListener= */ null);
@@ -176,9 +177,7 @@
                 eq(mMockTaskListener));
 
         // Verify that the layout is created again.
-        clearInvocations(mMockCompatLayout);
-        clearInvocations(mMockLetterboxEduLayout);
-        clearInvocations(mController);
+        clearInvocations(mMockCompatLayout, mMockLetterboxEduLayout, mController);
         mController.onCompatInfoChanged(taskInfo, mMockTaskListener);
 
         verify(mMockCompatLayout, never()).updateCompatInfo(any(), any(), anyBoolean());
@@ -201,9 +200,7 @@
         verify(mController).createLetterboxEduWindowManager(any(), eq(taskInfo),
                 eq(mMockTaskListener));
 
-        clearInvocations(mMockCompatLayout);
-        clearInvocations(mMockLetterboxEduLayout);
-        clearInvocations(mController);
+        clearInvocations(mMockCompatLayout, mMockLetterboxEduLayout, mController);
         mController.onCompatInfoChanged(taskInfo, mMockTaskListener);
 
         verify(mMockCompatLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */
@@ -212,9 +209,7 @@
                 true);
 
         // Verify that the layout is created again.
-        clearInvocations(mMockCompatLayout);
-        clearInvocations(mMockLetterboxEduLayout);
-        clearInvocations(mController);
+        clearInvocations(mMockCompatLayout, mMockLetterboxEduLayout, mController);
         mController.onCompatInfoChanged(taskInfo, mMockTaskListener);
 
         verify(mMockCompatLayout, never()).updateCompatInfo(any(), any(), anyBoolean());
@@ -289,8 +284,7 @@
         verify(mMockLetterboxEduLayout).updateDisplayLayout(mMockDisplayLayout);
 
         // No update if the insets state is the same.
-        clearInvocations(mMockCompatLayout);
-        clearInvocations(mMockLetterboxEduLayout);
+        clearInvocations(mMockCompatLayout, mMockLetterboxEduLayout);
         mOnInsetsChangedListenerCaptor.getValue().insetsChanged(new InsetsState(insetsState));
         verify(mMockCompatLayout, never()).updateDisplayLayout(mMockDisplayLayout);
         verify(mMockLetterboxEduLayout, never()).updateDisplayLayout(mMockDisplayLayout);
@@ -363,8 +357,7 @@
         verify(mMockCompatLayout, times(2)).updateVisibility(false);
         verify(mMockLetterboxEduLayout, times(2)).updateVisibility(false);
 
-        clearInvocations(mMockCompatLayout);
-        clearInvocations(mMockLetterboxEduLayout);
+        clearInvocations(mMockCompatLayout, mMockLetterboxEduLayout);
 
         // Verify button remains hidden after keyguard becomes not showing since IME is showing.
         mController.onKeyguardShowingChanged(false);
@@ -390,8 +383,7 @@
         verify(mMockCompatLayout, times(2)).updateVisibility(false);
         verify(mMockLetterboxEduLayout, times(2)).updateVisibility(false);
 
-        clearInvocations(mMockCompatLayout);
-        clearInvocations(mMockLetterboxEduLayout);
+        clearInvocations(mMockCompatLayout, mMockLetterboxEduLayout);
 
         // Verify button remains hidden after IME is hidden since keyguard is showing.
         mController.onImeVisibilityChanged(DISPLAY_ID, /* isShowing= */ false);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java
index 337b738..f3a8cf4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java
@@ -26,6 +26,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -54,6 +55,7 @@
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.transition.Transitions;
 
 import org.junit.After;
 import org.junit.Before;
@@ -74,6 +76,12 @@
 @SmallTest
 public class LetterboxEduWindowManagerTest extends ShellTestCase {
 
+    private static final int USER_ID_1 = 1;
+    private static final int USER_ID_2 = 2;
+
+    private static final String PREF_KEY_1 = String.valueOf(USER_ID_1);
+    private static final String PREF_KEY_2 = String.valueOf(USER_ID_2);
+
     private static final int TASK_ID = 1;
 
     private static final int TASK_WIDTH = 200;
@@ -86,17 +94,21 @@
     private ArgumentCaptor<WindowManager.LayoutParams> mWindowAttrsCaptor;
     @Captor
     private ArgumentCaptor<Runnable> mEndCallbackCaptor;
+    @Captor
+    private ArgumentCaptor<Runnable> mRunOnIdleCaptor;
 
     @Mock private LetterboxEduAnimationController mAnimationController;
     @Mock private SyncTransactionQueue mSyncTransactionQueue;
     @Mock private ShellTaskOrganizer.TaskListener mTaskListener;
     @Mock private SurfaceControlViewHost mViewHost;
+    @Mock private Transitions mTransitions;
     @Mock private Runnable mOnDismissCallback;
 
     private SharedPreferences mSharedPreferences;
-    private String mPrefKey;
     @Nullable
-    private Boolean mInitialPrefValue = null;
+    private Boolean mInitialPrefValue1 = null;
+    @Nullable
+    private Boolean mInitialPrefValue2 = null;
 
     @Before
     public void setUp() {
@@ -105,20 +117,28 @@
         mSharedPreferences = mContext.getSharedPreferences(
                 LetterboxEduWindowManager.HAS_SEEN_LETTERBOX_EDUCATION_PREF_NAME,
                 Context.MODE_PRIVATE);
-        mPrefKey = String.valueOf(mContext.getUserId());
-        if (mSharedPreferences.contains(mPrefKey)) {
-            mInitialPrefValue = mSharedPreferences.getBoolean(mPrefKey, /* default= */ false);
-            mSharedPreferences.edit().remove(mPrefKey).apply();
+        if (mSharedPreferences.contains(PREF_KEY_1)) {
+            mInitialPrefValue1 = mSharedPreferences.getBoolean(PREF_KEY_1, /* default= */ false);
+            mSharedPreferences.edit().remove(PREF_KEY_1).apply();
+        }
+        if (mSharedPreferences.contains(PREF_KEY_2)) {
+            mInitialPrefValue2 = mSharedPreferences.getBoolean(PREF_KEY_2, /* default= */ false);
+            mSharedPreferences.edit().remove(PREF_KEY_2).apply();
         }
     }
 
     @After
     public void tearDown() {
         SharedPreferences.Editor editor = mSharedPreferences.edit();
-        if (mInitialPrefValue == null) {
-            editor.remove(mPrefKey);
+        if (mInitialPrefValue1 == null) {
+            editor.remove(PREF_KEY_1);
         } else {
-            editor.putBoolean(mPrefKey, mInitialPrefValue);
+            editor.putBoolean(PREF_KEY_1, mInitialPrefValue1);
+        }
+        if (mInitialPrefValue2 == null) {
+            editor.remove(PREF_KEY_2);
+        } else {
+            editor.putBoolean(PREF_KEY_2, mInitialPrefValue2);
         }
         editor.apply();
     }
@@ -133,19 +153,9 @@
     }
 
     @Test
-    public void testCreateLayout_alreadyShownToUser_doesNotCreateLayout() {
-        LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ true);
-        mSharedPreferences.edit().putBoolean(mPrefKey, true).apply();
-
-        assertFalse(windowManager.createLayout(/* canShow= */ true));
-
-        assertNull(windowManager.mLayout);
-    }
-
-    @Test
     public void testCreateLayout_taskBarEducationIsShowing_doesNotCreateLayout() {
         LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */
-                true, /* isTaskbarEduShowing= */ true);
+                true, USER_ID_1, /* isTaskbarEduShowing= */ true);
 
         assertFalse(windowManager.createLayout(/* canShow= */ true));
 
@@ -158,7 +168,7 @@
 
         assertTrue(windowManager.createLayout(/* canShow= */ false));
 
-        assertFalse(mSharedPreferences.getBoolean(mPrefKey, /* default= */ false));
+        assertFalse(mSharedPreferences.getBoolean(PREF_KEY_1, /* default= */ false));
         assertNull(windowManager.mLayout);
     }
 
@@ -168,7 +178,6 @@
 
         assertTrue(windowManager.createLayout(/* canShow= */ true));
 
-        assertTrue(mSharedPreferences.getBoolean(mPrefKey, /* default= */ false));
         LetterboxEduDialogLayout layout = windowManager.mLayout;
         assertNotNull(layout);
         verify(mViewHost).setView(eq(layout), mWindowAttrsCaptor.capture());
@@ -179,6 +188,8 @@
         assertNotNull(dialogTitle);
         spyOn(dialogTitle);
 
+        // The education shouldn't be marked as seen until enter animation is done.
+        assertFalse(mSharedPreferences.getBoolean(PREF_KEY_1, /* default= */ false));
         // Clicking the layout does nothing until enter animation is done.
         layout.performClick();
         verify(mAnimationController, never()).startExitAnimation(any(), any());
@@ -187,6 +198,7 @@
 
         verifyAndFinishEnterAnimation(layout);
 
+        assertTrue(mSharedPreferences.getBoolean(PREF_KEY_1, /* default= */ false));
         verify(dialogTitle).sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
         // Exit animation should start following a click on the layout.
         layout.performClick();
@@ -204,6 +216,53 @@
     }
 
     @Test
+    public void testCreateLayout_alreadyShownToUser_createsLayoutForOtherUserOnly() {
+        LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ true,
+                USER_ID_1, /* isTaskbarEduShowing= */ false);
+
+        assertTrue(windowManager.createLayout(/* canShow= */ true));
+
+        assertNotNull(windowManager.mLayout);
+        verifyAndFinishEnterAnimation(windowManager.mLayout);
+        assertTrue(mSharedPreferences.getBoolean(PREF_KEY_1, /* default= */ false));
+
+        windowManager.release();
+        windowManager = createWindowManager(/* eligible= */ true,
+                USER_ID_1, /* isTaskbarEduShowing= */ false);
+
+        assertFalse(windowManager.createLayout(/* canShow= */ true));
+        assertNull(windowManager.mLayout);
+
+        clearInvocations(mTransitions, mAnimationController);
+
+        windowManager = createWindowManager(/* eligible= */ true,
+                USER_ID_2, /* isTaskbarEduShowing= */ false);
+
+        assertTrue(windowManager.createLayout(/* canShow= */ true));
+
+        assertNotNull(windowManager.mLayout);
+        verifyAndFinishEnterAnimation(windowManager.mLayout);
+        assertTrue(mSharedPreferences.getBoolean(PREF_KEY_1, /* default= */ false));
+    }
+
+    @Test
+    public void testCreateLayout_windowManagerReleasedBeforeTransitionsIsIdle_doesNotStartAnim() {
+        LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ true);
+
+        assertTrue(windowManager.createLayout(/* canShow= */ true));
+        assertNotNull(windowManager.mLayout);
+
+        verify(mTransitions).runOnIdle(mRunOnIdleCaptor.capture());
+
+        windowManager.release();
+
+        mRunOnIdleCaptor.getValue().run();
+
+        verify(mAnimationController, never()).startEnterAnimation(any(), any());
+        assertFalse(mSharedPreferences.getBoolean(PREF_KEY_1, /* default= */ false));
+    }
+
+    @Test
     public void testUpdateCompatInfo_updatesLayoutCorrectly() {
         LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ true);
 
@@ -212,7 +271,7 @@
         assertNotNull(layout);
 
         assertTrue(windowManager.updateCompatInfo(
-                createTaskInfo(/* eligible= */ true, new Rect(50, 25, 150, 75)),
+                createTaskInfo(/* eligible= */ true, USER_ID_1, new Rect(50, 25, 150, 75)),
                 mTaskListener, /* canShow= */ true));
 
         verifyLayout(layout, layout.getLayoutParams(), /* expectedWidth= */ 100,
@@ -303,6 +362,13 @@
     }
 
     private void verifyAndFinishEnterAnimation(LetterboxEduDialogLayout layout) {
+        verify(mTransitions).runOnIdle(mRunOnIdleCaptor.capture());
+
+        // startEnterAnimation isn't called until run-on-idle runnable is called.
+        verify(mAnimationController, never()).startEnterAnimation(any(), any());
+
+        mRunOnIdleCaptor.getValue().run();
+
         verify(mAnimationController).startEnterAnimation(eq(layout), mEndCallbackCaptor.capture());
         mEndCallbackCaptor.getValue().run();
     }
@@ -313,14 +379,15 @@
     }
 
     private LetterboxEduWindowManager createWindowManager(boolean eligible) {
-        return createWindowManager(eligible, /* isTaskbarEduShowing= */ false);
+        return createWindowManager(eligible, USER_ID_1, /* isTaskbarEduShowing= */ false);
     }
 
     private LetterboxEduWindowManager createWindowManager(boolean eligible,
-            boolean isTaskbarEduShowing) {
+            int userId, boolean isTaskbarEduShowing) {
         LetterboxEduWindowManager windowManager = new LetterboxEduWindowManager(mContext,
-                createTaskInfo(eligible), mSyncTransactionQueue, mTaskListener,
-                createDisplayLayout(), mOnDismissCallback, mAnimationController);
+                createTaskInfo(eligible, userId), mSyncTransactionQueue, mTaskListener,
+                createDisplayLayout(), mTransitions, mOnDismissCallback,
+                mAnimationController);
 
         spyOn(windowManager);
         doReturn(mViewHost).when(windowManager).createSurfaceViewHost();
@@ -346,11 +413,16 @@
     }
 
     private static TaskInfo createTaskInfo(boolean eligible) {
-        return createTaskInfo(eligible, new Rect(0, 0, TASK_WIDTH, TASK_HEIGHT));
+        return createTaskInfo(eligible, USER_ID_1);
     }
 
-    private static TaskInfo createTaskInfo(boolean eligible, Rect bounds) {
+    private static TaskInfo createTaskInfo(boolean eligible, int userId) {
+        return createTaskInfo(eligible, userId, new Rect(0, 0, TASK_WIDTH, TASK_HEIGHT));
+    }
+
+    private static TaskInfo createTaskInfo(boolean eligible, int userId, Rect bounds) {
         ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
+        taskInfo.userId = userId;
         taskInfo.taskId = TASK_ID;
         taskInfo.topActivityEligibleForLetterboxEducation = eligible;
         taskInfo.configuration.windowConfiguration.setBounds(bounds);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java
index 78903dc..ff6dfdb 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java
@@ -49,7 +49,6 @@
 import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.compatui.CompatUIController;
 import com.android.wm.shell.startingsurface.StartingWindowController;
 
 import org.junit.Before;
@@ -67,7 +66,6 @@
     @Mock private ITaskOrganizerController mTaskOrganizerController;
     @Mock private Context mContext;
     @Mock private Handler mHandler;
-    @Mock private CompatUIController mCompatUI;
     @Mock private SyncTransactionQueue mSyncTransactionQueue;
     @Mock private ShellExecutor mTestExecutor;
     @Mock private DisplayController mDisplayController;
@@ -86,9 +84,11 @@
         try {
             doReturn(ParceledListSlice.<TaskAppearedInfo>emptyList())
                     .when(mTaskOrganizerController).registerTaskOrganizer(any());
-        } catch (RemoteException e) { }
+        } catch (RemoteException e) {
+        }
+        // NOTE: KidsModeTaskOrganizer should have a null CompatUIController.
         mOrganizer = spy(new KidsModeTaskOrganizer(mTaskOrganizerController, mTestExecutor,
-                mHandler, mContext, mCompatUI, mSyncTransactionQueue, mDisplayController,
+                mHandler, mContext, mSyncTransactionQueue, mDisplayController,
                 mDisplayInsetsController, Optional.empty(), mObserver));
         mOrganizer.initialize(mStartingWindowController);
         doReturn(mTransaction).when(mOrganizer).getWindowContainerTransaction();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 935f669..aef298e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -59,6 +59,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.Optional;
+import java.util.Set;
 
 /**
  * Unit tests for {@link PipController}
@@ -209,4 +210,16 @@
 
         verify(mMockPipMotionHelper, never()).movePip(any(Rect.class));
     }
+
+    @Test
+    public void onKeepClearAreasChanged_updatesPipBoundsState() {
+        final int displayId = 1;
+        final Rect keepClearArea = new Rect(0, 0, 10, 10);
+        when(mMockPipBoundsState.getDisplayId()).thenReturn(displayId);
+
+        mPipController.mDisplaysChangedListener.onKeepClearAreasChanged(
+                displayId, Set.of(keepClearArea), Set.of());
+
+        verify(mMockPipBoundsState).setKeepClearAreas(Set.of(keepClearArea), Set.of());
+    }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index dbf93b4..a0b1297 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -46,6 +46,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
@@ -93,7 +94,7 @@
  * Tests for the shell transitions.
  *
  * Build/Install/Run:
- *  atest WMShellUnitTests:ShellTransitionTests
+ * atest WMShellUnitTests:ShellTransitionTests
  */
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -600,6 +601,83 @@
         assertTrue(DefaultTransitionHandler.isRotationSeamless(seamlessDisplay, displays));
     }
 
+    @Test
+    public void testRunWhenIdle() {
+        Transitions transitions = createTestTransitions();
+        transitions.replaceDefaultHandlerForTest(mDefaultHandler);
+
+        Runnable runnable1 = mock(Runnable.class);
+        Runnable runnable2 = mock(Runnable.class);
+        Runnable runnable3 = mock(Runnable.class);
+        Runnable runnable4 = mock(Runnable.class);
+
+        transitions.runOnIdle(runnable1);
+
+        // runnable1 is executed immediately because there are no active transitions.
+        verify(runnable1, times(1)).run();
+
+        clearInvocations(runnable1);
+
+        IBinder transitToken1 = new Binder();
+        transitions.requestStartTransition(transitToken1,
+                new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
+        TransitionInfo info1 = new TransitionInfoBuilder(TRANSIT_OPEN)
+                .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
+        transitions.onTransitionReady(transitToken1, info1, mock(SurfaceControl.Transaction.class),
+                mock(SurfaceControl.Transaction.class));
+        assertEquals(1, mDefaultHandler.activeCount());
+
+        transitions.runOnIdle(runnable2);
+        transitions.runOnIdle(runnable3);
+
+        // runnable2 and runnable3 aren't executed immediately because there is an active
+        // transaction.
+
+        IBinder transitToken2 = new Binder();
+        transitions.requestStartTransition(transitToken2,
+                new TransitionRequestInfo(TRANSIT_CLOSE, null /* trigger */, null /* remote */));
+        TransitionInfo info2 = new TransitionInfoBuilder(TRANSIT_CLOSE)
+                .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
+        transitions.onTransitionReady(transitToken2, info2, mock(SurfaceControl.Transaction.class),
+                mock(SurfaceControl.Transaction.class));
+        assertEquals(1, mDefaultHandler.activeCount());
+
+        mDefaultHandler.finishAll();
+        mMainExecutor.flushAll();
+        // first transition finished
+        verify(mOrganizer, times(1)).finishTransition(eq(transitToken1), any(), any());
+        verify(mOrganizer, times(0)).finishTransition(eq(transitToken2), any(), any());
+        // But now the "queued" transition is running
+        assertEquals(1, mDefaultHandler.activeCount());
+
+        // runnable2 and runnable3 are still not executed because the second transition is still
+        // active.
+        verify(runnable2, times(0)).run();
+        verify(runnable3, times(0)).run();
+
+        mDefaultHandler.finishAll();
+        mMainExecutor.flushAll();
+        verify(mOrganizer, times(1)).finishTransition(eq(transitToken2), any(), any());
+
+        // runnable2 and runnable3 are executed after the second transition finishes because there
+        // are no other active transitions, runnable1 isn't executed again.
+        verify(runnable1, times(0)).run();
+        verify(runnable2, times(1)).run();
+        verify(runnable3, times(1)).run();
+
+        clearInvocations(runnable2);
+        clearInvocations(runnable3);
+
+        transitions.runOnIdle(runnable4);
+
+        // runnable4 is executed immediately because there are no active transitions, all other
+        // runnables aren't executed again.
+        verify(runnable1, times(0)).run();
+        verify(runnable2, times(0)).run();
+        verify(runnable3, times(0)).run();
+        verify(runnable4, times(1)).run();
+    }
+
     class TransitionInfoBuilder {
         final TransitionInfo mInfo;
 
@@ -749,7 +827,7 @@
         IWindowManager mockWM = mock(IWindowManager.class);
         final IDisplayWindowListener[] displayListener = new IDisplayWindowListener[1];
         try {
-            doReturn(new int[] {DEFAULT_DISPLAY}).when(mockWM).registerDisplayWindowListener(any());
+            doReturn(new int[]{DEFAULT_DISPLAY}).when(mockWM).registerDisplayWindowListener(any());
         } catch (RemoteException e) {
             // No remote stuff happening, so this can't be hit
         }
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 63b831d..c80fb18 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -118,7 +118,7 @@
                 "libz",
             ],
         },
-        linux_glibc: {
+        host_linux: {
             srcs: [
                 "CursorWindow.cpp",
             ],
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index dd272cd..c24cabb 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -310,6 +310,11 @@
     return has101012Support;
 }
 
+bool HardwareBitmapUploader::hasAlpha8Support() {
+    static bool hasAlpha8Support = checkSupport(AHARDWAREBUFFER_FORMAT_R8_UNORM);
+    return hasAlpha8Support;
+}
+
 static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) {
     FormatInfo formatInfo;
     switch (skBitmap.info().colorType()) {
@@ -363,6 +368,13 @@
             }
             formatInfo.format = GL_RGBA;
             break;
+        case kAlpha_8_SkColorType:
+            formatInfo.isSupported = HardwareBitmapUploader::hasAlpha8Support();
+            formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8_UNORM;
+            formatInfo.format = GL_R8;
+            formatInfo.type = GL_UNSIGNED_BYTE;
+            formatInfo.vkFormat = VK_FORMAT_R8_UNORM;
+            break;
         default:
             ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType());
             formatInfo.valid = false;
diff --git a/libs/hwui/HardwareBitmapUploader.h b/libs/hwui/HardwareBitmapUploader.h
index 34f43cd..81057a2 100644
--- a/libs/hwui/HardwareBitmapUploader.h
+++ b/libs/hwui/HardwareBitmapUploader.h
@@ -30,11 +30,13 @@
 #ifdef __ANDROID__
     static bool hasFP16Support();
     static bool has1010102Support();
+    static bool hasAlpha8Support();
 #else
     static bool hasFP16Support() {
         return true;
     }
     static bool has1010102Support() { return true; }
+    static bool hasAlpha8Support() { return true; }
 #endif
 };
 
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index bcfe9c3..86ae399 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -69,7 +69,6 @@
 bool Properties::enableHighContrastText = false;
 
 bool Properties::waitForGpuCompletion = false;
-bool Properties::forceDrawFrame = false;
 
 bool Properties::filterOutTestOverhead = false;
 bool Properties::disableVsync = false;
@@ -135,7 +134,7 @@
     skpCaptureEnabled = debuggingEnabled && base::GetBoolProperty(PROPERTY_CAPTURE_SKP_ENABLED, false);
 
     SkAndroidFrameworkTraceUtil::setEnableTracing(
-            base::GetBoolProperty(PROPERTY_SKIA_ATRACE_ENABLED, false));
+            base::GetBoolProperty(PROPERTY_SKIA_ATRACE_ENABLED, true));
 
     runningInEmulator = base::GetBoolProperty(PROPERTY_IS_EMULATOR, false);
 
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index cc9094c..6b8f439 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -100,6 +100,8 @@
 
     int stretchEffectCount = 0;
 
+    bool forceDrawFrame = false;
+
     struct Out {
         bool hasFunctors = false;
         // This is only updated if evaluateAnimations is true
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 1a89cfd..67f4758 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -104,6 +104,10 @@
 
 sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(const SkBitmap& bitmap) {
 #ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
+    if (bitmap.colorType() == kAlpha_8_SkColorType &&
+        !uirenderer::HardwareBitmapUploader::hasAlpha8Support()) {
+        return nullptr;
+    }
     return uirenderer::HardwareBitmapUploader::allocateHardwareBitmap(bitmap);
 #else
     return Bitmap::allocateHeapBitmap(bitmap.info());
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index 27865b3..c48448d 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -259,7 +259,8 @@
 }
 
 static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize) {
+                                                          jlong proxyPtr, jlongArray frameInfo,
+                                                          jint frameInfoSize) {
     LOG_ALWAYS_FATAL_IF(frameInfoSize != UI_THREAD_FRAME_INFO_SIZE,
                         "Mismatched size expectations, given %d expected %zu", frameInfoSize,
                         UI_THREAD_FRAME_INFO_SIZE);
@@ -413,6 +414,12 @@
     proxy->setContentDrawBounds(left, top, right, bottom);
 }
 
+static void android_view_ThreadedRenderer_forceDrawNextFrame(JNIEnv* env, jobject clazz,
+                                                             jlong proxyPtr) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    proxy->forceDrawNextFrame();
+}
+
 class JGlobalRefHolder {
 public:
     JGlobalRefHolder(JavaVM* vm, jobject object) : mVm(vm), mObject(object) {}
@@ -770,11 +777,6 @@
     Properties::enableHighContrastText = enable;
 }
 
-static void android_view_ThreadedRenderer_hackySetRTAnimationsEnabled(JNIEnv*, jclass,
-        jboolean enable) {
-    Properties::enableRTAnimations = enable;
-}
-
 static void android_view_ThreadedRenderer_setDebuggingEnabled(JNIEnv*, jclass, jboolean enable) {
     Properties::debuggingEnabled = enable;
 }
@@ -804,6 +806,11 @@
     RenderProxy::preload();
 }
 
+static void android_view_ThreadedRenderer_setRtAnimationsEnabled(JNIEnv* env, jobject clazz,
+                                                                 jboolean enabled) {
+    RenderProxy::setRtAnimationsEnabled(enabled);
+}
+
 // Plumbs the display density down to DeviceInfo.
 static void android_view_ThreadedRenderer_setDisplayDensityDpi(JNIEnv*, jclass, jint densityDpi) {
     // Convert from dpi to density-independent pixels.
@@ -935,6 +942,7 @@
         {"nDrawRenderNode", "(JJ)V", (void*)android_view_ThreadedRendererd_drawRenderNode},
         {"nSetContentDrawBounds", "(JIIII)V",
          (void*)android_view_ThreadedRenderer_setContentDrawBounds},
+        {"nForceDrawNextFrame", "(J)V", (void*)android_view_ThreadedRenderer_forceDrawNextFrame},
         {"nSetPictureCaptureCallback",
          "(JLandroid/graphics/HardwareRenderer$PictureCapturedCallback;)V",
          (void*)android_view_ThreadedRenderer_setPictureCapturedCallbackJNI},
@@ -959,8 +967,6 @@
          (void*)android_view_ThreadedRenderer_createHardwareBitmapFromRenderNode},
         {"disableVsync", "()V", (void*)android_view_ThreadedRenderer_disableVsync},
         {"nSetHighContrastText", "(Z)V", (void*)android_view_ThreadedRenderer_setHighContrastText},
-        {"nHackySetRTAnimationsEnabled", "(Z)V",
-         (void*)android_view_ThreadedRenderer_hackySetRTAnimationsEnabled},
         {"nSetDebuggingEnabled", "(Z)V", (void*)android_view_ThreadedRenderer_setDebuggingEnabled},
         {"nSetIsolatedProcess", "(Z)V", (void*)android_view_ThreadedRenderer_setIsolatedProcess},
         {"nSetContextPriority", "(I)V", (void*)android_view_ThreadedRenderer_setContextPriority},
@@ -974,6 +980,8 @@
          (void*)android_view_ThreadedRenderer_isWebViewOverlaysEnabled},
         {"nSetDrawingEnabled", "(Z)V", (void*)android_view_ThreadedRenderer_setDrawingEnabled},
         {"nIsDrawingEnabled", "()Z", (void*)android_view_ThreadedRenderer_isDrawingEnabled},
+        {"nSetRtAnimationsEnabled", "(Z)V",
+         (void*)android_view_ThreadedRenderer_setRtAnimationsEnabled},
 };
 
 static JavaVM* mJvm = nullptr;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index bdad772..122c77f 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -390,7 +390,7 @@
         return;
     }
 
-    if (CC_LIKELY(mSwapHistory.size() && !Properties::forceDrawFrame)) {
+    if (CC_LIKELY(mSwapHistory.size() && !info.forceDrawFrame)) {
         nsecs_t latestVsync = mRenderThread.timeLord().latestVsync();
         SwapHistory& lastSwap = mSwapHistory.back();
         nsecs_t vsyncDelta = std::abs(lastSwap.vsyncTime - latestVsync);
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 8c98c72..59c914f 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -133,6 +133,7 @@
 }
 
 void DrawFrameTask::postAndWait() {
+    ATRACE_CALL();
     AutoMutex _lock(mLock);
     mRenderThread->queue().post([this]() { run(); });
     mSignal.wait(mLock);
@@ -147,6 +148,8 @@
     bool canDrawThisFrame;
     {
         TreeInfo info(TreeInfo::MODE_FULL, *mContext);
+        info.forceDrawFrame = mForceDrawFrame;
+        mForceDrawFrame = false;
         canUnblockUiThread = syncFrameState(info);
         canDrawThisFrame = info.out.canDrawThisFrame;
 
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index 25ed935..d6fc292 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -88,6 +88,8 @@
         mFrameCompleteCallback = std::move(callback);
     }
 
+    void forceDrawNextFrame() { mForceDrawFrame = true; }
+
 private:
     class HintSessionWrapper {
     public:
@@ -132,6 +134,8 @@
     nsecs_t mLastDequeueBufferDuration = 0;
     nsecs_t mLastTargetWorkDuration = 0;
     std::optional<HintSessionWrapper> mHintSessionWrapper;
+
+    bool mForceDrawFrame = false;
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 026699c..a44b498 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -133,6 +133,10 @@
     return mDrawFrameTask.frameInfo();
 }
 
+void RenderProxy::forceDrawNextFrame() {
+    mDrawFrameTask.forceDrawNextFrame();
+}
+
 int RenderProxy::syncAndDrawFrame() {
     return mDrawFrameTask.drawFrame();
 }
@@ -424,6 +428,15 @@
     thread.queue().post([&thread]() { thread.preload(); });
 }
 
+void RenderProxy::setRtAnimationsEnabled(bool enabled) {
+    if (RenderThread::hasInstance()) {
+        RenderThread::getInstance().queue().post(
+                [enabled]() { Properties::enableRTAnimations = enabled; });
+    } else {
+        Properties::enableRTAnimations = enabled;
+    }
+}
+
 } /* namespace renderthread */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 491dbd7..ee9efd4 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -82,6 +82,7 @@
     void setOpaque(bool opaque);
     void setColorMode(ColorMode mode);
     int64_t* frameInfo();
+    void forceDrawNextFrame();
     int syncAndDrawFrame();
     void destroy();
 
@@ -143,6 +144,8 @@
 
     static void preload();
 
+    static void setRtAnimationsEnabled(bool enabled);
+
 private:
     RenderThread& mRenderThread;
     CanvasContext* mContext;
diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
index de2c621..613a6ae 100644
--- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp
+++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
@@ -104,7 +104,6 @@
         // If we're reporting GPU memory usage we need to first start with a clean slate
         RenderProxy::purgeCaches();
     }
-    Properties::forceDrawFrame = true;
     TestContext testContext;
     testContext.setRenderOffscreen(opts.renderOffscreen);
 
@@ -144,6 +143,7 @@
             .setVsync(vsync, vsync, UiFrameInfoBuilder::INVALID_VSYNC_ID,
                       UiFrameInfoBuilder::UNKNOWN_DEADLINE,
                       UiFrameInfoBuilder::UNKNOWN_FRAME_INTERVAL);
+        proxy->forceDrawNextFrame();
         proxy->syncAndDrawFrame();
     }
 
@@ -163,6 +163,7 @@
                           UiFrameInfoBuilder::UNKNOWN_DEADLINE,
                           UiFrameInfoBuilder::UNKNOWN_FRAME_INTERVAL);
             scene->doFrame(i);
+            proxy->forceDrawNextFrame();
             proxy->syncAndDrawFrame();
         }
         if (opts.reportFrametimeWeight) {
diff --git a/libs/storage/IMountService.cpp b/libs/storage/IMountService.cpp
index 055dbb2..99508a2 100644
--- a/libs/storage/IMountService.cpp
+++ b/libs/storage/IMountService.cpp
@@ -48,8 +48,6 @@
     TRANSACTION_isObbMounted,
     TRANSACTION_getMountedObbPath,
     TRANSACTION_isExternalStorageEmulated,
-    TRANSACTION_decryptStorage,
-    TRANSACTION_encryptStorage,
 };
 
 class BpMountService: public BpInterface<IMountService>
@@ -517,40 +515,6 @@
         path = reply.readString16();
         return true;
     }
-
-    int32_t decryptStorage(const String16& password)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
-        data.writeString16(password);
-        if (remote()->transact(TRANSACTION_decryptStorage, data, &reply) != NO_ERROR) {
-            ALOGD("decryptStorage could not contact remote\n");
-            return -1;
-        }
-        int32_t err = reply.readExceptionCode();
-        if (err < 0) {
-            ALOGD("decryptStorage caught exception %d\n", err);
-            return err;
-        }
-        return reply.readInt32();
-    }
-
-    int32_t encryptStorage(const String16& password)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
-        data.writeString16(password);
-        if (remote()->transact(TRANSACTION_encryptStorage, data, &reply) != NO_ERROR) {
-            ALOGD("encryptStorage could not contact remote\n");
-            return -1;
-        }
-        int32_t err = reply.readExceptionCode();
-        if (err < 0) {
-            ALOGD("encryptStorage caught exception %d\n", err);
-            return err;
-        }
-        return reply.readInt32();
-    }
 };
 
 IMPLEMENT_META_INTERFACE(MountService, "android.os.storage.IStorageManager")
diff --git a/libs/storage/include/storage/IMountService.h b/libs/storage/include/storage/IMountService.h
index 5b07318..5a9c39b 100644
--- a/libs/storage/include/storage/IMountService.h
+++ b/libs/storage/include/storage/IMountService.h
@@ -70,8 +70,6 @@
             const sp<IObbActionListener>& token, const int32_t nonce) = 0;
     virtual bool isObbMounted(const String16& filename) = 0;
     virtual bool getMountedObbPath(const String16& filename, String16& path) = 0;
-    virtual int32_t decryptStorage(const String16& password) = 0;
-    virtual int32_t encryptStorage(const String16& password) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/location/java/android/location/GnssExcessPathInfo.java b/location/java/android/location/GnssExcessPathInfo.java
new file mode 100644
index 0000000..72b2374
--- /dev/null
+++ b/location/java/android/location/GnssExcessPathInfo.java
@@ -0,0 +1,375 @@
+/*
+ * 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 android.location;
+
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_ATTENUATION;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_REFLECTING_PLANE;
+
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
+
+/**
+ * Contains the info of an excess path signal caused by reflection
+ *
+ * @hide
+ */
+@SystemApi
+public final class GnssExcessPathInfo implements Parcelable {
+
+    private static final int HAS_EXCESS_PATH_LENGTH_MASK = EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH;
+    private static final int HAS_EXCESS_PATH_LENGTH_UNC_MASK =
+            EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC;
+    private static final int HAS_REFLECTING_PLANE_MASK = EXCESS_PATH_INFO_HAS_REFLECTING_PLANE;
+    private static final int HAS_ATTENUATION_MASK = EXCESS_PATH_INFO_HAS_ATTENUATION;
+
+    /* A bitmask of fields present in this object (see HAS_* constants defined above) */
+    private final int mFlags;
+    private final float mExcessPathLengthMeters;
+    private final float mExcessPathLengthUncertaintyMeters;
+    @Nullable
+    private final GnssReflectingPlane mReflectingPlane;
+    private final float mAttenuationDb;
+
+    private GnssExcessPathInfo(
+            int flags,
+            float excessPathLengthMeters,
+            float excessPathLengthUncertaintyMeters,
+            @Nullable GnssReflectingPlane reflectingPlane,
+            float attenuationDb) {
+        mFlags = flags;
+        mExcessPathLengthMeters = excessPathLengthMeters;
+        mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
+        mReflectingPlane = reflectingPlane;
+        mAttenuationDb = attenuationDb;
+    }
+
+    /**
+     * Gets a bitmask of fields present in this object.
+     *
+     * <p>This API exists for JNI since it is easier for JNI to get one integer flag than looking up
+     * several has* methods.
+     * @hide
+     */
+    public int getFlags() {
+        return mFlags;
+    }
+
+    /** Returns {@code true} if {@link #getExcessPathLengthMeters()} is valid. */
+    public boolean hasExcessPathLength() {
+        return (mFlags & HAS_EXCESS_PATH_LENGTH_MASK) != 0;
+    }
+
+    /**
+     * Returns the excess path length to be subtracted from pseudorange before using it in
+     * calculating location.
+     *
+     * <p>{@link #hasExcessPathLength()} must be true when calling this method. Otherwise, an
+     * {@link UnsupportedOperationException} will be thrown.
+     */
+    @FloatRange(from = 0.0f)
+    public float getExcessPathLengthMeters() {
+        if (!hasExcessPathLength()) {
+            throw new UnsupportedOperationException(
+                    "getExcessPathLengthMeters() is not supported when hasExcessPathLength() is "
+                            + "false");
+        }
+        return mExcessPathLengthMeters;
+    }
+
+    /** Returns {@code true} if {@link #getExcessPathLengthUncertaintyMeters()} is valid. */
+    public boolean hasExcessPathLengthUncertainty() {
+        return (mFlags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0;
+    }
+
+    /**
+     * Returns the error estimate (1-sigma) for the excess path length estimate.
+     *
+     * <p>{@link #hasExcessPathLengthUncertainty()} must be true when calling this method.
+     * Otherwise, an {@link UnsupportedOperationException} will be thrown.
+     */
+    @FloatRange(from = 0.0f)
+    public float getExcessPathLengthUncertaintyMeters() {
+        if (!hasExcessPathLengthUncertainty()) {
+            throw new UnsupportedOperationException(
+                    "getExcessPathLengthUncertaintyMeters() is not supported when "
+                            + "hasExcessPathLengthUncertainty() is false");
+        }
+        return mExcessPathLengthUncertaintyMeters;
+    }
+
+    /**
+     * Returns {@code true} if {@link #getReflectingPlane()} is valid.
+     *
+     * <p>Returns false if the satellite signal goes through multiple reflections or if reflection
+     * plane serving is not supported.
+     */
+    public boolean hasReflectingPlane() {
+        return (mFlags & HAS_REFLECTING_PLANE_MASK) != 0;
+    }
+
+    /**
+     * Returns the reflecting plane characteristics at which the signal has bounced.
+     *
+     * <p>{@link #hasReflectingPlane()} must be true when calling this method. Otherwise, an
+     * {@link UnsupportedOperationException} will be thrown.
+     */
+    @NonNull
+    public GnssReflectingPlane getReflectingPlane() {
+        if (!hasReflectingPlane()) {
+            throw new UnsupportedOperationException(
+                    "getReflectingPlane() is not supported when hasReflectingPlane() is false");
+        }
+        return mReflectingPlane;
+    }
+
+    /** Returns {@code true} if {@link #getAttenuationDb()} is valid. */
+    public boolean hasAttenuation() {
+        return (mFlags & HAS_ATTENUATION_MASK) != 0;
+    }
+
+    /**
+     * Returns the expected reduction of signal strength of this path in non-negative dB.
+     *
+     * <p>{@link #hasAttenuation()} must be true when calling this method. Otherwise, an
+     * {@link UnsupportedOperationException} will be thrown.
+     */
+    @FloatRange(from = 0.0f)
+    public float getAttenuationDb() {
+        if (!hasAttenuation()) {
+            throw new UnsupportedOperationException(
+                    "getAttenuationDb() is not supported when hasAttenuation() is false");
+        }
+        return mAttenuationDb;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel parcel, int parcelFlags) {
+        parcel.writeInt(mFlags);
+        if (hasExcessPathLength()) {
+            parcel.writeFloat(mExcessPathLengthMeters);
+        }
+        if (hasExcessPathLengthUncertainty()) {
+            parcel.writeFloat(mExcessPathLengthUncertaintyMeters);
+        }
+        if (hasReflectingPlane()) {
+            mReflectingPlane.writeToParcel(parcel, parcelFlags);
+        }
+        if (hasAttenuation()) {
+            parcel.writeFloat(mAttenuationDb);
+        }
+    }
+
+    public static final @NonNull Creator<GnssExcessPathInfo> CREATOR =
+            new Creator<GnssExcessPathInfo>() {
+                @Override
+                @NonNull
+                public GnssExcessPathInfo createFromParcel(@NonNull Parcel parcel) {
+                    int flags = parcel.readInt();
+                    float excessPathLengthMeters =
+                            (flags & HAS_EXCESS_PATH_LENGTH_MASK) != 0
+                                    ? parcel.readFloat() : 0;
+                    float excessPathLengthUncertaintyMeters =
+                            (flags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0
+                                    ? parcel.readFloat() : 0;
+                    GnssReflectingPlane reflectingPlane =
+                            (flags & HAS_REFLECTING_PLANE_MASK) != 0
+                                    ? GnssReflectingPlane.CREATOR.createFromParcel(parcel) : null;
+                    float attenuationDb =
+                            (flags & HAS_ATTENUATION_MASK) != 0
+                                    ? parcel.readFloat() : 0;
+                    return new GnssExcessPathInfo(flags, excessPathLengthMeters,
+                            excessPathLengthUncertaintyMeters, reflectingPlane, attenuationDb);
+                }
+
+                @Override
+                public GnssExcessPathInfo[] newArray(int i) {
+                    return new GnssExcessPathInfo[i];
+                }
+            };
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof GnssExcessPathInfo) {
+            GnssExcessPathInfo that = (GnssExcessPathInfo) obj;
+            return this.mFlags == that.mFlags
+                    && (!hasExcessPathLength() || Float.compare(this.mExcessPathLengthMeters,
+                    that.mExcessPathLengthMeters) == 0)
+                    && (!hasExcessPathLengthUncertainty() || Float.compare(
+                    this.mExcessPathLengthUncertaintyMeters,
+                    that.mExcessPathLengthUncertaintyMeters) == 0)
+                    && (!hasReflectingPlane() || Objects.equals(this.mReflectingPlane,
+                    that.mReflectingPlane))
+                    && (!hasAttenuation() || Float.compare(this.mAttenuationDb,
+                    that.mAttenuationDb) == 0);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mFlags,
+                mExcessPathLengthMeters,
+                mExcessPathLengthUncertaintyMeters,
+                mReflectingPlane,
+                mAttenuationDb);
+    }
+
+    @NonNull
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder("GnssExcessPathInfo[");
+        if (hasExcessPathLength()) {
+            builder.append(" ExcessPathLengthMeters=").append(mExcessPathLengthMeters);
+        }
+        if (hasExcessPathLengthUncertainty()) {
+            builder.append(" ExcessPathLengthUncertaintyMeters=").append(
+                    mExcessPathLengthUncertaintyMeters);
+        }
+        if (hasReflectingPlane()) {
+            builder.append(" ReflectingPlane=").append(mReflectingPlane);
+        }
+        if (hasAttenuation()) {
+            builder.append(" AttenuationDb=").append(mAttenuationDb);
+        }
+        builder.append(']');
+        return builder.toString();
+    }
+
+    /** Builder for {@link GnssExcessPathInfo}. */
+    public static final class Builder {
+        private int mFlags;
+        private float mExcessPathLengthMeters;
+        private float mExcessPathLengthUncertaintyMeters;
+        @Nullable
+        private GnssReflectingPlane mReflectingPlane;
+        private float mAttenuationDb;
+
+        /** Constructor for {@link Builder}. */
+        public Builder() {}
+
+        /**
+         * Sets the excess path length to be subtracted from pseudorange before using it in
+         * calculating location.
+         */
+        @NonNull
+        public Builder setExcessPathLengthMeters(
+                @FloatRange(from = 0.0f) float excessPathLengthMeters) {
+            Preconditions.checkArgumentInRange(excessPathLengthMeters, 0, Float.MAX_VALUE,
+                    "excessPathLengthMeters");
+            mExcessPathLengthMeters = excessPathLengthMeters;
+            mFlags |= HAS_EXCESS_PATH_LENGTH_MASK;
+            return this;
+        }
+
+        /**
+         * Clears the excess path length.
+         *
+         * <p>This is to negate {@link #setExcessPathLengthMeters} call.
+         */
+        @NonNull
+        public Builder clearExcessPathLengthMeters() {
+            mExcessPathLengthMeters = 0;
+            mFlags &= ~HAS_EXCESS_PATH_LENGTH_MASK;
+            return this;
+        }
+
+        /** Sets the error estimate (1-sigma) for the excess path length estimate */
+        @NonNull
+        public Builder setExcessPathLengthUncertaintyMeters(
+                @FloatRange(from = 0.0f) float excessPathLengthUncertaintyMeters) {
+            Preconditions.checkArgumentInRange(excessPathLengthUncertaintyMeters, 0,
+                    Float.MAX_VALUE, "excessPathLengthUncertaintyMeters");
+            mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
+            mFlags |= HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+            return this;
+        }
+
+        /**
+         * Clears the error estimate (1-sigma) for the excess path length estimate
+         *
+         * <p>This is to negate {@link #setExcessPathLengthUncertaintyMeters} call.
+         */
+        @NonNull
+        public Builder clearExcessPathLengthUncertaintyMeters() {
+            mExcessPathLengthUncertaintyMeters = 0;
+            mFlags &= ~HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+            return this;
+        }
+
+        /** Sets the reflecting plane information */
+        @NonNull
+        public Builder setReflectingPlane(@Nullable GnssReflectingPlane reflectingPlane) {
+            mReflectingPlane = reflectingPlane;
+            if (reflectingPlane != null) {
+                mFlags |= HAS_REFLECTING_PLANE_MASK;
+            } else {
+                mFlags &= ~HAS_REFLECTING_PLANE_MASK;
+            }
+            return this;
+        }
+
+        /**
+         * Sets the attenuation value in dB.
+         */
+        @NonNull
+        public Builder setAttenuationDb(@FloatRange(from = 0.0f) float attenuationDb) {
+            Preconditions.checkArgumentInRange(attenuationDb, 0, Float.MAX_VALUE,
+                    "attenuationDb");
+            mAttenuationDb = attenuationDb;
+            mFlags |= HAS_ATTENUATION_MASK;
+            return this;
+        }
+
+        /**
+         * Clears the attenuation value in dB.
+         *
+         * <p>This is to negate {@link #setAttenuationDb(float)} call.
+         */
+        @NonNull
+        public Builder clearAttenuationDb() {
+            mAttenuationDb = 0;
+            mFlags &= ~HAS_ATTENUATION_MASK;
+            return this;
+        }
+
+        /** Builds a {@link GnssExcessPathInfo} instance as specified by this builder. */
+        @NonNull
+        public GnssExcessPathInfo build() {
+            return new GnssExcessPathInfo(
+                    mFlags,
+                    mExcessPathLengthMeters,
+                    mExcessPathLengthUncertaintyMeters,
+                    mReflectingPlane,
+                    mAttenuationDb);
+        }
+    }
+}
diff --git a/location/java/android/location/GnssReflectingPlane.java b/location/java/android/location/GnssReflectingPlane.java
index 1acdd1e..115cbec 100644
--- a/location/java/android/location/GnssReflectingPlane.java
+++ b/location/java/android/location/GnssReflectingPlane.java
@@ -22,9 +22,14 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.Objects;
+
 /**
  * Holds the characteristics of the reflecting plane that a satellite signal has bounced from.
  *
+ * <p>Starting with Android T, this class supports {@link #equals} and {@link #hashCode}, which
+ * are not supported before that.
+ *
  * @hide
  */
 @SystemApi
@@ -107,18 +112,6 @@
                 }
             };
 
-    @NonNull
-    @Override
-    public String toString() {
-        final String format = "   %-29s = %s\n";
-        StringBuilder builder = new StringBuilder("ReflectingPlane:\n");
-        builder.append(String.format(format, "LatitudeDegrees = ", mLatitudeDegrees));
-        builder.append(String.format(format, "LongitudeDegrees = ", mLongitudeDegrees));
-        builder.append(String.format(format, "AltitudeMeters = ", mAltitudeMeters));
-        builder.append(String.format(format, "AzimuthDegrees = ", mAzimuthDegrees));
-        return builder.toString();
-    }
-
     @Override
     public void writeToParcel(@NonNull Parcel parcel, int flags) {
         parcel.writeDouble(mLatitudeDegrees);
@@ -127,6 +120,35 @@
         parcel.writeDouble(mAzimuthDegrees);
     }
 
+    @NonNull
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder("ReflectingPlane[");
+        builder.append(" LatitudeDegrees=").append(mLatitudeDegrees);
+        builder.append(" LongitudeDegrees=").append(mLongitudeDegrees);
+        builder.append(" AltitudeMeters=").append(mAltitudeMeters);
+        builder.append(" AzimuthDegrees=").append(mAzimuthDegrees);
+        builder.append(']');
+        return builder.toString();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof GnssReflectingPlane) {
+            GnssReflectingPlane that = (GnssReflectingPlane) obj;
+            return Double.compare(this.mLatitudeDegrees, that.mLatitudeDegrees) == 0
+                    && Double.compare(this.mLongitudeDegrees, that.mLongitudeDegrees) == 0
+                    && Double.compare(this.mAltitudeMeters, that.mAltitudeMeters) == 0
+                    && Double.compare(this.mAzimuthDegrees, that.mAzimuthDegrees) == 0;
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mLatitudeDegrees, mLatitudeDegrees, mAltitudeMeters, mAzimuthDegrees);
+    }
+
     /** Builder for {@link GnssReflectingPlane} */
     public static final class Builder {
         /** For documentation, see corresponding fields in {@link GnssReflectingPlane}. */
diff --git a/location/java/android/location/GnssSingleSatCorrection.java b/location/java/android/location/GnssSingleSatCorrection.java
index 262630b..a7fce0a 100644
--- a/location/java/android/location/GnssSingleSatCorrection.java
+++ b/location/java/android/location/GnssSingleSatCorrection.java
@@ -16,6 +16,11 @@
 
 package android.location;
 
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.SINGLE_SAT_CORRECTION_HAS_COMBINED_ATTENUATION;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH_UNC;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY;
+
 import android.annotation.FloatRange;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -26,6 +31,8 @@
 
 import com.android.internal.util.Preconditions;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -36,106 +43,47 @@
 @SystemApi
 public final class GnssSingleSatCorrection implements Parcelable {
 
-    /**
-     * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
-     * #mProbSatIsLos}.
-     *
-     * @hide
-     */
-    public static final int HAS_PROB_SAT_IS_LOS_MASK = 1 << 0;
+    private static final int HAS_PROB_SAT_IS_LOS_MASK =
+            SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY;
+    private static final int HAS_COMBINED_EXCESS_PATH_LENGTH_MASK =
+            SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH;
+    private static final int HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK =
+            SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH_UNC;
+    private static final int HAS_COMBINED_ATTENUATION_MASK =
+            SINGLE_SAT_CORRECTION_HAS_COMBINED_ATTENUATION;
 
-    /**
-     * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
-     * #mExcessPathLengthMeters}.
-     *
-     * @hide
-     */
-    public static final int HAS_EXCESS_PATH_LENGTH_MASK = 1 << 1;
-
-    /**
-     * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
-     * #mExcessPathLengthUncertaintyMeters}.
-     *
-     * @hide
-     */
-    public static final int HAS_EXCESS_PATH_LENGTH_UNC_MASK = 1 << 2;
-
-    /**
-     * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
-     * #mReflectingPlane}.
-     *
-     * @hide
-     */
-    public static final int HAS_REFLECTING_PLANE_MASK = 1 << 3;
-
-    /** A bitmask of fields present in this object (see HAS_* constants defined above) */
+    /* A bitmask of fields present in this object (see HAS_* constants defined above). */
     private final int mSingleSatCorrectionFlags;
 
-    /** Defines the constellation of the given satellite as defined in {@link GnssStatus}. */
-    @GnssStatus.ConstellationType
     private final int mConstellationType;
-
-    /**
-     * Satellite vehicle ID number
-     *
-     * <p>Interpretation depends on {@link GnssStatus#getSvid(int)}.
-     */
-    @IntRange(from = 0)
     private final int mSatId;
-
-    /**
-     * Carrier frequency of the signal to be corrected, for example it can be the GPS center
-     * frequency for L1 = 1,575,420,000 Hz, varying GLO channels, etc.
-     *
-     * <p>For an L1, L5 receiver tracking a satellite on L1 and L5 at the same time, two correction
-     * objects will be reported for this same satellite, in one of the correction objects, all the
-     * values related to L1 will be filled, and in the other all of the values related to L5 will be
-     * filled.
-     */
-    @FloatRange(from = 0.0f,  fromInclusive = false)
     private final float mCarrierFrequencyHz;
-
-    /**
-     * The probability that the satellite is estimated to be in Line-of-Sight condition at the given
-     * location.
-     */
-    @FloatRange(from = 0.0f, to = 1.0f)
     private final float mProbSatIsLos;
+    private final float mCombinedExcessPathLengthMeters;
+    private final float mCombinedExcessPathLengthUncertaintyMeters;
+    private final float mCombinedAttenuationDb;
 
-    /**
-     * Excess path length to be subtracted from pseudorange before using it in calculating location.
-     */
-    @FloatRange(from = 0.0f)
-    private final float mExcessPathLengthMeters;
-
-    /** Error estimate (1-sigma) for the Excess path length estimate */
-    @FloatRange(from = 0.0f)
-    private final float mExcessPathLengthUncertaintyMeters;
-
-    /**
-     * Defines the reflecting plane location and azimuth information
-     *
-     * <p>The flag HAS_REFLECTING_PLANE will be used to set this value to invalid if the satellite
-     * signal goes through multiple reflections or if reflection plane serving is not supported.
-     */
-    @Nullable
-    private final GnssReflectingPlane mReflectingPlane;
+    @NonNull
+    private final List<GnssExcessPathInfo> mGnssExcessPathInfoList;
 
     private GnssSingleSatCorrection(int singleSatCorrectionFlags, int constellationType, int satId,
             float carrierFrequencyHz, float probSatIsLos, float excessPathLengthMeters,
-            float excessPathLengthUncertaintyMeters, GnssReflectingPlane reflectingPlane) {
+            float excessPathLengthUncertaintyMeters,
+            float combinedAttenuationDb,
+            @NonNull List<GnssExcessPathInfo> gnssExcessPathInfoList) {
         mSingleSatCorrectionFlags = singleSatCorrectionFlags;
         mConstellationType = constellationType;
         mSatId = satId;
         mCarrierFrequencyHz = carrierFrequencyHz;
         mProbSatIsLos = probSatIsLos;
-        mExcessPathLengthMeters = excessPathLengthMeters;
-        mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
-        mReflectingPlane = reflectingPlane;
+        mCombinedExcessPathLengthMeters = excessPathLengthMeters;
+        mCombinedExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
+        mCombinedAttenuationDb = combinedAttenuationDb;
+        mGnssExcessPathInfoList = gnssExcessPathInfoList;
     }
 
     /**
-     * Gets a bitmask of fields present in this object
+     * Gets a bitmask of fields present in this object.
      *
      * @hide
      */
@@ -193,29 +141,46 @@
     }
 
     /**
-     * Returns the Excess path length to be subtracted from pseudorange before using it in
+     * Returns the combined excess path length to be subtracted from pseudorange before using it in
      * calculating location.
      */
     @FloatRange(from = 0.0f)
     public float getExcessPathLengthMeters() {
-        return mExcessPathLengthMeters;
+        return mCombinedExcessPathLengthMeters;
     }
 
-    /** Returns the error estimate (1-sigma) for the Excess path length estimate */
+    /** Returns the error estimate (1-sigma) for the combined excess path length estimate. */
     @FloatRange(from = 0.0f)
     public float getExcessPathLengthUncertaintyMeters() {
-        return mExcessPathLengthUncertaintyMeters;
+        return mCombinedExcessPathLengthUncertaintyMeters;
     }
 
     /**
-     * Returns the reflecting plane characteristics at which the signal has bounced
+     * Returns the combined expected reduction of signal strength for this satellite in
+     * non-negative dB.
+     */
+    @FloatRange(from = 0.0f)
+    public float getCombinedAttenuationDb() {
+        return mCombinedAttenuationDb;
+    }
+
+    /**
+     * Returns the reflecting plane characteristics at which the signal has bounced.
      *
-     * <p>The flag HAS_REFLECTING_PLANE will be used to set this value to invalid if the satellite
-     * signal goes through multiple reflections or if reflection plane serving is not supported
+     * @deprecated Combined excess path does not have a reflecting plane.
      */
     @Nullable
+    @Deprecated
     public GnssReflectingPlane getReflectingPlane() {
-        return mReflectingPlane;
+        return null;
+    }
+
+    /**
+     * Returns the list of {@link GnssExcessPathInfo} associated with this satellite signal.
+     */
+    @NonNull
+    public List<GnssExcessPathInfo> getGnssExcessPathInfoList() {
+        return mGnssExcessPathInfoList;
     }
 
     /** Returns {@code true} if {@link #getProbabilityLineOfSight()} is valid. */
@@ -225,17 +190,27 @@
 
     /** Returns {@code true} if {@link #getExcessPathLengthMeters()} is valid. */
     public boolean hasExcessPathLength() {
-        return (mSingleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_MASK) != 0;
+        return (mSingleSatCorrectionFlags & HAS_COMBINED_EXCESS_PATH_LENGTH_MASK) != 0;
     }
 
     /** Returns {@code true} if {@link #getExcessPathLengthUncertaintyMeters()} is valid. */
     public boolean hasExcessPathLengthUncertainty() {
-        return (mSingleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0;
+        return (mSingleSatCorrectionFlags & HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK) != 0;
     }
 
-    /** Returns {@code true} if {@link #getReflectingPlane()} is valid. */
+    /**
+     * Returns {@code true} if {@link #getReflectingPlane()} is valid.
+     *
+     * @deprecated Combined excess path does not have a reflecting plane.
+     */
+    @Deprecated
     public boolean hasReflectingPlane() {
-        return (mSingleSatCorrectionFlags & HAS_REFLECTING_PLANE_MASK) != 0;
+        return false;
+    }
+
+    /** Returns {@code true} if {@link #getCombinedAttenuationDb()} is valid. */
+    public boolean hasCombinedAttenuation() {
+        return (mSingleSatCorrectionFlags & HAS_COMBINED_ATTENUATION_MASK) != 0;
     }
 
     @Override
@@ -253,14 +228,15 @@
             parcel.writeFloat(mProbSatIsLos);
         }
         if (hasExcessPathLength()) {
-            parcel.writeFloat(mExcessPathLengthMeters);
+            parcel.writeFloat(mCombinedExcessPathLengthMeters);
         }
         if (hasExcessPathLengthUncertainty()) {
-            parcel.writeFloat(mExcessPathLengthUncertaintyMeters);
+            parcel.writeFloat(mCombinedExcessPathLengthUncertaintyMeters);
         }
-        if (hasReflectingPlane()) {
-            mReflectingPlane.writeToParcel(parcel, flags);
+        if (hasCombinedAttenuation()) {
+            parcel.writeFloat(mCombinedAttenuationDb);
         }
+        parcel.writeTypedList(mGnssExcessPathInfoList);
     }
 
     public static final Creator<GnssSingleSatCorrection> CREATOR =
@@ -274,18 +250,21 @@
                     float carrierFrequencyHz = parcel.readFloat();
                     float probSatIsLos = (singleSatCorrectionFlags & HAS_PROB_SAT_IS_LOS_MASK) != 0
                             ? parcel.readFloat() : 0;
-                    float excessPathLengthMeters =
-                            (singleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_MASK) != 0
+                    float combinedExcessPathLengthMeters =
+                            (singleSatCorrectionFlags & HAS_COMBINED_EXCESS_PATH_LENGTH_MASK) != 0
                                     ? parcel.readFloat() : 0;
-                    float excessPathLengthUncertaintyMeters =
-                            (singleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0
+                    float combinedExcessPathLengthUncertaintyMeters =
+                            (singleSatCorrectionFlags & HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK)
+                                    != 0 ? parcel.readFloat() : 0;
+                    float combinedAttenuationDb =
+                            (singleSatCorrectionFlags & HAS_COMBINED_ATTENUATION_MASK) != 0
                                     ? parcel.readFloat() : 0;
-                    GnssReflectingPlane reflectingPlane =
-                            (singleSatCorrectionFlags & HAS_REFLECTING_PLANE_MASK) != 0
-                                    ? GnssReflectingPlane.CREATOR.createFromParcel(parcel) : null;
+                    List<GnssExcessPathInfo> gnssExcessPathInfoList = parcel.createTypedArrayList(
+                            GnssExcessPathInfo.CREATOR);
                     return new GnssSingleSatCorrection(singleSatCorrectionFlags, constellationType,
-                            satId, carrierFrequencyHz, probSatIsLos, excessPathLengthMeters,
-                            excessPathLengthUncertaintyMeters, reflectingPlane);
+                            satId, carrierFrequencyHz, probSatIsLos, combinedExcessPathLengthMeters,
+                            combinedExcessPathLengthUncertaintyMeters, combinedAttenuationDb,
+                            gnssExcessPathInfoList);
                 }
 
                 @Override
@@ -296,56 +275,24 @@
 
     @Override
     public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
+        if (obj instanceof GnssSingleSatCorrection) {
+            GnssSingleSatCorrection that = (GnssSingleSatCorrection) obj;
+            return this.mSingleSatCorrectionFlags == that.mSingleSatCorrectionFlags
+                    && this.mConstellationType == that.mConstellationType
+                    && this.mSatId == that.mSatId
+                    && Float.compare(mCarrierFrequencyHz, that.mCarrierFrequencyHz) == 0
+                    && (!hasValidSatelliteLineOfSight() || Float.compare(mProbSatIsLos,
+                    that.mProbSatIsLos) == 0)
+                    && (!hasExcessPathLength() || Float.compare(mCombinedExcessPathLengthMeters,
+                    that.mCombinedExcessPathLengthMeters) == 0)
+                    && (!hasExcessPathLengthUncertainty() || Float.compare(
+                    mCombinedExcessPathLengthUncertaintyMeters,
+                    that.mCombinedExcessPathLengthUncertaintyMeters) == 0)
+                    && (!hasCombinedAttenuation() || Float.compare(mCombinedAttenuationDb,
+                    that.mCombinedAttenuationDb) == 0)
+                    && mGnssExcessPathInfoList.equals(that.mGnssExcessPathInfoList);
         }
-        if (!(obj instanceof GnssSingleSatCorrection)) {
-            return false;
-        }
-
-        GnssSingleSatCorrection other = (GnssSingleSatCorrection) obj;
-        if (mConstellationType != other.mConstellationType) {
-            return false;
-        }
-        if (mSatId != other.mSatId) {
-            return false;
-        }
-        if (Float.compare(mCarrierFrequencyHz, other.mCarrierFrequencyHz) != 0) {
-            return false;
-        }
-
-        if (hasValidSatelliteLineOfSight() != other.hasValidSatelliteLineOfSight()) {
-            return false;
-        }
-        if (hasValidSatelliteLineOfSight()
-                && Float.compare(mProbSatIsLos, other.mProbSatIsLos) != 0) {
-            return false;
-        }
-
-        if (hasExcessPathLength() != other.hasExcessPathLength()) {
-            return false;
-        }
-        if (hasExcessPathLength()
-                && Float.compare(mExcessPathLengthMeters, other.mExcessPathLengthMeters) != 0) {
-            return false;
-        }
-
-        if (hasExcessPathLengthUncertainty() != other.hasExcessPathLengthUncertainty()) {
-            return false;
-        }
-        if (hasExcessPathLengthUncertainty() && Float.compare(mExcessPathLengthUncertaintyMeters,
-                other.mExcessPathLengthUncertaintyMeters) != 0) {
-            return false;
-        }
-
-        if (hasReflectingPlane() != other.hasReflectingPlane()) {
-            return false;
-        }
-        if (hasReflectingPlane()
-                && !mReflectingPlane.equals(other.mReflectingPlane)) {
-            return false;
-        }
-        return true;
+        return false;
     }
 
     @Override
@@ -355,9 +302,10 @@
                 mSatId,
                 mCarrierFrequencyHz,
                 mProbSatIsLos,
-                mExcessPathLengthMeters,
-                mExcessPathLengthUncertaintyMeters,
-                mReflectingPlane);
+                mCombinedExcessPathLengthMeters,
+                mCombinedExcessPathLengthUncertaintyMeters,
+                mCombinedAttenuationDb,
+                mGnssExcessPathInfoList);
     }
 
     @NonNull
@@ -371,14 +319,19 @@
             builder.append(" ProbSatIsLos=").append(mProbSatIsLos);
         }
         if (hasExcessPathLength()) {
-            builder.append(" ExcessPathLengthMeters=").append(mExcessPathLengthMeters);
+            builder.append(" CombinedExcessPathLengthMeters=").append(
+                    mCombinedExcessPathLengthMeters);
         }
         if (hasExcessPathLengthUncertainty()) {
-            builder.append(" ExcessPathLengthUncertaintyMeters=").append(
-                    mExcessPathLengthUncertaintyMeters);
+            builder.append(" CombinedExcessPathLengthUncertaintyMeters=").append(
+                    mCombinedExcessPathLengthUncertaintyMeters);
         }
-        if (hasReflectingPlane()) {
-            builder.append(" ReflectingPlane=").append(mReflectingPlane);
+        if (hasCombinedAttenuation()) {
+            builder.append(" CombinedAttenuationDb=").append(
+                    mCombinedAttenuationDb);
+        }
+        if (!mGnssExcessPathInfoList.isEmpty()) {
+            builder.append(' ').append(mGnssExcessPathInfoList.toString());
         }
         builder.append(']');
         return builder.toString();
@@ -386,21 +339,16 @@
 
     /** Builder for {@link GnssSingleSatCorrection} */
     public static final class Builder {
-
-        /**
-         * For documentation of below fields, see corresponding fields in {@link
-         * GnssSingleSatCorrection}.
-         */
         private int mSingleSatCorrectionFlags;
-
         private int mConstellationType;
         private int mSatId;
         private float mCarrierFrequencyHz;
         private float mProbSatIsLos;
-        private float mExcessPathLengthMeters;
-        private float mExcessPathLengthUncertaintyMeters;
-        @Nullable
-        private GnssReflectingPlane mReflectingPlane;
+        private float mCombinedExcessPathLengthMeters;
+        private float mCombinedExcessPathLengthUncertaintyMeters;
+        private float mCombinedAttenuationDb;
+        @NonNull
+        private List<GnssExcessPathInfo> mGnssExcessInfoList = new ArrayList<>();
 
         /** Sets the constellation type. */
         @NonNull public Builder setConstellationType(
@@ -409,18 +357,18 @@
             return this;
         }
 
-        /** Sets the Satellite ID defined in the ICD of the given constellation. */
+        /** Sets the satellite ID defined in the ICD of the given constellation. */
         @NonNull public Builder setSatelliteId(@IntRange(from = 0) int satId) {
             Preconditions.checkArgumentNonnegative(satId, "satId should be non-negative.");
             mSatId = satId;
             return this;
         }
 
-        /** Sets the Carrier frequency in Hz. */
+        /** Sets the carrier frequency in Hz. */
         @NonNull public Builder setCarrierFrequencyHz(
                 @FloatRange(from = 0.0f,  fromInclusive = false) float carrierFrequencyHz) {
-            Preconditions.checkArgument(
-                    carrierFrequencyHz >= 0, "carrierFrequencyHz should be non-negative.");
+            Preconditions.checkArgumentInRange(
+                    carrierFrequencyHz, 0, Float.MAX_VALUE, "carrierFrequencyHz");
             mCarrierFrequencyHz = carrierFrequencyHz;
             return this;
         }
@@ -450,58 +398,90 @@
         }
 
         /**
-         * Sets the Excess path length to be subtracted from pseudorange before using it in
+         * Sets the combined excess path length to be subtracted from pseudorange before using it in
          * calculating location.
          */
-        @NonNull public Builder setExcessPathLengthMeters(
-                @FloatRange(from = 0.0f) float excessPathLengthMeters) {
-            Preconditions.checkArgument(excessPathLengthMeters >= 0,
-                    "excessPathLengthMeters should be non-negative.");
-            mExcessPathLengthMeters = excessPathLengthMeters;
-            mSingleSatCorrectionFlags |= HAS_EXCESS_PATH_LENGTH_MASK;
+        @NonNull
+        public Builder setExcessPathLengthMeters(
+                @FloatRange(from = 0.0f) float combinedExcessPathLengthMeters) {
+            Preconditions.checkArgumentInRange(combinedExcessPathLengthMeters, 0, Float.MAX_VALUE,
+                    "excessPathLengthMeters");
+            mCombinedExcessPathLengthMeters = combinedExcessPathLengthMeters;
+            mSingleSatCorrectionFlags |= HAS_COMBINED_EXCESS_PATH_LENGTH_MASK;
             return this;
         }
 
         /**
-         * Clears the Excess path length.
+         * Clears the combined excess path length.
          *
          * <p>This is to negate {@link #setExcessPathLengthMeters} call.
          */
         @NonNull public Builder clearExcessPathLengthMeters() {
-            mExcessPathLengthMeters = 0;
-            mSingleSatCorrectionFlags &= ~HAS_EXCESS_PATH_LENGTH_MASK;
+            mCombinedExcessPathLengthMeters = 0;
+            mSingleSatCorrectionFlags &= ~HAS_COMBINED_EXCESS_PATH_LENGTH_MASK;
             return this;
         }
 
-        /** Sets the error estimate (1-sigma) for the Excess path length estimate */
+        /** Sets the error estimate (1-sigma) for the combined excess path length estimate. */
         @NonNull public Builder setExcessPathLengthUncertaintyMeters(
-                @FloatRange(from = 0.0f) float excessPathLengthUncertaintyMeters) {
-            Preconditions.checkArgument(excessPathLengthUncertaintyMeters >= 0,
-                    "excessPathLengthUncertaintyMeters should be non-negative.");
-            mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
-            mSingleSatCorrectionFlags |= HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+                @FloatRange(from = 0.0f) float combinedExcessPathLengthUncertaintyMeters) {
+            Preconditions.checkArgumentInRange(combinedExcessPathLengthUncertaintyMeters, 0,
+                    Float.MAX_VALUE, "excessPathLengthUncertaintyMeters");
+            mCombinedExcessPathLengthUncertaintyMeters = combinedExcessPathLengthUncertaintyMeters;
+            mSingleSatCorrectionFlags |= HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK;
             return this;
         }
 
         /**
-         * Clears the error estimate (1-sigma) for the Excess path length estimate
+         * Clears the error estimate (1-sigma) for the combined excess path length estimate.
          *
          * <p>This is to negate {@link #setExcessPathLengthUncertaintyMeters} call.
          */
         @NonNull public Builder clearExcessPathLengthUncertaintyMeters() {
-            mExcessPathLengthUncertaintyMeters = 0;
-            mSingleSatCorrectionFlags &= ~HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+            mCombinedExcessPathLengthUncertaintyMeters = 0;
+            mSingleSatCorrectionFlags &= ~HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK;
             return this;
         }
 
-        /** Sets the reflecting plane information */
+        /**
+         * Sets the combined attenuation in Db.
+         */
+        @NonNull public Builder setCombinedAttenuationDb(
+                @FloatRange(from = 0.0f) float combinedAttenuationDb) {
+            Preconditions.checkArgumentInRange(combinedAttenuationDb, 0, Float.MAX_VALUE,
+                    "combinedAttenuationDb");
+            mCombinedAttenuationDb = combinedAttenuationDb;
+            mSingleSatCorrectionFlags |= HAS_COMBINED_ATTENUATION_MASK;
+            return this;
+        }
+
+        /**
+         * Clears the combined attenuation.
+         *
+         * <p>This is to negate {@link #setCombinedAttenuationDb} call.
+         */
+        @NonNull public Builder clearCombinedAttenuationDb() {
+            mCombinedAttenuationDb = 0;
+            mSingleSatCorrectionFlags &= ~HAS_COMBINED_ATTENUATION_MASK;
+            return this;
+        }
+
+        /**
+         * Sets the reflecting plane information.
+         *
+         * @deprecated Combined excess path does not have a reflecting plane.
+         */
+        @Deprecated
         @NonNull public Builder setReflectingPlane(@Nullable GnssReflectingPlane reflectingPlane) {
-            mReflectingPlane = reflectingPlane;
-            if (reflectingPlane != null) {
-                mSingleSatCorrectionFlags |= HAS_REFLECTING_PLANE_MASK;
-            } else {
-                mSingleSatCorrectionFlags &= ~HAS_REFLECTING_PLANE_MASK;
-            }
+            return this;
+        }
+
+        /**
+         * Sets the collection of {@link GnssExcessPathInfo}.
+         */
+        @NonNull
+        public Builder setGnssExcessPathInfoList(@NonNull List<GnssExcessPathInfo> infoList) {
+            mGnssExcessInfoList = new ArrayList<>(infoList);
             return this;
         }
 
@@ -512,9 +492,10 @@
                     mSatId,
                     mCarrierFrequencyHz,
                     mProbSatIsLos,
-                    mExcessPathLengthMeters,
-                    mExcessPathLengthUncertaintyMeters,
-                    mReflectingPlane);
+                    mCombinedExcessPathLengthMeters,
+                    mCombinedExcessPathLengthUncertaintyMeters,
+                    mCombinedAttenuationDb,
+                    mGnssExcessInfoList);
         }
     }
 }
diff --git a/location/java/android/location/LastLocationRequest.java b/location/java/android/location/LastLocationRequest.java
index fe0a14f..ec03a33 100644
--- a/location/java/android/location/LastLocationRequest.java
+++ b/location/java/android/location/LastLocationRequest.java
@@ -17,7 +17,6 @@
 package android.location;
 
 import static android.Manifest.permission.LOCATION_BYPASS;
-import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -223,9 +222,8 @@
          *
          * @hide
          */
-        // TODO: remove WRITE_SECURE_SETTINGS.
         @SystemApi
-        @RequiresPermission(anyOf = {WRITE_SECURE_SETTINGS, LOCATION_BYPASS})
+        @RequiresPermission(LOCATION_BYPASS)
         public @NonNull LastLocationRequest.Builder setAdasGnssBypass(boolean adasGnssBypass) {
             mAdasGnssBypass = adasGnssBypass;
             return this;
@@ -242,9 +240,8 @@
          *
          * @hide
          */
-        // TODO: remove WRITE_SECURE_SETTINGS.
         @SystemApi
-        @RequiresPermission(anyOf = {WRITE_SECURE_SETTINGS, LOCATION_BYPASS})
+        @RequiresPermission(LOCATION_BYPASS)
         public @NonNull Builder setLocationSettingsIgnored(boolean locationSettingsIgnored) {
             mLocationSettingsIgnored = locationSettingsIgnored;
             return this;
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index f1605f1..033056c 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -132,31 +132,31 @@
     }
 
     /**
-     * Construct a new Location object that is copied from an existing one.
+     * Constructs a new location copied from the given location.
      */
-    public Location(@NonNull Location l) {
-        set(l);
+    public Location(@NonNull Location location) {
+        set(location);
     }
 
     /**
      * Turns this location into a copy of the given location.
      */
-    public void set(@NonNull Location l) {
-        mFieldsMask = l.mFieldsMask;
-        mProvider = l.mProvider;
-        mTimeMs = l.mTimeMs;
-        mElapsedRealtimeNs = l.mElapsedRealtimeNs;
-        mElapsedRealtimeUncertaintyNs = l.mElapsedRealtimeUncertaintyNs;
-        mLatitudeDegrees = l.mLatitudeDegrees;
-        mLongitudeDegrees = l.mLongitudeDegrees;
-        mHorizontalAccuracyMeters = l.mHorizontalAccuracyMeters;
-        mAltitudeMeters = l.mAltitudeMeters;
-        mAltitudeAccuracyMeters = l.mAltitudeAccuracyMeters;
-        mSpeedMetersPerSecond = l.mSpeedMetersPerSecond;
-        mSpeedAccuracyMetersPerSecond = l.mSpeedAccuracyMetersPerSecond;
-        mBearingDegrees = l.mBearingDegrees;
-        mBearingAccuracyDegrees = l.mBearingAccuracyDegrees;
-        mExtras = (l.mExtras == null) ? null : new Bundle(l.mExtras);
+    public void set(@NonNull Location location) {
+        mFieldsMask = location.mFieldsMask;
+        mProvider = location.mProvider;
+        mTimeMs = location.mTimeMs;
+        mElapsedRealtimeNs = location.mElapsedRealtimeNs;
+        mElapsedRealtimeUncertaintyNs = location.mElapsedRealtimeUncertaintyNs;
+        mLatitudeDegrees = location.mLatitudeDegrees;
+        mLongitudeDegrees = location.mLongitudeDegrees;
+        mHorizontalAccuracyMeters = location.mHorizontalAccuracyMeters;
+        mAltitudeMeters = location.mAltitudeMeters;
+        mAltitudeAccuracyMeters = location.mAltitudeAccuracyMeters;
+        mSpeedMetersPerSecond = location.mSpeedMetersPerSecond;
+        mSpeedAccuracyMetersPerSecond = location.mSpeedAccuracyMetersPerSecond;
+        mBearingDegrees = location.mBearingDegrees;
+        mBearingAccuracyDegrees = location.mBearingAccuracyDegrees;
+        mExtras = (location.mExtras == null) ? null : new Bundle(location.mExtras);
     }
 
     /**
@@ -182,14 +182,13 @@
     }
 
     /**
-     * Returns the approximate distance in meters between this
-     * location and the given location.  Distance is defined using
-     * the WGS84 ellipsoid.
+     * Returns the approximate distance in meters between this location and the given location.
+     * Distance is defined using the WGS84 ellipsoid.
      *
      * @param dest the destination location
      * @return the approximate distance in meters
      */
-    public @FloatRange float distanceTo(@NonNull Location dest) {
+    public @FloatRange(from = 0.0) float distanceTo(@NonNull Location dest) {
         BearingDistanceCache cache = sBearingDistanceCache.get();
         // See if we already have the result
         if (mLatitudeDegrees != cache.mLat1 || mLongitudeDegrees != cache.mLon1
@@ -201,11 +200,10 @@
     }
 
     /**
-     * Returns the approximate initial bearing in degrees East of true
-     * North when traveling along the shortest path between this
-     * location and the given location.  The shortest path is defined
-     * using the WGS84 ellipsoid.  Locations that are (nearly)
-     * antipodal may produce meaningless results.
+     * Returns the approximate initial bearing in degrees east of true north when traveling along
+     * the shortest path between this location and the given location. The shortest path is defined
+     * using the WGS84 ellipsoid. Locations that are (nearly) antipodal may produce meaningless
+     * results.
      *
      * @param dest the destination location
      * @return the initial bearing in degrees
@@ -254,7 +252,7 @@
      * not be used to order or compare locations. Prefer {@link #getElapsedRealtimeNanos} for that
      * purpose, as the elapsed realtime clock is guaranteed to be monotonic.
      *
-     * <p>On the other hand, this method may be useful for presenting a human readable time to the
+     * <p>On the other hand, this method may be useful for presenting a human-readable time to the
      * user, or as a heuristic for comparing location fixes across reboot or across devices.
      *
      * <p>All locations generated by the {@link LocationManager} are guaranteed to have this time
@@ -263,25 +261,24 @@
      *
      * @return the Unix epoch time of this location
      */
-    public @IntRange long getTime() {
+    public @IntRange(from = 0) long getTime() {
         return mTimeMs;
     }
 
     /**
      * Sets the Unix epoch time of this location fix, in milliseconds since the start of the Unix
-     * epoch (00:00:00 January 1, 1970 UTC).
+     * epoch (00:00:00 January 1 1970 UTC).
      *
      * @param timeMs the Unix epoch time of this location
-     * @see #getTime for more information about times / clocks
      */
-    public void setTime(@IntRange long timeMs) {
+    public void setTime(@IntRange(from = 0) long timeMs) {
         mTimeMs = timeMs;
     }
 
     /**
      * Return the time of this fix in nanoseconds of elapsed realtime since system boot.
      *
-     * <p>This value can be compared with {@link android.os.SystemClock#elapsedRealtimeNanos}, to
+     * <p>This value can be compared with {@link android.os.SystemClock#elapsedRealtimeNanos} to
      * reliably order or compare locations. This is reliable because elapsed realtime is guaranteed
      * to be monotonic and continues to increment even when the system is in deep sleep (unlike
      * {@link #getTime}). However, since elapsed realtime is with reference to system boot, it does
@@ -292,7 +289,7 @@
      *
      * @return elapsed realtime of this location in nanoseconds
      */
-    public @IntRange long getElapsedRealtimeNanos() {
+    public @IntRange(from = 0) long getElapsedRealtimeNanos() {
         return mElapsedRealtimeNs;
     }
 
@@ -302,7 +299,7 @@
      * @return elapsed realtime of this location in milliseconds
      * @see #getElapsedRealtimeNanos()
      */
-    public @IntRange long getElapsedRealtimeMillis() {
+    public @IntRange(from = 0) long getElapsedRealtimeMillis() {
         return NANOSECONDS.toMillis(mElapsedRealtimeNs);
     }
 
@@ -312,7 +309,7 @@
      *
      * @return age of this location in milliseconds
      */
-    public @IntRange long getElapsedRealtimeAgeMillis() {
+    public @IntRange(from = 0) long getElapsedRealtimeAgeMillis() {
         return getElapsedRealtimeAgeMillis(SystemClock.elapsedRealtime());
     }
 
@@ -323,7 +320,8 @@
      * @param referenceRealtimeMs reference realtime in milliseconds
      * @return age of this location in milliseconds
      */
-    public @IntRange long getElapsedRealtimeAgeMillis(@IntRange long referenceRealtimeMs) {
+    public long getElapsedRealtimeAgeMillis(
+            @IntRange(from = 0) long referenceRealtimeMs) {
         return referenceRealtimeMs - getElapsedRealtimeMillis();
     }
 
@@ -332,7 +330,7 @@
      *
      * @param elapsedRealtimeNs elapsed realtime in nanoseconds
      */
-    public void setElapsedRealtimeNanos(@IntRange long elapsedRealtimeNs) {
+    public void setElapsedRealtimeNanos(@IntRange(from = 0) long elapsedRealtimeNs) {
         mElapsedRealtimeNs = elapsedRealtimeNs;
     }
 
@@ -346,7 +344,7 @@
      *
      * @return uncertainty in nanoseconds of the elapsed realtime of this location
      */
-    public @FloatRange double getElapsedRealtimeUncertaintyNanos() {
+    public @FloatRange(from = 0.0) double getElapsedRealtimeUncertaintyNanos() {
         return mElapsedRealtimeUncertaintyNs;
     }
 
@@ -358,20 +356,20 @@
      *                                     this location
      */
     public void setElapsedRealtimeUncertaintyNanos(
-            @FloatRange double elapsedRealtimeUncertaintyNs) {
+            @FloatRange(from = 0.0) double elapsedRealtimeUncertaintyNs) {
         mElapsedRealtimeUncertaintyNs = elapsedRealtimeUncertaintyNs;
         mFieldsMask |= HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK;
     }
 
     /**
-     * True if this location has a elapsed realtime uncertainty, false otherwise.
+     * True if this location has an elapsed realtime uncertainty, false otherwise.
      */
     public boolean hasElapsedRealtimeUncertaintyNanos() {
         return (mFieldsMask & HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK) != 0;
     }
 
     /**
-     * Removes the elapsed realtime uncertainy from this location.
+     * Removes the elapsed realtime uncertainty from this location.
      */
     public void removeElapsedRealtimeUncertaintyNanos() {
         mFieldsMask &= ~HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK;
@@ -383,7 +381,7 @@
      *
      * @return latitude of this location
      */
-    public @FloatRange double getLatitude() {
+    public @FloatRange(from = -90.0, to = 90.0) double getLatitude() {
         return mLatitudeDegrees;
     }
 
@@ -392,7 +390,7 @@
      *
      * @param latitudeDegrees latitude in degrees
      */
-    public void setLatitude(@FloatRange double latitudeDegrees) {
+    public void setLatitude(@FloatRange(from = -90.0, to = 90.0) double latitudeDegrees) {
         mLatitudeDegrees = latitudeDegrees;
     }
 
@@ -402,7 +400,7 @@
      *
      * @return longitude of this location
      */
-    public @FloatRange double getLongitude() {
+    public @FloatRange(from = -180.0, to = 180.0) double getLongitude() {
         return mLongitudeDegrees;
     }
 
@@ -411,7 +409,7 @@
      *
      * @param longitudeDegrees longitude in degrees
      */
-    public void setLongitude(@FloatRange double longitudeDegrees) {
+    public void setLongitude(@FloatRange(from = -180.0, to = 180.0) double longitudeDegrees) {
         mLongitudeDegrees = longitudeDegrees;
     }
 
@@ -423,12 +421,12 @@
      * reported location, there is a 68% chance that the true location falls within this circle.
      * This accuracy value is only valid for horizontal positioning, and not vertical positioning.
      *
-     * <p>This is only valid if {@link #hasSpeed()} is true. All locations generated by the
+     * <p>This is only valid if {@link #hasAccuracy()} is true. All locations generated by the
      * {@link LocationManager} include horizontal accuracy.
      *
      * @return horizontal accuracy of this location
      */
-    public @FloatRange float getAccuracy() {
+    public @FloatRange(from = 0.0) float getAccuracy() {
         return mHorizontalAccuracyMeters;
     }
 
@@ -437,7 +435,7 @@
      *
      * @param horizontalAccuracyMeters horizontal altitude in meters
      */
-    public void setAccuracy(@FloatRange float horizontalAccuracyMeters) {
+    public void setAccuracy(@FloatRange(from = 0.0) float horizontalAccuracyMeters) {
         mHorizontalAccuracyMeters = horizontalAccuracyMeters;
         mFieldsMask |= HAS_HORIZONTAL_ACCURACY_MASK;
     }
@@ -500,7 +498,7 @@
      *
      * @return vertical accuracy of this location
      */
-    public @FloatRange float getVerticalAccuracyMeters() {
+    public @FloatRange(from = 0.0) float getVerticalAccuracyMeters() {
         return mAltitudeAccuracyMeters;
     }
 
@@ -509,7 +507,7 @@
      *
      * @param altitudeAccuracyMeters altitude accuracy in meters
      */
-    public void setVerticalAccuracyMeters(@FloatRange float altitudeAccuracyMeters) {
+    public void setVerticalAccuracyMeters(@FloatRange(from = 0.0) float altitudeAccuracyMeters) {
         mAltitudeAccuracyMeters = altitudeAccuracyMeters;
         mFieldsMask |= HAS_ALTITUDE_ACCURACY_MASK;
     }
@@ -538,17 +536,16 @@
      *
      * @return speed at the time of this location
      */
-    public @FloatRange float getSpeed() {
+    public @FloatRange(from = 0.0) float getSpeed() {
         return mSpeedMetersPerSecond;
     }
 
     /**
-     * Set the speed at the time of this location, in meters per second. Prefer not to set negative
-     * speeds.
+     * Set the speed at the time of this location, in meters per second.
      *
      * @param speedMetersPerSecond speed in meters per second
      */
-    public void setSpeed(@FloatRange float speedMetersPerSecond) {
+    public void setSpeed(@FloatRange(from = 0.0) float speedMetersPerSecond) {
         mSpeedMetersPerSecond = speedMetersPerSecond;
         mFieldsMask |= HAS_SPEED_MASK;
     }
@@ -576,7 +573,7 @@
      *
      * @return vertical accuracy of this location
      */
-    public @FloatRange float getSpeedAccuracyMetersPerSecond() {
+    public @FloatRange(from = 0.0) float getSpeedAccuracyMetersPerSecond() {
         return mSpeedAccuracyMetersPerSecond;
     }
 
@@ -585,7 +582,8 @@
      *
      * @param speedAccuracyMeterPerSecond speed accuracy in meters per second
      */
-    public void setSpeedAccuracyMetersPerSecond(@FloatRange float speedAccuracyMeterPerSecond) {
+    public void setSpeedAccuracyMetersPerSecond(
+            @FloatRange(from = 0.0) float speedAccuracyMeterPerSecond) {
         mSpeedAccuracyMetersPerSecond = speedAccuracyMeterPerSecond;
         mFieldsMask |= HAS_SPEED_ACCURACY_MASK;
     }
@@ -613,7 +611,7 @@
      *
      * @return bearing at the time of this location
      */
-    public @FloatRange(from = 0f, to = 360f, toInclusive = false) float getBearing() {
+    public @FloatRange(from = 0.0, to = 360.0, toInclusive = false) float getBearing() {
         return mBearingDegrees;
     }
 
@@ -663,7 +661,7 @@
      *
      * @return bearing accuracy in degrees of this location
      */
-    public @FloatRange float getBearingAccuracyDegrees() {
+    public @FloatRange(from = 0.0) float getBearingAccuracyDegrees() {
         return mBearingAccuracyDegrees;
     }
 
@@ -672,7 +670,7 @@
      *
      * @param bearingAccuracyDegrees bearing accuracy in degrees
      */
-    public void setBearingAccuracyDegrees(@FloatRange float bearingAccuracyDegrees) {
+    public void setBearingAccuracyDegrees(@FloatRange(from = 0.0) float bearingAccuracyDegrees) {
         mBearingAccuracyDegrees = bearingAccuracyDegrees;
         mFieldsMask |= HAS_BEARING_ACCURACY_MASK;
     }
@@ -692,9 +690,11 @@
     }
 
     /**
-     * Returns true if the Location came from a mock provider.
+     * Returns true if this is a mock location. If this location comes from the Android framework,
+     * this indicates that the location was provided by a test location provider, and thus may not
+     * be related to the actual location of the device.
      *
-     * @return true if this Location came from a mock provider, false otherwise
+     * @return true if this location came from a mock provider, false otherwise
      * @deprecated Prefer {@link #isMock()} instead.
      */
     @Deprecated
@@ -703,9 +703,9 @@
     }
 
     /**
-     * Flag this Location as having come from a mock provider or not.
+     * Flag this location as having come from a mock provider or not.
      *
-     * @param isFromMockProvider true if this Location came from a mock provider, false otherwise
+     * @param isFromMockProvider true if this location came from a mock provider, false otherwise
      * @deprecated Prefer {@link #setMock(boolean)} instead.
      * @hide
      */
@@ -745,7 +745,7 @@
      * will be present for any location.
      *
      * <ul>
-     * <li> satellites - the number of satellites used to derive the GNSS fix
+     * <li> satellites - the number of satellites used to derive a GNSS fix
      * </ul>
      */
     public @Nullable Bundle getExtras() {
@@ -899,7 +899,13 @@
         return s.toString();
     }
 
-    /** Dumps location. */
+    /**
+     * Dumps location information to the given Printer.
+     *
+     * @deprecated Prefer to use {@link #toString()} along with whatever custom formatting is
+     * required instead of this method. It is not this class's job to manage print representations.
+     */
+    @Deprecated
     public void dump(@NonNull Printer pw, @Nullable String prefix) {
         pw.println(prefix + this);
     }
@@ -1209,10 +1215,10 @@
      * @throws IllegalArgumentException if results is null or has length < 1
      */
     public static void distanceBetween(
-            @FloatRange double startLatitude,
-            @FloatRange double startLongitude,
-            @FloatRange double endLatitude,
-            @FloatRange double endLongitude,
+            @FloatRange(from = -90.0, to = 90.0) double startLatitude,
+            @FloatRange(from = -180.0, to = 180.0) double startLongitude,
+            @FloatRange(from = -90.0, to = 90.0) double endLatitude,
+            @FloatRange(from = -180.0, to = 180.0)  double endLongitude,
             float[] results) {
         if (results == null || results.length < 1) {
             throw new IllegalArgumentException("results is null or has length < 1");
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 59c989b..a504cfe 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -679,9 +679,8 @@
      *
      * @hide
      */
-    // TODO: remove WRITE_SECURE_SETTINGS.
     @SystemApi
-    @RequiresPermission(anyOf = {WRITE_SECURE_SETTINGS, LOCATION_BYPASS})
+    @RequiresPermission(LOCATION_BYPASS)
     public void setAdasGnssLocationEnabled(boolean enabled) {
         try {
             mService.setAdasGnssLocationEnabledForUser(enabled, mContext.getUser().getIdentifier());
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index 59f4f5e..09474b5 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -17,7 +17,6 @@
 package android.location;
 
 import static android.Manifest.permission.LOCATION_BYPASS;
-import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
 
 import static java.lang.Math.max;
 import static java.lang.Math.min;
@@ -665,10 +664,9 @@
      * @hide
      * @deprecated LocationRequests should be treated as immutable.
      */
-    // TODO: remove WRITE_SECURE_SETTINGS.
     @SystemApi
     @Deprecated
-    @RequiresPermission(anyOf = {WRITE_SECURE_SETTINGS, LOCATION_BYPASS})
+    @RequiresPermission(LOCATION_BYPASS)
     public @NonNull LocationRequest setLocationSettingsIgnored(boolean locationSettingsIgnored) {
         mBypass = locationSettingsIgnored;
         return this;
@@ -1136,9 +1134,8 @@
          *
          * @hide
          */
-        // TODO: remove WRITE_SECURE_SETTINGS
         @SystemApi
-        @RequiresPermission(anyOf = {WRITE_SECURE_SETTINGS, LOCATION_BYPASS})
+        @RequiresPermission(LOCATION_BYPASS)
         public @NonNull Builder setAdasGnssBypass(boolean adasGnssBypass) {
             mAdasGnssBypass = adasGnssBypass;
             return this;
@@ -1155,9 +1152,8 @@
          *
          * @hide
          */
-        // TODO: remove WRITE_SECURE_SETTINGS
         @SystemApi
-        @RequiresPermission(anyOf = {WRITE_SECURE_SETTINGS, LOCATION_BYPASS})
+        @RequiresPermission(LOCATION_BYPASS)
         public @NonNull Builder setLocationSettingsIgnored(boolean locationSettingsIgnored) {
             mBypass = locationSettingsIgnored;
             return this;
diff --git a/media/java/android/media/AudioDeviceVolumeManager.java b/media/java/android/media/AudioDeviceVolumeManager.java
index 0e9c99b..11cacd0 100644
--- a/media/java/android/media/AudioDeviceVolumeManager.java
+++ b/media/java/android/media/AudioDeviceVolumeManager.java
@@ -17,6 +17,7 @@
 package android.media;
 
 import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -27,6 +28,8 @@
 
 import com.android.internal.annotations.GuardedBy;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
@@ -40,6 +43,22 @@
 
     // define when using Log.*
     //private static final String TAG = "AudioDeviceVolumeManager";
+
+    /** Indicates no special treatment in the handling of the volume adjustment */
+    public static final int ADJUST_MODE_NORMAL = 0;
+    /** Indicates the start of a volume adjustment */
+    public static final int ADJUST_MODE_START = 1;
+    /** Indicates the end of a volume adjustment */
+    public static final int ADJUST_MODE_END = 2;
+
+    @IntDef(flag = false, prefix = "ADJUST_MODE", value = {
+            ADJUST_MODE_NORMAL,
+            ADJUST_MODE_START,
+            ADJUST_MODE_END}
+    )
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface VolumeAdjustmentMode {}
+
     private static IAudioService sService;
 
     private final String mPackageName;
@@ -65,18 +84,33 @@
         void onAudioDeviceVolumeChanged(
                 @NonNull AudioDeviceAttributes device,
                 @NonNull VolumeInfo vol);
+
+        /**
+         * Called when the volume for the given audio device has been adjusted.
+         * @param device the audio device whose volume has been adjusted
+         * @param vol the volume info for the device
+         * @param direction the direction of the adjustment
+         * @param mode the volume adjustment mode
+         */
+        void onAudioDeviceVolumeAdjusted(
+                @NonNull AudioDeviceAttributes device,
+                @NonNull VolumeInfo vol,
+                @AudioManager.VolumeAdjustment int direction,
+                @VolumeAdjustmentMode int mode);
     }
 
     static class ListenerInfo {
         final @NonNull OnAudioDeviceVolumeChangedListener mListener;
         final @NonNull Executor mExecutor;
         final @NonNull AudioDeviceAttributes mDevice;
+        final @NonNull boolean mHandlesVolumeAdjustment;
 
         ListenerInfo(@NonNull OnAudioDeviceVolumeChangedListener listener, @NonNull Executor exe,
-                @NonNull AudioDeviceAttributes device) {
+                @NonNull AudioDeviceAttributes device, boolean handlesVolumeAdjustment) {
             mListener = listener;
             mExecutor = exe;
             mDevice = device;
+            mHandlesVolumeAdjustment = handlesVolumeAdjustment;
         }
     }
 
@@ -98,11 +132,12 @@
          * @param device device for which volume is monitored
          */
         public void register(boolean register, @NonNull AudioDeviceAttributes device,
-                @NonNull List<VolumeInfo> volumes) {
+                @NonNull List<VolumeInfo> volumes, boolean handlesVolumeAdjustment) {
             try {
                 getService().registerDeviceVolumeDispatcherForAbsoluteVolume(register,
                         this, mPackageName,
-                        Objects.requireNonNull(device), Objects.requireNonNull(volumes));
+                        Objects.requireNonNull(device), Objects.requireNonNull(volumes),
+                        handlesVolumeAdjustment);
             } catch (RemoteException e) {
                 e.rethrowFromSystemServer();
             }
@@ -116,12 +151,29 @@
                 volumeListeners = (ArrayList<ListenerInfo>) mDeviceVolumeListeners.clone();
             }
             for (ListenerInfo listenerInfo : volumeListeners) {
-                if (listenerInfo.mDevice.equals(device)) {
+                if (listenerInfo.mDevice.equalTypeAddress(device)) {
                     listenerInfo.mExecutor.execute(
                             () -> listenerInfo.mListener.onAudioDeviceVolumeChanged(device, vol));
                 }
             }
         }
+
+        @Override
+        public void dispatchDeviceVolumeAdjusted(
+                @NonNull AudioDeviceAttributes device, @NonNull VolumeInfo vol, int direction,
+                int mode) {
+            final ArrayList<ListenerInfo> volumeListeners;
+            synchronized (mDeviceVolumeListenerLock) {
+                volumeListeners = (ArrayList<ListenerInfo>) mDeviceVolumeListeners.clone();
+            }
+            for (ListenerInfo listenerInfo : volumeListeners) {
+                if (listenerInfo.mDevice.equalTypeAddress(device)) {
+                    listenerInfo.mExecutor.execute(
+                            () -> listenerInfo.mListener.onAudioDeviceVolumeAdjusted(device, vol,
+                                    direction, mode));
+                }
+            }
+        }
     }
 
     /**
@@ -139,10 +191,12 @@
             @NonNull AudioDeviceAttributes device,
             @NonNull VolumeInfo volume,
             @NonNull @CallbackExecutor Executor executor,
-            @NonNull OnAudioDeviceVolumeChangedListener vclistener) {
+            @NonNull OnAudioDeviceVolumeChangedListener vclistener,
+            boolean handlesVolumeAdjustment) {
         final ArrayList<VolumeInfo> volumes = new ArrayList<>(1);
         volumes.add(volume);
-        setDeviceAbsoluteMultiVolumeBehavior(device, volumes, executor, vclistener);
+        setDeviceAbsoluteMultiVolumeBehavior(device, volumes, executor, vclistener,
+                handlesVolumeAdjustment);
     }
 
     /**
@@ -153,6 +207,9 @@
      * @param volumes the list of volumes the given device responds to
      * @param executor the Executor used for receiving volume updates through the listener
      * @param vclistener the callback for volume updates
+     * @param handlesVolumeAdjustment whether the controller handles volume adjustments separately
+     *  from volume changes. If true, adjustments from {@link AudioManager#adjustStreamVolume}
+     *  will be sent via {@link OnAudioDeviceVolumeChangedListener#onAudioDeviceVolumeAdjusted}.
      */
     @RequiresPermission(anyOf = { android.Manifest.permission.MODIFY_AUDIO_ROUTING,
             android.Manifest.permission.BLUETOOTH_PRIVILEGED })
@@ -160,14 +217,15 @@
             @NonNull AudioDeviceAttributes device,
             @NonNull List<VolumeInfo> volumes,
             @NonNull @CallbackExecutor Executor executor,
-            @NonNull OnAudioDeviceVolumeChangedListener vclistener) {
+            @NonNull OnAudioDeviceVolumeChangedListener vclistener,
+            boolean handlesVolumeAdjustment) {
         Objects.requireNonNull(device);
         Objects.requireNonNull(volumes);
         Objects.requireNonNull(executor);
         Objects.requireNonNull(vclistener);
 
-        // TODO verify not already registered
-        //final ListenerInfo listenerInfo = new ListenerInfo(vclistener, executor, device);
+        final ListenerInfo listenerInfo = new ListenerInfo(
+                vclistener, executor, device, handlesVolumeAdjustment);
         synchronized (mDeviceVolumeListenerLock) {
             if (mDeviceVolumeListeners == null) {
                 mDeviceVolumeListeners = new ArrayList<>();
@@ -176,8 +234,91 @@
                 if (mDeviceVolumeDispatcherStub == null) {
                     mDeviceVolumeDispatcherStub = new DeviceVolumeDispatcherStub();
                 }
+            } else {
+                for (ListenerInfo info : mDeviceVolumeListeners) {
+                    if (info.mListener == vclistener) {
+                        throw new IllegalArgumentException(
+                                "attempt to call setDeviceAbsoluteMultiVolumeBehavior() "
+                                        + "on a previously registered listener");
+                    }
+                }
             }
-            mDeviceVolumeDispatcherStub.register(true, device, volumes);
+            mDeviceVolumeListeners.add(listenerInfo);
+            mDeviceVolumeDispatcherStub.register(true, device, volumes, handlesVolumeAdjustment);
+        }
+    }
+
+    /**
+     * Manages the OnDeviceVolumeBehaviorChangedListener listeners and
+     * DeviceVolumeBehaviorDispatcherStub
+     */
+    private final CallbackUtil.LazyListenerManager<OnDeviceVolumeBehaviorChangedListener>
+            mDeviceVolumeBehaviorChangedListenerMgr = new CallbackUtil.LazyListenerManager();
+
+    /**
+     * @hide
+     * Interface definition of a callback to be invoked when the volume behavior of an audio device
+     * is updated.
+     */
+    public interface OnDeviceVolumeBehaviorChangedListener {
+        /**
+         * Called on the listener to indicate that the volume behavior of a device has changed.
+         * @param device the audio device whose volume behavior changed
+         * @param volumeBehavior the new volume behavior of the audio device
+         */
+        void onDeviceVolumeBehaviorChanged(
+                @NonNull AudioDeviceAttributes device,
+                @AudioManager.DeviceVolumeBehavior int volumeBehavior);
+    }
+
+    /**
+     * @hide
+     * Adds a listener for being notified of changes to any device's volume behavior.
+     * @throws SecurityException if the caller doesn't hold the required permission
+     */
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+            android.Manifest.permission.QUERY_AUDIO_STATE
+    })
+    public void addOnDeviceVolumeBehaviorChangedListener(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OnDeviceVolumeBehaviorChangedListener listener)
+            throws SecurityException {
+        mDeviceVolumeBehaviorChangedListenerMgr.addListener(executor, listener,
+                "addOnDeviceVolumeBehaviorChangedListener",
+                () -> new DeviceVolumeBehaviorDispatcherStub());
+    }
+
+    /**
+     * @hide
+     * Removes a previously added listener of changes to device volume behavior.
+     */
+
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+            android.Manifest.permission.QUERY_AUDIO_STATE
+    })
+    public void removeOnDeviceVolumeBehaviorChangedListener(
+            @NonNull OnDeviceVolumeBehaviorChangedListener listener) {
+        mDeviceVolumeBehaviorChangedListenerMgr.removeListener(listener,
+                "removeOnDeviceVolumeBehaviorChangedListener");
+    }
+
+    private final class DeviceVolumeBehaviorDispatcherStub
+            extends IDeviceVolumeBehaviorDispatcher.Stub implements CallbackUtil.DispatcherStub {
+        public void register(boolean register) {
+            try {
+                getService().registerDeviceVolumeBehaviorDispatcher(register, this);
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+        }
+
+        @Override
+        public void dispatchDeviceVolumeBehaviorChanged(@NonNull AudioDeviceAttributes device,
+                @AudioManager.DeviceVolumeBehavior int volumeBehavior) {
+            mDeviceVolumeBehaviorChangedListenerMgr.callListeners((listener) ->
+                    listener.onDeviceVolumeBehaviorChanged(device, volumeBehavior));
         }
     }
 
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 1a56b15..491a5cd 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -604,6 +604,13 @@
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int FLAG_FROM_KEY = 1 << 12;
 
+    /**
+     * Indicates that an absolute volume controller is notifying AudioService of a change in the
+     * volume or mute status of an external audio system.
+     * @hide
+     */
+    public static final int FLAG_ABSOLUTE_VOLUME = 1 << 13;
+
     /** @hide */
     @IntDef(prefix = {"ENCODED_SURROUND_OUTPUT_"}, value = {
             ENCODED_SURROUND_OUTPUT_UNKNOWN,
@@ -661,6 +668,7 @@
             FLAG_SHOW_UI_WARNINGS,
             FLAG_SHOW_VIBRATE_HINT,
             FLAG_FROM_KEY,
+            FLAG_ABSOLUTE_VOLUME,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Flags {}
@@ -682,6 +690,7 @@
         FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, "FLAG_SHOW_UI_WARNINGS");
         FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, "FLAG_SHOW_VIBRATE_HINT");
         FLAG_NAMES.put(FLAG_FROM_KEY, "FLAG_FROM_KEY");
+        FLAG_NAMES.put(FLAG_ABSOLUTE_VOLUME, "FLAG_ABSOLUTE_VOLUME");
     }
 
     /** @hide */
@@ -8393,6 +8402,12 @@
      * {@link #addAssistantServicesUids(int[])} and not yet removed with
      * {@link #removeAssistantServicesUids(int[])}
      *
+     * <p> Note that during native audioserver crash and after boot up the list of assistant
+     * UIDs will be reset to an empty list (i.e. no UID will be considered as assistant)
+     * Just after user switch, the list of assistant will also reset to empty.
+     * In both cases,The component's UID of the assistiant role or assistant setting will be
+     * automitically added to the list by the audio service.
+     *
      * @return array of assistants UIDs
      *
      * @hide
diff --git a/media/java/android/media/IAudioDeviceVolumeDispatcher.aidl b/media/java/android/media/IAudioDeviceVolumeDispatcher.aidl
index 65633fe..70b4ab6 100644
--- a/media/java/android/media/IAudioDeviceVolumeDispatcher.aidl
+++ b/media/java/android/media/IAudioDeviceVolumeDispatcher.aidl
@@ -27,5 +27,7 @@
 oneway interface IAudioDeviceVolumeDispatcher {
 
     void dispatchDeviceVolumeChanged(in AudioDeviceAttributes device, in VolumeInfo vol);
+    void dispatchDeviceVolumeAdjusted(in AudioDeviceAttributes device, in VolumeInfo vol,
+            int direction, int mode);
 
 }
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index bdbb740..e28178a 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -33,17 +33,18 @@
 import android.media.IAudioServerStateDispatcher;
 import android.media.ICapturePresetDevicesRoleDispatcher;
 import android.media.ICommunicationDeviceDispatcher;
+import android.media.IDeviceVolumeBehaviorDispatcher;
 import android.media.IMuteAwaitConnectionCallback;
 import android.media.IPlaybackConfigDispatcher;
 import android.media.IRecordingConfigDispatcher;
 import android.media.IRingtonePlayer;
 import android.media.IStrategyPreferredDevicesDispatcher;
 import android.media.ISpatializerCallback;
+import android.media.ISpatializerHeadTrackerAvailableCallback;
 import android.media.ISpatializerHeadTrackingModeCallback;
 import android.media.ISpatializerHeadToSoundStagePoseCallback;
 import android.media.ISpatializerOutputCallback;
 import android.media.IVolumeController;
-import android.media.IVolumeController;
 import android.media.PlayerBase;
 import android.media.VolumeInfo;
 import android.media.VolumePolicy;
@@ -414,6 +415,11 @@
 
     boolean isHeadTrackerEnabled(in AudioDeviceAttributes device);
 
+    boolean isHeadTrackerAvailable();
+
+    void registerSpatializerHeadTrackerAvailableCallback(
+            in ISpatializerHeadTrackerAvailableCallback cb, boolean register);
+
     void setSpatializerEnabled(boolean enabled);
 
     boolean canBeSpatialized(in AudioAttributes aa, in AudioFormat af);
@@ -476,6 +482,10 @@
 
     void setTestDeviceConnectionState(in AudioDeviceAttributes device, boolean connected);
 
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING,android.Manifest.permission.QUERY_AUDIO_STATE})")
+    void registerDeviceVolumeBehaviorDispatcher(boolean register,
+            in IDeviceVolumeBehaviorDispatcher dispatcher);
+
     List<AudioFocusInfo> getFocusStack();
 
     boolean sendFocusLoss(in AudioFocusInfo focusLoser, in IAudioPolicyCallback apcb);
@@ -499,7 +509,8 @@
     void registerDeviceVolumeDispatcherForAbsoluteVolume(boolean register,
             in IAudioDeviceVolumeDispatcher cb,
             in String packageName,
-            in AudioDeviceAttributes device, in List<VolumeInfo> volumes);
+            in AudioDeviceAttributes device, in List<VolumeInfo> volumes,
+            boolean handlesvolumeAdjustment);
 
     String getHalVersion();
 }
diff --git a/core/java/com/android/internal/telephony/ICarrierPrivilegesListener.aidl b/media/java/android/media/IDeviceVolumeBehaviorDispatcher.aidl
similarity index 64%
copy from core/java/com/android/internal/telephony/ICarrierPrivilegesListener.aidl
copy to media/java/android/media/IDeviceVolumeBehaviorDispatcher.aidl
index 6ca8cec..2b19bff 100644
--- a/core/java/com/android/internal/telephony/ICarrierPrivilegesListener.aidl
+++ b/media/java/android/media/IDeviceVolumeBehaviorDispatcher.aidl
@@ -14,9 +14,18 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony;
+package android.media;
 
-oneway interface ICarrierPrivilegesListener {
-    void onCarrierPrivilegesChanged(
-            in List<String> privilegedPackageNames, in int[] privilegedUids);
+import android.media.AudioDeviceAttributes;
+
+/**
+ * AIDL for AudioService to signal changes to an audio device's volume behavior
+ *
+ * {@hide}
+ */
+oneway interface IDeviceVolumeBehaviorDispatcher {
+
+    void dispatchDeviceVolumeBehaviorChanged(in AudioDeviceAttributes device,
+            int deviceVolumeBehavior);
+
 }
diff --git a/packages/ConnectivityT/framework-t/src/android/net/netstats/IUsageCallback.aidl b/media/java/android/media/ISpatializerHeadTrackerAvailableCallback.aidl
similarity index 65%
rename from packages/ConnectivityT/framework-t/src/android/net/netstats/IUsageCallback.aidl
rename to media/java/android/media/ISpatializerHeadTrackerAvailableCallback.aidl
index 4e8a5b2..dc5ee1d 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/netstats/IUsageCallback.aidl
+++ b/media/java/android/media/ISpatializerHeadTrackerAvailableCallback.aidl
@@ -14,16 +14,14 @@
  * limitations under the License.
  */
 
-package android.net.netstats;
-
-import android.net.DataUsageRequest;
+package android.media;
 
 /**
- * Interface for NetworkStatsService to notify events to the callers of registerUsageCallback.
+ * AIDL for the AudioService to signal whether audio device used by Spatializer has head tracker.
  *
- * @hide
+ * {@hide}
  */
-oneway interface IUsageCallback {
-    void onThresholdReached(in DataUsageRequest request);
-    void onCallbackReleased(in DataUsageRequest request);
+oneway interface ISpatializerHeadTrackerAvailableCallback {
+
+    void dispatchSpatializerHeadTrackerAvailable(boolean available);
 }
diff --git a/media/java/android/media/MediaActionSound.java b/media/java/android/media/MediaActionSound.java
index ec56d61..ad1405a 100644
--- a/media/java/android/media/MediaActionSound.java
+++ b/media/java/android/media/MediaActionSound.java
@@ -25,7 +25,8 @@
 
 /**
  * <p>A class for producing sounds that match those produced by various actions
- * taken by the media and camera APIs.  </p>
+ * taken by the media and camera APIs. It is recommended to call methods in this class
+ * in a background thread since it relies on binder calls.</p>
  *
  * <p>This class is recommended for use with the {@link android.hardware.camera2} API, since the
  * camera2 API does not play any sounds on its own for any capture or video recording actions.</p>
@@ -109,7 +110,7 @@
 
     /**
      * <p>Returns true if the application must play the shutter sound in accordance
-     * to certain regional restrictions. </p>
+     * to certain regional restrictions.</p>
      *
      * <p>If this method returns true, applications are strongly recommended to use
      * MediaActionSound.play(SHUTTER_CLICK) or START_VIDEO_RECORDING whenever it captures
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 4563259..e39914d 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -223,19 +223,19 @@
   </thead>
   <tbody>
    <tr>
-    <td>{@code "crop-left"}</td>
+    <td>{@link MediaFormat#KEY_CROP_LEFT}</td>
     <td>Integer</td>
     <td>The left-coordinate (x) of the crop rectangle</td>
    </tr><tr>
-    <td>{@code "crop-top"}</td>
+    <td>{@link MediaFormat#KEY_CROP_TOP}</td>
     <td>Integer</td>
     <td>The top-coordinate (y) of the crop rectangle</td>
    </tr><tr>
-    <td>{@code "crop-right"}</td>
+    <td>{@link MediaFormat#KEY_CROP_RIGHT}</td>
     <td>Integer</td>
     <td>The right-coordinate (x) <strong>MINUS 1</strong> of the crop rectangle</td>
    </tr><tr>
-    <td>{@code "crop-bottom"}</td>
+    <td>{@link MediaFormat#KEY_CROP_BOTTOM}</td>
     <td>Integer</td>
     <td>The bottom-coordinate (y) <strong>MINUS 1</strong> of the crop rectangle</td>
    </tr><tr>
@@ -251,12 +251,16 @@
  <pre class=prettyprint>
  MediaFormat format = decoder.getOutputFormat(&hellip;);
  int width = format.getInteger(MediaFormat.KEY_WIDTH);
- if (format.containsKey("crop-left") && format.containsKey("crop-right")) {
-     width = format.getInteger("crop-right") + 1 - format.getInteger("crop-left");
+ if (format.containsKey(MediaFormat.KEY_CROP_LEFT)
+         && format.containsKey(MediaFormat.KEY_CROP_RIGHT)) {
+     width = format.getInteger(MediaFormat.KEY_CROP_RIGHT) + 1
+                 - format.getInteger(MediaFormat.KEY_CROP_LEFT);
  }
  int height = format.getInteger(MediaFormat.KEY_HEIGHT);
- if (format.containsKey("crop-top") && format.containsKey("crop-bottom")) {
-     height = format.getInteger("crop-bottom") + 1 - format.getInteger("crop-top");
+ if (format.containsKey(MediaFormat.KEY_CROP_TOP)
+         && format.containsKey(MediaFormat.KEY_CROP_BOTTOM)) {
+     height = format.getInteger(MediaFormat.KEY_CROP_BOTTOM) + 1
+                  - format.getInteger(MediaFormat.KEY_CROP_TOP);
  }
  </pre>
  <p class=note>
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 4956dbe..9dea5b9 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -359,6 +359,42 @@
     public static final String KEY_HEIGHT = "height";
 
     /**
+     * A key describing the bottom-coordinate (y) of the crop rectangle.
+     * This is the bottom-most row included in the crop frame,
+     * where row indices start at 0.
+     * Additional information on the crop rectangle semantics can be found at
+     * {@link android.media.MediaCodec}.
+     */
+    public static final String KEY_CROP_BOTTOM = "crop-bottom";
+
+    /**
+     * A key describing the left-coordinate (x) of the crop rectangle.
+     * This is the left-most column included in the crop frame,
+     * where column indices start at 0.
+     * Additional information on the crop rectangle semantics can be found at
+     * {@link android.media.MediaCodec}.
+     */
+    public static final String KEY_CROP_LEFT = "crop-left";
+
+    /**
+     * A key describing the right-coordinate (x) of the crop rectangle.
+     * This is the right-most column included in the crop frame,
+     * where column indices start at 0.
+     * Additional information on the crop rectangle semantics can be found at
+     * {@link android.media.MediaCodec}.
+     */
+    public static final String KEY_CROP_RIGHT = "crop-right";
+
+    /**
+     * A key describing the top-coordinate (y) of the crop rectangle.
+     * This is the top-most row included in the crop frame,
+     * where row indices start at 0.
+     * Additional information on the crop rectangle semantics can be found at
+     * {@link android.media.MediaCodec}.
+     */
+    public static final String KEY_CROP_TOP = "crop-top";
+
+    /**
      * A key describing the maximum expected width of the content in a video
      * decoder format, in case there are resolution changes in the video content.
      * The associated value is an integer
@@ -793,8 +829,11 @@
      * By default, the decoder will output the same number of channels as present in the encoded
      * stream, if supported. Set this value to limit the number of output channels, and use
      * the downmix information in the stream, if available.
-     * <p>Values larger than the number of channels in the content to decode are ignored.
+     * <p>Values larger than the number of channels in the content to decode behave just
+     * like the actual channel count of the content (e.g. passing 99 for the decoding of 5.1 content
+     * will behave like using 6).
      * <p>This key is only used during decoding.
+     * @deprecated Use the non-AAC-specific key {@link #KEY_MAX_OUTPUT_CHANNEL_COUNT} instead
      */
     public static final String KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count";
 
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index ee0293d..283a41a 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -539,6 +539,7 @@
     /**
      * Gets the Deduplication ID of the route if available.
      * @see RouteDiscoveryPreference#shouldRemoveDuplicates()
+     * @hide
      */
     @NonNull
     public Set<String> getDeduplicationIds() {
@@ -968,6 +969,7 @@
          * <p>
          * If it's {@code null}, the route will not be removed.
          * @see RouteDiscoveryPreference#shouldRemoveDuplicates()
+         * @hide
          */
         @NonNull
         public Builder setDeduplicationIds(@NonNull Set<String> id) {
diff --git a/media/java/android/media/RouteDiscoveryPreference.java b/media/java/android/media/RouteDiscoveryPreference.java
index 0ba36fe..207460a 100644
--- a/media/java/android/media/RouteDiscoveryPreference.java
+++ b/media/java/android/media/RouteDiscoveryPreference.java
@@ -119,6 +119,7 @@
      * first in the provided list will remain.
      *
      * @see #shouldRemoveDuplicates()
+     * @hide
      */
     @NonNull
     public List<String> getDeduplicationPackageOrder() {
@@ -130,6 +131,7 @@
      * <p>
      * If it's not empty, it will only discover routes from the provider whose package name
      * belongs to the list.
+     * @hide
      */
     @NonNull
     public List<String> getAllowedPackages() {
@@ -151,6 +153,7 @@
      * Gets whether duplicate routes removal is enabled.
      *
      * @see #getDeduplicationPackageOrder()
+     * @hide
      */
     public boolean shouldRemoveDuplicates() {
         return !mPackageOrder.isEmpty();
@@ -293,6 +296,7 @@
          * <p>
          * If it's non-empty, media router only discovers route from the provider in the list.
          * The default value is empty, which discovers routes from all providers.
+         * @hide
          */
         @NonNull
         public Builder setAllowedPackages(@NonNull List<String> allowedPackages) {
@@ -324,6 +328,7 @@
          *
          * @param packageOrder ordered list of package names used to remove duplicate routes, or an
          *                     empty list if deduplication should not be enabled.
+         * @hide
          */
         @NonNull
         public Builder setDeduplicationPackageOrder(@NonNull List<String> packageOrder) {
diff --git a/media/java/android/media/Spatializer.java b/media/java/android/media/Spatializer.java
index be0ef37..74ca4b8 100644
--- a/media/java/android/media/Spatializer.java
+++ b/media/java/android/media/Spatializer.java
@@ -185,6 +185,45 @@
         return false;
     }
 
+    /**
+     * Returns whether a head tracker is currently available for the audio device used by the
+     * spatializer effect.
+     * @return true if a head tracker is available and the effect is enabled, false otherwise.
+     * @see OnHeadTrackerAvailableListener
+     * @see #addOnHeadTrackerAvailableListener(Executor, OnHeadTrackerAvailableListener)
+     */
+    public boolean isHeadTrackerAvailable() {
+        try {
+            return mAm.getService().isHeadTrackerAvailable();
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+        return false;
+    }
+
+    /**
+     * Adds a listener to be notified of changes to the availability of a head tracker.
+     * @param executor the {@code Executor} handling the callback
+     * @param listener the listener to receive availability updates
+     * @see #removeOnHeadTrackerAvailableListener(OnHeadTrackerAvailableListener)
+     */
+    public void addOnHeadTrackerAvailableListener(@NonNull @CallbackExecutor Executor executor,
+            @NonNull OnHeadTrackerAvailableListener listener) {
+        mHeadTrackerListenerMgr.addListener(executor, listener,
+                "addOnHeadTrackerAvailableListener",
+                () -> new SpatializerHeadTrackerAvailableDispatcherStub());
+    }
+
+    /**
+     * Removes a previously registered listener for the availability of a head tracker.
+     * @param listener the listener previously registered with
+     *      {@link #addOnHeadTrackerAvailableListener(Executor, OnHeadTrackerAvailableListener)}
+     */
+    public void removeOnHeadTrackerAvailableListener(
+            @NonNull OnHeadTrackerAvailableListener listener) {
+        mHeadTrackerListenerMgr.removeListener(listener, "removeOnHeadTrackerAvailableListener");
+    }
+
     /** @hide */
     @IntDef(flag = false, value = {
             SPATIALIZER_IMMERSIVE_LEVEL_OTHER,
@@ -401,6 +440,22 @@
                 @HeadTrackingModeSet int mode);
     }
 
+    /**
+     * Interface to be notified of changes to the availability of a head tracker on the audio
+     * device to be used by the spatializer effect.
+     */
+    public interface OnHeadTrackerAvailableListener {
+        /**
+         * Called when the availability of the head tracker changed.
+         * @param spatializer the {@code Spatializer} instance for which the head tracker
+         *                    availability was updated
+         * @param available true if the audio device that would output audio processed by
+         *                  the {@code Spatializer} has a head tracker associated with it, false
+         *                  otherwise.
+         */
+        void onHeadTrackerAvailableChanged(@NonNull Spatializer spatializer,
+                boolean available);
+    }
 
     /**
      * @hide
@@ -827,8 +882,12 @@
 
     /**
      * @hide
-     * Returns the id of the output stream used for the spatializer effect playback
+     * Returns the id of the output stream used for the spatializer effect playback.
+     * This getter or associated listener {@link OnSpatializerOutputChangedListener} can be used for
+     * handling spatializer output-specific configurations (e.g. disabling speaker post-processing
+     * to avoid double-processing of the spatialized path).
      * @return id of the output stream, or 0 if no spatializer playback is active
+     * @see #setOnSpatializerOutputChangedListener(Executor, OnSpatializerOutputChangedListener)
      */
     @SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
     @RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
@@ -865,6 +924,8 @@
             mOutputDispatcher = new SpatializerOutputDispatcherStub();
             try {
                 mAm.getService().registerSpatializerOutputCallback(mOutputDispatcher);
+                // immediately report the current output
+                mOutputDispatcher.dispatchSpatializerOutputChanged(getOutput());
             } catch (RemoteException e) {
                 mOutputListener = null;
                 mOutputDispatcher = null;
@@ -935,6 +996,36 @@
     }
 
     //-----------------------------------------------------------------------------
+    // head tracker availability callback management and stub
+    /**
+     * manages the OnHeadTrackerAvailableListener listeners and the
+     * SpatializerHeadTrackerAvailableDispatcherStub
+     */
+    private final CallbackUtil.LazyListenerManager<OnHeadTrackerAvailableListener>
+            mHeadTrackerListenerMgr = new CallbackUtil.LazyListenerManager();
+
+    private final class SpatializerHeadTrackerAvailableDispatcherStub
+            extends ISpatializerHeadTrackerAvailableCallback.Stub
+            implements CallbackUtil.DispatcherStub {
+        @Override
+        public void register(boolean register) {
+            try {
+                mAm.getService().registerSpatializerHeadTrackerAvailableCallback(this, register);
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+        }
+
+        @Override
+        @SuppressLint("GuardedBy") // lock applied inside callListeners method
+        public void dispatchSpatializerHeadTrackerAvailable(boolean available) {
+            mHeadTrackerListenerMgr.callListeners(
+                    (listener) -> listener.onHeadTrackerAvailableChanged(
+                            Spatializer.this, available));
+        }
+    }
+
+    //-----------------------------------------------------------------------------
     // head pose callback management and stub
     private final Object mPoseListenerLock = new Object();
     /**
diff --git a/media/java/android/media/metrics/BundleSession.java b/media/java/android/media/metrics/BundleSession.java
index 743d233..0f0fdfe 100644
--- a/media/java/android/media/metrics/BundleSession.java
+++ b/media/java/android/media/metrics/BundleSession.java
@@ -32,6 +32,15 @@
     private final @NonNull MediaMetricsManager mManager;
     private final @NonNull LogSessionId mLogSessionId;
 
+    /**
+     * A key describing the statsd atom into which to place this bundle's other contents.
+     * The associated value is an integer.
+     *
+     * @see #reportBundleMetrics
+     */
+
+    public static final String KEY_STATSD_ATOM = "bundlesession-statsd-atom";
+
     /** @hide */
     public BundleSession(@NonNull String id, @NonNull MediaMetricsManager manager) {
         mId = id;
@@ -44,6 +53,10 @@
     /**
      * Reports metrics via bundle.
      *
+     * The key {@link #KEY_STATSD_ATOM} references an integer value that
+     * indicates the statsd atom for the data in this bundle. Other keys
+     * and their types are defined on a per-atom basis.
+     *
      */
     public void reportBundleMetrics(@NonNull PersistableBundle metrics) {
         mManager.reportBundleMetrics(mId, metrics);
@@ -68,5 +81,6 @@
 
     @Override
     public void close() {
+        mManager.releaseSessionId(mLogSessionId.getStringId());
     }
 }
diff --git a/media/java/android/media/metrics/EditingSession.java b/media/java/android/media/metrics/EditingSession.java
index 2a48a72..2ddf623b 100644
--- a/media/java/android/media/metrics/EditingSession.java
+++ b/media/java/android/media/metrics/EditingSession.java
@@ -59,5 +59,6 @@
 
     @Override
     public void close() {
+        mManager.releaseSessionId(mLogSessionId.getStringId());
     }
 }
diff --git a/media/java/android/media/metrics/IMediaMetricsManager.aidl b/media/java/android/media/metrics/IMediaMetricsManager.aidl
index a774403..51b1cc2 100644
--- a/media/java/android/media/metrics/IMediaMetricsManager.aidl
+++ b/media/java/android/media/metrics/IMediaMetricsManager.aidl
@@ -41,4 +41,6 @@
     String getEditingSessionId(int userId);
     String getBundleSessionId(int userId);
     void reportBundleMetrics(in String sessionId, in PersistableBundle metrics, int userId);
+
+    void releaseSessionId(in String sessionId, int userId);
 }
diff --git a/media/java/android/media/metrics/MediaMetricsManager.java b/media/java/android/media/metrics/MediaMetricsManager.java
index 7229c47..0898874 100644
--- a/media/java/android/media/metrics/MediaMetricsManager.java
+++ b/media/java/android/media/metrics/MediaMetricsManager.java
@@ -171,6 +171,18 @@
     }
 
     /**
+     * Creates a generic bundle session.
+     */
+    @NonNull
+    public void releaseSessionId(@NonNull String sessionId) {
+        try {
+            mService.releaseSessionId(sessionId, mUserId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Reports error event.
      * @hide
      */
diff --git a/media/java/android/media/metrics/PlaybackSession.java b/media/java/android/media/metrics/PlaybackSession.java
index aad510e..f8dd756 100644
--- a/media/java/android/media/metrics/PlaybackSession.java
+++ b/media/java/android/media/metrics/PlaybackSession.java
@@ -100,5 +100,6 @@
     @Override
     public void close() {
         mClosed = true;
+        mManager.releaseSessionId(mLogSessionId.getStringId());
     }
 }
diff --git a/media/java/android/media/metrics/PlaybackStateEvent.java b/media/java/android/media/metrics/PlaybackStateEvent.java
index 8e74825..cfe0ff8 100644
--- a/media/java/android/media/metrics/PlaybackStateEvent.java
+++ b/media/java/android/media/metrics/PlaybackStateEvent.java
@@ -31,6 +31,11 @@
  * Playback state event.
  */
 public final class PlaybackStateEvent extends Event implements Parcelable {
+
+        // RBE -- we should be getting these values from the proto, not doing them
+        // hand-coded values here.
+        // frameorks/proto_logging/stats/message/mediametrics_message.pb.h
+        // package libstatslog?
     /** Playback has not started (initial state) */
     public static final int STATE_NOT_STARTED = 0;
     /** Playback is buffering in the background for initial playback start */
diff --git a/media/java/android/media/metrics/RecordingSession.java b/media/java/android/media/metrics/RecordingSession.java
index d388351..87cc250 100644
--- a/media/java/android/media/metrics/RecordingSession.java
+++ b/media/java/android/media/metrics/RecordingSession.java
@@ -61,5 +61,6 @@
     @Override
     public void close() {
         mClosed = true;
+        mManager.releaseSessionId(mLogSessionId.getStringId());
     }
 }
diff --git a/media/java/android/media/metrics/TranscodingSession.java b/media/java/android/media/metrics/TranscodingSession.java
index e6d359a..352138e 100644
--- a/media/java/android/media/metrics/TranscodingSession.java
+++ b/media/java/android/media/metrics/TranscodingSession.java
@@ -59,5 +59,6 @@
 
     @Override
     public void close() {
+        mManager.releaseSessionId(mLogSessionId.getStringId());
     }
 }
diff --git a/media/java/android/media/projection/IMediaProjection.aidl b/media/java/android/media/projection/IMediaProjection.aidl
index 19fc052..b136d5b 100644
--- a/media/java/android/media/projection/IMediaProjection.aidl
+++ b/media/java/android/media/projection/IMediaProjection.aidl
@@ -17,6 +17,7 @@
 package android.media.projection;
 
 import android.media.projection.IMediaProjectionCallback;
+import android.window.WindowContainerToken;
 
 /** {@hide} */
 interface IMediaProjection {
@@ -28,4 +29,16 @@
     int applyVirtualDisplayFlags(int flags);
     void registerCallback(IMediaProjectionCallback callback);
     void unregisterCallback(IMediaProjectionCallback callback);
+
+    /**
+     * Returns the {@link android.window.WindowContainerToken} identifying the task to record, or
+     * {@code null} if there is none.
+     */
+    WindowContainerToken getTaskRecordingWindowContainerToken();
+
+    /**
+     * Updates the {@link android.window.WindowContainerToken} identifying the task to record, or
+     * {@code null} if there is none.
+     */
+    void setTaskRecordingWindowContainerToken(in WindowContainerToken token);
 }
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index 4dde5e8..b5f9593 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -25,13 +25,14 @@
 import android.hardware.display.VirtualDisplay;
 import android.hardware.display.VirtualDisplayConfig;
 import android.os.Handler;
-import android.os.IBinder;
 import android.os.RemoteException;
 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;
 
@@ -171,16 +172,34 @@
             @NonNull VirtualDisplayConfig.Builder virtualDisplayConfig,
             @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
         try {
-            final Context windowContext = mContext.createWindowContext(
-                    mContext.getDisplayNoVerify(),
-                    TYPE_APPLICATION, null /* options */);
-            final IBinder windowContextToken = windowContext.getWindowContextToken();
+            final IWindowManager wmService = WindowManagerGlobal.getWindowManagerService();
+            final WindowContainerToken taskWindowContainerToken =
+                    mImpl.getTaskRecordingWindowContainerToken();
+            Context windowContext = null;
+            ContentRecordingSession session;
+            if (taskWindowContainerToken == null) {
+                windowContext = mContext.createWindowContext(mContext.getDisplayNoVerify(),
+                        TYPE_APPLICATION, null /* options */);
+                session = ContentRecordingSession.createDisplaySession(
+                        windowContext.getWindowContextToken());
+            } else {
+                session = ContentRecordingSession.createTaskSession(
+                        taskWindowContainerToken.asBinder());
+            }
             virtualDisplayConfig.setWindowManagerMirroring(true);
             final DisplayManager dm = mContext.getSystemService(DisplayManager.class);
             final VirtualDisplay virtualDisplay = dm.createVirtualDisplay(this,
-                    virtualDisplayConfig.build(),
-                    callback, handler, windowContext);
-            setSession(windowContextToken, virtualDisplay);
+                    virtualDisplayConfig.build(), callback, handler, windowContext);
+            if (virtualDisplay == null) {
+                // Since WM handling a new display and DM creating a new VirtualDisplay is async,
+                // WM may have tried to start task recording and encountered an error that required
+                // stopping recording entirely. The VirtualDisplay would then be null when the
+                // MediaProjection is no longer active.
+                return null;
+            }
+            session.setDisplayId(virtualDisplay.getDisplay().getDisplayId());
+            // Successfully set up, so save the current session details.
+            wmService.setContentRecordingSession(session);
             return virtualDisplay;
         } catch (RemoteException e) {
             // Can not capture if WMS is not accessible, so bail out.
@@ -189,28 +208,6 @@
     }
 
     /**
-     * Updates the {@link ContentRecordingSession} describing the recording taking place on this
-     * {@link VirtualDisplay}.
-     *
-     * @throws RemoteException if updating the session on the server failed.
-     */
-    private void setSession(@NonNull IBinder windowContextToken,
-            @Nullable VirtualDisplay virtualDisplay)
-            throws RemoteException {
-        if (virtualDisplay == null) {
-            // Not able to set up a new VirtualDisplay.
-            return;
-        }
-        // Identify the VirtualDisplay that will be hosting the recording.
-        ContentRecordingSession session = ContentRecordingSession.createDisplaySession(
-                windowContextToken);
-        session.setDisplayId(virtualDisplay.getDisplay().getDisplayId());
-        // TODO(b/216625226) handle task recording.
-        // Successfully set up, so save the current session details.
-        WindowManagerGlobal.getWindowManagerService().setContentRecordingSession(session);
-    }
-
-    /**
      * Stops projection.
      */
     public void stop() {
diff --git a/media/java/android/media/tv/AdRequest.java b/media/java/android/media/tv/AdRequest.java
index 0542c55..f2fb93d 100644
--- a/media/java/android/media/tv/AdRequest.java
+++ b/media/java/android/media/tv/AdRequest.java
@@ -163,7 +163,11 @@
 
     /**
      * Gets the metadata of the media file.
-     * <p>This includes additional information the TV input needs to play the AD media.
+     *
+     * <p>This includes additional information the TV input needs to play the AD media. This may
+     * include fields in {@link android.media.MediaFormat} like
+     * {@link android.media.MediaFormat#KEY_SAMPLE_RATE}, or integrity information like SHA. What
+     * data is included depends on the format of the media file.
      *
      * @return The metadata of the media file. Can be an empty bundle for
      *         {@link #REQUEST_TYPE_STOP}.
diff --git a/media/java/android/media/tv/AitInfo.java b/media/java/android/media/tv/AitInfo.java
index 8e80a62..c88a2b5 100644
--- a/media/java/android/media/tv/AitInfo.java
+++ b/media/java/android/media/tv/AitInfo.java
@@ -17,7 +17,7 @@
 package android.media.tv;
 
 import android.annotation.NonNull;
-import android.media.tv.interactive.TvInteractiveAppInfo;
+import android.media.tv.interactive.TvInteractiveAppServiceInfo;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -50,7 +50,7 @@
     /**
      * Constructs AIT info.
      */
-    public AitInfo(@TvInteractiveAppInfo.InteractiveAppType int type, int version) {
+    public AitInfo(@TvInteractiveAppServiceInfo.InteractiveAppType int type, int version) {
         mType = type;
         mVersion = version;
     }
@@ -58,7 +58,7 @@
     /**
      * Gets interactive app type.
      */
-    @TvInteractiveAppInfo.InteractiveAppType
+    @TvInteractiveAppServiceInfo.InteractiveAppType
     public int getType() {
         return mType;
     }
diff --git a/media/java/android/media/tv/CommandRequest.java b/media/java/android/media/tv/CommandRequest.java
index ffb6e07..3245fb5 100644
--- a/media/java/android/media/tv/CommandRequest.java
+++ b/media/java/android/media/tv/CommandRequest.java
@@ -24,6 +24,8 @@
  * A request for command from broadcast signal.
  */
 public final class CommandRequest extends BroadcastInfoRequest implements Parcelable {
+    public static final String ARGUMENT_TYPE_XML = "xml";
+    public static final String ARGUMENT_TYPE_JSON = "json";
     private static final @TvInputManager.BroadcastInfoType int REQUEST_TYPE =
             TvInputManager.BROADCAST_INFO_TYPE_COMMAND;
 
@@ -41,35 +43,38 @@
                 }
             };
 
-    private final String mNameSpace;
+    private final String mNamespace;
     private final String mName;
     private final String mArguments;
+    private final String mArgumentType;
 
     static CommandRequest createFromParcelBody(Parcel in) {
         return new CommandRequest(in);
     }
 
-    public CommandRequest(int requestId, @RequestOption int option, @NonNull String nameSpace,
-            @NonNull String name, @NonNull String arguments) {
+    public CommandRequest(int requestId, @RequestOption int option, @NonNull String namespace,
+            @NonNull String name, @NonNull String arguments, @NonNull String argumentType) {
         super(REQUEST_TYPE, requestId, option);
-        mNameSpace = nameSpace;
+        mNamespace = namespace;
         mName = name;
         mArguments = arguments;
+        mArgumentType = argumentType;
     }
 
     CommandRequest(Parcel source) {
         super(REQUEST_TYPE, source);
-        mNameSpace = source.readString();
+        mNamespace = source.readString();
         mName = source.readString();
         mArguments = source.readString();
+        mArgumentType = source.readString();
     }
 
     /**
      * Gets the namespace of the command.
      */
     @NonNull
-    public String getNameSpace() {
-        return mNameSpace;
+    public String getNamespace() {
+        return mNamespace;
     }
 
     /**
@@ -89,6 +94,15 @@
         return mArguments;
     }
 
+    /**
+     * Gets the argument type of the command.
+     * It could be either JSON or XML.
+     */
+    @NonNull
+    public String getArgumentType() {
+        return mArgumentType;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -97,8 +111,9 @@
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         super.writeToParcel(dest, flags);
-        dest.writeString(mNameSpace);
+        dest.writeString(mNamespace);
         dest.writeString(mName);
         dest.writeString(mArguments);
+        dest.writeString(mArgumentType);
     }
 }
diff --git a/media/java/android/media/tv/CommandResponse.java b/media/java/android/media/tv/CommandResponse.java
index c8853f1..8e448cd 100644
--- a/media/java/android/media/tv/CommandResponse.java
+++ b/media/java/android/media/tv/CommandResponse.java
@@ -25,6 +25,8 @@
  * A response for command from broadcast signal.
  */
 public final class CommandResponse extends BroadcastInfoResponse implements Parcelable {
+    public static final String RESPONSE_TYPE_XML = "xml";
+    public static final String RESPONSE_TYPE_JSON = "json";
     private static final @TvInputManager.BroadcastInfoType int RESPONSE_TYPE =
             TvInputManager.BROADCAST_INFO_TYPE_COMMAND;
 
@@ -43,20 +45,23 @@
             };
 
     private final String mResponse;
+    private final String mResponseType;
 
     static CommandResponse createFromParcelBody(Parcel in) {
         return new CommandResponse(in);
     }
 
-    public CommandResponse(int requestId, int sequence,
-            @ResponseResult int responseResult, @Nullable String response) {
+    public CommandResponse(int requestId, int sequence, @ResponseResult int responseResult,
+            @Nullable String response, @NonNull String responseType) {
         super(RESPONSE_TYPE, requestId, sequence, responseResult);
         mResponse = response;
+        mResponseType = responseType;
     }
 
     CommandResponse(Parcel source) {
         super(RESPONSE_TYPE, source);
         mResponse = source.readString();
+        mResponseType = source.readString();
     }
 
     /**
@@ -68,6 +73,15 @@
         return mResponse;
     }
 
+    /**
+     * Gets the type of the command response.
+     * It could be either JSON or XML.
+     */
+    @NonNull
+    public String getResponseType() {
+        return mResponseType;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -77,5 +91,6 @@
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         super.writeToParcel(dest, flags);
         dest.writeString(mResponse);
+        dest.writeString(mResponseType);
     }
 }
diff --git a/media/java/android/media/tv/DsmccResponse.java b/media/java/android/media/tv/DsmccResponse.java
index e14e8791..657d839 100644
--- a/media/java/android/media/tv/DsmccResponse.java
+++ b/media/java/android/media/tv/DsmccResponse.java
@@ -122,11 +122,12 @@
         mBiopMessageType = BIOP_MESSAGE_TYPE_STREAM;
         mFileDescriptor = null;
         mChildList = null;
-        mEventIds = eventIds;
-        mEventNames = eventNames;
-        if (mEventIds.length != eventNames.length) {
+        if (!((eventIds != null && eventNames != null && eventIds.length == eventNames.length)
+                || (eventIds == null && eventNames == null))) {
             throw new IllegalStateException("The size of eventIds and eventNames must be equal");
         }
+        mEventIds = eventIds;
+        mEventNames = eventNames;
     }
 
     private DsmccResponse(@NonNull Parcel source) {
@@ -137,10 +138,13 @@
             case BIOP_MESSAGE_TYPE_SERVICE_GATEWAY:
             case BIOP_MESSAGE_TYPE_DIRECTORY:
                 int childNum = source.readInt();
-                mChildList = new ArrayList<>();
-                for (int i = 0; i < childNum; i++) {
-                    mChildList.add(source.readString());
-                }
+                if (childNum > 0) {
+                    mChildList = new ArrayList<>();
+                    for (int i = 0; i < childNum; i++) {
+                        mChildList.add(source.readString());
+                    }
+                } else
+                    mChildList = null;
                 mFileDescriptor = null;
                 mEventIds = null;
                 mEventNames = null;
@@ -153,11 +157,16 @@
                 break;
             case BIOP_MESSAGE_TYPE_STREAM:
                 int eventNum = source.readInt();
-                mEventIds = new int[eventNum];
-                mEventNames = new String[eventNum];
-                for (int i = 0; i < eventNum; i++) {
-                    mEventIds[i] = source.readInt();
-                    mEventNames[i] = source.readString();
+                if (eventNum > 0) {
+                    mEventIds = new int[eventNum];
+                    mEventNames = new String[eventNum];
+                    for (int i = 0; i < eventNum; i++) {
+                        mEventIds[i] = source.readInt();
+                        mEventNames[i] = source.readString();
+                    }
+                } else {
+                    mEventIds = null;
+                    mEventNames = null;
                 }
                 mChildList = null;
                 mFileDescriptor = null;
@@ -196,7 +205,7 @@
                 && !mBiopMessageType.equals(BIOP_MESSAGE_TYPE_SERVICE_GATEWAY)) {
             throw new IllegalStateException("Not directory object");
         }
-        return new ArrayList<String>(mChildList);
+        return mChildList != null ? new ArrayList<String>(mChildList) : new ArrayList<String>();
     }
 
     /**
@@ -207,7 +216,7 @@
         if (!mBiopMessageType.equals(BIOP_MESSAGE_TYPE_STREAM)) {
             throw new IllegalStateException("Not stream event object");
         }
-        return mEventIds;
+        return mEventIds != null ? mEventIds : new int[0];
     }
 
     /**
@@ -218,7 +227,7 @@
         if (!mBiopMessageType.equals(BIOP_MESSAGE_TYPE_STREAM)) {
             throw new IllegalStateException("Not stream event object");
         }
-        return mEventNames;
+        return mEventNames != null ? mEventNames : new String[0];
     }
 
     @Override
@@ -233,20 +242,26 @@
         switch (mBiopMessageType) {
             case BIOP_MESSAGE_TYPE_SERVICE_GATEWAY:
             case BIOP_MESSAGE_TYPE_DIRECTORY:
-                dest.writeInt(mChildList.size());
-                for (String child : mChildList) {
-                    dest.writeString(child);
-                }
+                if (mChildList != null && mChildList.size() > 0) {
+                    dest.writeInt(mChildList.size());
+                    for (String child : mChildList) {
+                        dest.writeString(child);
+                    }
+                } else
+                    dest.writeInt(0);
                 break;
             case BIOP_MESSAGE_TYPE_FILE:
                 dest.writeFileDescriptor(mFileDescriptor.getFileDescriptor());
                 break;
             case BIOP_MESSAGE_TYPE_STREAM:
-                dest.writeInt(mEventIds.length);
-                for (int i = 0; i < mEventIds.length; i++) {
-                    dest.writeInt(mEventIds[i]);
-                    dest.writeString(mEventNames[i]);
-                }
+                if (mEventIds != null && mEventIds.length > 0) {
+                    dest.writeInt(mEventIds.length);
+                    for (int i = 0; i < mEventIds.length; i++) {
+                        dest.writeInt(mEventIds[i]);
+                        dest.writeString(mEventNames[i]);
+                    }
+                } else
+                    dest.writeInt(0);
                 break;
             default:
                 throw new IllegalStateException("unexpected BIOP message type");
diff --git a/media/java/android/media/tv/SectionRequest.java b/media/java/android/media/tv/SectionRequest.java
index 5957528..078e832 100644
--- a/media/java/android/media/tv/SectionRequest.java
+++ b/media/java/android/media/tv/SectionRequest.java
@@ -80,6 +80,11 @@
 
     /**
      * Gets the version number of requested session. If it is null, value will be -1.
+     * <p>The consistency of version numbers between request and response depends on
+     * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+     * REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
+     * different from the version of the request. Otherwise, response with a different version from
+     * its request will be considered invalid.
      */
     public int getVersion() {
         return mVersion;
diff --git a/media/java/android/media/tv/SectionResponse.java b/media/java/android/media/tv/SectionResponse.java
index 35836be..f38ea9d 100644
--- a/media/java/android/media/tv/SectionResponse.java
+++ b/media/java/android/media/tv/SectionResponse.java
@@ -74,14 +74,20 @@
     }
 
     /**
-     * Gets the Version number of requested session.
+     * Gets the Version number of requested session. If it is null, value will be -1.
+     * <p>The consistency of version numbers between request and response depends on
+     * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+     * REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
+     * different from the version of the request. Otherwise, response with a different version from
+     * its request will be considered invalid.
      */
     public int getVersion() {
         return mVersion;
     }
 
     /**
-     * Gets the raw data of session.
+     * Gets the raw data of session. The sessionData field represents payload data of the session
+     * after session header, which includes version and sessionId.
      */
     @NonNull
     public Bundle getSessionData() {
diff --git a/media/java/android/media/tv/StreamEventResponse.java b/media/java/android/media/tv/StreamEventResponse.java
index f952ce9..05dc39a 100644
--- a/media/java/android/media/tv/StreamEventResponse.java
+++ b/media/java/android/media/tv/StreamEventResponse.java
@@ -43,7 +43,7 @@
             };
 
     private final int mEventId;
-    private final long mNpt;
+    private final long mNptMillis;
     private final byte[] mData;
 
     static StreamEventResponse createFromParcelBody(Parcel in) {
@@ -51,20 +51,24 @@
     }
 
     public StreamEventResponse(int requestId, int sequence, @ResponseResult int responseResult,
-            int eventId, long npt, @Nullable byte[] data) {
+            int eventId, long nptMillis, @Nullable byte[] data) {
         super(RESPONSE_TYPE, requestId, sequence, responseResult);
         mEventId = eventId;
-        mNpt = npt;
+        mNptMillis = nptMillis;
         mData = data;
     }
 
     private StreamEventResponse(@NonNull Parcel source) {
         super(RESPONSE_TYPE, source);
         mEventId = source.readInt();
-        mNpt = source.readLong();
+        mNptMillis = source.readLong();
         int dataLength = source.readInt();
-        mData = new byte[dataLength];
-        source.readByteArray(mData);
+        if (dataLength > 0) {
+            mData = new byte[dataLength];
+            source.readByteArray(mData);
+        } else {
+            mData = null;
+        }
     }
 
     /**
@@ -76,9 +80,10 @@
 
     /**
      * Returns the NPT(Normal Play Time) value when the event occurred or will occur.
+     * <p>The time unit of NPT is millisecond.
      */
-    public long getNpt() {
-        return mNpt;
+    public long getNptMillis() {
+        return mNptMillis;
     }
 
     /**
@@ -98,8 +103,12 @@
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         super.writeToParcel(dest, flags);
         dest.writeInt(mEventId);
-        dest.writeLong(mNpt);
-        dest.writeInt(mData.length);
-        dest.writeByteArray(mData);
+        dest.writeLong(mNptMillis);
+        if (mData != null && mData.length > 0) {
+            dest.writeInt(mData.length);
+            dest.writeByteArray(mData);
+        } else {
+            dest.writeInt(0);
+        }
     }
 }
diff --git a/media/java/android/media/tv/TableRequest.java b/media/java/android/media/tv/TableRequest.java
index 37df4ea..a1a6b51 100644
--- a/media/java/android/media/tv/TableRequest.java
+++ b/media/java/android/media/tv/TableRequest.java
@@ -91,7 +91,12 @@
     }
 
     /**
-     * Gets the version number of requested table.
+     * Gets the version number of requested table. If it is null, value will be -1.
+     * <p>The consistency of version numbers between request and response depends on
+     * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+     * REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
+     * different from the version of the request. Otherwise, response with a different version from
+     * its request will be considered invalid.
      */
     public int getVersion() {
         return mVersion;
diff --git a/media/java/android/media/tv/TableResponse.java b/media/java/android/media/tv/TableResponse.java
index e9f1136..afc9bee 100644
--- a/media/java/android/media/tv/TableResponse.java
+++ b/media/java/android/media/tv/TableResponse.java
@@ -76,7 +76,12 @@
     }
 
     /**
-     * Gets the Version number of table.
+     * Gets the version number of requested table. If it is null, value will be -1.
+     * <p>The consistency of version numbers between request and response depends on
+     * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+     * REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
+     * different from the version of the request. Otherwise, response with a different version from
+     * its request will be considered invalid.
      */
     public int getVersion() {
         return mVersion;
diff --git a/media/java/android/media/tv/TimelineResponse.java b/media/java/android/media/tv/TimelineResponse.java
index fbeb0c4..7de30f5 100644
--- a/media/java/android/media/tv/TimelineResponse.java
+++ b/media/java/android/media/tv/TimelineResponse.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -79,8 +80,8 @@
      * that conveys Time Values on it.
      */
     @Nullable
-    public String getSelector() {
-        return mSelector;
+    public Uri getSelector() {
+        return Uri.parse(mSelector);
     }
 
     /**
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 69fe5ee..149c2f4 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -680,7 +680,7 @@
          * @param session A {@link TvInputManager.Session} associated with this callback.
          * @param strength The current signal strength.
          */
-        public void onSignalStrength(Session session, @SignalStrength int strength) {
+        public void onSignalStrengthUpdated(Session session, @SignalStrength int strength) {
         }
 
         /**
@@ -898,7 +898,7 @@
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    mSessionCallback.onSignalStrength(mSession, strength);
+                    mSessionCallback.onSignalStrengthUpdated(mSession, strength);
                     if (mSession.mIAppNotificationEnabled
                             && mSession.getInteractiveAppSession() != null) {
                         mSession.getInteractiveAppSession().notifySignalStrength(strength);
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 4d63af7..ff3d06c 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -1083,7 +1083,7 @@
          * @param inputId The ID of the TV input bound to this view.
          * @param strength The current signal strength.
          */
-        public void onSignalStrength(
+        public void onSignalStrengthUpdated(
                 @NonNull String inputId, @TvInputManager.SignalStrength int strength) {
         }
 
@@ -1406,16 +1406,16 @@
         }
 
         @Override
-        public void onSignalStrength(Session session, int strength) {
+        public void onSignalStrengthUpdated(Session session, int strength) {
             if (DEBUG) {
-                Log.d(TAG, "onSignalStrength(strength=" + strength + ")");
+                Log.d(TAG, "onSignalStrengthUpdated(strength=" + strength + ")");
             }
             if (this != mSessionCallback) {
-                Log.w(TAG, "onSignalStrength - session not created");
+                Log.w(TAG, "onSignalStrengthUpdated - session not created");
                 return;
             }
             if (mCallback != null) {
-                mCallback.onSignalStrength(mInputId, strength);
+                mCallback.onSignalStrengthUpdated(mInputId, strength);
             }
         }
 
diff --git a/media/java/android/media/tv/interactive/AppLinkInfo.aidl b/media/java/android/media/tv/interactive/AppLinkInfo.aidl
index 6759fc4..f551c9f 100644
--- a/media/java/android/media/tv/interactive/AppLinkInfo.aidl
+++ b/media/java/android/media/tv/interactive/AppLinkInfo.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
diff --git a/media/java/android/media/tv/interactive/AppLinkInfo.java b/media/java/android/media/tv/interactive/AppLinkInfo.java
index cd201f7..d5e995c 100644
--- a/media/java/android/media/tv/interactive/AppLinkInfo.java
+++ b/media/java/android/media/tv/interactive/AppLinkInfo.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -17,7 +17,8 @@
 package android.media.tv.interactive;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -25,91 +26,58 @@
  * App link information used by TV interactive app to launch Android apps.
  */
 public final class AppLinkInfo implements Parcelable {
-    private @NonNull String mPackageName;
-    private @NonNull String mClassName;
-    private @Nullable String mUriScheme;
-    private @Nullable String mUriHost;
-    private @Nullable String mUriPrefix;
-
+    private @NonNull ComponentName mComponentName;
+    private @NonNull Uri mUri;
 
     /**
      * Creates a new AppLinkInfo.
+     *
+     * @param packageName Package Name of AppLinkInfo.
+     * @param className Class Name of AppLinkInfo.
+     * @param uriString Uri of AppLinkInfo.
      */
-    private AppLinkInfo(
+    public AppLinkInfo(
             @NonNull String packageName,
             @NonNull String className,
-            @Nullable String uriScheme,
-            @Nullable String uriHost,
-            @Nullable String uriPrefix) {
-        this.mPackageName = packageName;
+            @NonNull String uriString) {
         com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mPackageName);
-        this.mClassName = className;
+                NonNull.class, null, packageName);
         com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mClassName);
-        this.mUriScheme = uriScheme;
-        this.mUriHost = uriHost;
-        this.mUriPrefix = uriPrefix;
+                NonNull.class, null, className);
+        this.mComponentName = new ComponentName(packageName, className);
+        this.mUri = Uri.parse(uriString);
     }
 
     /**
-     * Gets package name of the App link.
+     * Gets component name of the App link, which contains package name and class name.
      */
     @NonNull
-    public String getPackageName() {
-        return mPackageName;
+    public ComponentName getComponentName() {
+        return mComponentName;
     }
 
     /**
-     * Gets package class of the App link.
+     * Gets URI of the App link.
      */
     @NonNull
-    public String getClassName() {
-        return mClassName;
-    }
-
-    /**
-     * Gets URI scheme of the App link.
-     */
-    @Nullable
-    public String getUriScheme() {
-        return mUriScheme;
-    }
-
-    /**
-     * Gets URI host of the App link.
-     */
-    @Nullable
-    public String getUriHost() {
-        return mUriHost;
-    }
-
-    /**
-     * Gets URI prefix of the App link.
-     */
-    @Nullable
-    public String getUriPrefix() {
-        return mUriPrefix;
+    public Uri getUri() {
+        return mUri;
     }
 
     @Override
     public String toString() {
         return "AppLinkInfo { "
-                + "packageName = " + mPackageName + ", "
-                + "className = " + mClassName + ", "
-                + "uriScheme = " + mUriScheme + ", "
-                + "uriHost = " + mUriHost + ", "
-                + "uriPrefix = " + mUriPrefix
+                + "packageName = " + mComponentName.getPackageName() + ", "
+                + "className = " + mComponentName.getClassName() + ", "
+                + "uri = " + mUri.toString()
                 + " }";
     }
 
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeString(mPackageName);
-        dest.writeString(mClassName);
-        dest.writeString(mUriScheme);
-        dest.writeString(mUriHost);
-        dest.writeString(mUriPrefix);
+        mComponentName.writeToParcel(dest, flags);
+        String uriString = mUri == null ? null : mUri.toString();
+        dest.writeString(uriString);
     }
 
     @Override
@@ -118,21 +86,13 @@
     }
 
     /* package-private */ AppLinkInfo(@NonNull Parcel in) {
-        String packageName = in.readString();
-        String className = in.readString();
-        String uriScheme = in.readString();
-        String uriHost = in.readString();
-        String uriPrefix = in.readString();
-
-        this.mPackageName = packageName;
+        mComponentName = ComponentName.readFromParcel(in);
         com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mPackageName);
-        this.mClassName = className;
+                NonNull.class, null, mComponentName.getPackageName());
         com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mClassName);
-        this.mUriScheme = uriScheme;
-        this.mUriHost = uriHost;
-        this.mUriPrefix = uriPrefix;
+                NonNull.class, null, mComponentName.getClassName());
+        String uriString = in.readString();
+        mUri = uriString == null ? null : Uri.parse(uriString);
     }
 
     @NonNull
@@ -148,86 +108,4 @@
                     return new AppLinkInfo(in);
                 }
             };
-
-    /**
-     * A builder for {@link AppLinkInfo}
-     */
-    public static final class Builder {
-        private @NonNull String mPackageName;
-        private @NonNull String mClassName;
-        private @Nullable String mUriScheme;
-        private @Nullable String mUriHost;
-        private @Nullable String mUriPrefix;
-
-        /**
-         * Creates a new Builder.
-         */
-        public Builder(
-                @NonNull String packageName,
-                @NonNull String className) {
-            mPackageName = packageName;
-            com.android.internal.util.AnnotationValidations.validate(
-                    NonNull.class, null, mPackageName);
-            mClassName = className;
-            com.android.internal.util.AnnotationValidations.validate(
-                    NonNull.class, null, mClassName);
-        }
-
-        /**
-         * Sets package name of the App link.
-         */
-        @NonNull
-        public Builder setPackageName(@NonNull String value) {
-            mPackageName = value;
-            return this;
-        }
-
-        /**
-         * Sets app name of the App link.
-         */
-        @NonNull
-        public Builder setClassName(@NonNull String value) {
-            mClassName = value;
-            return this;
-        }
-
-        /**
-         * Sets URI scheme of the App link.
-         */
-        @NonNull
-        public Builder setUriScheme(@Nullable String value) {
-            mUriScheme = value;
-            return this;
-        }
-
-        /**
-         * Sets URI host of the App link.
-         */
-        @NonNull
-        public Builder setUriHost(@Nullable String value) {
-            mUriHost = value;
-            return this;
-        }
-
-        /**
-         * Sets URI prefix of the App link.
-         */
-        @NonNull
-        public Builder setUriPrefix(@Nullable String value) {
-            mUriPrefix = value;
-            return this;
-        }
-
-        /** Builds the instance. This builder should not be touched after calling this! */
-        @NonNull
-        public AppLinkInfo build() {
-            AppLinkInfo o = new AppLinkInfo(
-                    mPackageName,
-                    mClassName,
-                    mUriScheme,
-                    mUriHost,
-                    mUriPrefix);
-            return o;
-        }
-    }
 }
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
index a3e58d1..50aa6fe 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -44,5 +44,7 @@
     void onRequestStreamVolume(int seq);
     void onRequestTrackInfoList(int seq);
     void onRequestCurrentTvInputId(int seq);
+    void onRequestSigning(
+            in String id, in String algorithm, in String alias, in byte[] data, int seq);
     void onAdRequest(in AdRequest request, int Seq);
 }
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
index aaabe34..9ff564e 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -23,7 +23,7 @@
 import android.media.tv.interactive.AppLinkInfo;
 import android.media.tv.interactive.ITvInteractiveAppClient;
 import android.media.tv.interactive.ITvInteractiveAppManagerCallback;
-import android.media.tv.interactive.TvInteractiveAppInfo;
+import android.media.tv.interactive.TvInteractiveAppServiceInfo;
 import android.net.Uri;
 import android.os.Bundle;
 import android.view.Surface;
@@ -33,8 +33,7 @@
  * @hide
  */
 interface ITvInteractiveAppManager {
-    List<TvInteractiveAppInfo> getTvInteractiveAppServiceList(int userId);
-    void prepare(String tiasId, int type, int userId);
+    List<TvInteractiveAppServiceInfo> getTvInteractiveAppServiceList(int userId);
     void registerAppLinkInfo(String tiasId, in AppLinkInfo info, int userId);
     void unregisterAppLinkInfo(String tiasId, in AppLinkInfo info, int userId);
     void sendAppLinkCommand(String tiasId, in Bundle command, int userId);
@@ -50,6 +49,8 @@
     void sendStreamVolume(in IBinder sessionToken, float volume, int userId);
     void sendTrackInfoList(in IBinder sessionToken, in List<TvTrackInfo> tracks, int userId);
     void sendCurrentTvInputId(in IBinder sessionToken, in String inputId, int userId);
+    void sendSigningResult(in IBinder sessionToken, in String signingId, in byte[] result,
+            int userId);
     void createSession(in ITvInteractiveAppClient client, in String iAppServiceId, int type,
             int seq, int userId);
     void releaseSession(in IBinder sessionToken, int userId);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl
index 23be4c6..fed86dc 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -16,7 +16,7 @@
 
 package android.media.tv.interactive;
 
-import android.media.tv.interactive.TvInteractiveAppInfo;
+import android.media.tv.interactive.TvInteractiveAppServiceInfo;
 
 /**
  * Interface to receive callbacks from ITvInteractiveAppManager regardless of sessions.
@@ -26,6 +26,6 @@
     void onInteractiveAppServiceAdded(in String iAppServiceId);
     void onInteractiveAppServiceRemoved(in String iAppServiceId);
     void onInteractiveAppServiceUpdated(in String iAppServiceId);
-    void onTvInteractiveAppInfoUpdated(in TvInteractiveAppInfo tvIAppInfo);
+    void onTvInteractiveAppServiceInfoUpdated(in TvInteractiveAppServiceInfo tvIAppInfo);
     void onStateChanged(in String iAppServiceId, int type, int state, int err);
 }
\ No newline at end of file
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppService.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppService.aidl
index b6d518f..fb58ca7 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppService.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppService.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -32,7 +32,6 @@
     void unregisterCallback(in ITvInteractiveAppServiceCallback callback);
     void createSession(in InputChannel channel, in ITvInteractiveAppSessionCallback callback,
             in String iAppServiceId, int type);
-    void prepare(int type);
     void registerAppLinkInfo(in AppLinkInfo info);
     void unregisterAppLinkInfo(in AppLinkInfo info);
     void sendAppLinkCommand(in Bundle command);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppServiceCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppServiceCallback.aidl
index 970b943..87b3c1d 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppServiceCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppServiceCallback.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
index c449d2475..e14b2bb 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -42,6 +42,7 @@
     void sendStreamVolume(float volume);
     void sendTrackInfoList(in List<TvTrackInfo> tracks);
     void sendCurrentTvInputId(in String inputId);
+    void sendSigningResult(in String signingId, in byte[] result);
     void release();
     void notifyTuned(in Uri channelUri);
     void notifyTrackSelected(int type, in String trackId);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
index 385f0d4..32b08b7 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -43,5 +43,6 @@
     void onRequestStreamVolume();
     void onRequestTrackInfoList();
     void onRequestCurrentTvInputId();
+    void onRequestSigning(in String id, in String algorithm, in String alias, in byte[] data);
     void onAdRequest(in AdRequest request);
 }
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
index f75aa56..d3cbcdc 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -28,7 +28,6 @@
 import android.media.tv.BroadcastInfoRequest;
 import android.media.tv.BroadcastInfoResponse;
 import android.media.tv.TvContentRating;
-import android.media.tv.TvInputInfo;
 import android.media.tv.TvInputManager;
 import android.media.tv.TvTrackInfo;
 import android.net.Uri;
@@ -249,7 +248,7 @@
      *
      * @see #sendAppLinkCommand(String, Bundle)
      * @see #ACTION_APP_LINK_COMMAND
-     * @see android.media.tv.interactive.TvInteractiveAppInfo#getId()
+     * @see TvInteractiveAppServiceInfo#getId()
      */
     public static final String INTENT_KEY_INTERACTIVE_APP_SERVICE_ID = "interactive_app_id";
 
@@ -269,7 +268,7 @@
      *
      * @see #sendAppLinkCommand(String, Bundle)
      * @see #ACTION_APP_LINK_COMMAND
-     * @see android.media.tv.interactive.TvInteractiveAppInfo#getSupportedTypes()
+     * @see android.media.tv.interactive.TvInteractiveAppServiceInfo#getSupportedTypes()
      * @see android.media.tv.interactive.TvInteractiveAppView#createBiInteractiveApp(Uri, Bundle)
      */
     public static final String INTENT_KEY_BI_INTERACTIVE_APP_TYPE = "bi_interactive_app_type";
@@ -285,6 +284,16 @@
      */
     public static final String INTENT_KEY_BI_INTERACTIVE_APP_URI = "bi_interactive_app_uri";
 
+    /**
+     * Intent key for command type. It's used to send app command to TV app. The value of this key
+     * could vary according to TV apps.
+     * <p>Type: String
+     *
+     * @see #sendAppLinkCommand(String, Bundle)
+     * @see #ACTION_APP_LINK_COMMAND
+     */
+    public static final String INTENT_KEY_COMMAND_TYPE = "command_type";
+
     private final ITvInteractiveAppManager mService;
     private final int mUserId;
 
@@ -478,6 +487,19 @@
             }
 
             @Override
+            public void onRequestSigning(
+                    String id, String algorithm, String alias, byte[] data, int seq) {
+                synchronized (mSessionCallbackRecordMap) {
+                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+                    if (record == null) {
+                        Log.e(TAG, "Callback not found for seq " + seq);
+                        return;
+                    }
+                    record.postRequestSigning(id, algorithm, alias, data);
+                }
+            }
+
+            @Override
             public void onSessionStateChanged(int state, int err, int seq) {
                 synchronized (mSessionCallbackRecordMap) {
                     SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
@@ -543,11 +565,11 @@
             }
 
             @Override
-            public void onTvInteractiveAppInfoUpdated(TvInteractiveAppInfo iAppInfo) {
+            public void onTvInteractiveAppServiceInfoUpdated(TvInteractiveAppServiceInfo iAppInfo) {
                 // TODO: add public API updateInteractiveAppInfo()
                 synchronized (mLock) {
                     for (TvInteractiveAppCallbackRecord record : mCallbackRecords) {
-                        record.postTvInteractiveAppInfoUpdated(iAppInfo);
+                        record.postTvInteractiveAppServiceInfoUpdated(iAppInfo);
                     }
                 }
             }
@@ -611,21 +633,23 @@
          * This is called when the information about an existing TV Interactive App service has been
          * updated.
          *
-         * <p>Because the system automatically creates a <code>TvInteractiveAppInfo</code> object
-         * for each TV Interactive App service based on the information collected from the
+         * <p>Because the system automatically creates a <code>TvInteractiveAppServiceInfo</code>
+         * object for each TV Interactive App service based on the information collected from the
          * <code>AndroidManifest.xml</code>, this method is only called back when such information
          * has changed dynamically.
          *
-         * @param iAppInfo The <code>TvInteractiveAppInfo</code> object that contains new
+         * @param iAppInfo The <code>TvInteractiveAppServiceInfo</code> object that contains new
          *                 information.
          * @hide
          */
-        public void onTvInteractiveAppInfoUpdated(@NonNull TvInteractiveAppInfo iAppInfo) {
+        public void onTvInteractiveAppServiceInfoUpdated(
+                @NonNull TvInteractiveAppServiceInfo iAppInfo) {
         }
 
         /**
          * This is called when the state of the interactive app service is changed.
          *
+         * @param iAppServiceId The ID of the TV Interactive App service.
          * @param type the interactive app type
          * @param state the current state of the service of the given type
          * @param err the error code for error state. {@link #ERROR_NONE} is used when the state is
@@ -633,7 +657,7 @@
          */
         public void onTvInteractiveAppServiceStateChanged(
                 @NonNull String iAppServiceId,
-                @TvInteractiveAppInfo.InteractiveAppType int type,
+                @TvInteractiveAppServiceInfo.InteractiveAppType int type,
                 @ServiceState int state,
                 @ErrorCode int err) {
         }
@@ -679,11 +703,12 @@
             });
         }
 
-        public void postTvInteractiveAppInfoUpdated(final TvInteractiveAppInfo iAppInfo) {
+        public void postTvInteractiveAppServiceInfoUpdated(
+                final TvInteractiveAppServiceInfo iAppInfo) {
             mExecutor.execute(new Runnable() {
                 @Override
                 public void run() {
-                    mCallback.onTvInteractiveAppInfoUpdated(iAppInfo);
+                    mCallback.onTvInteractiveAppServiceInfoUpdated(iAppInfo);
                 }
             });
         }
@@ -736,11 +761,11 @@
     /**
      * Returns the complete list of TV Interactive App service on the system.
      *
-     * @return List of {@link TvInteractiveAppInfo} for each TV Interactive App service that
+     * @return List of {@link TvInteractiveAppServiceInfo} for each TV Interactive App service that
      *         describes its meta information.
      */
     @NonNull
-    public List<TvInteractiveAppInfo> getTvInteractiveAppServiceList() {
+    public List<TvInteractiveAppServiceInfo> getTvInteractiveAppServiceList() {
         try {
             return mService.getTvInteractiveAppServiceList(mUserId);
         } catch (RemoteException e) {
@@ -749,18 +774,12 @@
     }
 
     /**
-     * Prepares TV Interactive App service environment for the given type.
-     */
-    public void prepare(@NonNull String tvIAppServiceId, int type) {
-        try {
-            mService.prepare(tvIAppServiceId, type, mUserId);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Registers app link info.
+     * Registers an Android application link info record which can be used to launch the specific
+     * Android application by TV interactive App RTE.
+     *
+     * @param tvIAppServiceId The ID of TV interactive service which the command to be sent to. The
+     *                        ID can be found in {@link TvInteractiveAppServiceInfo#getId()}.
+     * @param appLinkInfo The Android application link info record to be registered.
      */
     public void registerAppLinkInfo(
             @NonNull String tvIAppServiceId, @NonNull AppLinkInfo appLinkInfo) {
@@ -772,7 +791,12 @@
     }
 
     /**
-     * Unregisters app link info.
+     * Unregisters an Android application link info record which can be used to launch the specific
+     * Android application by TV interactive App RTE.
+     *
+     * @param tvIAppServiceId The ID of TV interactive service which the command to be sent to. The
+     *                        ID can be found in {@link TvInteractiveAppServiceInfo#getId()}.
+     * @param appLinkInfo The Android application link info record to be unregistered.
      */
     public void unregisterAppLinkInfo(
             @NonNull String tvIAppServiceId, @NonNull AppLinkInfo appLinkInfo) {
@@ -787,7 +811,7 @@
      * Sends app link command.
      *
      * @param tvIAppServiceId The ID of TV interactive service which the command to be sent to. The
-     *                        ID can be found in {@link TvInputInfo#getId()}.
+     *                        ID can be found in {@link TvInteractiveAppServiceInfo#getId()}.
      * @param command The command to be sent.
      */
     public void sendAppLinkCommand(@NonNull String tvIAppServiceId, @NonNull Bundle command) {
@@ -805,8 +829,8 @@
      * @param executor A {@link Executor} that the status change will be delivered to.
      */
     public void registerCallback(
-            @NonNull TvInteractiveAppCallback callback,
-            @CallbackExecutor @NonNull Executor executor) {
+            @CallbackExecutor @NonNull Executor executor,
+            @NonNull TvInteractiveAppCallback callback) {
         Preconditions.checkNotNull(callback);
         Preconditions.checkNotNull(executor);
         synchronized (mLock) {
@@ -1011,6 +1035,18 @@
             }
         }
 
+        void sendSigningResult(@NonNull String signingId, @NonNull byte[] result) {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.sendSigningResult(mToken, signingId, result, mUserId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
         /**
          * Sets the {@link android.view.Surface} for this session.
          *
@@ -1644,6 +1680,15 @@
             });
         }
 
+        void postRequestSigning(String id, String algorithm, String alias, byte[] data) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mSessionCallback.onRequestSigning(mSession, id, algorithm, alias, data);
+                }
+            });
+        }
+
         void postAdRequest(final AdRequest request) {
             mHandler.post(new Runnable() {
                 @Override
@@ -1781,12 +1826,27 @@
          * called.
          *
          * @param session A {@link TvInteractiveAppService.Session} associated with this callback.
-         * @hide
          */
         public void onRequestCurrentTvInputId(Session session) {
         }
 
         /**
+         * This is called when
+         * {@link TvInteractiveAppService.Session#requestSigning(String, String, String, byte[])} is
+         * called.
+         *
+         * @param session A {@link TvInteractiveAppService.Session} associated with this callback.
+         * @param signingId the ID to identify the request.
+         * @param algorithm the standard name of the signature algorithm requested, such as
+         *                  MD5withRSA, SHA256withDSA, etc.
+         * @param alias the alias of the corresponding {@link java.security.KeyStore}.
+         * @param data the original bytes to be signed.
+         */
+        public void onRequestSigning(
+                Session session, String signingId, String algorithm, String alias, byte[] data) {
+        }
+
+        /**
          * This is called when {@link TvInteractiveAppService.Session#notifySessionStateChanged} is
          * called.
          *
@@ -1813,8 +1873,8 @@
         }
 
         /**
-         * This is called when {@link TvIAppService.Session#notifyTeletextAppStateChanged} is
-         * called.
+         * This is called when {@link TvInteractiveAppService.Session#notifyTeletextAppStateChanged}
+         * is called.
          *
          * @param session A {@link TvInteractiveAppManager.Session} associated with this callback.
          * @param state the current state.
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
index 52b00b7..b103b10 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppService.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -16,9 +16,12 @@
 
 package android.media.tv.interactive;
 
+import android.annotation.CallSuper;
 import android.annotation.MainThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.Px;
+import android.annotation.SdkConstant;
 import android.annotation.StringDef;
 import android.annotation.SuppressLint;
 import android.app.ActivityManager;
@@ -76,15 +79,14 @@
 
     private static final int DETACH_MEDIA_VIEW_TIMEOUT_MS = 5000;
 
-    // TODO: cleanup and unhide APIs.
-
     /**
      * This is the interface name that a service implementing a TV Interactive App service should
      * say that it supports -- that is, this is the action it uses for its intent filter. To be
      * supported, the service must also require the
-     * android.Manifest.permission#BIND_TV_INTERACTIVE_APP permission so that other applications
-     * cannot abuse it.
+     * {@link android.Manifest.permission#BIND_TV_INTERACTIVE_APP} permission so that other
+     * applications cannot abuse it.
      */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
     public static final String SERVICE_INTERFACE =
             "android.media.tv.interactive.TvInteractiveAppService";
 
@@ -216,11 +218,6 @@
             }
 
             @Override
-            public void prepare(int type) {
-                onPrepare(type);
-            }
-
-            @Override
             public void registerAppLinkInfo(AppLinkInfo appLinkInfo) {
                 onRegisterAppLinkInfo(appLinkInfo);
             }
@@ -239,18 +236,13 @@
     }
 
     /**
-     * Prepares TV Interactive App service for the given type.
-     */
-    public abstract void onPrepare(@TvInteractiveAppInfo.InteractiveAppType int type);
-
-    /**
-     * Registers App link info.
+     * Called when a request to register an Android application link info record is received.
      */
     public void onRegisterAppLinkInfo(@NonNull AppLinkInfo appLinkInfo) {
     }
 
     /**
-     * Unregisters App link info.
+     * Called when a request to unregister an Android application link info record is received.
      */
     public void onUnregisterAppLinkInfo(@NonNull AppLinkInfo appLinkInfo) {
     }
@@ -276,7 +268,7 @@
     @Nullable
     public abstract Session onCreateSession(
             @NonNull String iAppServiceId,
-            @TvInteractiveAppInfo.InteractiveAppType int type);
+            @TvInteractiveAppServiceInfo.InteractiveAppType int type);
 
     /**
      * Notifies the system when the state of the interactive app RTE has been changed.
@@ -288,7 +280,7 @@
      *              {@link TvInteractiveAppManager#SERVICE_STATE_ERROR}.
      */
     public final void notifyStateChanged(
-            @TvInteractiveAppInfo.InteractiveAppType int type,
+            @TvInteractiveAppServiceInfo.InteractiveAppType int type,
             @TvInteractiveAppManager.ServiceState int state,
             @TvInteractiveAppManager.ErrorCode int error) {
         SomeArgs args = SomeArgs.obtain();
@@ -351,6 +343,7 @@
          * @param enable {@code true} if you want to enable the media view. {@code false}
          *            otherwise.
          */
+        @CallSuper
         public void setMediaViewEnabled(final boolean enable) {
             mHandler.post(new Runnable() {
                 @Override
@@ -371,6 +364,15 @@
         }
 
         /**
+         * Returns {@code true} if media view is enabled, {@code false} otherwise.
+         *
+         * @see #setMediaViewEnabled(boolean)
+         */
+        public boolean isMediaViewEnabled() {
+            return mMediaViewEnabled;
+        }
+
+        /**
          * Starts TvInteractiveAppService session.
          */
         public void onStartInteractiveApp() {
@@ -383,7 +385,7 @@
         }
 
         /**
-         * Resets TvIAppService session.
+         * Resets TvInteractiveAppService session.
          */
         public void onResetInteractiveApp() {
         }
@@ -395,9 +397,10 @@
          * no matter if it's created successfully or not.
          *
          * @see #notifyBiInteractiveAppCreated(Uri, String)
-         * @see #onDestroyBiInteractiveApp(String)
+         * @see #onDestroyBiInteractiveAppRequest(String)
          */
-        public void onCreateBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) {
+        public void onCreateBiInteractiveAppRequest(
+                @NonNull Uri biIAppUri, @Nullable Bundle params) {
         }
 
 
@@ -405,11 +408,11 @@
          * Destroys broadcast-independent(BI) interactive application.
          *
          * @param biIAppId the BI interactive app ID from
-         *                 {@link #onCreateBiInteractiveApp(Uri, Bundle)}}
+         *                 {@link #onCreateBiInteractiveAppRequest(Uri, Bundle)}
          *
-         * @see #onCreateBiInteractiveApp(Uri, Bundle)
+         * @see #onCreateBiInteractiveAppRequest(Uri, Bundle)
          */
-        public void onDestroyBiInteractiveApp(@NonNull String biIAppId) {
+        public void onDestroyBiInteractiveAppRequest(@NonNull String biIAppId) {
         }
 
         /**
@@ -433,6 +436,8 @@
 
         /**
          * Receives current stream volume.
+         *
+         * @param volume a volume value between {@code 0.0f} and {@code 1.0f}, inclusive.
          */
         public void onStreamVolume(float volume) {
         }
@@ -450,6 +455,17 @@
         }
 
         /**
+         * Receives signing result.
+         * @param signingId the ID to identify the request. It's the same as the corresponding ID in
+         *        {@link Session#requestSigning(String, String, String, byte[])}
+         * @param result the signed result.
+         *
+         * @see #requestSigning(String, String, String, byte[])
+         */
+        public void onSigningResult(@NonNull String signingId, @NonNull byte[] result) {
+        }
+
+        /**
          * Called when the application sets the surface.
          *
          * <p>The TV Interactive App service should render interactive app UI onto the given
@@ -467,11 +483,11 @@
          * in {@link #onSetSurface}. This method is always called at least once, after
          * {@link #onSetSurface} is called with non-null surface.
          *
-         * @param format The new PixelFormat of the surface.
+         * @param format The new {@link PixelFormat} of the surface.
          * @param width The new width of the surface.
          * @param height The new height of the surface.
          */
-        public void onSurfaceChanged(int format, int width, int height) {
+        public void onSurfaceChanged(@PixelFormat.Format int format, int width, int height) {
         }
 
         /**
@@ -482,10 +498,10 @@
          * containing {@link TvInteractiveAppView}. Note that the size of the underlying surface can
          * be different if the surface was changed by calling {@link #layoutSurface}.
          *
-         * @param width The width of the media view.
-         * @param height The height of the media view.
+         * @param width The width of the media view, in pixels.
+         * @param height The height of the media view, in pixels.
          */
-        public void onMediaViewSizeChanged(int width, int height) {
+        public void onMediaViewSizeChanged(@Px int width, @Px int height) {
         }
 
         /**
@@ -631,6 +647,7 @@
          * @param right Right position in pixels, relative to the overlay view.
          * @param bottom Bottom position in pixels, relative to the overlay view.
          */
+        @CallSuper
         public void layoutSurface(final int left, final int top, final int right,
                 final int bottom) {
             if (left > right || top > bottom) {
@@ -659,6 +676,7 @@
          * Requests broadcast related information from the related TV input.
          * @param request the request for broadcast info
          */
+        @CallSuper
         public void requestBroadcastInfo(@NonNull final BroadcastInfoRequest request) {
             executeOrPostRunnableOnMainThread(new Runnable() {
                 @MainThread
@@ -683,6 +701,7 @@
          * Remove broadcast information request from the related TV input.
          * @param requestId the ID of the request
          */
+        @CallSuper
         public void removeBroadcastInfo(final int requestId) {
             executeOrPostRunnableOnMainThread(new Runnable() {
                 @MainThread
@@ -709,6 +728,7 @@
          * @param cmdType type of the specific command
          * @param parameters parameters of the specific command
          */
+        @CallSuper
         public void sendPlaybackCommandRequest(
                 @PlaybackCommandType @NonNull String cmdType, @Nullable Bundle parameters) {
             executeOrPostRunnableOnMainThread(new Runnable() {
@@ -733,6 +753,7 @@
         /**
          * Sets broadcast video bounds.
          */
+        @CallSuper
         public void setVideoBounds(@NonNull Rect rect) {
             executeOrPostRunnableOnMainThread(new Runnable() {
                 @MainThread
@@ -755,6 +776,7 @@
         /**
          * Requests the URI of the current channel.
          */
+        @CallSuper
         public void requestCurrentChannelUri() {
             executeOrPostRunnableOnMainThread(new Runnable() {
                 @MainThread
@@ -777,6 +799,7 @@
         /**
          * Requests the logic channel number (LCN) of the current channel.
          */
+        @CallSuper
         public void requestCurrentChannelLcn() {
             executeOrPostRunnableOnMainThread(new Runnable() {
                 @MainThread
@@ -799,6 +822,7 @@
         /**
          * Requests stream volume.
          */
+        @CallSuper
         public void requestStreamVolume() {
             executeOrPostRunnableOnMainThread(new Runnable() {
                 @MainThread
@@ -821,6 +845,7 @@
         /**
          * Requests the list of {@link TvTrackInfo}.
          */
+        @CallSuper
         public void requestTrackInfoList() {
             executeOrPostRunnableOnMainThread(new Runnable() {
                 @MainThread
@@ -845,6 +870,7 @@
          *
          * @see android.media.tv.TvInputInfo
          */
+        @CallSuper
         public void requestCurrentTvInputId() {
             executeOrPostRunnableOnMainThread(new Runnable() {
                 @MainThread
@@ -865,10 +891,52 @@
         }
 
         /**
+         * Requests signing of the given data.
+         *
+         * <p>This is used when the corresponding server of the broadcast-independent interactive
+         * app requires signing during handshaking, and the interactive app service doesn't have
+         * the built-in private key. The private key is provided by the content providers and
+         * pre-built in the related app, such as TV app.
+         *
+         * @param signingId the ID to identify the request. When a result is received, this ID can
+         *                  be used to correlate the result with the request.
+         * @param algorithm the standard name of the signature algorithm requested, such as
+         *                  MD5withRSA, SHA256withDSA, etc. The name is from standards like
+         *                  FIPS PUB 186-4 and PKCS #1.
+         * @param alias the alias of the corresponding {@link java.security.KeyStore}.
+         * @param data the original bytes to be signed.
+         *
+         * @see #onSigningResult(String, byte[])
+         * @see TvInteractiveAppView#createBiInteractiveApp(Uri, Bundle)
+         * @see TvInteractiveAppView#BI_INTERACTIVE_APP_KEY_ALIAS
+         */
+        @CallSuper
+        public void requestSigning(@NonNull String signingId, @NonNull String algorithm,
+                @NonNull String alias, @NonNull byte[] data) {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) {
+                            Log.d(TAG, "requestSigning");
+                        }
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onRequestSigning(signingId, algorithm, alias, data);
+                        }
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "error in requestSigning", e);
+                    }
+                }
+            });
+        }
+
+        /**
          * Sends an advertisement request to be processed by the related TV input.
          *
          * @param request The advertisement request
          */
+        @CallSuper
         public void requestAd(@NonNull final AdRequest request) {
             executeOrPostRunnableOnMainThread(new Runnable() {
                 @MainThread
@@ -901,11 +969,11 @@
         }
 
         void createBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) {
-            onCreateBiInteractiveApp(biIAppUri, params);
+            onCreateBiInteractiveAppRequest(biIAppUri, params);
         }
 
         void destroyBiInteractiveApp(@NonNull String biIAppId) {
-            onDestroyBiInteractiveApp(biIAppId);
+            onDestroyBiInteractiveAppRequest(biIAppId);
         }
 
         void setTeletextAppEnabled(boolean enable) {
@@ -932,6 +1000,10 @@
             onCurrentTvInputId(inputId);
         }
 
+        void sendSigningResult(String signingId, byte[] result) {
+            onSigningResult(signingId, result);
+        }
+
         void release() {
             onRelease();
             if (mSurface != null) {
@@ -1032,6 +1104,7 @@
          *            used when the state is not
          *            {@link TvInteractiveAppManager#INTERACTIVE_APP_STATE_ERROR}.
          */
+        @CallSuper
         public void notifySessionStateChanged(
                 @TvInteractiveAppManager.InteractiveAppState int state,
                 @TvInteractiveAppManager.ErrorCode int err) {
@@ -1060,8 +1133,9 @@
          * @param biIAppId BI interactive app ID, which can be used to destroy the BI interactive
          *                 app. {@code null} if it's not created successfully.
          *
-         * @see #onCreateBiInteractiveApp(Uri, Bundle)
+         * @see #onCreateBiInteractiveAppRequest(Uri, Bundle)
          */
+        @CallSuper
         public final void notifyBiInteractiveAppCreated(
                 @NonNull Uri biIAppUri, @Nullable String biIAppId) {
             executeOrPostRunnableOnMainThread(new Runnable() {
@@ -1087,6 +1161,7 @@
          * Notifies when the digital teletext app state is changed.
          * @param state the current state.
          */
+        @CallSuper
         public final void notifyTeletextAppStateChanged(
                 @TvInteractiveAppManager.TeletextAppState int state) {
             executeOrPostRunnableOnMainThread(new Runnable() {
@@ -1397,6 +1472,11 @@
         }
 
         @Override
+        public void sendSigningResult(@NonNull String signingId, @NonNull byte[] result) {
+            mSessionImpl.sendSigningResult(signingId, result);
+        }
+
+        @Override
         public void release() {
             mSessionImpl.scheduleMediaViewCleanup();
             mSessionImpl.release();
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppInfo.aidl b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.aidl
similarity index 86%
rename from media/java/android/media/tv/interactive/TvInteractiveAppInfo.aidl
rename to media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.aidl
index 5e15016..4b6127c 100644
--- a/media/java/android/media/tv/interactive/TvInteractiveAppInfo.aidl
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -16,4 +16,4 @@
 
 package android.media.tv.interactive;
 
-parcelable TvInteractiveAppInfo;
\ No newline at end of file
+parcelable TvInteractiveAppServiceInfo;
\ No newline at end of file
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppInfo.java b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java
similarity index 87%
rename from media/java/android/media/tv/interactive/TvInteractiveAppInfo.java
rename to media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java
index 6103db0..3e08852 100644
--- a/media/java/android/media/tv/interactive/TvInteractiveAppInfo.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -45,9 +45,9 @@
 /**
  * This class is used to specify meta information of a TV interactive app.
  */
-public final class TvInteractiveAppInfo implements Parcelable {
+public final class TvInteractiveAppServiceInfo implements Parcelable {
     private static final boolean DEBUG = false;
-    private static final String TAG = "TvInteractiveAppInfo";
+    private static final String TAG = "TvInteractiveAppServiceInfo";
 
     private static final String XML_START_TAG_NAME = "tv-interactive-app";
 
@@ -71,7 +71,13 @@
     private final String mId;
     private int mTypes;
 
-    public TvInteractiveAppInfo(@NonNull Context context, @NonNull ComponentName component) {
+    /**
+     * Constructs a TvInteractiveAppServiceInfo object.
+     *
+     * @param context the application context
+     * @param component the component name of the TvInteractiveAppService
+     */
+    public TvInteractiveAppServiceInfo(@NonNull Context context, @NonNull ComponentName component) {
         if (context == null) {
             throw new IllegalArgumentException("context cannot be null.");
         }
@@ -94,28 +100,28 @@
         mId = id;
         mTypes = toTypesFlag(types);
     }
-    private TvInteractiveAppInfo(ResolveInfo service, String id, int types) {
+    private TvInteractiveAppServiceInfo(ResolveInfo service, String id, int types) {
         mService = service;
         mId = id;
         mTypes = types;
     }
 
-    private TvInteractiveAppInfo(@NonNull Parcel in) {
+    private TvInteractiveAppServiceInfo(@NonNull Parcel in) {
         mService = ResolveInfo.CREATOR.createFromParcel(in);
         mId = in.readString();
         mTypes = in.readInt();
     }
 
-    public static final @NonNull Creator<TvInteractiveAppInfo> CREATOR =
-            new Creator<TvInteractiveAppInfo>() {
+    public static final @NonNull Creator<TvInteractiveAppServiceInfo> CREATOR =
+            new Creator<TvInteractiveAppServiceInfo>() {
                 @Override
-                public TvInteractiveAppInfo createFromParcel(Parcel in) {
-                    return new TvInteractiveAppInfo(in);
+                public TvInteractiveAppServiceInfo createFromParcel(Parcel in) {
+                    return new TvInteractiveAppServiceInfo(in);
                 }
 
                 @Override
-                public TvInteractiveAppInfo[] newArray(int size) {
-                    return new TvInteractiveAppInfo[size];
+                public TvInteractiveAppServiceInfo[] newArray(int size) {
+                    return new TvInteractiveAppServiceInfo[size];
                 }
             };
 
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppView.java b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
index 773e54f..1df757b 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppView.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -46,6 +46,7 @@
 import android.view.ViewGroup;
 import android.view.ViewRootImpl;
 
+import java.security.KeyStore;
 import java.util.List;
 import java.util.concurrent.Executor;
 
@@ -61,6 +62,41 @@
     private static final int UNSET_TVVIEW_SUCCESS = 3;
     private static final int UNSET_TVVIEW_FAIL = 4;
 
+    /**
+     * Used to share client {@link java.security.cert.Certificate} with
+     * {@link TvInteractiveAppService}.
+     * @see #createBiInteractiveApp(Uri, Bundle)
+     * @see java.security.cert.Certificate
+     */
+    public static final String BI_INTERACTIVE_APP_KEY_CERTIFICATE = "certificate";
+    /**
+     * Used to share the {@link KeyStore} alias with {@link TvInteractiveAppService}.
+     * @see #createBiInteractiveApp(Uri, Bundle)
+     * @see KeyStore#aliases()
+     */
+    public static final String BI_INTERACTIVE_APP_KEY_ALIAS = "alias";
+    /**
+     * Used to share the {@link java.security.PrivateKey} with {@link TvInteractiveAppService}.
+     * <p>The private key is optional. It is used to encrypt data when necessary.
+     *
+     * @see #createBiInteractiveApp(Uri, Bundle)
+     * @see java.security.PrivateKey
+     */
+    public static final String BI_INTERACTIVE_APP_KEY_PRIVATE_KEY = "private_key";
+    /**
+     * Additional HTTP headers to be used by {@link TvInteractiveAppService} to load the
+     * broadcast-independent interactive application.
+     * @see #createBiInteractiveApp(Uri, Bundle)
+     */
+    public static final String BI_INTERACTIVE_APP_KEY_HTTP_ADDITIONAL_HEADERS =
+            "http_additional_headers";
+    /**
+     * HTTP user agent to be used by {@link TvInteractiveAppService} for broadcast-independent
+     * interactive application.
+     * @see #createBiInteractiveApp(Uri, Bundle)
+     */
+    public static final String BI_INTERACTIVE_APP_KEY_HTTP_USER_AGENT = "http_user_agent";
+
     private final TvInteractiveAppManager mTvInteractiveAppManager;
     private final Handler mHandler = new Handler();
     private final Object mCallbackLock = new Object();
@@ -148,12 +184,14 @@
     /**
      * Sets the callback to be invoked when an event is dispatched to this TvInteractiveAppView.
      *
-     * @param callback The callback to receive events. A value of {@code null} removes the existing
-     *                 callback.
+     * @param callback the callback to receive events. MUST NOT be {@code null}.
+     *
+     * @see #clearCallback()
      */
     public void setCallback(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull TvInteractiveAppCallback callback) {
+        com.android.internal.util.AnnotationValidations.validate(NonNull.class, null, callback);
         synchronized (mCallbackLock) {
             mCallbackExecutor = executor;
             mCallback = callback;
@@ -162,6 +200,8 @@
 
     /**
      * Clears the callback.
+     *
+     * @see #setCallback(Executor, TvInteractiveAppCallback)
      */
     public void clearCallback() {
         synchronized (mCallbackLock) {
@@ -238,7 +278,9 @@
     }
 
     /**
-     * Resets this TvInteractiveAppView.
+     * Resets this TvInteractiveAppView to release its resources.
+     *
+     * <p>It can be reused by call {@link #prepareInteractiveApp(String, int)}.
      */
     public void reset() {
         if (DEBUG) Log.d(TAG, "reset()");
@@ -364,6 +406,19 @@
         mOnUnhandledInputEventListener = listener;
         // TODO: handle CallbackExecutor
     }
+
+    /**
+     * Gets the {@link OnUnhandledInputEventListener}.
+     * <p>Returns {@code null} if the listener is not set or is cleared.
+     *
+     * @see #setOnUnhandledInputEventListener(Executor, OnUnhandledInputEventListener)
+     * @see #clearOnUnhandledInputEventListener()
+     */
+    @Nullable
+    public OnUnhandledInputEventListener getOnUnhandledInputEventListener() {
+        return mOnUnhandledInputEventListener;
+    }
+
     /**
      * Clears the {@link OnUnhandledInputEventListener}.
      */
@@ -386,16 +441,17 @@
     }
 
     /**
-     * Prepares the interactive application.
+     * Prepares the interactive application runtime environment of corresponding
+     * {@link TvInteractiveAppService}.
      *
      * @param iAppServiceId the interactive app service ID, which can be found in
-     *                      {@link TvInteractiveAppInfo#getId()}.
+     *                      {@link TvInteractiveAppServiceInfo#getId()}.
      *
      * @see android.media.tv.interactive.TvInteractiveAppManager#getTvInteractiveAppServiceList()
      */
     public void prepareInteractiveApp(
             @NonNull String iAppServiceId,
-            @TvInteractiveAppInfo.InteractiveAppType int type) {
+            @TvInteractiveAppServiceInfo.InteractiveAppType int type) {
         // TODO: document and handle the cases that this method is called multiple times.
         if (DEBUG) {
             Log.d(TAG, "prepareInteractiveApp");
@@ -432,6 +488,8 @@
 
     /**
      * Resets the interactive application.
+     *
+     * <p>This releases the resources of the corresponding {@link TvInteractiveAppService.Session}.
      */
     public void resetInteractiveApp() {
         if (DEBUG) {
@@ -471,6 +529,8 @@
 
     /**
      * Sends stream volume to related TV interactive app.
+     *
+     * @param volume a volume value between {@code 0.0f} and {@code 1.0f}, inclusive.
      */
     public void sendStreamVolume(float volume) {
         if (DEBUG) {
@@ -509,6 +569,27 @@
         }
     }
 
+    /**
+     * Sends signing result to related TV interactive app.
+     *
+     * <p>This is used when the corresponding server of the broadcast-independent interactive
+     * app requires signing during handshaking, and the interactive app service doesn't have
+     * the built-in private key. The private key is provided by the content providers and
+     * pre-built in the related app, such as TV app.
+     *
+     * @param signingId the ID to identify the request. It's the same as the corresponding ID in
+     *        {@link TvInteractiveAppService.Session#requestSigning(String, String, String, byte[])}
+     * @param result the signed result.
+     */
+    public void sendSigningResult(@NonNull String signingId, @NonNull byte[] result) {
+        if (DEBUG) {
+            Log.d(TAG, "sendSigningResult");
+        }
+        if (mSession != null) {
+            mSession.sendSigningResult(signingId, result);
+        }
+    }
+
     private void resetInternal() {
         mSessionCallback = null;
         if (mSession != null) {
@@ -527,7 +608,14 @@
      * <p>{@link TvInteractiveAppCallback#onBiInteractiveAppCreated(String, Uri, String)} will be
      * called for the result.
      *
+     * @param biIAppUri URI associated this BI interactive app.
+     * @param params optional parameters for broadcast-independent interactive application, such as
+     *               {@link #BI_INTERACTIVE_APP_KEY_CERTIFICATE}.
+     *
      * @see TvInteractiveAppCallback#onBiInteractiveAppCreated(String, Uri, String)
+     * @see #BI_INTERACTIVE_APP_KEY_CERTIFICATE
+     * @see #BI_INTERACTIVE_APP_KEY_HTTP_ADDITIONAL_HEADERS
+     * @see #BI_INTERACTIVE_APP_KEY_HTTP_USER_AGENT
      */
     public void createBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) {
         if (DEBUG) {
@@ -721,6 +809,22 @@
         public void onRequestCurrentTvInputId(@NonNull String iAppServiceId) {
         }
 
+        /**
+         * This is called when
+         * {@link TvInteractiveAppService.Session#requestSigning(String, String, String, byte[])} is
+         * called.
+         *
+         * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+         * @param signingId the ID to identify the request.
+         * @param algorithm the standard name of the signature algorithm requested, such as
+         *                  MD5withRSA, SHA256withDSA, etc.
+         * @param alias the alias of the corresponding {@link java.security.KeyStore}.
+         * @param data the original bytes to be signed.
+         */
+        public void onRequestSigning(@NonNull String iAppServiceId, @NonNull String signingId,
+                @NonNull String algorithm, @NonNull String alias, @NonNull byte[] data) {
+        }
+
     }
 
     /**
@@ -1027,5 +1131,20 @@
                 mCallback.onRequestCurrentTvInputId(mIAppServiceId);
             }
         }
+
+        @Override
+        public void onRequestSigning(
+                Session session, String id, String algorithm, String alias, byte[] data) {
+            if (DEBUG) {
+                Log.d(TAG, "onRequestSigning");
+            }
+            if (this != mSessionCallback) {
+                Log.w(TAG, "onRequestSigning - session not created");
+                return;
+            }
+            if (mCallback != null) {
+                mCallback.onRequestSigning(mIAppServiceId, id, algorithm, alias, data);
+            }
+        }
     }
 }
diff --git a/media/java/android/media/tv/tuner/Lnb.java b/media/java/android/media/tv/tuner/Lnb.java
index 50a2083..3b70890 100644
--- a/media/java/android/media/tv/tuner/Lnb.java
+++ b/media/java/android/media/tv/tuner/Lnb.java
@@ -167,10 +167,10 @@
 
     private Lnb() {}
 
-    void setCallbackAndOwner(Executor executor, @Nullable LnbCallback callback, Tuner tuner) {
+    void setCallbackAndOwner(Tuner tuner, Executor executor, @Nullable LnbCallback callback) {
         synchronized (mCallbackLock) {
             if (callback != null && executor != null) {
-                addCallback(callback, executor);
+                addCallback(executor, callback);
             }
         }
         setOwner(tuner);
@@ -179,12 +179,12 @@
     /**
      * Adds LnbCallback
      *
-     * @param callback the callback to receive notifications from LNB.
      * @param executor the executor on which callback will be invoked. Cannot be null.
+     * @param callback the callback to receive notifications from LNB.
      */
-    public void addCallback(@NonNull  LnbCallback callback, @NonNull Executor executor) {
-        Objects.requireNonNull(callback, "callback must not be null");
+    public void addCallback(@NonNull Executor executor, @NonNull LnbCallback callback) {
         Objects.requireNonNull(executor, "executor must not be null");
+        Objects.requireNonNull(callback, "callback must not be null");
         synchronized (mCallbackLock) {
             mCallbackMap.put(callback, executor);
         }
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 1e32cad..ef0270b 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -62,7 +62,9 @@
 import android.os.Message;
 import android.os.Process;
 import android.util.Log;
+
 import com.android.internal.util.FrameworkStatsLog;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
@@ -2147,12 +2149,12 @@
             Objects.requireNonNull(executor, "executor must not be null");
             Objects.requireNonNull(cb, "LnbCallback must not be null");
             if (mLnb != null) {
-                mLnb.setCallbackAndOwner(executor, cb, this);
+                mLnb.setCallbackAndOwner(this, executor, cb);
                 return mLnb;
             }
             if (checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_LNB, mLnbLock)
                     && mLnb != null) {
-                mLnb.setCallbackAndOwner(executor, cb, this);
+                mLnb.setCallbackAndOwner(this, executor, cb);
                 setLnb(mLnb);
                 return mLnb;
             }
@@ -2186,7 +2188,7 @@
                     mLnbHandle = null;
                 }
                 mLnb = newLnb;
-                mLnb.setCallbackAndOwner(executor, cb, this);
+                mLnb.setCallbackAndOwner(this, executor, cb);
                 setLnb(mLnb);
             }
             return mLnb;
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 4f7b711..2f4dd8f 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -1003,19 +1003,9 @@
 }
 
 static jbyteArray android_media_MediaDrm_getSupportedCryptoSchemesNative(JNIEnv *env) {
+    sp<IDrm> drm = android::DrmUtils::MakeDrm();
     std::vector<uint8_t> bv;
-    for (auto &factory : DrmUtils::MakeDrmFactories()) {
-        sp<drm::V1_3::IDrmFactory> factoryV1_3 = drm::V1_3::IDrmFactory::castFrom(factory);
-        if (factoryV1_3 == nullptr) {
-            continue;
-        }
-        factoryV1_3->getSupportedCryptoSchemes(
-            [&](const hardware::hidl_vec<hardware::hidl_array<uint8_t, 16>>& schemes) {
-                for (const auto &scheme : schemes) {
-                    bv.insert(bv.end(), scheme.data(), scheme.data() + scheme.size());
-                }
-            });
-    }
+    drm->getSupportedSchemes(bv);
 
     jbyteArray jUuidBytes = env->NewByteArray(bv.size());
     env->SetByteArrayRegion(jUuidBytes, 0, bv.size(), reinterpret_cast<const jbyte *>(bv.data()));
diff --git a/media/packages/BluetoothMidiService/AndroidManifest.xml b/media/packages/BluetoothMidiService/AndroidManifest.xml
index 858f85f..6928b94 100644
--- a/media/packages/BluetoothMidiService/AndroidManifest.xml
+++ b/media/packages/BluetoothMidiService/AndroidManifest.xml
@@ -20,8 +20,6 @@
         xmlns:tools="http://schemas.android.com/tools"
         package="com.android.bluetoothmidiservice"
         >
-    <uses-sdk android:minSdkVersion="33" android:targetSdkVersion="33" />
-
     <uses-feature android:name="android.hardware.bluetooth_le"
          android:required="true"/>
     <uses-feature android:name="android.software.midi"
diff --git a/media/packages/BluetoothMidiService/AndroidManifestBase.xml b/media/packages/BluetoothMidiService/AndroidManifestBase.xml
index 99dcaaa..468f6ee 100644
--- a/media/packages/BluetoothMidiService/AndroidManifestBase.xml
+++ b/media/packages/BluetoothMidiService/AndroidManifestBase.xml
@@ -19,7 +19,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.bluetoothmidiservice"
           >
-    <uses-sdk android:minSdkVersion="33" android:targetSdkVersion="33" />
     <application
         android:label="BluetoothMidi"
         android:defaultToDeviceProtectedStorage="true"
diff --git a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
index 4c3b689..0e62490 100644
--- a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
+++ b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
@@ -150,6 +150,7 @@
         @Override
         public void onCharacteristicRead(BluetoothGatt gatt,
                 BluetoothGattCharacteristic characteristic,
+                byte[] value,
                 int status) {
             Log.d(TAG, "onCharacteristicRead " + status);
 
@@ -164,8 +165,8 @@
             BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
                     CLIENT_CHARACTERISTIC_CONFIG);
             if (descriptor != null) {
-                descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
-                boolean result = mBluetoothGatt.writeDescriptor(descriptor);
+                int result = mBluetoothGatt.writeDescriptor(descriptor,
+                        BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                 Log.d(TAG, "writeDescriptor returned " + result);
             } else {
                 Log.e(TAG, "No CLIENT_CHARACTERISTIC_CONFIG for device " + mBluetoothDevice);
@@ -184,12 +185,13 @@
 
         @Override
         public void onCharacteristicChanged(BluetoothGatt gatt,
-                                            BluetoothGattCharacteristic characteristic) {
+                                            BluetoothGattCharacteristic characteristic,
+                                            byte[] value) {
             if (DEBUG) {
-                logByteArray("Received ", characteristic.getValue(), 0,
-                        characteristic.getValue().length);
+                logByteArray("Received BLE packet", value, 0,
+                        value.length);
             }
-            mPacketDecoder.decodePacket(characteristic.getValue(), mOutputReceiver);
+            mPacketDecoder.decodePacket(value, mOutputReceiver);
         }
 
         @Override
@@ -227,17 +229,14 @@
                 mCachedBuffer = new byte[count];
             }
             System.arraycopy(buffer, 0, mCachedBuffer, 0, count);
-            if (!mCharacteristic.setValue(mCachedBuffer)) {
-                Log.w(TAG, "could not set characteristic value");
-                return false;
-            }
 
             if (DEBUG) {
                 logByteArray("Sent ", mCharacteristic.getValue(), 0,
                        mCharacteristic.getValue().length);
             }
 
-            if (!mBluetoothGatt.writeCharacteristic(mCharacteristic)) {
+            if (mBluetoothGatt.writeCharacteristic(mCharacteristic, mCachedBuffer,
+                    mCharacteristic.getWriteType()) != BluetoothGatt.GATT_SUCCESS) {
                 Log.w(TAG, "could not write characteristic to Bluetooth GATT");
                 return false;
             }
diff --git a/mms/java/android/telephony/MmsManager.java b/mms/java/android/telephony/MmsManager.java
index d541da0..b893b45 100644
--- a/mms/java/android/telephony/MmsManager.java
+++ b/mms/java/android/telephony/MmsManager.java
@@ -70,7 +70,8 @@
             }
 
             iMms.sendMessage(subId, ActivityThread.currentPackageName(), contentUri,
-                    locationUrl, configOverrides, sentIntent, messageId);
+                    locationUrl, configOverrides, sentIntent, messageId,
+                    mContext.getAttributionTag());
         } catch (RemoteException e) {
             // Ignore it
         }
@@ -102,7 +103,7 @@
             }
             iMms.downloadMessage(subId, ActivityThread.currentPackageName(),
                     locationUrl, contentUri, configOverrides, downloadedIntent,
-                    messageId);
+                    messageId, mContext.getAttributionTag());
         } catch (RemoteException e) {
             // Ignore it
         }
diff --git a/mms/java/com/android/internal/telephony/IMms.aidl b/mms/java/com/android/internal/telephony/IMms.aidl
index e0e0a4a..3cdde10 100644
--- a/mms/java/com/android/internal/telephony/IMms.aidl
+++ b/mms/java/com/android/internal/telephony/IMms.aidl
@@ -26,7 +26,7 @@
  */
 interface IMms {
     /**
-     * Send an MMS message
+     * Send an MMS message with attribution tag.
      *
      * @param subId the SIM id
      * @param callingPkg the package name of the calling app
@@ -38,10 +38,11 @@
      * @param sentIntent if not NULL this <code>PendingIntent</code> is
      *  broadcast when the message is successfully sent, or failed
      * @param messageId An id that uniquely identifies the message requested to be sent.
+     * @param attributionTag a tag that attributes the call to a client App.
      */
     void sendMessage(int subId, String callingPkg, in Uri contentUri,
             String locationUrl, in Bundle configOverrides, in PendingIntent sentIntent,
-            in long messageId);
+            in long messageId, String attributionTag);
 
     /**
      * Download an MMS message using known location and transaction id
@@ -57,10 +58,11 @@
      * @param downloadedIntent if not NULL this <code>PendingIntent</code> is
      *  broadcast when the message is downloaded, or the download is failed
      * @param messageId An id that uniquely identifies the message requested to be downloaded.
+     * @param attributionTag a tag that attributes the call to a client App.
     */
     void downloadMessage(int subId, String callingPkg, String locationUrl,
             in Uri contentUri, in Bundle configOverrides,
-            in PendingIntent downloadedIntent, in long messageId);
+            in PendingIntent downloadedIntent, in long messageId, String attributionTag);
 
     /**
      * Import a text message into system's SMS store
diff --git a/packages/BackupRestoreConfirmation/res/values/strings.xml b/packages/BackupRestoreConfirmation/res/values/strings.xml
index 3fb3fd4..5c90fd0 100644
--- a/packages/BackupRestoreConfirmation/res/values/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values/strings.xml
@@ -44,8 +44,6 @@
     <string name="backup_enc_password_text">Please enter a password to use for encrypting the full backup data. If this is left blank, your current backup password will be used:</string>
     <!-- Text for message to user that they may optionally supply an encryption password to use for a full backup operation. -->
     <string name="backup_enc_password_optional">If you wish to encrypt the full backup data, enter a password below:</string>
-    <!-- Text for message to user that they must supply an encryption password to use for a full backup operation because their phone is locked. -->
-    <string name="backup_enc_password_required">Since your device is encrypted, you are required to encrypt your backup. Please enter a password below:</string>
 
     <!-- Text for message to user when performing a full restore operation, explaining that they must enter the password originally used to encrypt the full backup data. -->
     <string name="restore_enc_password_text">If the restore data is encrypted, please enter the password below:</string>
diff --git a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
index d6b6bf8..3c790f0 100644
--- a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
+++ b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
@@ -27,8 +27,6 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.storage.IStorageManager;
-import android.os.storage.StorageManager;
 import android.text.Editable;
 import android.text.TextWatcher;
 import android.util.Slog;
@@ -66,10 +64,8 @@
 
     Handler mHandler;
     IBackupManager mBackupManager;
-    IStorageManager mStorageManager;
     FullObserver mObserver;
     int mToken;
-    boolean mIsEncrypted;
     boolean mDidAcknowledge;
     String mAction;
 
@@ -144,7 +140,6 @@
         }
 
         mBackupManager = IBackupManager.Stub.asInterface(ServiceManager.getService(Context.BACKUP_SERVICE));
-        mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));
 
         mHandler = new ObserverHandler(getApplicationContext());
         final Object oldObserver = getLastNonConfigurationInstance();
@@ -248,20 +243,13 @@
             mDenyButton.setEnabled(!mDidAcknowledge);
         }
 
-        // We vary the password prompt depending on whether one is predefined, and whether
-        // the device is encrypted.
-        mIsEncrypted = deviceIsEncrypted();
+        // We vary the password prompt depending on whether one is predefined.
         if (!haveBackupPassword()) {
             curPwDesc.setVisibility(View.GONE);
             mCurPassword.setVisibility(View.GONE);
             if (layoutId == R.layout.confirm_backup) {
                 TextView encPwDesc = findViewById(R.id.enc_password_desc);
-                if (mIsEncrypted) {
-                    encPwDesc.setText(R.string.backup_enc_password_required);
-                    monitorEncryptionPassword();
-                } else {
-                    encPwDesc.setText(R.string.backup_enc_password_optional);
-                }
+                encPwDesc.setText(R.string.backup_enc_password_optional);
             }
         }
     }
@@ -312,20 +300,6 @@
         }
     }
 
-    boolean deviceIsEncrypted() {
-        try {
-            return mStorageManager.getEncryptionState()
-                     != StorageManager.ENCRYPTION_STATE_NONE
-                && mStorageManager.getPasswordType()
-                     != StorageManager.CRYPT_TYPE_DEFAULT;
-        } catch (Exception e) {
-            // If we can't talk to the storagemanager service we have a serious problem; fail
-            // "secure" i.e. assuming that the device is encrypted.
-            Slog.e(TAG, "Unable to communicate with storagemanager service: " + e.getMessage());
-            return true;
-        }
-    }
-
     boolean haveBackupPassword() {
         try {
             return mBackupManager.hasBackupPassword();
diff --git a/packages/CompanionDeviceManager/res/color/selector.xml b/packages/CompanionDeviceManager/res/color/selector.xml
index 56e5dca..aebc5d5 100644
--- a/packages/CompanionDeviceManager/res/color/selector.xml
+++ b/packages/CompanionDeviceManager/res/color/selector.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
diff --git a/packages/CompanionDeviceManager/res/drawable/btn_negative_multiple_devices.xml b/packages/CompanionDeviceManager/res/drawable/btn_negative_multiple_devices.xml
index 125fee6..ebe16a7 100644
--- a/packages/CompanionDeviceManager/res/drawable/btn_negative_multiple_devices.xml
+++ b/packages/CompanionDeviceManager/res/drawable/btn_negative_multiple_devices.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -20,6 +21,6 @@
     <corners android:topLeftRadius="16dp" android:topRightRadius="16dp"
              android:bottomLeftRadius="16dp" android:bottomRightRadius="16dp"/>
     <stroke
-        android:width="2dp"
+        android:width="1dp"
         android:color="@android:color/system_accent1_600" />
 </shape>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/drawable/btn_negative_top.xml b/packages/CompanionDeviceManager/res/drawable/btn_negative_top.xml
index 7df92bb..3cd7929 100644
--- a/packages/CompanionDeviceManager/res/drawable/btn_negative_top.xml
+++ b/packages/CompanionDeviceManager/res/drawable/btn_negative_top.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -17,6 +18,6 @@
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
     <solid android:color="@android:color/system_accent1_100"/>
-    <corners android:topLeftRadius="12dp" android:topRightRadius="12dp"
-             android:bottomLeftRadius="4dp" android:bottomRightRadius="4dp"/>
+    <corners android:topLeftRadius="4dp" android:topRightRadius="4dp"
+             android:bottomLeftRadius="12dp" android:bottomRightRadius="12dp"/>
 </shape>
diff --git a/packages/CompanionDeviceManager/res/drawable/btn_positive_bottom.xml b/packages/CompanionDeviceManager/res/drawable/btn_positive_bottom.xml
index 55e96f6..2cff473 100644
--- a/packages/CompanionDeviceManager/res/drawable/btn_positive_bottom.xml
+++ b/packages/CompanionDeviceManager/res/drawable/btn_positive_bottom.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -17,6 +18,6 @@
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
     <solid android:color="@android:color/system_accent1_100"/>
-    <corners android:topLeftRadius="4dp" android:topRightRadius="4dp"
-             android:bottomLeftRadius="12dp" android:bottomRightRadius="12dp"/>
+    <corners android:topLeftRadius="12dp" android:topRightRadius="12dp"
+             android:bottomLeftRadius="4dp" android:bottomRightRadius="4dp"/>
 </shape>
diff --git a/packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml b/packages/CompanionDeviceManager/res/drawable/helper_back_button.xml
similarity index 95%
rename from packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml
rename to packages/CompanionDeviceManager/res/drawable/helper_back_button.xml
index f9ec5d0..8e92051f 100644
--- a/packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml
+++ b/packages/CompanionDeviceManager/res/drawable/helper_back_button.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_apps.xml b/packages/CompanionDeviceManager/res/drawable/ic_apps.xml
index 93a0cba..d1ec863 100644
--- a/packages/CompanionDeviceManager/res/drawable/ic_apps.xml
+++ b/packages/CompanionDeviceManager/res/drawable/ic_apps.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_device_other.xml b/packages/CompanionDeviceManager/res/drawable/ic_device_other.xml
new file mode 100644
index 0000000..2a8eb24
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable/ic_device_other.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp" android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:tint="?attr/colorControlNormal">
+    <path android:fillColor="@android:color/white"
+          android:pathData="M7,20H4Q3.175,20 2.588,19.413Q2,18.825 2,18V6Q2,5.175 2.588,4.588Q3.175,4 4,4H20V6H4Q4,6 4,6Q4,6 4,6V18Q4,18 4,18Q4,18 4,18H7ZM9,20V18.2Q8.55,17.775 8.275,17.225Q8,16.675 8,16Q8,15.325 8.275,14.775Q8.55,14.225 9,13.8V12H13V13.8Q13.45,14.225 13.725,14.775Q14,15.325 14,16Q14,16.675 13.725,17.225Q13.45,17.775 13,18.2V20ZM11,17.5Q11.65,17.5 12.075,17.075Q12.5,16.65 12.5,16Q12.5,15.35 12.075,14.925Q11.65,14.5 11,14.5Q10.35,14.5 9.925,14.925Q9.5,15.35 9.5,16Q9.5,16.65 9.925,17.075Q10.35,17.5 11,17.5ZM21,20H16Q15.575,20 15.288,19.712Q15,19.425 15,19V10Q15,9.575 15.288,9.287Q15.575,9 16,9H21Q21.425,9 21.712,9.287Q22,9.575 22,10V19Q22,19.425 21.712,19.712Q21.425,20 21,20ZM17,18H20V11H17Z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_info.xml b/packages/CompanionDeviceManager/res/drawable/ic_info.xml
new file mode 100644
index 0000000..d9f6a27
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable/ic_info.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:tint="@android:color/system_accent1_600">
+    <path android:fillColor="@android:color/white"
+          android:pathData="M11,17H13V11H11ZM12,9Q12.425,9 12.713,8.712Q13,8.425 13,8Q13,7.575 12.713,7.287Q12.425,7 12,7Q11.575,7 11.288,7.287Q11,7.575 11,8Q11,8.425 11.288,8.712Q11.575,9 12,9ZM12,22Q9.925,22 8.1,21.212Q6.275,20.425 4.925,19.075Q3.575,17.725 2.788,15.9Q2,14.075 2,12Q2,9.925 2.788,8.1Q3.575,6.275 4.925,4.925Q6.275,3.575 8.1,2.787Q9.925,2 12,2Q14.075,2 15.9,2.787Q17.725,3.575 19.075,4.925Q20.425,6.275 21.212,8.1Q22,9.925 22,12Q22,14.075 21.212,15.9Q20.425,17.725 19.075,19.075Q17.725,20.425 15.9,21.212Q14.075,22 12,22ZM12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12ZM12,20Q15.325,20 17.663,17.663Q20,15.325 20,12Q20,8.675 17.663,6.337Q15.325,4 12,4Q8.675,4 6.338,6.337Q4,8.675 4,12Q4,15.325 6.338,17.663Q8.675,20 12,20Z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_notifications.xml b/packages/CompanionDeviceManager/res/drawable/ic_notifications.xml
index 4ac4d04..e5825bc 100644
--- a/packages/CompanionDeviceManager/res/drawable/ic_notifications.xml
+++ b/packages/CompanionDeviceManager/res/drawable/ic_notifications.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_storage.xml b/packages/CompanionDeviceManager/res/drawable/ic_storage.xml
index d8b7f59..406a3b5 100644
--- a/packages/CompanionDeviceManager/res/drawable/ic_storage.xml
+++ b/packages/CompanionDeviceManager/res/drawable/ic_storage.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_watch.xml b/packages/CompanionDeviceManager/res/drawable/ic_watch.xml
new file mode 100644
index 0000000..d7a28d9
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable/ic_watch.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:tint="?attr/colorControlNormal">
+    <path android:fillColor="@android:color/white"
+          android:pathData="M9,22 L7.65,17.45Q6.45,16.5 5.725,15.075Q5,13.65 5,12Q5,10.35 5.725,8.925Q6.45,7.5 7.65,6.55L9,2H15L16.35,6.55Q17.55,7.5 18.275,8.925Q19,10.35 19,12Q19,13.65 18.275,15.075Q17.55,16.5 16.35,17.45L15,22ZM12,17Q14.075,17 15.538,15.537Q17,14.075 17,12Q17,9.925 15.538,8.462Q14.075,7 12,7Q9.925,7 8.463,8.462Q7,9.925 7,12Q7,14.075 8.463,15.537Q9.925,17 12,17ZM10.1,5.25Q11.075,4.975 12,4.975Q12.925,4.975 13.9,5.25L13.5,4H10.5ZM10.5,20H13.5L13.9,18.75Q12.925,19.025 12,19.025Q11.075,19.025 10.1,18.75ZM10.1,4H10.5H13.5H13.9Q12.925,4 12,4Q11.075,4 10.1,4ZM10.5,20H10.1Q11.075,20 12,20Q12.925,20 13.9,20H13.5Z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
index 9e5b166..c37054e 100644
--- a/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
+++ b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- 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
@@ -22,69 +21,111 @@
 
     <!-- Do NOT change the ID of the root LinearLayout above: it's referenced in CTS tests. -->
 
-    <TextView
-        android:id="@+id/title"
+    <ImageView
+        android:id="@+id/profile_icon"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
+        android:layout_height="32dp"
         android:gravity="center"
-        android:paddingHorizontal="12dp"
-        style="@*android:style/TextAppearance.Widget.Toolbar.Title"/>
+        android:layout_marginTop="18dp"
+        android:tint="@android:color/system_accent1_600"/>
 
-    <TextView
-        android:id="@+id/summary"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="12dp"
-        android:layout_marginBottom="12dp"
-        android:gravity="center"
-        android:textColor="?android:attr/textColorSecondary"
-        android:textSize="14sp" />
+    <LinearLayout style="@style/Description">
+        <TextView
+            android:id="@+id/title"
+            style="@style/DescriptionTitle" />
+
+        <TextView
+            android:id="@+id/summary"
+            style="@style/DescriptionSummary" />
+
+    </LinearLayout>
 
     <RelativeLayout
         android:layout_width="match_parent"
         android:layout_height="0dp"
         android:layout_weight="1">
 
-        <androidx.recyclerview.widget.RecyclerView
-            android:id="@+id/device_list"
+        <LinearLayout
+            android:id="@+id/multiple_device_list"
             android:layout_width="match_parent"
-            android:scrollbars="vertical"
-            android:layout_height="200dp" />
+            android:layout_height="wrap_content"
+            android:layout_marginTop="12dp"
+            android:layout_marginBottom="12dp"
+            android:orientation="vertical"
+            android:visibility="gone">
+
+            <View
+                android:id="@+id/border_top"
+                style="@style/DeviceListBorder" />
+
+            <androidx.recyclerview.widget.RecyclerView
+                android:id="@+id/device_list"
+                android:layout_width="match_parent"
+                android:scrollbars="vertical"
+                android:layout_marginBottom="12dp"
+                android:layout_height="200dp" />
+
+            <View
+                android:id="@+id/border_bottom"
+                style="@style/DeviceListBorder" />
+
+        </LinearLayout>
 
         <androidx.recyclerview.widget.RecyclerView
             android:id="@+id/permission_list"
             android:layout_width="match_parent"
             android:layout_height="wrap_content" />
 
+        <ProgressBar
+            android:id="@+id/spinner"
+            android:layout_width="56dp"
+            android:layout_height="56dp"
+            android:layout_centerInParent="true"
+            android:indeterminate="true"
+            android:tint="@android:color/system_accent1_600"
+            android:visibility="gone"
+            style="?android:attr/progressBarStyleLarge" />
+
     </RelativeLayout>
 
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:gravity="center"
         android:orientation="vertical"
-        android:layout_marginTop="24dp">
+        android:layout_marginTop="16dp">
 
         <!-- Do NOT change the IDs of the buttons: they are referenced in CTS tests. -->
 
         <Button
-            android:id="@+id/btn_negative"
-            style="@style/NegativeButton"
-            android:text="@string/consent_no" />
-
-        <Button
             android:id="@+id/btn_positive"
             style="@style/PositiveButton"
             android:text="@string/consent_yes" />
 
         <Button
-            android:id="@+id/btn_negative_multiple_devices"
-            android:layout_marginLeft="170dp"
-            android:layout_marginBottom="10dp"
-            style="@style/NegativeButtonMultipleDevices"
-            android:textColor = "?android:textColorPrimary"
-            android:visibility="gone"
+            android:id="@+id/btn_negative"
+            android:layout_marginBottom="12dp"
+            style="@style/NegativeButton"
             android:text="@string/consent_no" />
 
     </LinearLayout>
 
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="bottom|right"
+        android:orientation="vertical"
+        android:layout_marginRight="16dp"
+        android:layout_marginBottom="16dp">
+
+        <!-- Do NOT change the IDs of the buttons: they are referenced in CTS tests. -->
+
+        <Button
+            android:id="@+id/btn_negative_multiple_devices"
+            style="@style/NegativeButtonMultipleDevices"
+            android:textColor="?android:textColorPrimary"
+            android:visibility="gone"
+            android:text="@string/consent_no" />
+    </LinearLayout>
+
 </LinearLayout>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/layout/data_transfer_confirmation.xml b/packages/CompanionDeviceManager/res/layout/data_transfer_confirmation.xml
index 7c50814..3d08493 100644
--- a/packages/CompanionDeviceManager/res/layout/data_transfer_confirmation.xml
+++ b/packages/CompanionDeviceManager/res/layout/data_transfer_confirmation.xml
@@ -15,54 +15,42 @@
   ~ limitations under the License.
   -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:id="@+id/activity_confirmation"
-              android:layout_width="match_parent"
-              android:layout_height="wrap_content"
-              android:background="@drawable/dialog_background"
-              android:elevation="16dp"
-              android:maxHeight="400dp"
-              android:orientation="vertical"
-              android:padding="18dp"
-              android:layout_gravity="center">
+              android:id="@+id/data_transfer_confirmation"
+              style="@style/ContainerLayout">
 
     <!-- Do NOT change the ID of the root LinearLayout above: it's referenced in CTS tests. -->
 
-    <TextView
-        android:id="@+id/title"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="center"
-        android:paddingHorizontal="12dp"
-        style="@*android:style/TextAppearance.Widget.Toolbar.Title"/>
+    <LinearLayout style="@style/Description">
+        <TextView
+            android:id="@+id/title"
+            style="@style/DescriptionTitle" />
 
-    <TextView
-        android:id="@+id/summary"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="12dp"
-        android:layout_marginBottom="12dp"
-        android:gravity="center"
-        android:textColor="?android:attr/textColorSecondary"
-        android:textSize="14sp" />
+        <TextView
+            android:id="@+id/summary"
+            style="@style/DescriptionSummary" />
+
+    </LinearLayout>
 
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:gravity="center"
         android:orientation="vertical"
-        android:layout_marginTop="24dp">
+        android:layout_marginTop="16dp">
 
         <!-- Do NOT change the IDs of the buttons: they are referenced in CTS tests. -->
 
         <Button
-            android:id="@+id/btn_negative"
-            style="@style/NegativeButton"
-            android:text="@string/consent_no" />
-
-        <Button
             android:id="@+id/btn_positive"
             style="@style/PositiveButton"
             android:text="@string/consent_yes" />
 
+        <Button
+            android:id="@+id/btn_negative"
+            android:layout_marginBottom="12dp"
+            style="@style/NegativeButton"
+            android:text="@string/consent_no" />
+
     </LinearLayout>
 
 </LinearLayout>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/layout/helper_confirmation.xml b/packages/CompanionDeviceManager/res/layout/helper_confirmation.xml
index c177039..a9ace44 100644
--- a/packages/CompanionDeviceManager/res/layout/helper_confirmation.xml
+++ b/packages/CompanionDeviceManager/res/layout/helper_confirmation.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -17,6 +18,7 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               android:id="@+id/helper_confirmation"
               android:theme="@style/ChooserActivity"
+              android:padding="12dp"
               style="@style/ContainerLayout">
 
     <ImageView
@@ -24,8 +26,8 @@
         android:layout_width="match_parent"
         android:layout_height="32dp"
         android:gravity="center"
-        android:layout_marginBottom="12dp"
-        android:layout_marginTop="1dp"/>
+        android:layout_marginTop="12dp"
+        android:layout_marginBottom="12dp"/>
 
     <TextView
         android:id="@+id/helper_title"
@@ -33,17 +35,18 @@
         android:layout_height="wrap_content"
         android:gravity="center"
         android:paddingHorizontal="12dp"
-        style="@*android:style/TextAppearance.Widget.Toolbar.Title"
-        android:textSize="20sp" />
+        android:textColor="?android:attr/textColorPrimary"
+        android:textSize="22sp" />
 
     <TextView
         android:id="@+id/helper_summary"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:layout_marginLeft="24dp"
+        android:layout_marginRight="24dp"
         android:layout_marginTop="12dp"
-        android:layout_marginLeft="20dp"
         android:layout_marginBottom="24dp"
-        android:gravity="start"
+        android:gravity="center"
         android:textColor="?android:attr/textColorSecondary"
         android:textSize="14sp" />
 
@@ -51,12 +54,14 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:orientation="horizontal"
+        android:layout_marginRight="12dp"
+        android:layout_marginBottom="12dp"
         android:gravity="end">
 
         <Button
-            android:id="@+id/btn_ok"
-            style="@style/VendorHelperOkButton"
-            android:text="@string/consent_ok" />
+            android:id="@+id/btn_back"
+            style="@style/VendorHelperBackButton"
+            android:text="@string/consent_back" />
 
     </LinearLayout>
 
diff --git a/packages/CompanionDeviceManager/res/layout/list_item_device.xml b/packages/CompanionDeviceManager/res/layout/list_item_device.xml
index b732b1b..eeb988f 100644
--- a/packages/CompanionDeviceManager/res/layout/list_item_device.xml
+++ b/packages/CompanionDeviceManager/res/layout/list_item_device.xml
@@ -28,7 +28,9 @@
         android:id="@android:id/icon"
         android:layout_width="24dp"
         android:layout_height="24dp"
-        android:layout_marginRight="12dp"/>
+        android:layout_marginLeft="24dp"
+        android:layout_marginRight="12dp"
+        android:tint="@android:color/system_accent1_600"/>
 
     <TextView
         android:id="@android:id/text1"
diff --git a/packages/CompanionDeviceManager/res/layout/list_item_permission.xml b/packages/CompanionDeviceManager/res/layout/list_item_permission.xml
index b8a0f79..3dce38d 100644
--- a/packages/CompanionDeviceManager/res/layout/list_item_permission.xml
+++ b/packages/CompanionDeviceManager/res/layout/list_item_permission.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -19,14 +20,17 @@
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:orientation="horizontal"
-              android:padding="5dp">
+              android:paddingLeft="32dp"
+              android:paddingRight="32dp"
+              android:paddingBottom="14dp">
 
     <ImageView
         android:id="@+id/permission_icon"
         android:layout_width="24dp"
         android:layout_height="24dp"
-        android:layout_marginTop="7dp"
+        android:layout_marginTop="8dp"
         android:layout_marginEnd="12dp"
+        android:tint="@android:color/system_accent1_600"
         android:contentDescription="Permission Icon"/>
 
     <LinearLayout
@@ -47,6 +51,7 @@
             android:id="@+id/permission_summary"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:paddingRight="24dp"
             android:textSize="14sp"
             android:textColor="?android:attr/textColorSecondary"/>
 
diff --git a/packages/CompanionDeviceManager/res/layout/vendor_header.xml b/packages/CompanionDeviceManager/res/layout/vendor_header.xml
index d04eadf..c35f59e 100644
--- a/packages/CompanionDeviceManager/res/layout/vendor_header.xml
+++ b/packages/CompanionDeviceManager/res/layout/vendor_header.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -21,7 +22,10 @@
     android:layout_height="wrap_content"
     android:orientation="horizontal"
     android:layout_gravity="center"
-    android:layout_marginBottom="16dp"
+    android:paddingTop="24dp"
+    android:paddingBottom="4dp"
+    android:paddingLeft="24dp"
+    android:paddingRight="24dp"
     android:visibility="gone" >
 
     <ImageView
@@ -39,10 +43,9 @@
 
     <ImageButton
         android:id="@+id/vendor_header_button"
-        style="?android:attr/actionOverflowButtonStyle"
+        android:background="@drawable/ic_info"
         android:layout_width="31dp"
         android:layout_height="32dp"
-        android:layout_marginLeft="100dp"
         android:layout_alignParentRight="true" />
 
 </RelativeLayout>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/values-af/strings.xml b/packages/CompanionDeviceManager/res/values-af/strings.xml
index 2d8ef73..64637c6 100644
--- a/packages/CompanionDeviceManager/res/values-af/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-af/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Kies \'n <xliff:g id="PROFILE_NAME">%1$s</xliff:g> om deur &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; bestuur te word"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> sal interaksie met jou kennisgewings mag hê en toegang kry tot jou Foon-, SMS-, Kontakte- en Kalender-toestemmings."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> sal interaksie met jou kennisgewings mag hê en toegang kry tot jou Foon-, SMS-, Kontakte- en Kalender-toestemmings."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Laat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toe om programme te stroom?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; afstandtoegang tot programme wat op &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; geïnstalleer is wanneer hierdie foon aan die internet gekoppel is."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; afstandtoegang tot programme wat op &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; geïnstalleer is wanneer hierdie tablet aan die internet gekoppel is."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; afstandtoegang tot programme wat op &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; geïnstalleer is wanneer hierdie toestel aan die internet gekoppel is."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Programme"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Stroom jou foon se programme"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toegang tot hierdie inligting op jou foon"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Oorkruistoestel-dienste"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toegang tot hierdie inligting op jou foon"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Kennisgewings"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Foto\'s en media"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Dienste"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"toestel"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Laat toe"</string>
     <string name="consent_no" msgid="2640796915611404382">"Moenie toelaat nie"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Dra programtoestemmings na jou horlosie toe oor"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Om dit makliker te maak om jou horlosie op te stel, sal programme wat gedurende opstelling op jou horlosie geïnstalleer word, dieselfde toestemmings as jou foon gebruik.\n\n Hierdie toestemmings kan toegang tot jou horlosie se mikrofoon en ligging insluit."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-am/strings.xml b/packages/CompanionDeviceManager/res/values-am/strings.xml
index 5cb306f..d7baf99 100644
--- a/packages/CompanionDeviceManager/res/values-am/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-am/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"በ&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; የሚተዳደር <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ይምረጡ"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ከማሳወቂያዎችዎ ጋር መስተጋብር እንዲፈጥር እና የእርስዎን ስልክ፣ ኤስኤምኤስ፣ እውቂያዎች እና የቀን መቁጠሪያ ፈቃዶች እንዲደርስ ይፈቀድለታል።"</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ከማሳወቂያዎችዎ ጋር መስተጋብር እንዲፈጥር እና የእርስዎን ስልክ፣ ኤስኤምኤስ፣ እውቂያዎች እና የቀን መቁጠሪያ ፈቃዶች እንዲደርስ ይፈቀድለታል።"</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; መተግበሪያዎችን እንዲለቅቅ ይፈቀድለት?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ሲገናኙ በዚህ ስልክ ላይ የተጫኑ መተግበሪያዎችን እንዲደርስ ለ&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; የርቀት መዳረሻ እንዲያቀርብ ይፍቀዱለት።"</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ሲገናኙ በዚህ ጡባዊ ላይ የተጫኑ መተግበሪያዎችን እንዲደርስ ለ&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; የርቀት መዳረሻ እንዲያቀርብ ይፍቀዱለት።"</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ሲገናኙ በዚህ መሳሪያ ላይ የተጫኑ መተግበሪያዎችን እንዲደርስ ለ&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; የርቀት መዳረሻ እንዲያቀርብ ይፍቀዱለት።"</string>
+    <string name="permission_apps" msgid="6142133265286656158">"መተግበሪያዎች"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"የስልክዎን መተግበሪያዎች በዥረት ይልቀቁ"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ይህን መረጃ ከስልክዎ እንዲደርስበት ይፍቀዱለት"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"መሣሪያ ተሻጋሪ አገልግሎቶች"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ይህን መረጃ ከስልክዎ ላይ እንዲደርስ ይፍቀዱለት"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"ማሳወቂያዎች"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"ፎቶዎች እና ሚዲያ"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"የGoogle Play አገልግሎቶች"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"መሣሪያ"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"ፍቀድ"</string>
     <string name="consent_no" msgid="2640796915611404382">"አትፍቀድ"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"የመተግበሪያ ፈቃዶችን ወደ የእጅ ሰዓትዎ ያስተላልፉ"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"የእጅ ሰዓትዎን ማቀናበርን ለማቅለል በማዋቀር ጊዜ በእጅ ሰዓትዎ ላይ የተጫኑ መተግበሪያዎች እንደ ስልክዎ ተመሳሳይ ፈቃዶችን ይጠቀማሉ።\n\n እነዚህ ፈቃዶች የእጅ ሰዓትዎ ማይክሮፎን እና አካባቢ መዳረሻን ሊያካትቱ ይችላሉ።"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml
index b4c74ad..17dde4e 100644
--- a/packages/CompanionDeviceManager/res/values-ar/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"‏اختَر <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ليديره تطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"سيتم السماح لتطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> بالتفاعل مع الإشعارات والوصول إلى أذونات الهاتف والرسائل القصيرة وجهات الاتصال والتقويم."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"سيتم السماح لتطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> بالتفاعل مع الإشعارات والوصول إلى أذونات الهاتف والرسائل القصيرة وجهات الاتصال والتقويم."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"‏هل تريد السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ببث التطبيقات؟"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"‏السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بمنح الإذن بالوصول عن بُعد إلى التطبيقات المثبَّتة &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; الإذن بالوصول عن بُعد إلى التطبيقات المثبَّتة على هذا الهاتف عندما يكون متصلاً بالإنترنت."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"‏السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بمنح &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; الإذن بالوصول عن بُعد إلى التطبيقات المثبَّتة على هذا الجهاز اللوحي عندما يكون متصلاً بالإنترنت."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"‏السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بمنح &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; الإذن بالوصول عن بُعد إلى التطبيقات المثبَّتة على هذا الجهاز عندما يكون متصلاً بالإنترنت."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"التطبيقات"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"بث تطبيقات هاتفك"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"‏السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بالوصول إلى هذه المعلومات من هاتفك"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"الخدمات التي تعمل بين الأجهزة"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"‏السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بالوصول إلى هذه المعلومات من هاتفك"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"الإشعارات"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"الصور والوسائط"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"‏خدمات Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"جهاز"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"السماح"</string>
     <string name="consent_no" msgid="2640796915611404382">"عدم السماح"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"نقل أذونات التطبيقات إلى ساعتك"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"لتسهيل إعداد ساعتك، فإن التطبيقات التي يتم تثبيتها على ساعتك أثناء الإعداد ستستخدم الأذونات نفسها التي يستخدمها هاتفك.\n\n قد تشتمل هذه الأذونات على الوصول إلى ميكروفون ساعتك وبيانات موقعها الجغرافي."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-as/strings.xml b/packages/CompanionDeviceManager/res/values-as/strings.xml
index b2865dc..66d1877 100644
--- a/packages/CompanionDeviceManager/res/values-as/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-as/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;এ পৰিচালনা কৰিব লগা এটা <xliff:g id="PROFILE_NAME">%1$s</xliff:g> বাছনি কৰক"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ক আপোনাৰ জাননী ব্যৱহাৰ কৰিবলৈ আৰু আপোনাৰ ফ’ন, এছএমএছ, সম্পৰ্ক আৰু কেলেণ্ডাৰৰ অনুমতি এক্সেছ কৰিবলৈ দিয়া হ’ব।"</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ক আপোনাৰ জাননী ব্যৱহাৰ কৰিবলৈ আৰু আপোনাৰ ফ’ন, এছএমএছ, সম্পৰ্ক আৰু কেলেণ্ডাৰৰ অনুমতি এক্সেছ কৰিবলৈ দিয়া হ’ব।"</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক এপ্লিকেশ্বন ষ্ট্ৰীম কৰিবলৈ অনুমতি দিবনে?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"সংযোগ কৰিলে &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক এই ফ’নটোত ইনষ্টল কৰি থোৱা এপ্লিকেশ্বনসমূহ এক্সেছ কৰিবলৈ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ক ৰিম’ট এক্সেছ দিবলৈ দিয়ক।"</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"সংযোগ কৰিলে &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক এই টেবলেটটোত ইনষ্টল কৰি থোৱা এপ্লিকেশ্বনসমূহ এক্সেছ কৰিবলৈ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ক ৰিম’ট এক্সেছ দিবলৈ দিয়ক।"</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"সংযোগ কৰিলে &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক এই ডিভাইচটোত ইনষ্টল কৰি থোৱা এপ্লিকেশ্বনসমূহ এক্সেছ কৰিবলৈ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ক ৰিম’ট এক্সেছ দিবলৈ দিয়ক।"</string>
+    <string name="permission_apps" msgid="6142133265286656158">"এপ্‌"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"আপোনাৰ ফ’নৰ এপ্‌ ষ্ট্ৰীম কৰক"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক আপোনাৰ ফ’নৰ পৰা এই তথ্যখিনি এক্সেছ কৰাৰ অনুমতি দিয়ক"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"ক্ৰছ-ডিভাইচ সেৱাসমূহ"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক আপোনাৰ ফ’নৰ পৰা এই তথ্যখিনি এক্সেছ কৰাৰ অনুমতি দিয়ক"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"জাননী"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"ফট’ আৰু মিডিয়া"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play সেৱা"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইচ"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"অনুমতি দিয়ক"</string>
     <string name="consent_no" msgid="2640796915611404382">"অনুমতি নিদিব"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"আপোনাৰ ঘড়ীলৈ এপৰ অনুমতিসমূহ স্থানান্তৰ কৰক"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"আপোনাৰ ঘড়ীটো ছেটআপ কৰাটো অধিক সহজ কৰি তুলিবলৈ, এয়া কৰাৰ সময়ত আপোনাৰ ঘড়ীটোত ইনষ্টল কৰি থোৱা এপ্‌সমূহে আপোনাৰ ফ’নৰ দৰে একেই অনুমতিসমূহ ব্যৱহাৰ কৰিব।\n\n এই অনুমতিসমূহত আপোনাৰ ঘড়ীৰ মাইক্ৰ’ফ’ন আৰু অৱস্থানৰ এক্সেছ অন্তৰ্ভুক্ত হ’ব পাৰে।"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-az/strings.xml b/packages/CompanionDeviceManager/res/values-az/strings.xml
index e8e4e76..6a83c2f 100644
--- a/packages/CompanionDeviceManager/res/values-az/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-az/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; tərəfindən idarə ediləcək <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirişlərinizə, Telefon, SMS, Kontaktlar və Təqvimə giriş əldə edəcək."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirişlərinizə, Telefon, SMS, Kontaktlar və Təqvimə giriş əldə edəcək."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinin tətbiqlərdə yayım etməsinə icazə verilsin?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazının qoşulduqda bu telefonda quraşdırılmış tətbiqlərə uzaqdan giriş icazəsi verməsinə imkan verin."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazının qoşulduqda bu planşetdə quraşdırılmış tətbiqlərə uzaqdan giriş icazəsi verməsinə imkan verin."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazının qoşulduqda bu cihazda quraşdırılmış tətbiqlərə uzaqdan giriş icazəsi verməsinə imkan verin."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Tətbiqlər"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Telefonunuzun tətbiqlərini yayımlayın"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə telefonunuzdan bu məlumata giriş icazəsi verin"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cihazlararası xidmətlər"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə telefonunuzdan bu məlumata giriş icazəsi verin"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Bildirişlər"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Foto və media"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play xidmətləri"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"İcazə verin"</string>
     <string name="consent_no" msgid="2640796915611404382">"İcazə verməyin"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Tətbiq icazələrini saatınıza köçürün"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Saatınızı ayarlamağı asanlaşdırmaq üçün ayarlama zamanı saatınızda quraşdırılmış tətbiqlər telefonunuzla eyni icazələrdən istifadə edəcək.\n\n Bu icazələrə saatınızın mikrofonuna və məkanına giriş daxil ola bilər."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
index 5d98a13..271597a 100644
--- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> će dobiti dozvolu za interakciju sa obaveštenjima i pristup dozvolama za telefon, SMS poruke, kontakte i kalendar."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> će dobiti dozvolu za interakciju sa obaveštenjima i pristup dozvolama za telefon, SMS poruke, kontakte i kalendar."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Želite da dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da strimuje aplikacije?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da daljinski pristupa aplikacijama instaliranim na telefonu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; kada je povezan."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da daljinski pristupa aplikacijama instaliranim na tabletu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; kada je povezan."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da daljinski pristupa aplikacijama instaliranim na uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; kada je povezan."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Aplikacije"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Strimujte aplikacije na telefonu"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pristupa ovim informacijama sa telefona"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluge na više uređaja"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pristupa ovim informacijama sa telefona"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Obaveštenja"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Slike i mediji"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play usluge"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Dozvoli"</string>
     <string name="consent_no" msgid="2640796915611404382">"Ne dozvoli"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Prenesite dozvole za aplikacije na sat"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Da bismo pojednostavili podešavanje sata, aplikacije instalirane na satu tokom podešavanja će koristiti iste dozvole kao telefon.\n\n Te dozvole mogu da obuhvataju pristup mikrofonu i lokaciji sata."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-be/strings.xml b/packages/CompanionDeviceManager/res/values-be/strings.xml
index 3a57bcc..11536cb2 100644
--- a/packages/CompanionDeviceManager/res/values-be/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-be/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Выберыце прыладу (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), якой будзе кіраваць праграма &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> атрымае доступ да вашых апавяшчэнняў, тэлефона, SMS, кантактаў і календара."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> атрымае доступ да вашых апавяшчэнняў, тэлефона, SMS, кантактаў і календара."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Дазволіць праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; перадаваць праграмы плынню?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; атрымліваць аддалены доступ да праграм, усталяваных на тэлефоне &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; (калі тэлефон падключаны)."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; атрымліваць аддалены доступ да праграм, усталяваных на планшэце &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; (калі планшэт падключаны)."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; атрымліваць аддалены доступ да праграм, усталяваных на прыладзе &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; (калі прылада падключана)."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Праграмы"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Трансліруйце змесціва праграм з вашага тэлефона"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; мець доступ да гэтай інфармацыі з вашага тэлефона"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Сэрвісы для некалькіх прылад"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; мець доступ да гэтай інфармацыі з вашага тэлефона"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Апавяшчэнні"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Фота і медыяфайлы"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Сэрвісы Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"прылада"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Дазволіць"</string>
     <string name="consent_no" msgid="2640796915611404382">"Не дазваляць"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Перанос дазволаў праграм на ваш гадзіннік"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Для праграм, усталяваных на гадзіннік падчас наладжвання, будуць дзейнічаць тыя самыя дазволы, што і на тэлефоне.\n\n Так гадзіннік можа атрымаць доступ да мікрафона і даных пра месцазнаходжанне."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-bg/strings.xml b/packages/CompanionDeviceManager/res/values-bg/strings.xml
index d29a908..0ee7370 100644
--- a/packages/CompanionDeviceManager/res/values-bg/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bg/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Изберете устройство (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), което да се управлява от &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ще получи разрешение да взаимодейства с известията ви и да осъществява достъп до разрешенията за телефона, SMS съобщенията, контактите и календара."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ще получи разрешение да взаимодейства с известията ви и да осъществява достъп до разрешенията за телефона, SMS съобщенията, контактите и календара."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Разрешавате ли на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да предава поточно приложения?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Разрешете на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да предоставя на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; отдалечен достъп до приложенията, инсталирани на този телефон, когато има установена връзка."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Разрешете на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да предоставя на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; отдалечен достъп до приложенията, инсталирани на този таблет, когато има установена връзка."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Разрешете на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да предоставя на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; отдалечен достъп до приложенията, инсталирани на това устройство, когато има установена връзка."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Приложения"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Поточно предаване на приложенията на телефона ви"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Разрешете на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да осъществява достъп до тази информация от телефона ви"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Услуги за различни устройства"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Разрешете на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да осъществява достъп до тази информация от телефона ви"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Известия"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Снимки и мултимедия"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Услуги за Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Разрешаване"</string>
     <string name="consent_no" msgid="2640796915611404382">"Забраняване"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Прехвърляне на разрешенията за приложенията към часовника"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"За по-лесно конфигуриране на часовника ви приложенията, инсталирани на него по време на настройването, ще използват същите разрешения като предоставените на телефона ви.\n\nТе може да включват достъп до микрофона и местоположението на часовника ви."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-bn/strings.xml b/packages/CompanionDeviceManager/res/values-bn/strings.xml
index 7d0b097..fb1ede0 100644
--- a/packages/CompanionDeviceManager/res/values-bn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bn/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> বেছে নিন যেটি &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ম্যানেজ করবে"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> আপনার বিজ্ঞপ্তির সাথে ইন্টার‌্যাক্ট করতে পারবে, তার সাথে আপনার ফোন, এমএসএস, পরিচিতি এবং ক্যালেন্ডারের অনুমতিও অ্যাক্সেস করতে পারবে।"</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> আপনার বিজ্ঞপ্তির সাথে ইন্টার‌্যাক্ট করতে পারবে, তার সাথে আপনার ফোন, এমএসএস, পরিচিতি এবং ক্যালেন্ডারের অনুমতিও অ্যাক্সেস করতে পারবে।"</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"অ্যাপ্লিকেশন স্ট্রিম করার জন্য &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; কে অনুমতি দেবেন?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; কে &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;এ দূরবর্তী অ্যাক্সেস প্রদান করতে দিন যাতে কানেক্ট থাকাকালীন এই ফোনে ইনস্টল করা অ্যাপ্লিকেশনগুলিতে অ্যাক্সেস করা যায়।"</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; কে &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;এ দূরবর্তী অ্যাক্সেস প্রদান করতে দিন যাতে কানেক্ট থাকাকালীন এই ট্যাবলেটে ইনস্টল করা অ্যাপ্লিকেশনগুলিতে অ্যাক্সেস করা যায়।"</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; কে &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;এ দূরবর্তী অ্যাক্সেস প্রদান করতে দিন যাতে কানেক্ট থাকাকালীন এই ডিভাইসে ইনস্টল করা অ্যাপ্লিকেশনগুলিতে অ্যাক্সেস করা যায়।"</string>
+    <string name="permission_apps" msgid="6142133265286656158">"অ্যাপ"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"আপনার ফোনের অ্যাপ স্ট্রিমিংয়ের মাধ্যমে কাস্ট করুন"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"আপনার ফোন থেকে &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; অ্যাপকে এই তথ্য অ্যাক্সেস করার অনুমতি দিন"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"ক্রস-ডিভাইস পরিষেবা"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"আপনার ফোন থেকে &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-কে এই তথ্য অ্যাক্সেস করার অনুমতি দিন"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"বিজ্ঞপ্তি"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"সব বিজ্ঞপ্তি পড়তে পারবে, যার মধ্যে পরিচিতি, মেসেজ ও ফটোর মতো তথ্য অন্তর্ভুক্ত"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"ফটো ও মিডিয়া"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play পরিষেবা"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইস"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"অনুমতি দিন"</string>
     <string name="consent_no" msgid="2640796915611404382">"অনুমতি দেবেন না"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"অ্যাপকে দেওয়া অনুমতি আপনার ঘড়িতে ট্রান্সফার করুন"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"ঘড়ি আরও সহজে সেট আপ করতে, সেট আপ চলাকালীন আপনার ঘড়িতে ইনস্টল করা অ্যাপ ফোনের মতো একই অনুমতি ব্যবহার করবে।\n\n এইসব অনুমতির মধ্যে আপনার ঘড়ির মাইক্রোফোন ও লোকেশন সম্পর্কে তথ্যের অ্যাক্সেস অন্তর্ভুক্ত থাকতে পারে।"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml
index a723da8..a28cb73 100644
--- a/packages/CompanionDeviceManager/res/values-bs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Odaberite uređaj <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> će se dozvoliti da ostvari interakciju s vašim obavještenjima i da pristupi odobrenjima za Telefon, SMS, Kontakte i Kalendar."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> će se dozvoliti da ostvari interakciju s vašim obavještenjima i da pristupi odobrenjima za Telefon, SMS, Kontakte i Kalendar."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Dozvoliti da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prenosi aplikacije?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; omogući daljinski pristup uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; radi pristupanja aplikacijama instaliranim na ovom telefonu kada je povezan s mrežom."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; omogući daljinski pristup uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; radi pristupanja aplikacijama instaliranim na ovom tabletu kada je povezan s mrežom."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; omogući daljinski pristup uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; radi pristupanja aplikacijama instaliranim na njemu kada je povezan s mrežom."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Aplikacije"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Prenosite aplikacije s telefona"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Dozvolite da aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pristupa ovim informacijama s telefona"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluga na više uređaja"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
-    <string name="title_computer" msgid="4693714143506569253">"Dozvolite da aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pristupa ovim informacijama s vašeg telefona"</string>
+    <string name="title_computer" msgid="4693714143506569253">"Dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da pristupa ovim informacijama s vašeg telefona"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Obavještenja"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Fotografije i mediji"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play usluge"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Dozvoli"</string>
     <string name="consent_no" msgid="2640796915611404382">"Nemoj dozvoliti"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Prijenos odobrenja za aplikaciju na sat"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Radi lakšeg postavljanja sata, aplikacije instalirane na satu tokom postavljanja će koristiti ista odobrenja kao i na telefonu.\n\n Ta odobrenja mogu uključivati pristup mikrofonu i lokaciji sata."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ca/strings.xml b/packages/CompanionDeviceManager/res/values-ca/strings.xml
index de7e225..ad46287 100644
--- a/packages/CompanionDeviceManager/res/values-ca/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ca/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Tria un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> perquè el gestioni &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> tindrà permís per interaccionar amb les teves notificacions i accedir al telèfon, als SMS, als contactes i al calendari."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> tindrà permís per interaccionar amb les teves notificacions i accedir al telèfon, als SMS, als contactes i al calendari."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Vols permetre que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; reprodueixi aplicacions en continu?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; proporcioni accés remot a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; per accedir a les aplicacions instal·lades en aquest telèfon quan estigui connectat."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; proporcioni accés remot a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; per accedir a les aplicacions instal·lades en aquesta tauleta quan estigui connectada."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; proporcioni accés remot a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; per accedir a les aplicacions instal·lades en aquest dispositiu quan estigui connectat."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Aplicacions"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Reprodueix en continu aplicacions del telèfon"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; accedeixi a aquesta informació del telèfon"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serveis multidispositiu"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; accedeixi a aquesta informació del telèfon"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Notificacions"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Fotos i contingut multimèdia"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Serveis de Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositiu"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Permet"</string>
     <string name="consent_no" msgid="2640796915611404382">"No permetis"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfereix els permisos de les aplicacions al teu rellotge"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Per facilitar la configuració del rellotge, les aplicacions instal·lades al rellotge durant la configuració utilitzaran els mateixos permisos que al teu telèfon.\n\n Aquests permisos poden incloure l\'accés al micròfon i a la ubicació del rellotge."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-cs/strings.xml b/packages/CompanionDeviceManager/res/values-cs/strings.xml
index f195e54..15f719a 100644
--- a/packages/CompanionDeviceManager/res/values-cs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-cs/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Vyberte zařízení <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, které chcete spravovat pomocí aplikace &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> bude moci interagovat s vašimi oznámeními a získá přístup k telefonu, SMS, kontaktům a kalendáři."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> bude moci interagovat s vašimi oznámeními a získá přístup k telefonu, SMS, kontaktům a kalendáři."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; streamovat aplikace?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; poskytovat &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; vzdálený přístup k aplikacím nainstalovaným v tomto telefonu, když je připojen."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; poskytovat &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; vzdálený přístup k aplikacím nainstalovaným v tomto tabletu, když je připojen."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; poskytovat &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; vzdálený přístup k aplikacím nainstalovaným v tomto zařízení, když je připojeno."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Aplikace"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Streamujte aplikace v telefonu"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Povolte aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; přístup k těmto informacím z vašeho telefonu"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Služby pro více zařízení"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Povolte aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; přístup k těmto informacím z vašeho telefonu"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Oznámení"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Fotky a média"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Služby Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"zařízení"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Povolit"</string>
     <string name="consent_no" msgid="2640796915611404382">"Nepovolovat"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Přesunout oprávnění aplikací do hodinek"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Abychom vám usnadnili nastavení hodinek, aplikace nainstalované do hodinek během úvodního nastavení budou používat stejná oprávnění jako váš telefon.\n\n Tato oprávnění mohou zahrnovat přístup k mikrofonu a poloze hodinek."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml
index a2aa5dd..9868d59 100644
--- a/packages/CompanionDeviceManager/res/values-da/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-da/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Vælg den enhed (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), som skal administreres af &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tilladelse til at interagere med dine notifikationer og adgang til dine tilladelser for Opkald, Sms, Kontakter og Kalender."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tilladelse til at interagere med dine notifikationer og adgang til dine tilladelser for Opkald, Sms, Kontakter og Kalender."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Vil du give &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilladelse til at streame apps?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Giver &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilladelse til at fjernstyre apps, som er installeret på &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, når telefonen har forbindelse til internettet."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Giver &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilladelse til at fjernstyre apps, som er installeret på &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, når tabletten har forbindelse til internettet."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Giver &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilladelse til at fjernstyre apps, som er installeret på &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, når enheden har forbindelse til internettet."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Stream din telefons apps"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Giv &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; adgang til disse oplysninger fra din telefon"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjenester, som kan tilsluttes en anden enhed"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Tillad, at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; får adgang til disse oplysninger fra din telefon"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Notifikationer"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Billeder og medier"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-tjenester"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"enhed"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Tillad"</string>
     <string name="consent_no" msgid="2640796915611404382">"Tillad ikke"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Overfør apptilladelser til dit ur"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"For at gøre det nemmere at konfigurere dit ur vil de apps, der installeres under konfigurationen, anvende de samme tilladelser som din telefon.\n\n Disse tilladelser kan omfatte adgang til dit urs mikrofon og lokation."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml
index 2b5ab11..d7cb1ef 100644
--- a/packages/CompanionDeviceManager/res/values-de/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-de/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Gerät (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) auswählen, das von &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; verwaltet werden soll"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> darf mit deinen Benachrichtigungen interagieren und auf die Berechtigungen „Telefon“, „SMS“, „Kontakte“ und „Kalender“ zugreifen."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> darf mit deinen Benachrichtigungen interagieren und auf die Berechtigungen „Telefon“, „SMS“, „Kontakte“ und „Kalender“ zugreifen."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Möchtest du &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; erlauben, Apps zu streamen?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Besteht eine Verbindung, darf &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; Remotezugriff auf die auf diesem Smartphone installierten Apps geben."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Besteht eine Verbindung, darf &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; Remotezugriff auf die auf diesem Tablet installierten Apps geben."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Besteht eine Verbindung, darf &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; Remotezugriff auf die auf diesem Gerät installierten Apps geben."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Smartphone-Apps streamen"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; Zugriff auf diese Informationen von deinem Smartphone gewähren"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Geräteübergreifende Dienste"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; Zugriff auf diese Informationen von deinem Smartphone gewähren"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Benachrichtigungen"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Fotos und Medien"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-Dienste"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"Gerät"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Zulassen"</string>
     <string name="consent_no" msgid="2640796915611404382">"Nicht zulassen"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"App-Berechtigungen auf Smartwatch übertragen"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Damit sich deine Smartwatch leichter einrichten lässt, erhalten die Apps, die während der Einrichtung auf deiner Smartwatch installiert werden, automatisch die gleichen Berechtigungen wie deine Smartphone-Apps.\n\n Zu diesen Berechtigungen kann der Zugriff auf das Mikrofon und den Standort deiner Smartwatch gehören."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-el/strings.xml b/packages/CompanionDeviceManager/res/values-el/strings.xml
index 339f85a..56a9633 100644
--- a/packages/CompanionDeviceManager/res/values-el/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-el/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"Επιλέξτε ένα προφίλ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> για διαχείριση από την εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> θα επιτρέπεται να αλληλεπιδρά με τις ειδοποιήσεις σας και να έχει πρόσβαση στις άδειες Τηλεφώνου, SMS, Επαφών και Ημερολογίου."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> θα επιτρέπεται να αλληλεπιδρά με τις ειδοποιήσεις σας και να έχει πρόσβαση στις άδειες Τηλεφώνου, SMS, Επαφών και Ημερολογίου."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Να επιτρέπεται στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; η ροή εφαρμογών;"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Επιτρέψτε στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να παρέχει απομακρυσμένη πρόσβαση στη συσκευή &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; κατά τη σύνδεση, προκειμένου να έχει πρόσβαση σε εφαρμογές που έχουν εγκατασταθεί σε αυτό το τηλέφωνο."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Επιτρέψτε στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να παρέχει απομακρυσμένη πρόσβαση στη συσκευή &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; κατά τη σύνδεση, προκειμένου να έχει πρόσβαση σε εφαρμογές που έχουν εγκατασταθεί σε αυτό το tablet."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Επιτρέψτε στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να παρέχει απομακρυσμένη πρόσβαση στη συσκευή &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; κατά τη σύνδεση, προκειμένου να έχει πρόσβαση σε εφαρμογές που έχουν εγκατασταθεί σε αυτήν τη συσκευή."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Εφαρμογές"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Μεταδώστε σε ροή τις εφαρμογές του τηλεφώνου σας"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Να επιτρέπεται στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; η πρόσβαση σε αυτές τις πληροφορίες από το τηλέφωνό σας."</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Υπηρεσίες πολλών συσκευών"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Επιτρέψτε στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να έχει πρόσβαση σε αυτές τις πληροφορίες από το τηλέφωνό σας"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Ειδοποιήσεις"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Μπορεί να διαβάσει όλες τις ειδοποιήσεις, συμπεριλαμβανομένων πληροφοριών όπως επαφές, μηνύματα και φωτογραφίες"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Φωτογραφίες και μέσα"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Υπηρεσίες Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"συσκευή"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Να επιτρέπεται"</string>
     <string name="consent_no" msgid="2640796915611404382">"Να μην επιτρέπεται"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Μεταφορά αδειών εφαρμογών στο ρολόι σας"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Για να είναι πιο εύκολη η ρύθμιση του ρολογιού σας, οι εφαρμογές που εγκαθίστανται στο ρολόι σας κατά τη ρύθμιση, θα χρησιμοποιούν τις ίδιες άδειες με το τηλέφωνό σας.\n\n Στις άδειες ενδέχεται να περιλαμβάνεται άδεια πρόσβασης στο μικρόφωνο και την τοποθεσία του ρολογιού σας."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
index d596411..cf08be0 100644
--- a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to stream applications?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this phone when connected."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this tablet when connected."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this device when connected."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Can read all notifications, including information like contacts, messages and photos"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
     <string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfer app permissions to your watch"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"To make it easier to set up your watch, apps installed on your watch during setup will use the same permissions as your phone.\n\n These permissions may include access to your watch’s microphone and location."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
index d596411..cf08be0 100644
--- a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to stream applications?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this phone when connected."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this tablet when connected."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this device when connected."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Can read all notifications, including information like contacts, messages and photos"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
     <string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfer app permissions to your watch"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"To make it easier to set up your watch, apps installed on your watch during setup will use the same permissions as your phone.\n\n These permissions may include access to your watch’s microphone and location."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
index d596411..cf08be0 100644
--- a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to stream applications?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this phone when connected."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this tablet when connected."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this device when connected."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Can read all notifications, including information like contacts, messages and photos"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
     <string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfer app permissions to your watch"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"To make it easier to set up your watch, apps installed on your watch during setup will use the same permissions as your phone.\n\n These permissions may include access to your watch’s microphone and location."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
index d596411..cf08be0 100644
--- a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to stream applications?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this phone when connected."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this tablet when connected."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this device when connected."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Can read all notifications, including information like contacts, messages and photos"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
     <string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfer app permissions to your watch"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"To make it easier to set up your watch, apps installed on your watch during setup will use the same permissions as your phone.\n\n These permissions may include access to your watch’s microphone and location."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
index 9f17a89..03c2991 100644
--- a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‎‏‎‎‎‏‎‎‏‏‎‎‎‎‏‎‏‏‏‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎Choose a ‎‏‎‎‏‏‎<xliff:g id="PROFILE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to be managed by &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt;‎‏‎‎‏‎"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‏‏‎‎‏‎‎‎‎‎‏‏‎‏‎‏‏‎‎‎‎‏‏‏‎‎‎‏‎‏‏‎‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‎‏‎‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions.‎‏‎‎‏‎"</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‏‏‎‎‏‎‎‎‎‎‏‏‎‏‎‏‏‎‎‎‎‏‏‏‎‎‎‏‎‏‏‎‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‎‏‎‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions.‎‏‎‎‏‎"</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎‎‏‎‎‏‎‎‎‏‏‏‎‎‏‏‎‎‎‏‏‎‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‏‏‎‎‏‏‏‏‎‎Allow &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to stream applications?‎‏‎‎‏‎"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‏‏‏‏‎‎‏‎‎‏‎‎‏‎‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‎‏‏‎‎‎‎‏‏‎‏‏‎‎‎‏‏‎‏‎‏‏‎‏‎‎Let &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to provide &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; remote access to access to applications installed on this phone when connected.‎‏‎‎‏‎"</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‎‏‎‏‎‏‎‏‎‎‎‎‏‎‎‎‎‎‎‏‎‎‏‏‏‎‏‎‏‎‎‏‏‏‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‏‏‎‎‎‎Let &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to provide &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; remote access to access to applications installed on this tablet when connected.‎‏‎‎‏‎"</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‎‏‎‏‎‏‏‏‏‏‎‎‎‏‏‎‏‎‎‎‏‏‎‏‎‏‎‏‏‏‎‏‎‎‎‏‎‎‏‎‏‎‎‏‎‎‏‎‏‏‎‏‏‎Let &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to provide &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; remote access to access to applications installed on this device when connected.‎‏‎‎‏‎"</string>
+    <string name="permission_apps" msgid="6142133265286656158">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‏‏‎‏‎‎‏‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎‏‎‎‎‎‏‎‎‎‎‏‎‏‎‏‏‏‎‎‎‎‏‎‎‏‏‏‏‎‎Apps‎‏‎‎‏‎"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‎‎‏‎‏‎‏‏‎‎‏‏‏‏‎‏‎‎‎‏‎‎‎‎‎‏‏‎‎‎‏‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‏‎‎‏‎‎‏‏‏‎Stream your phone’s apps‎‏‎‎‏‎"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‏‎‏‎‏‏‎‎‎‎‎‏‎‎‏‏‏‎‎‎‏‎‏‎‏‏‎‏‎‎‎‎‏‏‏‎‎‏‎‎‏‏‎‎‏‏‎‎Allow &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to access this information from your phone‎‏‎‎‏‎"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‏‏‎‏‏‏‎‎‎‎‎‏‎‏‎‏‎‏‎‏‎‏‎‎‎‎‏‎‏‎‏‎‎‏‎‏‎‎‏‏‎‏‎‏‏‏‏‎‎‏‎‏‎Cross-device services‎‏‎‎‏‎"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‏‎‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‎‎‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‎‎‎‏‎‎‏‎‏‎Allow &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to access this information from your phone‎‏‎‎‏‎"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‏‎‎‎‎‎‏‎‏‏‏‏‎‏‎‏‏‎‎‎‎‏‎‏‎‎‎‏‏‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎Notifications‎‏‎‎‏‎"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‏‎‎‎‏‎‎‏‏‎‏‏‏‎‏‏‏‎‏‎‎‎‎‏‎‎‎‎‏‎‏‎‏‎‎‎‎‎‏‏‎‏‏‎‎‎‏‏‏‏‎‎‎‏‏‎Can read all notifications, including information like contacts, messages, and photos‎‏‎‎‏‎"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‏‎‎‎‎‏‎‏‎‏‎‏‎‏‎‏‏‏‎‎‎‎‎‏‎‏‏‏‎‏‏‏‏‏‎‎‎‎‏‎‏‎‏‏‏‎Photos and media‎‏‎‎‏‎"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‎‏‎‎‏‎‏‏‏‏‏‎‏‎‎‏‏‏‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‏‏‎‎‏‎‏‏‏‎‏‎‏‎‎‏‎‏‎Google Play services‎‏‎‎‏‎"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‎‎‏‏‏‎‏‏‏‏‏‎‎‏‎‎‏‎‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‎‎‎‎‎‎‎‏‏‏‎‏‏‎‏‏‎‎‎device‎‏‎‎‏‎"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‏‎‏‏‎‎‏‎‎‏‎‏‏‏‏‎‎‏‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‎‏‎‏‏‎‎‎‎‎‎‏‏‏‏‎‎‎‎Allow‎‏‎‎‏‎"</string>
     <string name="consent_no" msgid="2640796915611404382">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‏‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‏‎‎‏‏‏‏‎‏‏‏‏‎‏‏‏‎‎‎‎‏‎‎‎‎‏‎‏‏‏‏‎‎Don’t allow‎‏‎‎‏‎"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‎‏‎‎‎‎‎‏‏‏‏‎‏‏‎‎‏‎‎‎‏‎‎‏‎‏‎‏‎‏‎‎‎‎‎‏‏‏‏‎‎‏‎‏‎‏‏‎‏‏‎‎‎‎‏‎‎Transfer app permissions to your watch‎‏‎‎‏‎"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‏‎‎‏‏‏‏‎‎‏‏‎‎‎‎‏‎‏‎‎‏‎‎‎‏‏‏‎‏‎‏‏‎‏‎‏‏‏‏‎‏‎‎‎‏‎‏‎‎To make it easier to set up your watch, apps installed on your watch during setup will use the same permissions as your phone.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎ These permissions may include access to your watch’s microphone and location.‎‏‎‎‏‎"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
index 5423d3e..b4dbab3 100644
--- a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para que &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; lo administre"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a los permisos de Teléfono, SMS, Contactos y Calendario."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a los permisos de Teléfono, SMS, Contactos y Calendario."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"¿Deseas permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; transmita aplicaciones?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; proporcione a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acceso remoto a las aplicaciones instaladas en este teléfono cuando esté conectado."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; proporcione &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acceso remoto a las aplicaciones instaladas en esta tablet cuando esté conectada."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; proporcione a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acceso remoto a las aplicaciones instaladas en este dispositivo cuando esté conectado."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Transmitir las apps de tu teléfono"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información de tu teléfono"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicios multidispositivo"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información de tu teléfono"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Notificaciones"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Fotos y contenido multimedia"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Servicios de Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
     <string name="consent_no" msgid="2640796915611404382">"No permitir"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfiere los permisos de la app a tu reloj"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Para que sea más fácil configurar tu reloj, las apps que se instalen en este durante la configuración usarán los mismos permisos que tu teléfono.\n\n Es posible que estos permisos incluyan el acceso al micrófono y a la ubicación del reloj."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-es/strings.xml b/packages/CompanionDeviceManager/res/values-es/strings.xml
index ccbdd25..79e554c 100644
--- a/packages/CompanionDeviceManager/res/values-es/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para gestionarlo con &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a tus permisos de teléfono, SMS, contactos y calendario."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a tus permisos de teléfono, SMS, contactos y calendario."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"¿Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; inicie aplicaciones?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda de forma remota a las aplicaciones instaladas en este teléfono cuando &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; esté conectado a Internet."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda de forma remota a las aplicaciones instaladas en este tablet cuando &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; esté conectado a Internet."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda de forma remota a las aplicaciones instaladas en este dispositivo cuando &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; esté conectado a Internet."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Aplicaciones"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Emite las aplicaciones de tu teléfono"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información desde tu teléfono"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicios multidispositivo"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información desde tu teléfono"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Notificaciones"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Puede leer todas las notificaciones, incluida información como contactos, mensajes y fotos"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotos y elementos multimedia"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Servicios de Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
     <string name="consent_no" msgid="2640796915611404382">"No permitir"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferir permisos de aplicaciones a tu reloj"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Para configurar fácilmente tu reloj, las aplicaciones que instales en él durante la configuración usarán los mismos permisos que tengan en tu teléfono.\n\n Estos permisos pueden incluir acceso al micrófono y a la ubicación del reloj."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-et/strings.xml b/packages/CompanionDeviceManager/res/values-et/strings.xml
index d8f1e99..f3e55c2 100644
--- a/packages/CompanionDeviceManager/res/values-et/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-et/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Valige seade <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, mida haldab rakendus &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> saab kasutada teie märguandeid ning pääseda juurde teie telefoni, SMS-ide, kontaktide ja kalendri lubadele."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> saab kasutada teie märguandeid ning pääseda juurde teie telefoni, SMS-ide, kontaktide ja kalendri lubadele."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Kas lubada rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; rakendusi voogesituse kaudu üle kanda?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lubatakse seadmele &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; pakkuda kaugjuurdepääsu, et ühendatuna pääseda juurde sellesse telefoni installitud rakendustele."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lubatakse seadmele &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; pakkuda kaugjuurdepääsu, et ühendatuna pääseda juurde sellesse tahvelarvutisse installitud rakendustele."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lubatakse seadmele &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; pakkuda kaugjuurdepääsu, et ühendatuna pääseda juurde sellesse seadmesse installitud rakendustele."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Rakendused"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Telefoni rakenduste voogesitamine"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Lubage rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pääseda teie telefonis juurde sellele teabele"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Seadmeülesed teenused"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Lubage rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pääseda teie telefonis juurde sellele teabele"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Märguanded"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Fotod ja meedia"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play teenused"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"seade"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Luba"</string>
     <string name="consent_no" msgid="2640796915611404382">"Ära luba"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Rakenduste lubade kellale ülekandmine"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Selleks et muuta kella seadistamine lihtsamaks, kasutavad teie kellas seadistamise ajal installitud rakendused samasid lubasid, mis neile telefonis antud on.\n\n Need load võivad hõlmata juurdepääsuluba kella mikrofonile ja asukohale."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-eu/strings.xml b/packages/CompanionDeviceManager/res/values-eu/strings.xml
index de76824..2d9a4c7 100644
--- a/packages/CompanionDeviceManager/res/values-eu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-eu/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Aukeratu &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; aplikazioak kudeatu beharreko <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"Jakinarazpenekin interakzioan aritzeko eta telefonoa, SMSak, kontaktuak eta egutegia erabiltzeko baimenak izango ditu <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Jakinarazpenekin interakzioan aritzeko eta telefonoa, SMSak, kontaktuak eta egutegia erabiltzeko baimenak izango ditu <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Aplikazioak igortzeko baimena eman nahi diozu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Utzi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; urrunetik atzitzen, telefonoa konektatuta dagoenean bertan instalatuta dauden aplikazioetarako sarbidea izateko."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Utzi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; urrunetik atzitzen, tableta konektatuta dagoenean bertan instalatuta dauden aplikazioetarako sarbidea izateko."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Utzi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; urrunetik atzitzen, gailua konektatuta dagoenean bertan instalatuta dauden aplikazioetarako sarbidea izateko."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Aplikazioak"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Igorri zuzenean telefonoko aplikazioak"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Eman informazioa telefonotik hartzeko baimena &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Gailu bat baino gehiagotarako zerbitzuak"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Eman informazio hori telefonotik hartzeko baimena &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Jakinarazpenak"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Argazkiak eta multimedia-edukia"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"gailua"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Eman baimena"</string>
     <string name="consent_no" msgid="2640796915611404382">"Ez eman baimenik"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferitu aplikazio-baimenak erlojura"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Erlojua errazago konfiguratzeko, konfigurazio-prozesua abian zen bitartean erlojuan instalatutako aplikazioek telefonoak darabiltzan baimen berak erabiliko dituzte.\n\n Baliteke baimen horien artean erlojuaren mikrofonoa eta kokapena atzitzeko baimenak egotea."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml
index 65ed2dd..b212b5f 100644
--- a/packages/CompanionDeviceManager/res/values-fa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"‏انتخاب <xliff:g id="PROFILE_NAME">%1$s</xliff:g> برای مدیریت کردن با &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>‏&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> می‌تواند با اعلان‌های شما تعامل داشته باشد و به اجازه‌های «تلفن»، «پیامک»، «مخاطبین»، و «تقویم» دسترسی پیدا کند."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> می‌تواند با اعلان‌های شما تعامل داشته باشد و به اجازه‌های «تلفن»، «پیامک»، «مخاطبین»، و «تقویم» دسترسی پیدا کند."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه می‌دهید برنامه‌ها را جاری‌سازی کند؟"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه می‌دهد برای &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; دسترسی ازراه‌دور ارائه دهد تا دستگاه موردنظر بتواند هنگام اتصال، به برنامه‌های نصب‌شده در این تلفن دسترسی داشته باشد."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه می‌دهد برای &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; دسترسی ازراه‌دور ارائه دهد تا دستگاه موردنظر بتواند هنگام اتصال، به برنامه‌های نصب‌شده در این رایانه لوحی دسترسی داشته باشد."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه می‌دهد برای &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; دسترسی ازراه‌دور ارائه دهد تا دستگاه موردنظر بتواند هنگام اتصال، به برنامه‌های نصب‌شده در این دستگاه دسترسی داشته باشد."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"برنامه‌ها"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"جاری‌سازی برنامه‌های تلفن"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"‏اجازه دادن به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; برای دسترسی به اطلاعات تلفن"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"سرویس‌های بین‌دستگاهی"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"‏&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; مجاز می‌شود به این اطلاعات در دستگاهتان دسترسی پیدا کند"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"اعلان‌ها"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"می‌تواند همه اعلان‌ها، ازجمله اطلاعاتی مثل مخاطبین، پیام‌ها، و عکس‌ها را بخواند"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"عکس‌ها و رسانه‌ها"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"‏خدمات Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"دستگاه"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"مجاز است"</string>
     <string name="consent_no" msgid="2640796915611404382">"مجاز نبودن"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"انتقال اجازه‌های برنامه به ساعت"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"برای آسان‌تر کردن راه‌اندازی ساعت، برنامه‌های نصب‌شده در ساعت درحین راه‌اندازی از همان اجازه‌های تلفن استفاده خواهند کرد.\n\n ممکن است این اجازه‌ها شامل دسترسی به میکروفون و مکان ساعت باشد."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-fi/strings.xml b/packages/CompanionDeviceManager/res/values-fi/strings.xml
index c8dbeb5..194bd86 100644
--- a/packages/CompanionDeviceManager/res/values-fi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fi/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Valitse <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, jota &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; hallinnoi"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> saa luvan hallinnoida ilmoituksiasi sekä pääsyn puhelimeesi, tekstiviesteihisi, kontakteihisi ja kalenteriisi."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> saa luvan hallinnoida ilmoituksiasi sekä pääsyn puhelimeesi, tekstiviesteihisi, kontakteihisi ja kalenteriisi."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Saako &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; striimata sovelluksia?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Salli, että &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; voi saada sovellukselta (&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>) etäpääsyoikeuden tälle puhelimelle asennettuihin sovelluksiin, kun laitteet on yhdistetty."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Salli, että &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; voi saada sovellukselta (&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>) etäpääsyoikeuden tälle tabletille asennettuihin sovelluksiin, kun laitteet on yhdistetty."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Salli, että &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; voi saada sovellukselta (&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>) etäpääsyoikeuden tälle laitteelle asennettuihin sovelluksiin, kun laitteet on yhdistetty."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Sovellukset"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Striimaa puhelimen sovelluksia"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Salli, että &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; saa pääsyn näihin puhelimesi tietoihin"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Laitteidenväliset palvelut"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Salli pääsy tähän tietoon puhelimellasi: &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Ilmoitukset"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Kuvat ja media"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Palvelut"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"laite"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Salli"</string>
     <string name="consent_no" msgid="2640796915611404382">"Älä salli"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Siirrä sovellusluvat kelloon"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Sovellukset, jotka on asennettu kelloon käyttöönoton aikana, käyttävät samoja lupia kuin puhelin. Näin kello on helpompi ottaa käyttöön.\n\n Näihin lupiin saattaa kuulua pääsy kellon mikrofoniin ja sijaintiin."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
index 3d5898b..066c88c 100644
--- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Choisissez un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qui sera géré par &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder aux autorisations pour votre téléphone, vos messages texte, vos contacts et votre agenda."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder aux autorisations pour votre téléphone, vos messages texte, vos contacts et votre agenda."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Permettre à l\'application &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; de diffuser des applications?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permettez à l\'application &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; de donner à l\'appareil &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; un accès à distance aux applications installées sur ce téléphone lorsqu\'il est connecté."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permettez à l\'application &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; de donner à l\'appareil &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; un accès à distance aux applications installées sur cette tablette lorsqu\'elle est connectée."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permettez à l\'application &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; de donner à l\'appareil &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; un accès à distance aux applications installées sur cet appareil lorsqu\'il est connecté."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Applications"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Diffusez les applications de votre téléphone"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Autorisez &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à ces informations à partir de votre téléphone"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Services multiappareils"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Autorisez &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à ces informations à partir de votre téléphone"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Photos et fichiers multimédias"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Services Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Autoriser"</string>
     <string name="consent_no" msgid="2640796915611404382">"Ne pas autoriser"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transférer les autorisations de l\'application à votre montre"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Pour faciliter la configuration de votre montre, les applications installées sur celle-ci reprennent les mêmes autorisations que celles installées sur votre téléphone.\n\n Ces autorisations peuvent comprendre l\'accès au microphone et à la position de votre montre."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-fr/strings.xml b/packages/CompanionDeviceManager/res/values-fr/strings.xml
index ecd89aa..1ffac09 100644
--- a/packages/CompanionDeviceManager/res/values-fr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Sélectionner le/la <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qui sera géré(e) par &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder au téléphone, aux SMS, aux contacts et à l\'agenda."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder au téléphone, aux SMS, aux contacts et à l\'agenda."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à diffuser des applis en streaming ?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à distance aux applis installées sur &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; quand ce téléphone est connecté à Internet."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à distance aux applis installées sur &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; quand cette tablette est connectée à Internet."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à distance aux applis installées sur &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; quand cet appareil est connecté à Internet."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Applis"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Caster les applis de votre téléphone"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à ces informations depuis votre téléphone"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Services inter-appareils"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à ces informations depuis votre téléphone"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Photos et contenus multimédias"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Services Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Autoriser"</string>
     <string name="consent_no" msgid="2640796915611404382">"Ne pas autoriser"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transférer les autorisations de l\'appli vers la montre"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Pour que votre montre soit plus facile à configurer, les applis qui y sont installées pendant la configuration utiliseront les mêmes autorisations que votre téléphone.\n\n Il peut s\'agir, par exemple, de l\'accès au micro et à la position de votre montre."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-gl/strings.xml b/packages/CompanionDeviceManager/res/values-gl/strings.xml
index d060f29..4784ad0 100644
--- a/packages/CompanionDeviceManager/res/values-gl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gl/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Escolle un perfil (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) para que o xestione a aplicación &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> poderá interactuar coas túas notificacións e acceder aos permisos do teu teléfono, das mensaxes, dos contactos e do calendario."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> poderá interactuar coas túas notificacións e acceder aos permisos do teu teléfono, das mensaxes, dos contactos e do calendario."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Queres permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; emita aplicacións noutros dispositivos?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lle outorgue a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acceso remoto a aplicacións instaladas neste teléfono cando teña conexión a Internet."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lle outorgue a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acceso remoto a aplicacións instaladas nesta tableta cando teña conexión a Internet."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lle outorgue a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acceso remoto a aplicacións instaladas neste dispositivo cando teña conexión a Internet."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Aplicacións"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Emite as aplicacións do teu teléfono"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que a aplicación &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información desde o teu teléfono"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servizos multidispositivo"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información desde o teu teléfono"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Notificacións"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Fotos e contido multimedia"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Servizos de Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
     <string name="consent_no" msgid="2640796915611404382">"Non permitir"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferir os permisos de aplicacións ao reloxo"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Para que che resulte máis doado configurar o reloxo, as aplicacións que instales nel durante a configuración usarán os mesmos permisos que o teléfono.\n\n Entre estes permisos poden estar incluídos os de acceso ao micrófono e á localización do teléfono."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml
index d06d8c6..8debe29a 100644
--- a/packages/CompanionDeviceManager/res/values-gu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; દ્વારા મેનેજ કરવા માટે કોઈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> પસંદ કરો"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ને તમારા નોટિફિકેશન સાથે ક્રિયાપ્રતિક્રિયા કરવાની તેમજ તમારો ફોન, SMS, સંપર્કો તેમજ કૅલેન્ડરની પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી આપવામાં આવશે."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ને તમારા નોટિફિકેશન સાથે ક્રિયાપ્રતિક્રિયા કરવાની તેમજ તમારો ફોન, SMS, સંપર્કો તેમજ કૅલેન્ડરની પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી આપવામાં આવશે."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"શું &lt;/strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને ઍપ્લિકેશનો સ્ટ્રીમ કરવાની મંજૂરી આપીએ?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"જ્યારે કનેક્ટ કરવામાં આવે, ત્યારે આ ફોન પર ઇન્સ્ટૉલ કરવામાં આવેલી ઍપ્લિકેશનોનો રિમોટ ઍક્સેસ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ને પ્રદાન કરવા દો."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"જ્યારે કનેક્ટ કરવામાં આવે, ત્યારે આ ટૅબ્લેટ પર ઇન્સ્ટૉલ કરવામાં આવેલી ઍપ્લિકેશનોનો રિમોટ ઍક્સેસ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ને પ્રદાન કરવા દો."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"જ્યારે કનેક્ટ કરવામાં આવે, ત્યારે આ ડિવાઇસ પર ઇન્સ્ટૉલ કરવામાં આવેલી ઍપ્લિકેશનોનો રિમોટ ઍક્સેસ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ને પ્રદાન કરવા દો."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"ઍપ"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"તમારા ફોનની ઍપ સ્ટ્રીમ કરો"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"તમારા ફોનમાંથી આ માહિતી ઍક્સેસ કરવા માટે, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને મંજૂરી આપો"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"ક્રોસ-ડિવાઇસ સેવાઓ"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"તમારા ફોનમાંથી આ માહિતી ઍક્સેસ કરવા માટે, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને મંજૂરી આપો"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"નોટિફિકેશન"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"ફોટા અને મીડિયા"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play સેવાઓ"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"ડિવાઇસ"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"મંજૂરી આપો"</string>
     <string name="consent_no" msgid="2640796915611404382">"મંજૂરી આપશો નહીં"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"તમારી ઘડિયાળમાં ઍપ પરવાનગીઓ ટ્રાન્સફર કરો"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"તમારી ઘડિયાળનું સેટઅપ કરવાનું સરળ બનાવવા માટે, સેટઅપ દરમિયાન તમારી ઘડિયાળ પર ઇન્સ્ટૉલ કરેલી ઍપ દ્વારા તમારા ફોન પર મળેલી પરવાનગીઓનો ઉપયોગ કરવામાં આવશે.\n\n આ પરવાનગીઓમાં તમારી ઘડિયાળના માઇક્રોફોન અને સ્થાન સંબંધિત માહિતીનો ઍક્સેસ શામેલ હોઈ શકે છે."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml
index 1be6af8..f48c8e2 100644
--- a/packages/CompanionDeviceManager/res/values-hi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"कोई <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चुनें, ताकि उसे &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; की मदद से प्रबंधित किया जा सके"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपकी सूचनाओं पर कार्रवाई कर पाएगा. साथ ही, यह आपके फ़ोन, एसएमएस, संपर्कों, और कैलेंडर की अनुमतियों को भी ऐक्सेस कर पाएगा."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपकी सूचनाओं पर कार्रवाई कर पाएगा. साथ ही, यह आपके फ़ोन, एसएमएस, संपर्कों, और कैलेंडर की अनुमतियों को भी ऐक्सेस कर पाएगा."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को ऐप्लिकेशन स्ट्रीम करने की अनुमति देनी है?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"कनेक्ट होने पर, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; के रिमोट ऐक्सेस की अनुमति दें, ताकि इस फ़ोन पर इंस्टॉल किए गए ऐप्लिकेशन ऐक्सेस किए जा सकें."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"कनेक्ट होने पर, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; के रिमोट ऐक्सेस की अनुमति दें, ताकि इस टैबलेट पर इंस्टॉल किए गए ऐप्लिकेशन ऐक्सेस किए जा सकें."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"कनेक्ट होने पर, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; के रिमोट ऐक्सेस की अनुमति दें, ताकि इस डिवाइस पर इंस्टॉल किए गए ऐप्लिकेशन ऐक्सेस किए जा सकें."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"ऐप्लिकेशन"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"अपने फ़ोन के ऐप्लिकेशन को स्ट्रीम करें"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को अपने फ़ोन से यह जानकारी ऐक्सेस करने की अनुमति दें"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"क्रॉस-डिवाइस से जुड़ी सेवाएं"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को अपने फ़ोन से यह जानकारी ऐक्सेस करने की अनुमति दें"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"सूचनाएं"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"फ़ोटो और मीडिया"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play सेवाएं"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"डिवाइस"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"अनुमति दें"</string>
     <string name="consent_no" msgid="2640796915611404382">"अनुमति न दें"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"ऐप्लिकेशन से जुड़ी अनुमतियों को अपनी वॉच में ट्रांसफ़र करें"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"वॉच को सेट अप करने की प्रोसेस को आसान बनाने के लिए, उस पर इंस्टॉल किए गए ऐप्लिकेशन को भी वही अनुमतियां मिलेंगी जो आपने उन ऐप्लिकेशन को फ़ोन पर दी होंगी.\n\n इन अनुमतियों में, आपकी वॉच के माइक्रोफ़ोन और जगह की जानकारी का ऐक्सेस शामिल हो सकता है."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-hr/strings.xml b/packages/CompanionDeviceManager/res/values-hr/strings.xml
index 610b7bd..ae9421a 100644
--- a/packages/CompanionDeviceManager/res/values-hr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> moći će stupati u interakciju s vašim obavijestima i pristupati dopuštenjima za telefon, SMS-ove, kontakte i kalendar."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> moći će stupati u interakciju s vašim obavijestima i pristupati dopuštenjima za telefon, SMS-ove, kontakte i kalendar."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Dopustiti aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pokretanje streama aplikacija?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Dopustite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da telefonu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; omogući udaljeni pristup aplikacijama koje su instalirane na tom telefonu kada su povezani."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Dopustite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da tabletu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; omogući udaljeni pristup aplikacijama koje su instalirane na tom tabletu kada su povezani."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Dopustite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; omogući udaljeni pristup aplikacijama koje su instalirane na tom uređaju kada su povezani."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Aplikacije"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Streaming aplikacija vašeg telefona"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Omogućite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da pristupa informacijama s vašeg telefona"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluge na različitim uređajima"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Omogućite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da pristupa informacijama s vašeg telefona"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Obavijesti"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Fotografije i mediji"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Usluge za Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Dopusti"</string>
     <string name="consent_no" msgid="2640796915611404382">"Nemoj dopustiti"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Prijenos dopuštenja aplikacije na sat"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Kako bi postavljanje sata bilo jednostavnije, aplikacije instalirane na satu će tijekom postavljanja upotrebljavati ista dopuštenja kao telefon.\n\n Ta dopuštenja mogu uključivati pristup mikrofonu i lokaciji sata."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml
index 625a3e9..6428a18 100644
--- a/packages/CompanionDeviceManager/res/values-hu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"A(z) &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; alkalmazással kezelni kívánt <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiválasztása"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> műveleteket végezhet majd az értesítésekkel, és hozzáférhet a telefonra, az SMS-ekre, a névjegyekre és a naptárra vonatkozó engedélyekhez."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> műveleteket végezhet majd az értesítésekkel, és hozzáférhet a telefonra, az SMS-ekre, a névjegyekre és a naptárra vonatkozó engedélyekhez."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Engedélyezi a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; alkalmazásnak appok streamelését?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Engedélyezheti a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; alkalmazásnak, hogy a(z) &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; eszköz számára távoli hozzáférést biztosítson a telefonra telepített alkalmazásokhoz, amikor a telefon csatlakoztatva van."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Engedélyezheti a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; alkalmazásnak, hogy a(z) &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; eszköz számára távoli hozzáférést biztosítson a táblagépre telepített alkalmazásokhoz, amikor a táblagép csatlakoztatva van."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Engedélyezheti a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; alkalmazásnak, hogy a(z) &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; eszköz számára távoli hozzáférést biztosítson az eszközre telepített alkalmazásokhoz, amikor az eszköz csatlakoztatva van."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Alkalmazások"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"A telefon alkalmazásainak streamelése"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Engedélyezi a(z) „<xliff:g id="APP_NAME">%1$s</xliff:g>” alkalmazás számára az információhoz való hozzáférést a telefonról"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Többeszközös szolgáltatások"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Engedélyezi a(z) „<xliff:g id="APP_NAME">%1$s</xliff:g>” alkalmazás számára az információhoz való hozzáférést a telefonról"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Értesítések"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Fotók és médiatartalmak"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-szolgáltatások"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"eszköz"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Engedélyezés"</string>
     <string name="consent_no" msgid="2640796915611404382">"Tiltás"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Alkalmazásengedélyek átvitele az órára"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Az óra beállításának megkönnyítése érdekében a beállítás során az órára telepített alkalmazások ugyanazokat az engedélyeket használják majd, mint a telefonja.\n\n Ezek az engedélyek magukban foglalhatják az óra mikrofonjához és helyadataihoz való hozzáférést."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml
index f09441f..8a6ae3f 100644
--- a/packages/CompanionDeviceManager/res/values-hy/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"Ընտրեք <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ը, որը պետք է կառավարվի &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; հավելվածի կողմից"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը կկարողանա փոխազդել ձեր ծանուցումների հետ և կստանա «Հեռախոս», «SMS», «Կոնտակտներ» և «Օրացույց» ծառայությունների թույլտվությունները։"</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը կկարողանա փոխազդել ձեր ծանուցումների հետ և կստանա «Հեռախոս», «SMS», «Կոնտակտներ» և «Օրացույց» ծառայությունների թույլտվությունները։"</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Թույլատրե՞լ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածին բացել հավելվածներ"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Թույլ տվեք, որ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածը կապի հաստատման դեպքում &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ին տրամադրի այս հեռախոսում տեղադրված հավելվածներ հեռակա մուտք գործելու թույլտվություն։"</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Թույլ տվեք, որ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածը կապի հաստատման դեպքում &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ին տրամադրի այս պլանշետում տեղադրված հավելվածներ հեռակա մուտք գործելու թույլտվություն։"</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Թույլ տվեք, որ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածը ինտերնետ կապի հաստատման դեպքում &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ին տրամադրի այս սարքում տեղադրված հավելվածներ հեռակա մուտք գործելու թույլտվություն։"</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Հավելվածներ"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Հեռարձակել հեռախոսի հավելվածները"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Թույլատրեք &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածին օգտագործել այս տեղեկությունները ձեր հեռախոսից"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Միջսարքային ծառայություններ"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Թույլատրեք &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածին օգտագործել այս տեղեկությունները ձեր հեռախոսից"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Ծանուցումներ"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Կարող է կարդալ բոլոր ծանուցումները, ներառյալ տեղեկությունները, օրինակ՝ կոնտակտները, հաղորդագրությունները և լուսանկարները"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Լուսանկարներ և մուլտիմեդիա"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ծառայություններ"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"սարք"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Թույլատրել"</string>
     <string name="consent_no" msgid="2640796915611404382">"Չթույլատրել"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Հավելվածների թույլտվությունների տեղափոխում ժամացույց"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Կարգավորման ժամանակ ժամացույցում տեղադրված հավելվածների համար կօգտագործվեն նույն թույլտվությունները, ինչ հեռախոսում։\n\n Այդ թույլտվությունները կարող են ներառել ժամացույցի խոսափողի կամ տեղադրության տվյալների օգտագործումը։"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-in/strings.xml b/packages/CompanionDeviceManager/res/values-in/strings.xml
index ef52808..1bec1da 100644
--- a/packages/CompanionDeviceManager/res/values-in/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-in/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk dikelola oleh &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan diizinkan berinteraksi dengan notifikasi dan mengakses izin Telepon, SMS, Kontak, dan Kalender."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan diizinkan berinteraksi dengan notifikasi dan mengakses izin Telepon, SMS, Kontak, dan Kalender."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; men-streaming aplikasi?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; memberikan akses jarak jauh ke &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; guna mengakses aplikasi yang diinstal di ponsel ini saat terhubung."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; memberikan akses jarak jauh ke &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; guna mengakses aplikasi yang diinstal di tablet ini saat terhubung."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; memberikan akses jarak jauh ke &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; guna mengakses aplikasi yang diinstal di perangkat ini saat terhubung."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Aplikasi"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Melakukan streaming aplikasi ponsel Anda"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; untuk mengakses informasi ini dari ponsel Anda"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Layanan lintas perangkat"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; mengakses informasi ini dari ponsel Anda"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Notifikasi"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Foto dan media"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Layanan Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"perangkat"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Izinkan"</string>
     <string name="consent_no" msgid="2640796915611404382">"Jangan izinkan"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfer izin aplikasi ke smartwatch"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Untuk mempermudah penyiapan smartwatch, aplikasi yang diinstal di smartwatch selama penyiapan akan menggunakan izin yang sama dengan ponsel.\n\n Izin ini dapat meliputi akses ke mikrofon dan lokasi smartwatch."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-is/strings.xml b/packages/CompanionDeviceManager/res/values-is/strings.xml
index c0ca2fcf3..2857f0b 100644
--- a/packages/CompanionDeviceManager/res/values-is/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-is/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Velja <xliff:g id="PROFILE_NAME">%1$s</xliff:g> sem &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; á að stjórna"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> fær aðgang að tilkynningum og heimildum síma, SMS, tengiliða og dagatals."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> fær aðgang að tilkynningum og heimildum síma, SMS, tengiliða og dagatals."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Leyfa &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; að streyma forritum?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Leyfa &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; að veita &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; fjaraðgang að forritum sem eru sett upp í þessum síma þegar tenging er á."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Leyfa &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; að veita &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; fjaraðgang að forritum sem eru sett upp í þessari spjaldtölvu þegar tenging er á."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Leyfa &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; að veita &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; fjaraðgang að forritum sem eru sett upp í þessu tæki þegar tenging er á."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Forrit"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Streymdu forritum símans"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Veita &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aðgang að þessum upplýsingum úr símanum þínum"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Þjónustur á milli tækja"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Veita &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aðgang að þessum upplýsingum úr símanum þínum"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Tilkynningar"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Myndir og efni"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Þjónusta Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"tæki"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Leyfa"</string>
     <string name="consent_no" msgid="2640796915611404382">"Ekki leyfa"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Flytja heimildir forrita yfir í úrið"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Til að auðvelda uppsetningu úrsins munu forrit sem eru sett upp í úrinu við uppsetningu nota sömu heimildir og stilltar eru í símanum.\n\n Þessar heimildir kunna að fela í sér aðgang að hljóðnema og staðsetningu úrsins."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-it/strings.xml b/packages/CompanionDeviceManager/res/values-it/strings.xml
index 5f88b7a..d165d97 100644
--- a/packages/CompanionDeviceManager/res/values-it/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-it/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Scegli un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> che sia gestito da &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> potrà interagire con le tue notifiche e accedere alle autorizzazioni Telefono, SMS, Contatti e Calendario."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> potrà interagire con le tue notifiche e accedere alle autorizzazioni Telefono, SMS, Contatti e Calendario."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Vuoi consentire all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di riprodurre applicazioni in streaming?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Consenti all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di fornire l\'accesso remoto a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; per accedere alle applicazioni installate su questo telefono quando è connesso."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Consenti all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di fornire l\'accesso remoto a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; per accedere alle applicazioni installate su questo tablet quando è connesso."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Consenti all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di fornire l\'accesso remoto a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; per accedere alle applicazioni installate su questo dispositivo quando è connesso."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"App"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Trasmetti in streaming le app del tuo telefono"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Consenti all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di accedere a queste informazioni dal tuo telefono"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servizi cross-device"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Consenti a &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di accedere a questa informazione dal tuo telefono"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Notifiche"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Foto e contenuti multimediali"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Consenti"</string>
     <string name="consent_no" msgid="2640796915611404382">"Non consentire"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Trasferisci le autorizzazioni app all\'orologio"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Per facilitare la configurazione dell\'orologio, le app installate su quest\'ultimo durante la configurazione useranno le stesse autorizzazioni delle app sul telefono.\n\n Queste autorizzazioni potrebbero includere l\'accesso al microfono e alla posizione dell\'orologio."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml
index 4a811f0a..08445e6 100644
--- a/packages/CompanionDeviceManager/res/values-iw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"‏בחירת <xliff:g id="PROFILE_NAME">%1$s</xliff:g> לניהול באמצעות &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"‏האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> תוכל לבצע פעולות בהתראות ותקבל הרשאות גישה לטלפון, ל-SMS לאנשי הקשר וליומן."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"‏האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> תוכל לבצע פעולות בהתראות ותקבל הרשאות גישה לטלפון, ל-SMS לאנשי הקשר וליומן."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"‏לאפשר לאפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; לשדר אפליקציות?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"‏האפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; יכולה לספק ל-&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; גישה מרחוק כדי לגשת לאפליקציות שמותקנות בטלפון הזה כשיש חיבור."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"‏האפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; יכולה לספק ל-&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; גישה מרחוק כדי לגשת לאפליקציות שמותקנות בטאבלט הזה כשיש חיבור."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"‏האפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; יכולה לספק למכשיר &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; גישה מרחוק כדי לגשת לאפליקציות שמותקנות במכשיר הזה כשיש חיבור."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"אפליקציות"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"שידור אפליקציות מהטלפון"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"‏מתן אישור לאפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; לגשת למידע הזה מהטלפון שלך"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"שירותים למספר מכשירים"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"‏מתן אישור לאפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; לגשת למידע הזה מהטלפון שלך"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"התראות"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"תמונות ומדיה"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"מכשיר"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"יש אישור"</string>
     <string name="consent_no" msgid="2640796915611404382">"אין אישור"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"העברת ההרשאות הניתנות לאפליקציות אל השעון שלך"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"כדי לפשט את הגדרת השעון, אפליקציות שמותקנות במהלך ההגדרה יקבלו את אותן הרשאות שניתנו בטלפון.\n\n ההרשאות האלה עשויות לכלול גישה למיקרופון ולמיקום של השעון."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ja/strings.xml b/packages/CompanionDeviceManager/res/values-ja/strings.xml
index 5e8d544..14566c74 100644
--- a/packages/CompanionDeviceManager/res/values-ja/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ja/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; の管理対象となる<xliff:g id="PROFILE_NAME">%1$s</xliff:g>の選択"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> は通知を使用でき、電話、SMS、連絡先、カレンダーの権限にもアクセスできるようになります。"</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> は通知を使用でき、電話、SMS、連絡先、カレンダーの権限にもアクセスできるようになります。"</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; にアプリのストリーミングを許可しますか?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"インターネット接続時に &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; がスマートフォン内にインストールされているアプリにリモートでアクセスすることを &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に許可します。"</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"インターネット接続時に &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; がタブレット内にインストールされているアプリにリモートでアクセスすることを &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に許可します。"</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"インターネット接続時に &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; がデバイス内にインストールされているアプリにリモートでアクセスすることを &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に許可します。"</string>
+    <string name="permission_apps" msgid="6142133265286656158">"アプリ"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"スマートフォンのアプリのストリーミング"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"スマートフォンのこの情報へのアクセスを &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に許可"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"クロスデバイス サービス"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"このスマートフォンからの情報へのアクセスを &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に許可"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"通知"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"写真とメディア"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 開発者サービス"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"デバイス"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"許可"</string>
     <string name="consent_no" msgid="2640796915611404382">"許可しない"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"スマートウォッチへのアプリの権限の移行"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"スマートウォッチのセットアップを簡単にするため、セットアップ時にスマートウォッチにインストールされたアプリに、スマートフォンと同じ権限が適用されます。\n\n これらの権限には、スマートウォッチのマイクや位置情報へのアクセス権も含まれることがあります。"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ka/strings.xml b/packages/CompanionDeviceManager/res/values-ka/strings.xml
index 3b179bf..f0c3dc98 100644
--- a/packages/CompanionDeviceManager/res/values-ka/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ka/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"აირჩიეთ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, რომელიც უნდა მართოს &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;-მა"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> შეძლებს თქვენს შეტყობინებებთან ინტერაქციას და თქვენი ტელეფონის, SMS-ების, კონტაქტებისა და კალენდრის ნებართვებზე წვდომას."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> შეძლებს თქვენს შეტყობინებებთან ინტერაქციას და თქვენი ტელეფონის, SMS-ების, კონტაქტებისა და კალენდრის ნებართვებზე წვდომას."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"გსურთ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-ს მისცეთ აპების სტრიმინგის საშუალება?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"მიეცით &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-ს საშუალება, &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ისთვის დაუშვას დისტანციური წვდომა ამ ტელეფონზე დაინსტალირებულ აპებზე მასთან დაკავშირებისას."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"მიეცით &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-ს საშუალება, &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ისთვის დაუშვას დისტანციური წვდომა ამ ტაბლეტზე დაინსტალირებულ აპებზე მასთან დაკავშირებისას."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"მიეცით &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-ს საშუალება, &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ისთვის დაუშვას დისტანციური წვდომა ამ მოწყობილობაზე დაინსტალირებულ აპებზე მასთან დაკავშირებისას."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"აპები"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"თქვენი ტელეფონის აპების სტრიმინგი"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"ნება დართეთ, რომ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; აპს ჰქონდეს ამ ინფორმაციაზე წვდომა თქვენი ტელეფონიდან"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"მოწყობილობათშორისი სერვისები"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"ნება დართეთ, რომ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; აპს ჰქონდეს ამ ინფორმაციაზე წვდომა თქვენი ტელეფონიდან"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"შეტყობინებები"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"შეუძლია წაიკითხოს ყველა შეტყობინება, მათ შორის ისეთი ინფორმაცია, როგორიცაა კონტაქტები, ტექსტური შეტყობინებები და ფოტოები"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"ფოტოები და მედია"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"მოწყობილობა"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"დაშვება"</string>
     <string name="consent_no" msgid="2640796915611404382">"არ დაიშვას"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"აპის ნებართვების საათისთვის გადაცემა"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"საათის დაყენების გასამარტივებლად თქვენს საათში დაინსტალირებული აპები იმავე ნებართვებს გამოიყენებს, რასაც ტელეფონზე იყენებს.\n\n ეს ნებართვები, შესაძლოა, მოიცავდეს თქვენი საათის მიკროფონსა და მდებარეობაზე წვდომას."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-kk/strings.xml b/packages/CompanionDeviceManager/res/values-kk/strings.xml
index a7efb15..607930d 100644
--- a/packages/CompanionDeviceManager/res/values-kk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kk/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; арқылы басқарылатын <xliff:g id="PROFILE_NAME">%1$s</xliff:g> құрылғысын таңдаңыз"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы хабарландыруларды, телефонды, SMS хабардарын, контактілерді және күнтізбе рұқсаттарын пайдалана алады."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы хабарландыруларды, телефонды, SMS хабардарын, контактілерді және күнтізбе рұқсаттарын пайдалана алады."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына қолданбаларды трансляциялауға рұқсат етілсін бе?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; желіге қосылған кезде, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына осы телефонға орнатылған қолданбаларды қашықтан пайдалануына рұқсат етіңіз."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; желіге қосылған кезде, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына осы планшетке орнатылған қолданбаларды қашықтан пайдалануына рұқсат етіңіз."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; желіге қосылған кезде, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына осы құрылғыға орнатылған қолданбаларды қашықтан пайдалануына рұқсат етіңіз."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Қолданбалар"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Телефон қолданбаларын трансляциялайды."</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына телефоныңыздағы осы ақпаратты пайдалануға рұқсат беріңіз."</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Аралық құрылғы қызметтері"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына телефоныңыздағы осы ақпаратты пайдалануға рұқсат беріңіз."</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Хабарландырулар"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Фотосуреттер мен медиафайлдар"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play қызметтері"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"құрылғы"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Рұқсат беру"</string>
     <string name="consent_no" msgid="2640796915611404382">"Рұқсат бермеу"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Қолданба рұқсаттарын сағатқа ауыстыру"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Реттеу кезінде сағатқа орнатылған қолданбалар телефондағыдай рұқсаттарды пайдаланады. Осылайша сағат оңай реттеледі.\n\n Бұл рұқсаттар сағаттың микрофоны мен геодерегін пайдалануды қамтиды."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-km/strings.xml b/packages/CompanionDeviceManager/res/values-km/strings.xml
index b185863..814b327 100644
--- a/packages/CompanionDeviceManager/res/values-km/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-km/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"ជ្រើសរើស <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ដើម្បីឱ្យស្ថិតក្រោម​ការគ្រប់គ្រងរបស់ &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> នឹងត្រូវបានអនុញ្ញាតឱ្យ​ធ្វើអន្តរកម្មជាមួយ​ការជូនដំណឹងរបស់អ្នក និងចូលប្រើការអនុញ្ញាត​ប្រតិទិន, ទូរសព្ទ, SMS និងទំនាក់ទំនងរបស់អ្នក។"</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> នឹងត្រូវបានអនុញ្ញាតឱ្យ​ធ្វើអន្តរកម្មជាមួយ​ការជូនដំណឹងរបស់អ្នក និងចូលប្រើការអនុញ្ញាត​ប្រតិទិន, ទូរសព្ទ, SMS និងទំនាក់ទំនងរបស់អ្នក។"</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ផ្សាយកម្មវិធីឬ?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ផ្ដល់ការចូលប្រើពីចម្ងាយដល់ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ដើម្បីចូលប្រើកម្មវិធី ដែលបានដំឡើងនៅលើទូរសព្ទនេះ នៅពេលភ្ជាប់អ៊ីនធឺណិត។"</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ផ្ដល់ការចូលប្រើពីចម្ងាយដល់ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ដើម្បីចូលប្រើកម្មវិធី ដែលបានដំឡើងនៅលើថេប្លេតនេះ នៅពេលភ្ជាប់អ៊ីនធឺណិត។"</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ផ្ដល់ការចូលប្រើពីចម្ងាយដល់ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ដើម្បីចូលប្រើកម្មវិធី ដែលបានដំឡើងនៅលើឧបករណ៍នេះ នៅពេលភ្ជាប់អ៊ីនធឺណិត។"</string>
+    <string name="permission_apps" msgid="6142133265286656158">"កម្មវិធី"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"បញ្ចាំងកម្មវិធីរបស់ទូរសព្ទអ្នក"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ចូលប្រើព័ត៌មាននេះពីទូរសព្ទរបស់អ្នក"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"សេវាកម្មឆ្លងកាត់ឧបករណ៍"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ចូលមើលព័ត៌មាននេះពីទូរសព្ទរបស់អ្នក"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"ការ​ជូនដំណឹង"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"អាចអាន​ការជូនដំណឹង​ទាំងអស់ រួមទាំង​ព័ត៌មាន​ដូចជាទំនាក់ទំនង សារ និងរូបថត"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"រូបថត និងមេឌៀ"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"សេវាកម្ម Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"ឧបករណ៍"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"អនុញ្ញាត"</string>
     <string name="consent_no" msgid="2640796915611404382">"កុំអនុញ្ញាត"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"ផ្ទេរការអនុញ្ញាតកម្មវិធីទៅនាឡិការបស់អ្នក"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"ដើម្បីជួយឱ្យការរៀបចំនាឡិការបស់អ្នកកាន់តែងាយស្រួល កម្មវិធីដែលបានដំឡើងនៅលើនាឡិការបស់អ្នកអំឡុងពេលរៀបចំនឹងប្រើការអនុញ្ញាតដូចគ្នានឹងទូរសព្ទរបស់អ្នកដែរ។\n\n ការអនុញ្ញាតទាំងនេះអាចរួមបញ្ចូលសិទ្ធិចូលប្រើទីតាំង និងមីក្រូហ្វូនរបស់នាឡិកាអ្នក។"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml
index 64576ce..7ba67a6 100644
--- a/packages/CompanionDeviceManager/res/values-kn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ಮೂಲಕ ನಿರ್ವಹಿಸಬೇಕಾದ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳೊಂದಿಗೆ ಸಂವಹನ ನಡೆಸಲು ಮತ್ತು ನಿಮ್ಮ ಫೋನ್, SMS, ಸಂಪರ್ಕಗಳು ಮತ್ತು Calendar ಅನುಮತಿಗಳನ್ನು ಪ್ರವೇಶಿಸಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಲಾಗುತ್ತದೆ."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳೊಂದಿಗೆ ಸಂವಹನ ನಡೆಸಲು ಮತ್ತು ನಿಮ್ಮ ಫೋನ್, SMS, ಸಂಪರ್ಕಗಳು ಮತ್ತು Calendar ಅನುಮತಿಗಳನ್ನು ಪ್ರವೇಶಿಸಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಲಾಗುತ್ತದೆ."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"ಆ್ಯಪ್‌ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಿ?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"ಕನೆಕ್ಟ್ ಆದಾಗ ಈ ಫೋನ್‌ನಲ್ಲಿ ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲಾದ ಆ್ಯಪ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸುವುದಕ್ಕಾಗಿ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ಗೆ ರಿಮೋಟ್ ಪ್ರವೇಶವನ್ನು ಒದಗಿಸಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಗೆ ಅನುಮತಿಸಿ."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"ಕನೆಕ್ಟ್ ಆದಾಗ ಈ ಟ್ಯಾಬ್ಲೆಟ್‌ನಲ್ಲಿ ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲಾದ ಆ್ಯಪ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸುವುದಕ್ಕಾಗಿ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ಗೆ ರಿಮೋಟ್ ಪ್ರವೇಶವನ್ನು ಒದಗಿಸಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಗೆ ಅನುಮತಿಸಿ."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"ಕನೆಕ್ಟ್ ಆದಾಗ ಈ ಸಾಧನದಲ್ಲಿ ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲಾದ ಆ್ಯಪ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸುವುದಕ್ಕಾಗಿ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ಗೆ ರಿಮೋಟ್ ಪ್ರವೇಶವನ್ನು ಒದಗಿಸಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಗೆ ಅನುಮತಿಸಿ."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"ಆ್ಯಪ್‌ಗಳು"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"ನಿಮ್ಮ ಫೋನ್‍ನ ಆ್ಯಪ್‌ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಿ"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"ನಿಮ್ಮ ಫೋನ್ ಮೂಲಕ ಈ ಮಾಹಿತಿಯನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಗೆ ಅನುಮತಿಸಿ"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"ಕ್ರಾಸ್-ಸಾಧನ ಸೇವೆಗಳು"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"ನಿಮ್ಮ ಫೋನ್ ಮೂಲಕ ಈ ಮಾಹಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಗೆ ಅನುಮತಿಸಿ"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"ಅಧಿಸೂಚನೆಗಳು"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"ಸಂಪರ್ಕಗಳು, ಸಂದೇಶಗಳು ಮತ್ತು ಫೋಟೋಗಳಂತಹ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಂತೆ ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳನ್ನು ಓದಬಹುದು"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"ಫೋಟೋಗಳು ಮತ್ತು ಮಾಧ್ಯಮ"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ಸೇವೆಗಳು"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"ಸಾಧನ"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"ಅನುಮತಿಸಿ"</string>
     <string name="consent_no" msgid="2640796915611404382">"ಅನುಮತಿಸಬೇಡಿ"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"ಆ್ಯಪ್ ಅನುಮತಿಗಳನ್ನು ನಿಮ್ಮ ವಾಚ್‌ಗೆ ವರ್ಗಾವಣೆ ಮಾಡಿ"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"ನಿಮ್ಮ ವಾಚ್ ಸೆಟಪ್ ಮಾಡುವುದನ್ನು ಸುಲಭವಾಗಿಸಲು, ಸೆಟಪ್‌ನ ಸಮಯದಲ್ಲಿ ನಿಮ್ಮ ವಾಚ್‌ನಲ್ಲಿ ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಿದ ಆ್ಯಪ್‌ಗಳು, ನಿಮ್ಮ ಫೋನ್‌ನಲ್ಲಿನ ಅನುಮತಿಗಳನ್ನೇ ಬಳಸಿಕೊಳ್ಳುತ್ತವೆ.\n\n ಈ ಅನುಮತಿಗಳು ನಿಮ್ಮ ವಾಚ್‌ನ ಮೈಕ್ರೊಫೋನ್ ಮತ್ತು ಸ್ಥಳದ ಪ್ರವೇಶವನ್ನು ಒಳಗೊಳ್ಳಬಹುದು."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml
index 5bf8eb4..3b4bc5c 100644
--- a/packages/CompanionDeviceManager/res/values-ko/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;에서 관리할 <xliff:g id="PROFILE_NAME">%1$s</xliff:g>을(를) 선택"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 알림과 상호작용하고 전화, SMS, 연락처, 캘린더 권한에 액세스할 수 있게 됩니다."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 알림과 상호작용하고 전화, SMS, 연락처, 캘린더 권한에 액세스할 수 있게 됩니다."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 애플리케이션을 스트리밍하도록 허용하시겠습니까?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"연결 시 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;에 이 휴대전화에 설치된 애플리케이션에 원격으로 액세스할 수 있는 권한을 제공하도록 허용합니다."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"연결 시 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;에 이 태블릿에 설치된 애플리케이션에 원격으로 액세스할 수 있는 권한을 제공하도록 허용합니다."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"연결 시 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;에 이 기기에 설치된 애플리케이션에 원격으로 액세스할 수 있는 권한을 제공하도록 허용합니다."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"앱"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"휴대전화의 앱을 스트리밍합니다."</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 앱이 휴대전화에서 이 정보에 액세스하도록 허용합니다."</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"교차 기기 서비스"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 앱이 휴대전화에서 이 정보에 액세스하도록 허용합니다."</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"알림"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"사진 및 미디어"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 서비스"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"기기"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"허용"</string>
     <string name="consent_no" msgid="2640796915611404382">"허용 안함"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"앱 권한을 시계로 이전"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"시계를 더 쉽게 설정하기 위해 설정하는 동안 시계에 설치된 앱에서 휴대전화와 동일한 권한을 사용합니다.\n\n 이러한 권한에는 시계의 마이크 및 위치 정보에 대한 액세스가 포함될 수 있습니다."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml
index 714dc93..365116e 100644
--- a/packages/CompanionDeviceManager/res/values-ky/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; тарабынан башкарылсын"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> билдирмелериңизди көрүп, телефонуңуздун, SMS билдирүүлөрүңүздүн, байланыштарыңыздын жана жылнаамаңыздын уруксаттарын пайдалана алат."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> билдирмелериңизди көрүп, телефонуңуздун, SMS билдирүүлөрүңүздүн, байланыштарыңыздын жана жылнаамаңыздын уруксаттарын пайдалана алат."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна колдонмолорду алып ойнотууга уруксат бересизби?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна Интернетке туташкан &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; телефонундагы колдонмолорго алыстан кирүү мүмкүнчүлүгүн бериңиз."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна Интернетке туташкан &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; планшетиндеги колдонмолорго алыстан кирүү мүмкүнчүлүгүн бериңиз."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна Интернетке туташкан &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; түзмөгүндөгү колдонмолорго алыстан кирүү мүмкүнчүлүгүн бериңиз."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Колдонмолор"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Телефондогу колдонмолорду алып ойнотуу"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна телефонуңуздагы ушул маалыматты көрүүгө уруксат бериңиз"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Түзмөктөр аралык кызматтар"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна телефонуңуздагы ушул маалыматты көрүүгө уруксат бериңиз"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Билдирмелер"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Сүрөттөр жана медиа"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play кызматтары"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"түзмөк"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Уруксат берүү"</string>
     <string name="consent_no" msgid="2640796915611404382">"Уруксат берилбесин"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Колдонмонун уруксаттарын саатка өткөрүү"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Сааттын жөндөлүшүн жеңилдетүү үчүн жөндөө учурунда саатыңызга орнотулган колдонмолор телефонуңуздагы уруксаттарды колдонот.\n\n Мындай уруксаттарга саатыңыздын микрофонун же жайгашкан жерин колдонуу кириши мүмкүн."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-lo/strings.xml b/packages/CompanionDeviceManager/res/values-lo/strings.xml
index 95cab69..29fcf2f 100644
--- a/packages/CompanionDeviceManager/res/values-lo/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lo/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"ເລືອກ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ເພື່ອໃຫ້ຖືກຈັດການໂດຍ &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ຈະໄດ້ຮັບອະນຸຍາດໃຫ້ໂຕ້ຕອບກັບການແຈ້ງເຕືອນຂອງທ່ານ ແລະ ເຂົ້າເຖິງການອະນຸຍາດໂທລະສັບ, SMS, ລາຍຊື່ຜູ້ຕິດຕໍ່ ແລະ ປະຕິທິນຂອງທ່ານໄດ້."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ຈະໄດ້ຮັບອະນຸຍາດໃຫ້ໂຕ້ຕອບກັບການແຈ້ງເຕືອນຂອງທ່ານ ແລະ ເຂົ້າເຖິງການອະນຸຍາດໂທລະສັບ, SMS, ລາຍຊື່ຜູ້ຕິດຕໍ່ ແລະ ປະຕິທິນຂອງທ່ານໄດ້."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"ອະນຸຍາດໃຫ້ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ສະຕຣີມແອັບພລິເຄຊັນໄດ້ບໍ?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"ໃຫ້ສິດ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ເພື່ອເຂົ້າເຖິງ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ຈາກໄລຍະໄກເພື່ອເຂົ້າເຖິງແອັບພລິເຄຊັນທີ່ຕິດຕັ້ງຢູ່ໂທລະສັບນີ້ເມື່ອເຊື່ອມຕໍ່ແລ້ວ."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"ໃຫ້ສິດ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ເພື່ອເຂົ້າເຖິງ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ຈາກໄລຍະໄກເພື່ອເຂົ້າເຖິງແອັບພລິເຄຊັນທີ່ຕິດຕັ້ງຢູ່ແທັບເລັດນີ້ເມື່ອເຊື່ອມຕໍ່ແລ້ວ."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"ໃຫ້ສິດ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ເພື່ອເຂົ້າເຖິງ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ຈາກໄລຍະໄກເພື່ອເຂົ້າເຖິງແອັບພລິເຄຊັນທີ່ຕິດຕັ້ງຢູ່ອຸປະກອນນີ້ເມື່ອເຊື່ອມຕໍ່ແລ້ວ."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"ແອັບ"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"ສະຕຣີມແອັບຂອງໂທລະສັບທ່ານ"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"ອະນຸຍາດ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ໃຫ້ເຂົ້າເຖິງຂໍ້ມູນນີ້ຈາກໂທລະສັບຂອງທ່ານໄດ້"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"ບໍລິການຂ້າມອຸປະກອນ"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"ອະນຸຍາດ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ໃຫ້ເຂົ້າເຖິງຂໍ້ມູນນີ້ຈາກໂທລະສັບຂອງທ່ານໄດ້"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"ການແຈ້ງເຕືອນ"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"ຮູບພາບ ແລະ ມີເດຍ"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"ບໍລິການ Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"ອຸປະກອນ"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"ອະນຸຍາດ"</string>
     <string name="consent_no" msgid="2640796915611404382">"ບໍ່ອະນຸຍາດ"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"ໂອນຍ້າຍການອະນຸຍາດແອັບໄປຫາໂມງຂອງທ່ານ"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"ເພື່ອເຮັດໃຫ້ຕັ້ງຄ່າໂມງຂອງທ່ານໄດ້ງ່າຍຂຶ້ນ, ແອັບທີ່ຕິດຕັ້ງຢູ່ໂມງຂອງທ່ານໃນລະຫວ່າງການຕັ້ງຄ່າຈະໃຊ້ການອະນຸຍາດດຽວກັນກັບໂທລະສັບຂອງທ່ານ.\n\n ການອະນຸຍາດເຫຼົ່ານີ້ອາດຮວມສິດເຂົ້າເຖິງໄມໂຄຣໂຟນ ແລະ ສະຖານທີ່ຂອງທ່ານນຳ."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-lt/strings.xml b/packages/CompanionDeviceManager/res/values-lt/strings.xml
index 5d32fbb..fad4a43 100644
--- a/packages/CompanionDeviceManager/res/values-lt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lt/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Jūsų <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, kurį valdys &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; (pasirinkite)"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ galės sąveikauti su pranešimų funkcija ir pasiekti telefoną, SMS, kontaktus ir kalendorių."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ galės sąveikauti su pranešimų funkcija ir pasiekti telefoną, SMS, kontaktus ir kalendorių."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Leisti &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; perduoti srautu programas?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Leiskite &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prisijungus suteikti &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; nuotolinę prieigą prie šiame telefone įdiegtų programų."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Leiskite &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prisijungus suteikti &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; nuotolinę prieigą prie šiame planšetiniame kompiuteryje įdiegtų programų."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Leiskite &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prisijungus suteikti &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; nuotolinę prieigą prie šiame įrenginyje įdiegtų programų."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Programos"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Telefono programų perdavimas srautu"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Leisti &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pasiekti šią informaciją iš jūsų telefono"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Pasl. keliuose įrenginiuose"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Leisti &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pasiekti šią informaciją iš jūsų telefono"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Pranešimai"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Nuotraukos ir medija"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"„Google Play“ paslaugos"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"įrenginys"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Leisti"</string>
     <string name="consent_no" msgid="2640796915611404382">"Neleisti"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Laikrodžio programų perkėlimo leidimai"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Kad būtų lengviau nustatyti laikrodį, jame atliekant sąranką įdiegtoms programoms bus naudojami tie patys leidimai kaip jūsų telefone.\n\n Šie leidimai gali apimti prieigą prie laikrodžio mikrofono ir vietovės."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-lv/strings.xml b/packages/CompanionDeviceManager/res/values-lv/strings.xml
index cabfc77..5562afb 100644
--- a/packages/CompanionDeviceManager/res/values-lv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lv/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Profila (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) izvēle, ko pārvaldīt lietotnē &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"Lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g> tiks atļauts mijiedarboties ar jūsu paziņojumiem un piekļūt šādām atļaujām: Tālrunis, Īsziņas, Kontaktpersonas un Kalendārs."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g> tiks atļauts mijiedarboties ar jūsu paziņojumiem un piekļūt šādām atļaujām: Tālrunis, Īsziņas, Kontaktpersonas un Kalendārs."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Vai atļaujat lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; straumēt lietojumprogrammas?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; nodrošināt attālu piekļuvi tālrunim &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, lai piekļūtu šajā tālrunī instalētajām lietojumprogrammām, kamēr ir izveidots savienojums."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; nodrošināt attālu piekļuvi planšetdatoram &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, lai piekļūtu šajā planšetdatorā instalētajām lietojumprogrammām, kamēr ir izveidots savienojums."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; nodrošināt attālu piekļuvi ierīcei &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, lai piekļūtu šajā ierīcē instalētajām lietojumprogrammām, kamēr ir izveidots savienojums."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Lietotnes"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Var straumēt jūsu tālruņa lietotnes"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; piekļūt šai informācijai no jūsu tālruņa"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Vairāku ierīču pakalpojumi"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; piekļūt šai informācijai no jūsu tālruņa"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Paziņojumi"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Fotoattēli un multivides faili"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play pakalpojumi"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"ierīce"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Atļaut"</string>
     <string name="consent_no" msgid="2640796915611404382">"Neatļaut"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Lietotņu atļauju pārsūtīšana uz pulksteni"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Lai atvieglotu pulksteņa iestatīšanu, iestatīšanas laikā pulkstenī instalētās lietotnes saņems tādas pašas atļaujas, kādas tām ir tālrunī.\n\n Tostarp lietotnes var saņemt atļauju piekļūt pulksteņa mikrofonam un atrašanās vietai."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-mk/strings.xml b/packages/CompanionDeviceManager/res/values-mk/strings.xml
index b4531b5..bb198df 100644
--- a/packages/CompanionDeviceManager/res/values-mk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mk/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"Изберете <xliff:g id="PROFILE_NAME">%1$s</xliff:g> со којшто ќе управува &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ќе може да остварува интеракција со известувањата и да пристапува до дозволите за телефонот, SMS, контактите и календарот."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ќе може да остварува интеракција со известувањата и да пристапува до дозволите за телефонот, SMS, контактите и календарот."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Да се дозволи &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да стримува апликации?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Дозволете &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да обезбеди далечински пристап на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; за да пристапува до апликации инсталирани на телефонов кога ќе се поврзе."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Дозволете &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да обезбеди далечински пристап на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; за да пристапува до апликации инсталирани на таблетов кога ќе се поврзе."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Дозволете &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да обезбеди далечински пристап на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; за да пристапува до апликации инсталирани на уредов кога ќе се поврзе."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Апликации"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Стримувајте ги апликациите на телефонот"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Овозможете &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да пристапува до овие податоци на телефонот"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Повеќенаменски услуги"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Овозможете &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да пристапува до овие податоци на телефонот"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Известувања"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"може да ги чита сите известувања, вклучително и податоци како контакти, пораки и фотографии"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Аудиовизуелни содржини"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Услуги на Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"уред"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Дозволи"</string>
     <string name="consent_no" msgid="2640796915611404382">"Не дозволувај"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Префрлете ги дозволите за апликациите на вашиот часовник"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"За полесно поставувањето на часовникот, апликациите инсталирани на часовникот при поставувањето ќе ги користат истите дозволи како на телефонот.\n\n Овие дозволи може да опфаќаат пристап до микрофонот и локацијата на часовникот."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ml/strings.xml b/packages/CompanionDeviceManager/res/values-ml/strings.xml
index 85952ca..b8c44a5 100644
--- a/packages/CompanionDeviceManager/res/values-ml/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ml/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ഉപയോഗിച്ച് മാനേജ് ചെയ്യുന്നതിന് ഒരു <xliff:g id="PROFILE_NAME">%1$s</xliff:g> തിരഞ്ഞെടുക്കുക"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"നിങ്ങളുടെ അറിയിപ്പുകളുമായി സംവദിക്കാനും നിങ്ങളുടെ ഫോൺ, SMS, കോൺടാക്റ്റുകൾ, കലണ്ടർ അനുമതികൾ എന്നിവ ആക്‌സസ് ചെയ്യാനും <xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനെ അനുവദിക്കും."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"നിങ്ങളുടെ അറിയിപ്പുകളുമായി സംവദിക്കാനും നിങ്ങളുടെ ഫോൺ, SMS, കോൺടാക്റ്റുകൾ, കലണ്ടർ അനുമതികൾ എന്നിവ ആക്‌സസ് ചെയ്യാനും <xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനെ അനുവദിക്കും."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"ആപ്പുകൾ സ്‌ട്രീം ചെയ്യാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കണോ?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"കണക്‌റ്റ് ചെയ്യുമ്പോൾ, ഈ ഫോണിൽ ഇൻസ്‌റ്റാൾ ചെയ്‌തിട്ടുള്ള ആപ്പുകൾ ആക്‌സസ് ചെയ്യാനുള്ള റിമോട്ട് ആക്‌സസ് &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; എന്നതിന് നൽകാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കുക."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"കണക്‌റ്റ് ചെയ്യുമ്പോൾ, ഈ ടാബ്‌ലെറ്റിൽ ഇൻസ്‌റ്റാൾ ചെയ്‌തിട്ടുള്ള ആപ്പുകൾ ആക്‌സസ് ചെയ്യാനുള്ള റിമോട്ട് ആക്‌സസ് &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; എന്നതിന് നൽകാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കുക."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"കണക്‌റ്റ് ചെയ്യുമ്പോൾ, ഈ ഉപകരണത്തിൽ ഇൻസ്‌റ്റാൾ ചെയ്‌തിട്ടുള്ള ആപ്പുകൾ ആക്‌സസ് ചെയ്യാനുള്ള റിമോട്ട് ആക്‌സസ് &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; എന്നതിന് നൽകാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കുക."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"ആപ്പുകൾ"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"നിങ്ങളുടെ ഫോണിലെ ആപ്പുകൾ സ്‌ട്രീം ചെയ്യാൻ"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"നിങ്ങളുടെ ഫോണിൽ നിന്ന് ഈ വിവരങ്ങൾ ആക്‌സസ് ചെയ്യാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ആപ്പിനെ അനുവദിക്കുക"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"ക്രോസ്-ഉപകരണ സേവനങ്ങൾ"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"നിങ്ങളുടെ ഫോണിൽ നിന്ന് ഈ വിവരങ്ങൾ ആക്‌സസ് ചെയ്യാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ആപ്പിനെ അനുവദിക്കുക"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"അറിയിപ്പുകൾ"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"കോൺടാക്‌റ്റുകൾ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ മുതലായ വിവരങ്ങൾ ഉൾപ്പെടെയുള്ള എല്ലാ അറിയിപ്പുകളും വായിക്കാനാകും"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"ഫോട്ടോകളും മീഡിയയും"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play സേവനങ്ങൾ"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"ഉപകരണം"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"അനുവദിക്കുക"</string>
     <string name="consent_no" msgid="2640796915611404382">"അനുവദിക്കരുത്"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"നിങ്ങളുടെ വാച്ചിലേക്ക് ആപ്പ് അനുമതികൾ കൈമാറുക"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"നിങ്ങളുടെ വാച്ച് സജ്ജീകരിക്കുന്നത് എളുപ്പമാക്കാൻ, സജ്ജീകരിക്കുമ്പോൾ ഫോണിലുള്ള അതേ അനുമതികൾ നിങ്ങളുടെ വാച്ചിൽ ഇൻസ്റ്റാൾ ചെയ്തിട്ടുള്ള ആപ്പുകൾ ഉപയോഗിക്കും.\n\n ഈ അനുമതികളിൽ നിങ്ങളുടെ വാച്ചിന്റെ മൈക്രോഫോണിലേക്കും ലോക്കേഷനിലേക്കുമുള്ള ആക്‌സസ് ഉൾപ്പെട്ടേക്കാം."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-mn/strings.xml b/packages/CompanionDeviceManager/res/values-mn/strings.xml
index c0d589d..7233c04 100644
--- a/packages/CompanionDeviceManager/res/values-mn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;-н удирдах<xliff:g id="PROFILE_NAME">%1$s</xliff:g>-г сонгоно уу"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>-д таны мэдэгдлүүдтэй харилцаж, таны Утас, SMS, Харилцагчид болон Календарийн зөвшөөрөлд хандахыг зөвшөөрнө."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>-д таны мэдэгдлүүдтэй харилцаж, таны Утас, SMS, Харилцагчид болон Календарийн зөвшөөрөлд хандахыг зөвшөөрнө."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д аппуудыг дамжуулахыг зөвшөөрөх үү?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-г холбогдсон үед энэ утсанд суулгасан аппуудад хандахын тулд алсын хандалт өгөхийг зөвшөөрнө үү."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-г холбогдсон үед энэ таблетад суулгасан аппуудад хандахын тулд алсын хандалт өгөхийг зөвшөөрнө үү."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-г холбогдсон үед энэ төхөөрөмжид суулгасан аппуудад хандахын тулд алсын хандалт өгөхийг зөвшөөрнө үү."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Аппууд"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Таны утасны аппуудыг дамжуулах"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д таны утаснаас энэ мэдээлэлд хандахыг зөвшөөрнө үү"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Төхөөрөмж хоорондын үйлчилгээ"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д таны утаснаас энэ мэдээлэлд хандахыг зөвшөөрнө үү"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Мэдэгдэл"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Харилцагчид, мессеж болон зураг зэрэг мэдээллийг оруулаад бүх мэдэгдлийг унших боломжтой"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Зураг болон медиа"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play үйлчилгээ"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"төхөөрөмж"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Зөвшөөрөх"</string>
     <string name="consent_no" msgid="2640796915611404382">"Бүү зөвшөөр"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Цагандаа аппын зөвшөөрлийг шилжүүлэх"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Таны цагийг тохируулахад илүү хялбар болгохын тулд тохируулгын үеэр таны цаган дээр суулгасан аппууд нь утастай тань ижил зөвшөөрлийг ашиглана.\n\n Эдгээр зөвшөөрөлд таны цагийн микрофон болон байршлын хандалт зэрэг багтаж магадгүй."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-mr/strings.xml b/packages/CompanionDeviceManager/res/values-mr/strings.xml
index 0ce6ab7..d2aa48c 100644
--- a/packages/CompanionDeviceManager/res/values-mr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mr/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; द्वारे व्यवस्थापित करण्यासाठी <xliff:g id="PROFILE_NAME">%1$s</xliff:g> निवडा"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ला तुमच्या सूचनांशी संवाद साधण्याची आणि तुमचा फोन, एसएमएस, संपर्क आणि Calendar च्या परवानग्या अ‍ॅक्सेस करण्याची अनुमती मिळेल."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ला तुमच्या सूचनांशी संवाद साधण्याची आणि तुमचा फोन, एसएमएस, संपर्क आणि Calendar च्या परवानग्या अ‍ॅक्सेस करण्याची अनुमती मिळेल."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला अ‍ॅप्लिकेशन स्ट्रीम करण्याची अनुमती द्यायची आहे का?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"कनेक्ट केलेले असताना या फोनवरील अ‍ॅप्लिकेशन अ‍ॅक्सेस करता यावीत यासाठी &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; चा रिमोट अ‍ॅक्सेस द्या."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"कनेक्ट केलेले असताना या टॅबलेटवरील अ‍ॅप्लिकेशन अ‍ॅक्सेस करता यावीत यासाठी &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; चा रिमोट अ‍ॅक्सेस द्या."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"कनेक्ट केलेले असताना या डिव्हाइसवरील अ‍ॅप्लिकेशन अ‍ॅक्सेस करता यावीत यासाठी &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; चा रिमोट अ‍ॅक्सेस द्या."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"ॲप्स"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"फोनवरील ॲप्स स्ट्रीम करा"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला ही माहिती तुमच्या फोनवरून अ‍ॅक्सेस करण्यासाठी अनुमती द्या"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"क्रॉस-डिव्हाइस सेवा"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला ही माहिती तुमच्या फोनवरून अ‍ॅक्सेस करण्यासाठी अनुमती द्या"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"सूचना"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"संपर्क, मेसेज आणि फोटो यांसारख्या माहितीचा समावेश असलेल्या सर्व सूचना वाचू शकते"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"फोटो आणि मीडिया"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play सेवा"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"डिव्हाइस"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"अनुमती द्या"</string>
     <string name="consent_no" msgid="2640796915611404382">"अनुमती देऊ नका"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"अ‍ॅप परवानग्या तुमच्या वॉचवर ट्रान्सफर करा"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"तुमचे वॉच सेट करणे आणखी सोपे करण्यासाठी, सेटअपदरम्यान तुमच्या वॉचवर इंस्टॉल केलेली ॲप्स ही तुमच्या फोनप्रमाणेच परवानग्या वापरतील.\n\n या परवानग्यांमध्ये तुमच्या वॉचचा मायक्रोफोन आणि स्थानाच्या अ‍ॅक्सेसचा समावेश असू शकतो."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ms/strings.xml b/packages/CompanionDeviceManager/res/values-ms/strings.xml
index 2ca8128..efc7412 100644
--- a/packages/CompanionDeviceManager/res/values-ms/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ms/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk diurus oleh &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan dibenarkan berinteraksi dengan pemberitahuan anda dan mengakses kebenaran Telefon, SMS, Kenalan dan Kalendar anda."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan dibenarkan berinteraksi dengan pemberitahuan anda dan mengakses kebenaran Telefon, SMS, Kenalan dan Kalendar anda."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Benarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; menstrim aplikasi?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Membenarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; memberi akses jauh kepada &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; untuk mengakses aplikasi yang dipasang pada telefon ini apabila disambungkan."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Membenarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; memberi akses jauh kepada &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; untuk mengakses aplikasi yang dipasang pada tablet ini apabila disambungkan."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Membenarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; memberi akses jauh kepada &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; untuk mengakses aplikasi yang dipasang pada peranti ini apabila disambungkan."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Apl"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Strim apl telefon anda"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Benarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; mengakses maklumat ini daripada telefon anda"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Perkhidmatan silang peranti"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Benarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; untuk mengakses maklumat ini daripada telefon anda"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Pemberitahuan"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Boleh membaca semua pemberitahuan, termasuk maklumat seperti kenalan, mesej dan foto"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Foto dan media"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Perkhidmatan Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"peranti"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Benarkan"</string>
     <string name="consent_no" msgid="2640796915611404382">"Jangan benarkan"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Pindahkan kebenaran apl pada jam tangan anda"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Untuk memudahkan penyediaan jam tangan anda, apl yang dipasang pada jam tangan anda semasa persediaan akan menggunakan kebenaran yang sama seperti telefon anda.\n\n Kebenaran ini mungkin termasuk akses kepada mikrofon dan lokasi jam tangan anda."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-my/strings.xml b/packages/CompanionDeviceManager/res/values-my/strings.xml
index 1fb20bf..ed678c9 100644
--- a/packages/CompanionDeviceManager/res/values-my/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-my/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; က စီမံခန့်ခွဲရန် <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ကို ရွေးချယ်ပါ"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"သင်၏ ‘ဖုန်း’၊ ‘SMS စာတိုစနစ်’၊ ‘အဆက်အသွယ်များ’ နှင့် ‘ပြက္ခဒိန်’ ခွင့်ပြုချက်များကို သုံးရန်နှင့် အကြောင်းကြားချက်များကို ပြန်လှန်တုံ့ပြန်ရန် <xliff:g id="APP_NAME">%1$s</xliff:g> အား ခွင့်ပြုပါမည်။"</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"သင်၏ ‘ဖုန်း’၊ ‘SMS စာတိုစနစ်’၊ ‘အဆက်အသွယ်များ’ နှင့် ‘ပြက္ခဒိန်’ ခွင့်ပြုချက်များကို သုံးရန်နှင့် အကြောင်းကြားချက်များကို ပြန်လှန်တုံ့ပြန်ရန် <xliff:g id="APP_NAME">%1$s</xliff:g> အား ခွင့်ပြုပါမည်။"</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"အပလီကေးရှင်းများကို တိုက်ရိုက်လွှင့်ရန် &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ကိုခွင့်ပြုမလား။"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"ချိတ်ဆက်ထားသည့်အခါ ဤဖုန်းတွင် ထည့်သွင်းထားသော အပလီကေးရှင်းများကို သုံးခွင့်ရရန်အတွက် &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ကိုအဝေးမှ သုံးခွင့်ပေးနိုင်ရန် &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; အားခွင့်ပြုပါ။"</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"ချိတ်ဆက်ထားသည့်အခါ ဤတက်ဘလက်တွင် ထည့်သွင်းထားသော အပလီကေးရှင်းများကို သုံးခွင့်ရရန်အတွက် &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ကိုအဝေးမှ သုံးခွင့်ပေးနိုင်ရန် &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; အားခွင့်ပြုပါ။"</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"ချိတ်ဆက်ထားသည့်အခါ ဤစက်တွင် ထည့်သွင်းထားသော အပလီကေးရှင်းများကို သုံးခွင့်ရရန်အတွက် &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ကိုအဝေးမှ သုံးခွင့်ပေးနိုင်ရန် &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; အားခွင့်ပြုပါ။"</string>
+    <string name="permission_apps" msgid="6142133265286656158">"အက်ပ်များ"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"သင့်ဖုန်းရှိအက်ပ်များကို တိုက်ရိုက်လွှင့်နိုင်သည်"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ကို သင့်ဖုန်းမှ ဤအချက်အလက် သုံးခွင့်ပြုမည်"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"စက်များကြားသုံး ဝန်ဆောင်မှုများ"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ကို သင့်ဖုန်းမှ ဤအချက်အလက် သုံးခွင့်ပြုမည်"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"အကြောင်းကြားချက်များ"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"ဓာတ်ပုံနှင့် မီဒီယာများ"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ဝန်ဆောင်မှုများ"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"စက်"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"ခွင့်ပြုရန်"</string>
     <string name="consent_no" msgid="2640796915611404382">"ခွင့်မပြုပါ"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"သင်၏နာရီသို့ အက်ပ်ခွင့်ပြုချက်များ လွှဲပြောင်းရန်"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"သင်၏နာရီ စနစ်ထည့်သွင်းရာတွင် ပိုလွယ်ကူစေရန် စနစ်ထည့်သွင်းနေစဉ်အတွင်း နာရီတွင်ထည့်သွင်းသော အက်ပ်များသည် သင့်ဖုန်းနှင့် အလားတူခွင့်ပြုချက်များကို သုံးပါမည်။\n\n ဤခွင့်ပြုချက်များတွင် သင့်နာရီ၏ မိုက်ခရိုဖုန်းနှင့် တည်နေရာတို့ကို သုံးခွင့် ပါဝင်နိုင်သည်။"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml
index aa73f5d..40caa23 100644
--- a/packages/CompanionDeviceManager/res/values-nb/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Velg <xliff:g id="PROFILE_NAME">%1$s</xliff:g> som skal administreres av &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tillatelse til å samhandle med varslene dine og får tilgang til Telefon, SMS, kontakter og Kalender."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tillatelse til å samhandle med varslene dine og får tilgang til Telefon, SMS, kontakter og Kalender."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Vil du gi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tillatelse til å strømme apper?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Tillat at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gir &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ekstern tilgang til apper som er installert på denne telefonen, når den er koblet til internett."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Tillat at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gir &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ekstern tilgang til apper som er installert på dette nettbrettet, når det er koblet til internett."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Tillat at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gir &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ekstern tilgang til apper som er installert på denne enheten, når den er koblet til internett."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Apper"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Strøm appene på telefonen"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Gi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilgang til denne informasjonen fra telefonen din"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjenester på flere enheter"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Gi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilgang til denne informasjonen fra telefonen din"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Varsler"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Bilder og medier"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-tjenester"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Tillat"</string>
     <string name="consent_no" msgid="2640796915611404382">"Ikke tillat"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Overfør apptillatelser til klokken din"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"For å gjøre det enklere å konfigurere klokken din bruker apper som installeres på klokken under konfigureringen, samme tillatelser som på telefonen.\n\n Disse tillatelsene kan inkludere tilgang til mikrofonen på klokken og posisjon."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ne/strings.xml b/packages/CompanionDeviceManager/res/values-ne/strings.xml
index 3ba75eb..2a27219 100644
--- a/packages/CompanionDeviceManager/res/values-ne/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ne/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"आफूले &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; प्रयोग गरी व्यवस्थापन गर्न चाहेको <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चयन गर्नुहोस्"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> लाई तपाईंका सूचना हेर्ने र फोन, SMS, कन्ट्याक्ट तथा पात्रोसम्बन्धी अनुमतिहरू हेर्ने तथा प्रयोग गर्ने अनुमति दिइने छ।"</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> लाई तपाईंका सूचना हेर्ने र फोन, SMS, कन्ट्याक्ट तथा पात्रोसम्बन्धी अनुमतिहरू हेर्ने तथा प्रयोग गर्ने अनुमति दिइने छ।"</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; लाई एपहरू स्ट्रिम गर्ने अनुमति दिने हो?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"यो डिभाइस इन्टरनेटमा कनेक्ट भएका बेला, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;लाई &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; लाई यो फोनमा इन्स्टल गरिएका एप टाढैबाट प्रयोग गर्ने अनुमति दिन दिनुहोस्।"</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"यो डिभाइस इन्टरनेटमा कनेक्ट भएका बेला, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;लाई &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; लाई यो ट्याब्लेटमा इन्स्टल गरिएका एप टाढैबाट प्रयोग गर्ने अनुमति दिन दिनुहोस्।"</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"यो डिभाइस इन्टरनेटमा कनेक्ट भएका बेला, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; लाई &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; लाई यो डिभाइसमा इन्स्टल गरिएका एप टाढैबाट प्रयोग गर्ने अनुमति दिन दिनुहोस्।"</string>
+    <string name="permission_apps" msgid="6142133265286656158">"एपहरू"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"आफ्नो फोनका एपहरू प्रयोग गर्नुहोस्"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; लाई तपाईंको फोनमा भएको यो जानकारी हेर्ने तथा प्रयोग गर्ने अनुमति दिनुहोस्"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"क्रस-डिभाइस सेवाहरू"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; लाई तपाईंको फोनमा भएको यो जानकारी हेर्ने तथा प्रयोग गर्ने अनुमति दिनुहोस्"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"सूचनाहरू"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"कन्ट्याक्ट, म्यासेज र फोटोलगायतका जानकारीसहित सबै सूचनाहरू पढ्न सक्छ"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"फोटो र मिडिया"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"यन्त्र"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"अनुमति दिनुहोस्"</string>
     <string name="consent_no" msgid="2640796915611404382">"अनुमति नदिनुहोस्"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"एपलाई दिइएका अनुमति घडीमा ट्रान्स्फर गर्नुहोस्"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"तपाईंको घडी सेटअप गर्ने कार्य सजिलो बनाउनका लागि सेटअप गर्ने क्रममा तपाईंको घडीमा इन्स्टल गरिएका एपहरूले पनि तपाईंको फोनमा दिइएको जस्तै अनुमति प्रयोग गर्ने छन्।\n\n यी अनुमतिमा तपाईंको घडीको माइक्रोफोन र लोकेसन प्रयोग गर्ने जस्ता अनुमति पर्न सक्छन्।"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-nl/strings.xml b/packages/CompanionDeviceManager/res/values-nl/strings.xml
index bc09a58..3b27f9d 100644
--- a/packages/CompanionDeviceManager/res/values-nl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nl/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"Een <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiezen om te beheren met &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> kan interactie hebben met je meldingen en toegang krijgen tot je rechten voor telefoon, sms, contacten en agenda."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> kan interactie hebben met je meldingen en toegang krijgen tot je rechten voor telefoon, sms, contacten en agenda."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Toestaan dat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; apps streamt?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Toestaan dat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; als er verbinding is &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; externe toegang geeft tot apps die zijn geïnstalleerd op deze telefoon."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Toestaan dat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; als er verbinding is &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; externe toegang geeft tot apps die zijn geïnstalleerd op deze tablet."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Toestaan dat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; als er verbinding is &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; externe toegang geeft tot apps die zijn geïnstalleerd op dit apparaat."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"De apps van je telefoon streamen"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toegang geven tot deze informatie op je telefoon"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device-services"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toegang geven tot deze informatie op je telefoon"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Meldingen"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Kan alle meldingen lezen, waaronder informatie zoals contacten, berichten en foto\'s"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Foto\'s en media"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-services"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"apparaat"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Toestaan"</string>
     <string name="consent_no" msgid="2640796915611404382">"Niet toestaan"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"App-rechten overzetten naar je horloge"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"We willen het makkelijker voor je maken om je horloge in te stellen. Daarom gebruiken apps die tijdens het instellen worden geïnstalleerd op je horloge, dezelfde rechten als op je telefoon.\n\n Deze rechten kunnen toegang tot de microfoon en locatie van je horloge omvatten."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-or/strings.xml b/packages/CompanionDeviceManager/res/values-or/strings.xml
index 92d0a5ef..3849f31 100644
--- a/packages/CompanionDeviceManager/res/values-or/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-or/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ଦ୍ୱାରା ପରିଚାଳିତ ହେବା ପାଇଁ ଏକ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>କୁ ବାଛନ୍ତୁ"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"ଆପଣଙ୍କ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ସହ ଇଣ୍ଟରାକ୍ଟ କରିବା ଏବଂ ଆପଣଙ୍କ ଫୋନ, SMS, ଯୋଗାଯୋଗ ଓ କ୍ୟାଲେଣ୍ଡର ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g>କୁ ଅନୁମତି ଦିଆଯିବ।"</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"ଆପଣଙ୍କ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ସହ ଇଣ୍ଟରାକ୍ଟ କରିବା ଏବଂ ଆପଣଙ୍କ ଫୋନ, SMS, ଯୋଗାଯୋଗ ଓ କ୍ୟାଲେଣ୍ଡର ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g>କୁ ଅନୁମତି ଦିଆଯିବ।"</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ ଆପ୍ଲିକେସନଗୁଡ଼ିକ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ ଅନୁମତି ଦେବେ କି?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ, ଏହି ଫୋନଟି ସଂଯୁକ୍ତ ହୋଇଥିବା ବେଳେ ଏଥିରେ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ଆପ୍ଲିକେସନଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;କୁ ରିମୋଟ ଆକ୍ସେସ ପ୍ରଦାନ କରିବାକୁ ଦିଅନ୍ତୁ।"</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ, ଏହି ଟାବଲେଟଟି ସଂଯୁକ୍ତ ହୋଇଥିବା ବେଳେ ଏଥିରେ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ଆପ୍ଲିକେସନଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;କୁ ରିମୋଟ ଆକ୍ସେସ ପ୍ରଦାନ କରିବାକୁ ଦିଅନ୍ତୁ।"</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ, ଏହି ଡିଭାଇସଟି ସଂଯୁକ୍ତ ହୋଇଥିବା ବେଳେ ଏଥିରେ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ଆପ୍ଲିକେସନଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;କୁ ରିମୋଟ ଆକ୍ସେସ ପ୍ରଦାନ କରିବାକୁ ଦିଅନ୍ତୁ।"</string>
+    <string name="permission_apps" msgid="6142133265286656158">"ଆପ୍ସ"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"ଆପଣଙ୍କ ଫୋନର ଆପ୍ସକୁ ଷ୍ଟ୍ରିମ କରନ୍ତୁ"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"ଆପଣଙ୍କ ଫୋନରୁ ଏହି ସୂଚନାକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"କ୍ରସ-ଡିଭାଇସ ସେବାଗୁଡ଼ିକ"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"ଆପଣଙ୍କ ଫୋନରୁ ଏହି ସୂଚନାକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"ଫଟୋ ଏବଂ ମିଡିଆ"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ସେବାଗୁଡ଼ିକ"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"ଡିଭାଇସ୍"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"ଅନୁମତି ଦିଅନ୍ତୁ"</string>
     <string name="consent_no" msgid="2640796915611404382">"ଅନୁମତି ଦିଅନ୍ତୁ ନାହିଁ"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"ଆପଣଙ୍କ ୱାଚକୁ ଆପ ଅନୁମତିଗୁଡ଼ିକ ଟ୍ରାନ୍ସଫର କରନ୍ତୁ"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"ଆପଣଙ୍କ ୱାଚ ସେଟ ଅପ କରିବାକୁ ସହଜ କରିବା ପାଇଁ, ସେଟଅପ ସମୟରେ ଆପଣଙ୍କର ୱାଚରେ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ଆପଗୁଡ଼ିକ ଆପଣଙ୍କ ଫୋନରେ ଥିବା ଆପଗୁଡ଼ିକ ପରି ସମାନ ଅନୁମତିଗୁଡ଼ିକ ବ୍ୟବହାର କରିବ।\n\n ଏହି ଅନୁମତିଗୁଡ଼ିକରେ ଆପଣଙ୍କ ୱାଚର ମାଇକ୍ରୋଫୋନ ଏବଂ ଲୋକେସନକୁ ଆକ୍ସେସ ଅନ୍ତର୍ଭୁକ୍ତ ହୋଇପାରେ।"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-pa/strings.xml b/packages/CompanionDeviceManager/res/values-pa/strings.xml
index c28be25..432f2b9 100644
--- a/packages/CompanionDeviceManager/res/values-pa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pa/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ ਕੀਤੇ ਜਾਣ ਲਈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ਚੁਣੋ"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਤੁਹਾਡੀਆਂ ਸੂਚਨਾਵਾਂ ਨਾਲ ਅੰਤਰਕਿਰਿਆ ਕਰਨ ਅਤੇ ਤੁਹਾਡੇ ਫ਼ੋਨ, SMS, ਸੰਪਰਕ ਅਤੇ ਕੈਲੰਡਰ ਦੀਆਂ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਹੋਵੇਗੀ।"</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਤੁਹਾਡੀਆਂ ਸੂਚਨਾਵਾਂ ਨਾਲ ਅੰਤਰਕਿਰਿਆ ਕਰਨ ਅਤੇ ਤੁਹਾਡੇ ਫ਼ੋਨ, SMS, ਸੰਪਰਕ ਅਤੇ ਕੈਲੰਡਰ ਦੀਆਂ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਹੋਵੇਗੀ।"</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"ਕੀ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&amp;gt ਨੂੰ ਐਪਲੀਕੇਸ਼ਨਾਂ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"ਕਨੈਕਟ ਹੋਣ \'ਤੇ ਇਸ ਫ਼ੋਨ \'ਤੇ ਸਥਾਪਤ ਐਪਲੀਕੇਸ਼ਨਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਰਿਮੋਟ ਪਹੁੰਚ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਦਿਓ।"</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"ਕਨੈਕਟ ਹੋਣ \'ਤੇ ਇਸ ਟੈਬਲੈੱਟ \'ਤੇ ਸਥਾਪਤ ਐਪਲੀਕੇਸ਼ਨਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਰਿਮੋਟ ਪਹੁੰਚ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਦਿਓ।"</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"ਕਨੈਕਟ ਹੋਣ \'ਤੇ ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਸਥਾਪਤ ਐਪਲੀਕੇਸ਼ਨਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਰਿਮੋਟ ਪਹੁੰਚ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਦਿਓ।"</string>
+    <string name="permission_apps" msgid="6142133265286656158">"ਐਪਾਂ"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"ਆਪਣੇ ਫ਼ੋਨ ਦੀਆਂ ਐਪਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰੋ"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਨ ਤੋਂ ਇਸ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"ਕ੍ਰਾਸ-ਡੀਵਾਈਸ ਸੇਵਾਵਾਂ"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਨ ਤੋਂ ਇਸ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"ਸੂਚਨਾਵਾਂ"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"ਫ਼ੋਟੋਆਂ ਅਤੇ ਮੀਡੀਆ"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ਸੇਵਾਵਾਂ"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"ਡੀਵਾਈਸ"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"ਇਜਾਜ਼ਤ ਦਿਓ"</string>
     <string name="consent_no" msgid="2640796915611404382">"ਇਜਾਜ਼ਤ ਨਾ ਦਿਓ"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"ਐਪ ਇਜਾਜ਼ਤਾਂ ਨੂੰ ਆਪਣੀ ਘੜੀ \'ਤੇ ਟ੍ਰਾਂਸਫ਼ਰ ਕਰੋ"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"ਤੁਹਾਡੀ ਘੜੀ ਦਾ ਸੈੱਟਅੱਪ ਕਰਨਾ ਆਸਾਨ ਬਣਾਉਣ ਲਈ, ਤੁਹਾਡੀ ਘੜੀ \'ਤੇ ਸਥਾਪਤ ਐਪਾਂ ਸੈੱਟਅੱਪ ਦੌਰਾਨ ਉਹੀ ਇਜਾਜ਼ਤਾਂ ਵਰਤਣਗੀਆਂ ਜੋ ਤੁਹਾਡਾ ਫ਼ੋਨ ਵਰਤਦਾ ਹੈ।\n\n ਇਨ੍ਹਾਂ ਇਜਾਜ਼ਤਾਂ ਵਿੱਚ ਤੁਹਾਡੀ ਘੜੀ ਦੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਅਤੇ ਟਿਕਾਣੇ ਤੱਕ ਪਹੁੰਚ ਸ਼ਾਮਲ ਹੋ ਸਕਦੀ ਹੈ।"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml
index f9fd206..a51c696 100644
--- a/packages/CompanionDeviceManager/res/values-pl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Wybierz profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, którym ma zarządzać aplikacja &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> będzie mogła korzystać z powiadomień oraz uprawnień dotyczących Telefonu, SMS-ów, Kontaktów i Kalendarza."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> będzie mogła korzystać z powiadomień oraz uprawnień dotyczących Telefonu, SMS-ów, Kontaktów i Kalendarza."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Zezwolić aplikacji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na strumieniowanie danych z aplikacji?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Zezwól na zapewnianie przez aplikację &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; zdalnego dostępu do aplikacji zainstalowanych na telefonie &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; po połączeniu jej z tym telefonem."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Zezwól na zapewnianie przez aplikację &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; zdalnego dostępu do aplikacji zainstalowanych na tablecie &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; po połączeniu jej z tym tabletem."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Zezwól na zapewnianie przez aplikację &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; zdalnego dostępu do aplikacji zainstalowanych na urządzeniu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; po połączeniu jej z urządzeniem."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Aplikacje"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Odtwarzaj strumieniowo aplikacje z telefonu"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Zezwól aplikacji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na dostęp do tych informacji na Twoim telefonie"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usługi na innym urządzeniu"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Zezwól aplikacji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na dostęp do tych informacji na Twoim telefonie"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Powiadomienia"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Zdjęcia i multimedia"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Usługi Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"urządzenie"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Zezwól"</string>
     <string name="consent_no" msgid="2640796915611404382">"Nie zezwalaj"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Przenieś uprawnienia aplikacji na zegarek"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Aby łatwiej było skonfigurować zegarek, aplikacje zainstalowane na nim podczas konfiguracji będą korzystały z tych samych uprawnień co telefon.\n\n Może to oznaczać dostęp do mikrofonu i lokalizacji na zegarku."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
index 161188c..7cd3a37 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerenciado pelo app &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça streaming de aplicativos?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permita que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; conceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acesso remoto aos aplicativos instalados no smartphone quando ele estiver conectado."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permita que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; conceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acesso remoto aos aplicativos instalados no tablet quando ele estiver conectado."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permita que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; conceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acesso remoto aos aplicativos instalados no dispositivo quando ele estiver conectado."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Faça streaming dos apps do seu smartphone"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse essas informações do smartphone"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Autorizar que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse essas informações do smartphone"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Notificações"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Pode ler todas as notificações, incluindo informações como contatos, mensagens e fotos"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotos e mídia"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
     <string name="consent_no" msgid="2640796915611404382">"Não permitir"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferir as permissões de apps para o relógio"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Para facilitar a configuração do relógio, os apps instalados nele durante a configuração vão usar as mesmas permissões que o smartphone.\n\n Essas permissões podem incluir acesso ao microfone ou à localização do relógio."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
index 9124a40..de412eb 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerido pela app &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com as suas notificações e aceder às autorizações do Telefone, SMS, Contactos e Calendário."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com as suas notificações e aceder às autorizações do Telefone, SMS, Contactos e Calendário."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Permitir que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça stream de aplicações?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; forneça acesso remoto ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; para aceder a aplicações instaladas neste telemóvel quando estiver ligado."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; forneça acesso remoto ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; para aceder a aplicações instaladas neste tablet quando estiver ligado."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; forneça acesso remoto ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; para aceder a aplicações instaladas neste dispositivo quando estiver ligado."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Faça stream das apps do telemóvel"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aceda a estas informações do seu telemóvel"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aceda a estas informações do seu telemóvel"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Notificações"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Pode ler todas as notificações, incluindo informações como contratos, mensagens e fotos"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotos e multimédia"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Serviços do Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
     <string name="consent_no" msgid="2640796915611404382">"Não permitir"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfira as autorizações da app para o seu relógio"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Para facilitar a configuração do seu relógio, as apps instaladas no mesmo durante a configuração utilizarão as mesmas autorizações que o telemóvel.\n\n Estas autorizações podem incluir o acesso ao microfone e à localização do seu relógio."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml
index 161188c..7cd3a37 100644
--- a/packages/CompanionDeviceManager/res/values-pt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerenciado pelo app &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça streaming de aplicativos?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permita que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; conceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acesso remoto aos aplicativos instalados no smartphone quando ele estiver conectado."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permita que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; conceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acesso remoto aos aplicativos instalados no tablet quando ele estiver conectado."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permita que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; conceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acesso remoto aos aplicativos instalados no dispositivo quando ele estiver conectado."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Faça streaming dos apps do seu smartphone"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse essas informações do smartphone"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Autorizar que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse essas informações do smartphone"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Notificações"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Pode ler todas as notificações, incluindo informações como contatos, mensagens e fotos"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotos e mídia"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
     <string name="consent_no" msgid="2640796915611404382">"Não permitir"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferir as permissões de apps para o relógio"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Para facilitar a configuração do relógio, os apps instalados nele durante a configuração vão usar as mesmas permissões que o smartphone.\n\n Essas permissões podem incluir acesso ao microfone ou à localização do relógio."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml
index da7ae9e..7e51104 100644
--- a/packages/CompanionDeviceManager/res/values-ro/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Alegeți un profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> pe care să îl gestioneze &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> va putea să interacționeze cu notificările dvs. și să vă acceseze permisiunile pentru Telefon, SMS-uri, Agendă și Calendar."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> va putea să interacționeze cu notificările dvs. și să vă acceseze permisiunile pentru Telefon, SMS-uri, Agendă și Calendar."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Lăsați &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să redea în stream aplicații?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Lăsați &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să ofere acces la distanță pentru &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ca să se poată accesa aplicațiile instalate pe acest telefon când se conectează utilizatorul."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Lăsați &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să ofere acces la distanță pentru &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ca să se poată accesa aplicațiile instalate pe această tabletă când se conectează utilizatorul."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Lăsați &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să ofere acces la distanță pentru &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ca să se poată accesa aplicațiile instalate pe acest dispozitiv când se conectează utilizatorul."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Aplicații"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Să redea în stream aplicațiile telefonului"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Permiteți ca &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să acceseze aceste informații de pe telefon"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicii pe mai multe dispozitive"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Permiteți ca &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să acceseze aceste informații de pe telefon"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Notificări"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Fotografii și media"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Servicii Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"dispozitiv"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Permiteți"</string>
     <string name="consent_no" msgid="2640796915611404382">"Nu permiteți"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferați permisiunile pentru aplicații pe ceas"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Ca să configurați mai ușor ceasul, aplicațiile instalate pe ceas în timpul procesului de configurare vor folosi aceleași permisiuni ca telefonul.\n\n Între acestea se poate număra accesul la microfonul și locația ceasului."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml
index dbb09c9..2fa1073 100644
--- a/packages/CompanionDeviceManager/res/values-ru/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Выберите устройство (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), которым будет управлять приложение &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"Приложению \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" будет предоставлен доступ к уведомлениям, а также следующие разрешения: телефон, SMS, контакты и календарь."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Приложению \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" будет предоставлен доступ к уведомлениям, а также следующие разрешения: телефон, SMS, контакты и календарь."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Разрешить приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; транслировать приложения?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Разрешить приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; при наличии подключения предоставить устройству &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; удаленный доступ к приложениям, установленным на этом телефоне."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Разрешить приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; при наличии подключения предоставить устройству &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; удаленный доступ к приложениям, установленным на этом планшете."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Разрешить приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; при наличии подключения предоставить устройству &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; удаленный доступ к приложениям, установленным на этом устройстве."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Приложения"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Трансляция приложений с телефона."</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Разрешите приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; получать эту информацию с вашего телефона"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Сервисы стриминга приложений"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Разрешите приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; получать эту информацию с вашего телефона"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Уведомления"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Фотографии и медиафайлы"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Сервисы Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Разрешить"</string>
     <string name="consent_no" msgid="2640796915611404382">"Запретить"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Перенос разрешений для приложений на часы"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Для приложений, установленных на часы во время настройки, будут использоваться те же разрешения, что и на телефоне.\n\n Например, может быть включен доступ к микрофону на часах или сведениям о местоположении."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-si/strings.xml b/packages/CompanionDeviceManager/res/values-si/strings.xml
index a3de2a3..6bb3c09 100644
--- a/packages/CompanionDeviceManager/res/values-si/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-si/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; මගින් කළමනාකරණය කරනු ලැබීමට <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ක් තෝරන්න"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ඔබගේ දැනුම්දීම් සමඟ අන්තර්ක්‍රියා කිරීමට සහ ඔබගේ දුරකථනය, කෙටි පණිවුඩ, සම්බන්ධතා සහ දින දර්ශන අවසර වෙත ප්‍රවේශ වීමට ඉඩ දෙනු ඇත."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ඔබගේ දැනුම්දීම් සමඟ අන්තර්ක්‍රියා කිරීමට සහ ඔබගේ දුරකථනය, කෙටි පණිවුඩ, සම්බන්ධතා සහ දින දර්ශන අවසර වෙත ප්‍රවේශ වීමට ඉඩ දෙනු ඇත."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට යෙදුම් ප්‍රවාහ කිරීමට ඉඩ දෙන්නද?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"සම්බන්ධ වූ විට මෙම දුරකථනයේ ස්ථාපනය කර ඇති යෙදුම් වෙත ප්‍රවේශ වීමට &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; හට දුරස්ථ ප්‍රවේශය ලබා දීමට ඉඩ දෙන්න."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"සම්බන්ධ වූ විට මෙම ටැබ්ලටයේ ස්ථාපනය කර ඇති යෙදුම් වෙත ප්‍රවේශ වීමට &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; හට දුරස්ථ ප්‍රවේශය ලබා දීමට ඉඩ දෙන්න."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"සම්බන්ධ වූ විට මෙම උපාංගයේ ස්ථාපනය කර ඇති යෙදුම් වෙත ප්‍රවේශ වීමට &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; හට දුරස්ථ ප්‍රවේශය ලබා දීමට ඉඩ දෙන්න."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"යෙදුම්"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"ඔබගේ දුරකථනයේ යෙදුම් ප්‍රවාහ කරන්න"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට ඔබගේ දුරකථනයෙන් මෙම තොරතුරුවලට ප්‍රවේශ වීමට ඉඩ දෙන්න"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"හරස්-උපාංග සේවා"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට ඔබගේ දුරකථනයෙන් මෙම තොරතුරුවලට ප්‍රවේශ වීමට ඉඩ දෙන්න"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"දැනුම්දීම්"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"ඡායාරූප සහ මාධ්‍ය"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play සේවා"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"උපාංගය"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"ඉඩ දෙන්න"</string>
     <string name="consent_no" msgid="2640796915611404382">"ඉඩ නොදෙන්න"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"ඔබගේ ඔරලෝසුවට යෙදුම් අවසර මාරු කිරීම"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"ඔබගේ ඔරලෝසුව පිහිටුවීම පහසු කිරීමට, පිහිටුවීමේදී ඔබගේ ඔරලෝසුවේ ස්ථාපනය කර ඇති යෙදුම් ඔබගේ දුරකථනයට සමාන අවසර භාවිත කරනු ඇත.\n\n මෙම අවසරවලට ඔබගේ ඔරලෝසුවේ මයික්‍රෆෝනයට සහ ස්ථානයට ප්‍රවේශය ඇතුළත් විය හැකිය."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml
index dd75ef5..878d264 100644
--- a/packages/CompanionDeviceManager/res/values-sk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"Vyberte profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ktorý bude spravovať aplikácia &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> bude môcť interagovať s vašimi upozorneniami a získavať prístup k povoleniam telefónu, SMS, kontaktov a kalendára."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> bude môcť interagovať s vašimi upozorneniami a získavať prístup k povoleniam telefónu, SMS, kontaktov a kalendára."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Chcete aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; povoliť streamovanie aplikácií?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Povoľte aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; vzdialený prístup k telefónu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, aby mala po pripojení prístup k aplikáciám, ktoré sú v ňom nainštalované."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Povoľte aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; vzdialený prístup k tabletu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, aby mala po pripojení prístup k aplikáciám, ktoré sú v ňom nainštalované."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Povoľte aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; vzdialený prístup k zariadeniu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, aby mala po pripojení prístup k aplikáciám, ktoré sú v ňom nainštalované."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Aplikácie"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Streamujte aplikácie telefónu"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Povoľte aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prístup k týmto informáciám z vášho telefónu"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Služby pre viacero zariadení"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Povoľte aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prístup k týmto informáciám z vášho telefónu"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Upozornenia"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Môže čítať všetky upozornenia vrátane informácií, ako sú kontakty, správy a fotky"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotky a médiá"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Služby Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"zariadenie"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Povoliť"</string>
     <string name="consent_no" msgid="2640796915611404382">"Nepovoliť"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Presun povolení aplikácie do hodiniek"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"V rámci zjednodušenia nastavenia hodiniek budú aplikácie nainštalované do hodiniek pri nastavovaní používať rovnaké povolenia ako váš telefón.\n\n Tieto povolenia môžu zahrnovať prístup k mikrofónu a polohe hodiniek."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml
index 7cb5fb5..0734ee1 100644
--- a/packages/CompanionDeviceManager/res/values-sl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"Izbira naprave <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ki jo bo upravljala aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> bosta omogočena interakcija z obvestili in dostop do dovoljenj za telefon, sporočila SMS, stike in koledar."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> bosta omogočena interakcija z obvestili in dostop do dovoljenj za telefon, sporočila SMS, stike in koledar."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Želite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovoliti pretočno predvajanje aplikacij?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovoli oddaljen dostop do telefona &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; za dostop do aplikacij, nameščenih v tem telefonu, ko je povezan v internet."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovoli oddaljen dostop do tabličnega računalnika &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; za dostop do aplikacij, nameščenih v tem tabličnem računalniku, ko je povezan v internet."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovoli oddaljen dostop do naprave &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; za dostop do aplikacij, nameščenih v tej napravi, ko je povezana v internet."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Aplikacije"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Pretočno predvajanje aplikacij telefona"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Dovolite, da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dostopa do teh podatkov v vašem telefonu."</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Storitve za zunanje naprave"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Dovolite, da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dostopa do teh podatkov v vašem telefonu."</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Obvestila"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Lahko bere vsa obvestila, vključno s podatki, kot so stiki, sporočila in fotografije."</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotografije in predstavnost"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Storitve Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"naprava"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Dovoli"</string>
     <string name="consent_no" msgid="2640796915611404382">"Ne dovoli"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Prenos dovoljenj za aplikacije v uro"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Za lažjo nastavitev ure bodo aplikacije, ki so bile med nastavljanjem nameščene v uri, uporabljale enaka dovoljenja kot tiste v telefonu.\n\n Ta dovoljenja lahko vključujejo dostop do mikrofona in lokacije ure."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml
index 62c711a..5ae1764 100644
--- a/packages/CompanionDeviceManager/res/values-sq/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Zgjidh një profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> që do të menaxhohet nga &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> do të lejohet të ndërveprojë me njoftimet e tua dhe të ketë qasje te lejet e \"Telefonit\", \"SMS-ve\", \"Kontakteve\" dhe \"Kalendarit\"."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> do të lejohet të ndërveprojë me njoftimet e tua dhe të ketë qasje te lejet e \"Telefonit\", \"SMS-ve\", \"Kontakteve\" dhe \"Kalendarit\"."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Të lejohet që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të transmetojë aplikacionet?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të ofrojë &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; qasje në distancë për të pasur qasje në aplikacionet e instaluara në këtë telefon kur lidhet."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të ofrojë &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; qasje në distancë për të pasur qasje në aplikacionet e instaluara në këtë tablet kur lidhet."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; t\'i ofrojë &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; qasje në distancë për të pasur qasje në aplikacionet e instaluara në këtë pajisje kur lidhet."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Aplikacionet"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Transmeto aplikacionet e telefonit tënd"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të ketë qasje në këtë informacion nga telefoni yt"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Shërbimet mes pajisjeve"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të ketë qasje në këtë informacion nga telefoni yt"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Njoftimet"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Fotografitë dhe media"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Shërbimet e Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"pajisja"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Lejo"</string>
     <string name="consent_no" msgid="2640796915611404382">"Mos lejo"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfero lejet e aplikacionit te ora jote"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Për ta bërë më të lehtë konfigurimin e orës, aplikacionet e instaluara në orën tënde gjatë konfigurimit do të përdorin të njëjtat leje si telefoni yt.\n\n Këto leje mund të përfshijnë qasje në mikrofonin dhe vendndodhjen e orës."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sr/strings.xml b/packages/CompanionDeviceManager/res/values-sr/strings.xml
index 8d51c62..1d4e036 100644
--- a/packages/CompanionDeviceManager/res/values-sr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Одаберите профил <xliff:g id="PROFILE_NAME">%1$s</xliff:g> којим ће управљати апликација &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ће добити дозволу за интеракцију са обавештењима и приступ дозволама за телефон, SMS поруке, контакте и календар."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ће добити дозволу за интеракцију са обавештењима и приступ дозволама за телефон, SMS поруке, контакте и календар."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Желите да дозволите апликацији &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да стримује апликације?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Дозволите апликацији &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да даљински приступа апликацијама инсталираним на телефону &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; када је повезан."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Дозволите апликацији &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да даљински приступа апликацијама инсталираним на таблету &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; када је повезан."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Дозволите апликацији &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да даљински приступа апликацијама инсталираним на уређају &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; када је повезан."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Апликације"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Стримујте апликације на телефону"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Дозволите да &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; приступа овим информацијама са телефона"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Услуге на више уређаја"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Дозволите да &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; приступа овим информацијама са телефона"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Обавештења"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Слике и медији"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play услуге"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"уређај"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Дозволи"</string>
     <string name="consent_no" msgid="2640796915611404382">"Не дозволи"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Пренесите дозволе за апликације на сат"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Да бисмо поједноставили подешавање сата, апликације инсталиране на сату током подешавања ће користити исте дозволе као телефон.\n\n Те дозволе могу да обухватају приступ микрофону и локацији сата."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sv/strings.xml b/packages/CompanionDeviceManager/res/values-sv/strings.xml
index ca1ec87..4e85534 100644
--- a/packages/CompanionDeviceManager/res/values-sv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sv/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Välj en <xliff:g id="PROFILE_NAME">%1$s</xliff:g> för hantering av &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får behörighet att interagera med dina aviseringar och komma åt behörigheterna för Telefon, Sms, Kontakter och Kalender."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får behörighet att interagera med dina aviseringar och komma åt behörigheterna för Telefon, Sms, Kontakter och Kalender."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Vill du tillåta att &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; streamar appar?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Låt &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ge &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; fjärråtkomst till åt appar som är installerade på den här telefonen när den är ansluten."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Låt &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ge &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; fjärråtkomst till appar som är installerade på den här surfplattan när den är ansluten."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Låt &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ge &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; fjärråtkomst till appar som är installerade på den här enheten när den är ansluten."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Appar"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Streama telefonens appar"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Ge &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; åtkomstbehörighet till denna information på telefonen"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjänster för flera enheter"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Ge &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; åtkomstbehörighet till denna information på telefonen"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Aviseringar"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Foton och media"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-tjänster"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Tillåt"</string>
     <string name="consent_no" msgid="2640796915611404382">"Tillåt inte"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Överför appbehörigheter till klockan"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Appar som installeras på klockan under konfigureringen får samma behörigheter som de har på telefonen så att konfigureringen ska bli enklare.\n\n Behörigheterna kan omfatta åtkomst till klockans mikrofon och plats."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sw/strings.xml b/packages/CompanionDeviceManager/res/values-sw/strings.xml
index cf92600..5ecbef0 100644
--- a/packages/CompanionDeviceManager/res/values-sw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sw/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Chagua <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ili idhibitiwe na &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> itaruhusiwa kufikia arifa zako na kufikia ruhusa za Simu, SMS, Anwani na Kalenda yako."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> itaruhusiwa kufikia arifa zako na kufikia ruhusa za Simu, SMS, Anwani na Kalenda yako."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Ungependa kuruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; itiririshe programu?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; iipe &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ufikiaji wa mbali wa programu zilizosakinishwa kwenye simu hii wakati imeunganishwa."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; iipe &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ufikiaji wa mbali wa programu zilizosakinishwa kwenye kompyuta hii kibao wakati imeunganishwa."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; iipe &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ufikiaji wa mbali wa programu zilizosakinishwa kwenye kifaa hiki wakati kimeunganishwa."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Programu"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Tiririsha programu za simu yako"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ifikie maelezo haya kutoka kwenye simu yako"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Huduma za kifaa kilichounganishwa kwingine"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ifikie maelezo haya kutoka kwenye simu yako"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Arifa"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Picha na maudhui"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Huduma za Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"kifaa"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Ruhusu"</string>
     <string name="consent_no" msgid="2640796915611404382">"Usiruhusu"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Hamishia idhini za programu kwenye saa yako"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Ili kurahisisha kuweka mipangilio ya saa yako, programu ambazo zimesakinishwa kwenye saa yako wakati wa kuweka mipangilio zitatumia ruhusa sawa na zinazotumika kwenye simu yako.\n\n Ruhusa hizi huenda zikajumuisha ufikiaji wa maikrofoni ya saa yako na maelezo ya mahali ilipo saa yako."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ta/strings.xml b/packages/CompanionDeviceManager/res/values-ta/strings.xml
index b86ea1c..fd81674 100644
--- a/packages/CompanionDeviceManager/res/values-ta/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ta/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ஆப்ஸ் நிர்வகிக்கக்கூடிய <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ஐத் தேர்ந்தெடுங்கள்"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"உங்கள் அறிவிப்புகளைப் பார்க்கவும் மொபைல், மெசேஜ், தொடர்புகள், கேலெண்டர் ஆகியவற்றை அணுகவும் <xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸுக்கு அனுமதி வழங்கப்படும்."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"உங்கள் அறிவிப்புகளைப் பார்க்கவும் மொபைல், மெசேஜ், தொடர்புகள், கேலெண்டர் ஆகியவற்றை அணுகவும் <xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸுக்கு அனுமதி வழங்கப்படும்."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"ஆப்ஸை ஸ்ட்ரீம் செய்ய &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"இணைக்கப்பட்டிருக்கும்போது இந்த மொபைலில் நிறுவப்பட்டிருக்கும் ஆப்ஸை அணுகுவதற்கான தொலைநிலை அணுகலை &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; சாதனத்திற்கு வழங்க &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதிக்கும்."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"இணைக்கப்பட்டிருக்கும்போது இந்த டேப்லெட்டில் நிறுவப்பட்டிருக்கும் ஆப்ஸை அணுகுவதற்கான தொலைநிலை அணுகலை &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; சாதனத்திற்கு வழங்க &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதிக்கும்."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"இணைக்கப்பட்டிருக்கும்போது இந்தச் சாதனத்தில் நிறுவப்பட்டிருக்கும் ஆப்ஸை அணுகுவதற்கான தொலைநிலை அணுகலை &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; சாதனத்திற்கு வழங்க &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதிக்கும்."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"ஆப்ஸ்"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"உங்கள் மொபைலின் ஆப்ஸை ஸ்ட்ரீம் செய்யலாம்"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"மொபைலில் உள்ள இந்தத் தகவல்களை அணுக, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதிக்கவும்"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"சாதனங்களுக்கு இடையேயான சேவைகள்"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"உங்கள் மொபைலிலிருந்து இந்தத் தகவலை அணுக &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதியுங்கள்"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"அறிவிப்புகள்"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"தொடர்புகள், மெசேஜ்கள், படங்கள் போன்ற தகவல்கள் உட்பட அனைத்து அறிவிப்புகளையும் படிக்க முடியும்"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"படங்கள் மற்றும் மீடியா"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play சேவைகள்"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"சாதனம்"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"அனுமதி"</string>
     <string name="consent_no" msgid="2640796915611404382">"அனுமதிக்க வேண்டாம்"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"ஆப்ஸ் அனுமதிகளை உங்கள் வாட்ச்சிற்கு மாற்றுதல்"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"உங்கள் வாட்ச் அமைவை எளிதாக்க, உங்கள் மொபைலில் வழங்கியுள்ள அனுமதிகளையே அமைவின்போது வாட்ச்சில் நிறுவப்பட்ட ஆப்ஸும் பயன்படுத்தும்.\n\n உங்கள் வாட்ச்சிலுள்ள மைக்ரோஃபோன், இருப்பிடம் ஆகியவற்றுக்கான அணுகலும் இந்த அனுமதிகளில் அடங்கக்கூடும்."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-te/strings.xml b/packages/CompanionDeviceManager/res/values-te/strings.xml
index 73cf3e8..30d3ed7 100644
--- a/packages/CompanionDeviceManager/res/values-te/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-te/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ద్వారా మేనేజ్ చేయబడటానికి ఒక <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ను ఎంచుకోండి"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"మీ నోటిఫికేషన్‌లతో ఇంటరాక్ట్ అవ్వడానికి ఇంకా మీ ఫోన్, SMS, కాంటాక్ట్‌లు, Calendar అనుమతులను యాక్సెస్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> అనుమతించబడుతుంది."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"మీ నోటిఫికేషన్‌లతో ఇంటరాక్ట్ అవ్వడానికి ఇంకా మీ ఫోన్, SMS, కాంటాక్ట్‌లు, Calendar అనుమతులను యాక్సెస్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> అనుమతించబడుతుంది."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"యాప్‌లను స్ట్రీమ్ చేయడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ను అనుమతించాలా?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"కనెక్ట్ అయినప్పుడు ఈ ఫోన్‌లో ఇన్‌స్టాల్ చేయబడిన యాప్‌లను యాక్సెస్ చేయడానికి &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; రిమోట్ యాక్సెస్‌ను అందించడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ను అనుమతించండి."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"కనెక్ట్ అయినప్పుడు ఈ టాబ్లెట్‌లో ఇన్‌స్టాల్ చేయబడిన యాప్‌లను యాక్సెస్ చేయడానికి &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; రిమోట్ యాక్సెస్‌ను అందించడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ను అనుమతించండి."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"కనెక్ట్ అయినప్పుడు ఈ పరికరంలో ఇన్‌స్టాల్ చేయబడిన యాప్‌లను యాక్సెస్ చేయడానికి &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; రిమోట్ యాక్సెస్‌ను అందించడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ను అనుమతించండి."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"యాప్‌లు"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"మీ ఫోన్ యాప్‌లను స్ట్రీమ్ చేయండి"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"మీ ఫోన్ నుండి ఈ సమాచారాన్ని యాక్సెస్ చేయడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; యాప్‌ను అనుమతించండి"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"క్రాస్-డివైజ్ సర్వీసులు"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"మీ ఫోన్ నుండి ఈ సమాచారాన్ని యాక్సెస్ చేయడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; యాప్‌ను అనుమతించండి"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"నోటిఫికేషన్‌లు"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"ఫోటోలు, మీడియా"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play సర్వీసులు"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"పరికరం"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"అనుమతించు"</string>
     <string name="consent_no" msgid="2640796915611404382">"అనుమతించవద్దు"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"మీ వాచ్‌కు యాప్ అనుమతులను బదిలీ చేయండి"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"మీ వాచ్‌ను సెటప్ చేయడాన్ని సులభతరం చేయడానికి, సెటప్ సమయంలో మీ వాచ్‌లో ఇన్‌స్టాల్ చేయబడిన యాప్‌లు మీ ఫోన్‌లో యాప్‌లకు ఉన్న అవే అనుమతులను ఉపయోగిస్తాయి.\n\n ఈ అనుమతులతో మీ వాచ్ మైక్రోఫోన్, అలాగే లొకేషన్ కూడా ఉండవచ్చు."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-th/strings.xml b/packages/CompanionDeviceManager/res/values-th/strings.xml
index 6f29346..7fec885 100644
--- a/packages/CompanionDeviceManager/res/values-th/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-th/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"เลือก<xliff:g id="PROFILE_NAME">%1$s</xliff:g>ที่จะให้มีการจัดการโดย &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> จะได้รับอนุญาตให้โต้ตอบกับการแจ้งเตือนและได้รับสิทธิ์เข้าถึงโทรศัพท์, SMS, รายชื่อติดต่อ และปฏิทิน"</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> จะได้รับอนุญาตให้โต้ตอบกับการแจ้งเตือนและได้รับสิทธิ์เข้าถึงโทรศัพท์, SMS, รายชื่อติดต่อ และปฏิทิน"</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; สตรีมแอปพลิเคชันใช่ไหม"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; มอบสิทธิ์เข้าถึงแอปพลิเคชันที่ติดตั้งในโทรศัพท์เครื่องนี้จากระยะไกลให้แก่ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; เมื่อมีการเชื่อมต่อ"</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; มอบสิทธิ์เข้าถึงแอปพลิเคชันที่ติดตั้งในแท็บเล็ตเครื่องนี้จากระยะไกลให้แก่ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; เมื่อมีการเชื่อมต่อ"</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; มอบสิทธิ์เข้าถึงแอปพลิเคชันที่ติดตั้งในอุปกรณ์เครื่องนี้จากระยะไกลให้แก่ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; เมื่อมีการเชื่อมต่อ"</string>
+    <string name="permission_apps" msgid="6142133265286656158">"แอป"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"สตรีมแอปของโทรศัพท์คุณ"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; เข้าถึงข้อมูลนี้จากโทรศัพท์ของคุณ"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"บริการหลายอุปกรณ์"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; เข้าถึงข้อมูลนี้จากโทรศัพท์ของคุณ"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"การแจ้งเตือน"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"สามารถอ่านการแจ้งเตือนทั้งหมด รวมถึงข้อมูลอย่างรายชื่อติดต่อ ข้อความ และรูปภาพ"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"รูปภาพและสื่อ"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"บริการ Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"อุปกรณ์"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"อนุญาต"</string>
     <string name="consent_no" msgid="2640796915611404382">"ไม่อนุญาต"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"โอนสิทธิ์ของแอปไปยังนาฬิกา"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"แอปที่ติดตั้งในนาฬิการะหว่างการตั้งค่าจะใช้สิทธิ์เดียวกันกับโทรศัพท์เพื่อให้การตั้งค่านาฬิกาง่ายขึ้น\n\n สิทธิ์เหล่านี้อาจรวมการเข้าถึงไมโครโฟนและตำแหน่งของนาฬิกา"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-tl/strings.xml b/packages/CompanionDeviceManager/res/values-tl/strings.xml
index e557a38..cc68c4b 100644
--- a/packages/CompanionDeviceManager/res/values-tl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tl/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Pumili ng <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para pamahalaan ng &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"Papayagan ang <xliff:g id="APP_NAME">%1$s</xliff:g> na makipag-ugnayan sa mga notification mo at ma-access ang iyong mga pahintulot sa Telepono, SMS, Mga Contact, at Kalendaryo."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Papayagan ang <xliff:g id="APP_NAME">%1$s</xliff:g> na makipag-ugnayan sa mga notification mo at ma-access ang iyong mga pahintulot sa Telepono, SMS, Mga Contact, at Kalendaryo."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na mag-stream ng mga application?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na bigyan ang &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ng malayuang access para ma-access ang mga application na naka-install sa teleponong ito kapag nakakonekta."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na bigyan ang &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ng malayuang access para ma-access ang mga application na naka-install sa tablet na ito kapag nakakonekta."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na bigyan ang &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ng malayuang access para ma-access ang mga application na naka-install sa device na ito kapag nakakonekta."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Mga App"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"I-stream ang mga app ng iyong telepono"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na i-access ang impormasyong ito sa iyong telepono"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Mga cross-device na serbisyo"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na i-access ang impormasyon sa iyong telepono"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Mga Notification"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Mga larawan at media"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Mga serbisyo ng Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Payagan"</string>
     <string name="consent_no" msgid="2640796915611404382">"Huwag payagan"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Ilipat sa iyong relo ang mga pahintulot sa app"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Para gawing mas madali na i-set up ang iyong relo, gagamitin ng mga app na naka-install sa relo mo sa oras ng pag-set up ang mga pahintulot na ginagamit din sa iyong telepono.\n\n Posibleng kasama sa mga pahintulot na ito ang access sa mikropono at lokasyon ng iyong relo."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml
index c75214b..79a50ec1 100644
--- a/packages/CompanionDeviceManager/res/values-tr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; tarafından yönetilecek bir <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> adlı uygulamanın bildirimlerinizle etkileşimde bulunup Telefon, SMS, Kişiler ve Takvim izinlerinize erişmesine izin verilir."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> adlı uygulamanın bildirimlerinizle etkileşimde bulunup Telefon, SMS, Kişiler ve Takvim izinlerinize erişmesine izin verilir."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasının, uygulamalarda akış gerçekleştirmesine izin verilsin mi?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasının, internete bağlanan bu telefondaki yüklü uygulamalara erişebilmesi için &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; adlı cihaza uzaktan erişim izni verin."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasının, internete bağlanan bu tabletteki yüklü uygulamalara erişebilmesi için &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; adlı cihaza uzaktan erişim izni verin."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasının, internete bağlanan bu cihazdaki yüklü uygulamalara erişebilmesi için &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; adlı cihaza uzaktan erişim izni verin."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Uygulamalar"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Telefonunuzun uygulamalarını akışla aktarın"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasının, telefonunuzdaki bu bilgilere erişmesine izin verin"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cihazlar arası hizmetler"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasının, telefonunuzdaki bu bilgilere erişmesine izin verin"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Bildirimler"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Fotoğraflar ve medya"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play hizmetleri"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"İzin ver"</string>
     <string name="consent_no" msgid="2640796915611404382">"İzin verme"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Uygulama izinlerini saatinize aktarma"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Kurulum sırasında saatinize yüklenen uygulamalar, saat kurulumunuzu kolaylaştırmak için telefonunuzla aynı izinleri kullanır.\n\n Saatinizin mikrofonuna ve konumuna erişim bu izinlere dahil olabilir."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-uk/strings.xml b/packages/CompanionDeviceManager/res/values-uk/strings.xml
index 46a25b2..891cf60 100644
--- a/packages/CompanionDeviceManager/res/values-uk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uk/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Виберіть <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, яким керуватиме додаток &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> зможе взаємодіяти з вашими сповіщеннями та отримає дозволи \"Телефон\", \"SMS\", \"Контакти\" й \"Календар\"."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> зможе взаємодіяти з вашими сповіщеннями та отримає дозволи \"Телефон\", \"SMS\", \"Контакти\" й \"Календар\"."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Дозволити додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; транслювати інші додатки?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Дозвольте додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; за наявності з’єднання надавати пристрою &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; віддалений доступ до додатків, установлених на цьому телефоні."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Дозвольте додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; за наявності з’єднання надавати пристрою &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; віддалений доступ до додатків, установлених на цьому планшеті."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Дозвольте додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; за наявності з’єднання надавати пристрою &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; віддалений доступ до додатків, установлених на цьому пристрої."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Додатки"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Транслювати додатки телефона"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Надайте додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; доступ до цієї інформації з телефона"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Сервіси для кількох пристроїв"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Надайте додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; доступ до цієї інформації з телефона"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Сповіщення"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Фотографії та медіафайли"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Сервіси Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"пристрій"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Дозволити"</string>
     <string name="consent_no" msgid="2640796915611404382">"Не дозволяти"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Перенести дозволи для додатків на годинник"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Задля зручності додатки, установлені на годиннику протягом налаштування, використовуватимуть ті самі дозволи, що й на телефоні.\n\n До таких дозволів може належати доступ до мікрофона й геоданих годинника."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ur/strings.xml b/packages/CompanionDeviceManager/res/values-ur/strings.xml
index c9f930f..a6f2d7b 100644
--- a/packages/CompanionDeviceManager/res/values-ur/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ur/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"‏&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; کے ذریعے نظم کئے جانے کیلئے <xliff:g id="PROFILE_NAME">%1$s</xliff:g> کو منتخب کریں"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"‏<xliff:g id="APP_NAME">%1$s</xliff:g> کو آپ کی اطلاعات کے ساتھ تعامل کرنے اور آپ کے فون، SMS، رابطوں اور کیلنڈر کی اجازتوں تک رسائی کی اجازت ہوگی۔"</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"‏<xliff:g id="APP_NAME">%1$s</xliff:g> کو آپ کی اطلاعات کے ساتھ تعامل کرنے اور آپ کے فون، SMS، رابطوں اور کیلنڈر کی اجازتوں تک رسائی کی اجازت ہوگی۔"</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"‏&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو ایپلیکیشنز کی سلسلہ بندی کرنے کی اجازت دیں؟"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"‏منسلک ہونے پر، اس فون پر انسٹال کردہ ایپلیکیشنز تک رسائی حاصل کرنے کے لیے &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‏&lt;/strong&gt; کے لیے ریموٹ تک رسائی فراہم کرنے کی اجازت دیں۔"</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"‏منسلک ہونے پر، اس ٹیبلیٹ پر انسٹال کردہ ایپلیکیشنز تک رسائی حاصل کرنے کے لیے &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‏&lt;/strong&gt; کے لیے ریموٹ تک رسائی فراہم کرنے کی اجازت دیں۔"</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"‏منسلک ہونے پر، اس آلے پر انسٹال کردہ ایپلیکیشنز تک رسائی حاصل کرنے کے لیے &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‏&lt;/strong&gt; کے لیے ریموٹ تک رسائی فراہم کرنے کی اجازت دیں۔"</string>
+    <string name="permission_apps" msgid="6142133265286656158">"ایپس"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"اپنے فون کی ایپس کی سلسلہ بندی کریں"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"‏‎&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;‎ کو اپنے فون سے ان معلومات تک رسائی حاصل کرنے کی اجازت دیں"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"کراس آلے کی سروس"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"‏اپنے فون سے اس معلومات تک رسائی حاصل Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کرنے کی اجازت دیں"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"اطلاعات"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"تصاویر اور میڈیا"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"‏Google Play سروسز"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"آلہ"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"اجازت دیں"</string>
     <string name="consent_no" msgid="2640796915611404382">"اجازت نہ دیں"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"اپنی گھڑی پر ایپ کی اجازتیں منتقل کریں"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"آپ کی گھڑی کو سیٹ اپ کرنے کے عمل کو زیادہ آسان بنانے کے لیے، سیٹ اپ کے دوران آپ کی گھڑی پر انسٹال کردہ ایپس انہیں اجازتوں کا استعمال کریں گی جن کا استعمال آپ کا فون کرتا ہے۔\n\n ان اجازتوں میں آپ کی گھڑی کے مائیکروفون اور مقام تک کی رسائی شامل ہو سکتی ہے۔"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-uz/strings.xml b/packages/CompanionDeviceManager/res/values-uz/strings.xml
index 91fdd94..cc7ca6e 100644
--- a/packages/CompanionDeviceManager/res/values-uz/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uz/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; boshqaradigan <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qurilmasini tanlang"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga bildirishnomalar bilan ishlash va telefon, SMS, kontaktlar va taqvimga kirishga ruxsat beriladi"</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga bildirishnomalar bilan ishlash va telefon, SMS, kontaktlar va taqvimga kirishga ruxsat beriladi"</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga ilovalarni strim qilishi uchun ruxsat berilsinmi?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ulanganda ushbu telefonda oʻrnatilgan ilovalarga masofadan kirish ruxsatini bering."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ulanganda ushbu planshetda oʻrnatilgan ilovalarga masofadan kirish ruxsatini bering."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ulanganda ushbu qurilmada oʻrnatilgan ilovalarga masofadan kirish ruxsatini bering."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Ilovalar"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Telefondagi ilovalarni translatsiya qilish"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga telefondagi ushbu maʼlumot uchun ruxsat bering"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Qurilmalararo xizmatlar"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga telefondagi ushbu maʼlumot uchun ruxsat bering"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Bildirishnomalar"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Barcha bildirishnomalarni, jumladan, kontaktlar, xabarlar va suratlarni oʻqishi mumkin"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Suratlar va media"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play xizmatlari"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"qurilma"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Ruxsat"</string>
     <string name="consent_no" msgid="2640796915611404382">"Ruxsat berilmasin"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Ilova uchun ruxsatlarni soatingizga uzating"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Soatingizni sozlashni qulaylashtirish maqsadida sozlash paytida soatingizga oʻrnatilgan ilovalar telefoningiz bilan bir xil ruxsatlardan foydalanadi.\n\n Bunday ruxsatlarga soatingiz mikrofoni va joylashuv axborotiga ruxsatlar kirishi mumkin."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-vi/strings.xml b/packages/CompanionDeviceManager/res/values-vi/strings.xml
index 4f96bd4..9e62d83 100644
--- a/packages/CompanionDeviceManager/res/values-vi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-vi/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"Chọn một <xliff:g id="PROFILE_NAME">%1$s</xliff:g> sẽ do &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; quản lý"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> sẽ được phép tương tác với thông báo cũng như truy cập vào Điện thoại, SMS, Danh bạ và Lịch."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> sẽ được phép tương tác với thông báo cũng như truy cập vào Điện thoại, SMS, Danh bạ và Lịch."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truyền trực tuyến ứng dụng?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập từ xa vào các ứng dụng đã cài đặt trên &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; khi điện thoại này có kết nối."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập từ xa vào các ứng dụng đã cài đặt trên &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; khi máy tính bảng này có kết nối."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập từ xa vào các ứng dụng đã cài đặt trên &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; khi thiết bị này có kết nối."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Ứng dụng"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Truyền các ứng dụng trên điện thoại của bạn"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập vào thông tin này trên điện thoại của bạn"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Dịch vụ trên nhiều thiết bị"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập vào thông tin này trên điện thoại của bạn"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Thông báo"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"Ảnh và nội dung nghe nhìn"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Dịch vụ Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"thiết bị"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Cho phép"</string>
     <string name="consent_no" msgid="2640796915611404382">"Không cho phép"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Chuyển quyền cho ứng dụng sang đồng hồ"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Để thiết lập đồng hồ dễ dàng hơn, trong quá trình thiết lập, các ứng dụng được cài đặt trên đồng hồ của bạn sẽ sử dụng các quyền giống như trên điện thoại.\n\n Các quyền này có thể bao gồm quyền sử dụng micrô và thông tin vị trí của đồng hồ."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
index 3fdccf2..2c8d7b4 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"选择要由&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”将能与通知互动,并可访问电话、短信、通讯录和日历。"</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”将能与通知互动,并可访问电话、短信、通讯录和日历。"</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"是否允许 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 流式传输应用?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"在 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; 连接到网络后,允许 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 远程访问该手机上安装的应用。"</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"在 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; 连接到网络后,允许 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 远程访问该平板电脑上安装的应用。"</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"在 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; 连接到网络后,允许 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 远程访问该设备上安装的应用。"</string>
+    <string name="permission_apps" msgid="6142133265286656158">"应用"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"流式传输手机的应用内容"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"允许“<xliff:g id="APP_NAME">%1$s</xliff:g>”&lt;strong&gt;&lt;/strong&gt;访问您手机中的这项信息"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"跨设备服务"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"允许 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 访问您手机中的这项信息"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"通知"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"照片和媒体内容"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 服务"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"设备"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"允许"</string>
     <string name="consent_no" msgid="2640796915611404382">"不允许"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"将应用权限转让给手表"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"为了让您更轻松地设置手表,在设置过程中安装在手表上的应用将使用与手机相同的权限。\n\n这些权限可能包括使用手表的麦克风和位置信息。"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
index a4dc0c9..3219f20 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"選擇由 &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; 管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知、電話、短訊、聯絡人和日曆資料。"</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知、電話、短訊、聯絡人和日曆資料。"</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;串流播放應用程式的內容嗎?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」連線時可透過遠端方式存取此手機上安裝的應用程式。"</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」連線時可透過遠端方式存取此平板電腦上安裝的應用程式。"</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」連線時可透過遠端方式存取此裝置上安裝的應用程式。"</string>
+    <string name="permission_apps" msgid="6142133265286656158">"應用程式"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"串流播放手機應用程式內容"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;存取您手機中的這項資料"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"跨裝置服務"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;存取您手機中的這項資料"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"通知"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"相片和媒體"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 服務"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"允許"</string>
     <string name="consent_no" msgid="2640796915611404382">"不允許"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"將應用程式權限轉移至手錶"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"為簡化手錶的設定程序,在設定過程中安裝到手錶上的應用程式都將沿用手機上的權限。\n\n這些權限可能包括手錶麥克風和位置的存取權。"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
index eec0424..83176d4 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
@@ -22,18 +22,30 @@
     <string name="chooser_title" msgid="2262294130493605839">"選擇要讓「<xliff:g id="APP_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知、電話、簡訊、聯絡人和日曆資料。"</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知、電話、簡訊、聯絡人和日曆資料。"</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;串流播放應用程式的內容嗎?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;連上網際網路時可從遠端存取該手機上安裝的應用程式。"</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;連上網際網路時可從遠端存取該平板電腦上安裝的應用程式。"</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;連上網際網路時可從遠端存取該裝置上安裝的應用程式。"</string>
+    <string name="permission_apps" msgid="6142133265286656158">"應用程式"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"串流傳輸手機應用程式內容"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;存取手機中的這項資訊"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"跨裝置服務"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;存取你手機中的這項資訊"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"通知"</string>
+    <!-- no translation found for permission_notification_summary (884075314530071011) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"相片和媒體"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 服務"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"允許"</string>
     <string name="consent_no" msgid="2640796915611404382">"不允許"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"將應用程式權限轉移到手錶上"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"為簡化手錶的設定程序,只要是在設定過程中安裝到手錶上的應用程式,都將沿用手機上的權限。\n\n 這些權限可能包括手錶的麥克風和位置資訊存取權。"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-zu/strings.xml b/packages/CompanionDeviceManager/res/values-zu/strings.xml
index be5a195..3f5031f 100644
--- a/packages/CompanionDeviceManager/res/values-zu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zu/strings.xml
@@ -22,18 +22,29 @@
     <string name="chooser_title" msgid="2262294130493605839">"Khetha i-<xliff:g id="PROFILE_NAME">%1$s</xliff:g> ezophathwa yi-&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_watch" product="default" msgid="7113724443198337683">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> izovunyelwa ukuxhumana nezaziso zakho futhi ifinyelele izimvume Zefoni yakho, -SMS, Abathintwayo kanye Nekhalenda."</string>
     <string name="summary_watch" product="tablet" msgid="7113724443198337683">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> izovunyelwa ukuxhumana nezaziso zakho futhi ifinyelele izimvume Zefoni yakho, -SMS, Abathintwayo kanye Nekhalenda."</string>
-    <string name="title_app_streaming" msgid="4459136600249308574">"Vumela &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukusakaza ama-applications?"</string>
-    <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Vumela &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukunikezela &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ngokufinyelela kwerimothi kuma-applications afakiwe kule foni uma ixhunyiwe."</string>
-    <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Vumela &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukunikezela &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ngokufinyelela kwerimothi kuma-applications afakiwe kule thebhulethi uma ixhunyiwe."</string>
-    <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Vumela &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukunikezela &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ngokufinyelela kwerimothi kuma-applications afakiwe kule divayisi uma ixhunyiwe."</string>
+    <string name="permission_apps" msgid="6142133265286656158">"Ama-app"</string>
+    <string name="permission_apps_summary" msgid="798718816711515431">"Sakaza ama-app wefoni yakho"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Vumela i-&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ifinyelele lolu lwazi kusukela efonini yakho"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Amasevisi amadivayisi amaningi"</string>
+    <!-- no translation found for helper_summary_app_streaming (7380294597268573523) -->
+    <skip />
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Vumela &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukufinyelela lolu lwazi kusuka efonini yakho"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
+    <string name="permission_notification" msgid="693762568127741203">"Izaziso"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Ingafunda zonke izaziso, okubandakanya ulwazi olufana noxhumana nabo, imilayezo, nezithombe"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Izithombe nemidiya"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Amasevisi we-Google Play"</string>
+    <!-- no translation found for helper_summary_computer (1676407599909474428) -->
+    <skip />
     <string name="profile_name_generic" msgid="6851028682723034988">"idivayisi"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"Vumela"</string>
     <string name="consent_no" msgid="2640796915611404382">"Ungavumeli"</string>
+    <!-- no translation found for consent_back (2560683030046918882) -->
+    <skip />
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Dlulisela izimvume ze-app ewashini lakho"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"Ukuze wenze kube lula ukusetha iwashi lakho, ama-app afakwe ewashini lakho phakathi nokusetha azosebenzisa izimvume ezifanayo nezefoni yakho.\n\n Lezi zimvume zingabandakanya ukufinyelela kumakrofoni nendawo yewashi lakho."</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml
index 55a1998..586a022 100644
--- a/packages/CompanionDeviceManager/res/values/strings.xml
+++ b/packages/CompanionDeviceManager/res/values/strings.xml
@@ -47,20 +47,11 @@
     <!-- Confirmation for associating an application with a companion device of APP_STREAMING profile (type) [CHAR LIMIT=NONE] -->
     <string name="title_app_streaming">Allow &lt;strong&gt;<xliff:g id="app_name" example="Exo">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone</string>
 
-    <!-- Description of the privileges the application will get if associated with the companion device of APP_STREAMING profile (type) [CHAR LIMIT=NONE] -->
-    <string name="summary_app_streaming" product="default">Let &lt;strong&gt;<xliff:g id="app_name" example="Exo">%1$s</xliff:g>&lt;/strong&gt; to provide &lt;strong&gt;<xliff:g id="device_name" example="Pixelbook Go">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this phone when connected.</string>
-
-    <!-- Description of the privileges the application will get if associated with the companion device of APP_STREAMING profile (type) [CHAR LIMIT=NONE] -->
-    <string name="summary_app_streaming" product="tablet">Let &lt;strong&gt;<xliff:g id="app_name" example="Exo">%1$s</xliff:g>&lt;/strong&gt; to provide &lt;strong&gt;<xliff:g id="device_name" example="Pixelbook Go">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this tablet when connected.</string>
-
-    <!-- Description of the privileges the application will get if associated with the companion device of APP_STREAMING profile (type) [CHAR LIMIT=NONE] -->
-    <string name="summary_app_streaming" product="device">Let &lt;strong&gt;<xliff:g id="app_name" example="Exo">%1$s</xliff:g>&lt;/strong&gt; to provide &lt;strong&gt;<xliff:g id="device_name" example="Pixelbook Go">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this device when connected.</string>
-
     <!-- Title of the helper dialog for APP_STREAMING profile [CHAR LIMIT=30]. -->
     <string name="helper_title_app_streaming">Cross-device services</string>
 
     <!-- Description of the helper dialog for APP_STREAMING profile. [CHAR LIMIT=NONE] -->
-    <string name="helper_summary_app_streaming">This service is used to stream apps between your devices</string>
+    <string name="helper_summary_app_streaming"><xliff:g id="app_name" example="GMS">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="device_type" example="Chromebook">%2$s</xliff:g> to access your phone\u2019s photos, media, and notifications</string>
 
     <!-- ================= DEVICE_PROFILE_AUTOMOTIVE_PROJECTION ================= -->
 
@@ -82,7 +73,7 @@
     <string name="permission_notification">Notifications</string>
 
     <!-- Description of notification permission of COMPUTER profile [CHAR LIMIT=NONE] -->
-    <string name="permission_notification_summary">Can read all notifications, including information like contracts, messages, and photos</string>
+    <string name="permission_notification_summary">Can read all notifications, including information like contacts, messages, and photos</string>
 
     <!-- Storage permission will be granted of COMPUTER profile [CHAR LIMIT=30] -->
     <string name="permission_storage">Photos and media</string>
@@ -94,10 +85,7 @@
     <string name="helper_title_computer">Google Play services</string>
 
     <!-- Description of the helper dialog for COMPUTER profile. [CHAR LIMIT=NONE] -->
-    <string name="helper_summary_computer" product="default">This service shares photos, media, and notifications form your phone to other devices</string>
-
-    <!-- Description of the helper dialog for COMPUTER profile. [CHAR LIMIT=NONE] -->
-    <string name="helper_summary_computer" product="tablet">This service shares photos, media, and notifications form your phone to other devices</string>
+    <string name="helper_summary_computer"> <xliff:g id="app_name" example="GMS">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="device_type" example="Chromebook">%2$s</xliff:g> to stream apps between your devices</string>
 
     <!-- ================= null profile ================= -->
 
@@ -115,8 +103,8 @@
     <!-- Negative button for the device-app association consent dialog [CHAR LIMIT=30] -->
     <string name="consent_no">Don\u2019t allow</string>
 
-    <!-- Ok button for the helper consent dialog [CHAR LIMIT=30] -->
-    <string name="consent_ok">OK</string>
+    <!-- Back button for the helper consent dialog [CHAR LIMIT=30] -->
+    <string name="consent_back">Back</string>
 
     <!-- ================== System data transfer ==================== -->
     <!-- Title of the permission sync confirmation dialog. [CHAR LIMIT=60] -->
diff --git a/packages/CompanionDeviceManager/res/values/styles.xml b/packages/CompanionDeviceManager/res/values/styles.xml
index 4a267db..faa3032 100644
--- a/packages/CompanionDeviceManager/res/values/styles.xml
+++ b/packages/CompanionDeviceManager/res/values/styles.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Copyright (C) 2022 The Android Open Source Project
   ~
@@ -16,53 +17,95 @@
 
 <resources>
     <style name="ContainerLayout">
-        <item name="android:padding">18dp</item>
-        <item name="android:elevation">16dp</item>
-        <item name="android:maxHeight">400dp</item>
-        <item name="android:orientation">vertical</item>
-        <item name="android:layout_gravity">center</item>
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">wrap_content</item>
+        <item name="android:orientation">vertical</item>
+        <item name="android:layout_gravity">center</item>
+        <item name="android:minWidth">340dp</item>
         <item name="android:background">@drawable/dialog_background</item>
     </style>
 
-    <style name="VendorHelperOkButton"
-           parent="@android:style/Widget.Material.Button.Borderless.Colored">
-        <item name="android:layout_width">50dp</item>
-        <item name="android:layout_height">35dp</item>
-        <item name="android:layout_marginTop">20dp</item>
-        <item name="android:textColor">@android:color/system_neutral1_900</item>
-        <item name="android:background">@drawable/helper_ok_button</item>
-    </style>
-
-    <style name="NegativeButton"
-           parent="@android:style/Widget.Material.Button.Borderless.Colored">
+    <style name="Description">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">wrap_content</item>
-        <item name="android:textAllCaps">false</item>
+        <item name="android:orientation">vertical</item>
+        <item name="android:layout_marginTop">18dp</item>
+        <item name="android:layout_marginBottom">18dp</item>
+        <item name="android:layout_marginLeft">24dp</item>
+        <item name="android:layout_marginRight">24dp</item>
+    </style>
+
+    <style name="DescriptionTitle"
+           parent="@*android:style/TextAppearance.Widget.Toolbar.Title">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:gravity">center</item>
+        <item name="android:layout_marginLeft">14dp</item>
+        <item name="android:layout_marginRight">14dp</item>
+        <item name="android:textSize">20sp</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+    </style>
+
+    <style name="DescriptionSummary">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:gravity">center</item>
+        <item name="android:layout_marginTop">18dp</item>
+        <item name="android:layout_marginLeft">18dp</item>
+        <item name="android:layout_marginRight">18dp</item>
         <item name="android:textSize">14sp</item>
+        <item name="android:textColor">?android:attr/textColorSecondary</item>
+    </style>
+
+    <style name="VendorHelperBackButton"
+           parent="@android:style/Widget.Material.Button.Borderless.Colored">
+        <item name="android:layout_width">60dp</item>
+        <item name="android:layout_height">36dp</item>
+        <item name="android:layout_marginTop">20dp</item>
+        <item name="android:textAllCaps">false</item>
         <item name="android:textColor">@android:color/system_neutral1_900</item>
-        <item name="android:background">@drawable/btn_negative_top</item>
+        <item name="android:background">@drawable/helper_back_button</item>
     </style>
 
     <style name="PositiveButton"
            parent="@android:style/Widget.Material.Button.Borderless.Colored">
-        <item name="android:layout_width">match_parent</item>
-        <item name="android:layout_height">wrap_content</item>
+        <item name="android:layout_width">300dp</item>
+        <item name="android:layout_height">56dp</item>
+        <item name="android:layout_marginLeft">24dp</item>
+        <item name="android:layout_marginRight">24dp</item>
+        <item name="android:layout_marginBottom">2dp</item>
+        <item name="android:textAllCaps">false</item>
+        <item name="android:textSize">14sp</item>
+        <item name="android:textColor">@android:color/system_neutral1_900</item>
+        <item name="android:background">@drawable/btn_positive_bottom</item>
+    </style>
+
+    <style name="NegativeButton"
+           parent="@android:style/Widget.Material.Button.Borderless.Colored">
+        <item name="android:layout_width">300dp</item>
+        <item name="android:layout_height">56dp</item>
+        <item name="android:layout_marginLeft">24dp</item>
+        <item name="android:layout_marginRight">24dp</item>
+        <item name="android:layout_marginTop">2dp</item>
         <item name="android:textAllCaps">false</item>
         <item name="android:textSize">14sp</item>
         <item name="android:textColor">@android:color/system_neutral1_900</item>
         <item name="android:layout_marginTop">4dp</item>
-        <item name="android:background">@drawable/btn_positive_bottom</item>
+        <item name="android:background">@drawable/btn_negative_top</item>
     </style>
 
     <style name="NegativeButtonMultipleDevices"
            parent="@android:style/Widget.Material.Button.Colored">
         <item name="android:layout_width">100dp</item>
-        <item name="android:layout_height">35dp</item>
-        <item name="android:layout_marginTop">20dp</item>
+        <item name="android:layout_height">36dp</item>
         <item name="android:textAllCaps">false</item>
         <item name="android:background">@drawable/btn_negative_multiple_devices</item>
     </style>
 
+    <style name="DeviceListBorder">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">1dp</item>
+        <item name="android:background">@android:color/system_accent1_300</item>
+    </style>
+
 </resources>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index 0ab126a..b596816 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -20,6 +20,12 @@
 import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
 import static android.companion.AssociationRequest.DEVICE_PROFILE_COMPUTER;
 import static android.companion.AssociationRequest.DEVICE_PROFILE_WATCH;
+import static android.companion.CompanionDeviceManager.REASON_CANCELED;
+import static android.companion.CompanionDeviceManager.REASON_DISCOVERY_TIMEOUT;
+import static android.companion.CompanionDeviceManager.REASON_USER_REJECTED;
+import static android.companion.CompanionDeviceManager.RESULT_DISCOVERY_TIMEOUT;
+import static android.companion.CompanionDeviceManager.RESULT_INTERNAL_ERROR;
+import static android.companion.CompanionDeviceManager.RESULT_USER_REJECTED;
 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
 
 import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DiscoveryState;
@@ -29,8 +35,10 @@
 import static com.android.companiondevicemanager.PermissionListAdapter.TYPE_STORAGE;
 import static com.android.companiondevicemanager.Utils.getApplicationLabel;
 import static com.android.companiondevicemanager.Utils.getHtmlFromResources;
+import static com.android.companiondevicemanager.Utils.getIcon;
 import static com.android.companiondevicemanager.Utils.getVendorHeaderIcon;
 import static com.android.companiondevicemanager.Utils.getVendorHeaderName;
+import static com.android.companiondevicemanager.Utils.hasVendorIcon;
 import static com.android.companiondevicemanager.Utils.prepareResultReceiverForIpc;
 
 import static java.util.Objects.requireNonNull;
@@ -56,6 +64,7 @@
 import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
+import android.widget.ProgressBar;
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
@@ -87,9 +96,6 @@
 
     private static final String FRAGMENT_DIALOG_TAG = "fragment_dialog";
 
-    // Activity result: Internal Error.
-    private static final int RESULT_INTERNAL_ERROR = 2;
-
     // AssociationRequestsProcessor -> UI
     private static final int RESULT_CODE_ASSOCIATION_CREATED = 0;
     private static final String EXTRA_ASSOCIATION = "association";
@@ -106,23 +112,27 @@
     private TextView mTitle;
     private TextView mSummary;
 
+    // Present for single device and multiple device only.
+    private ImageView mProfileIcon;
+
     // Only present for selfManaged devices.
     private ImageView mVendorHeaderImage;
     private TextView mVendorHeaderName;
     private ImageButton mVendorHeaderButton;
 
     // Progress indicator is only shown while we are looking for the first suitable device for a
-    // "regular" (ie. not self-managed) association.
-    private View mProgressIndicator;
+    // multiple device association.
+    private ProgressBar mProgressIndicator;
 
     // Present for self-managed association requests and "single-device" regular association
     // regular.
     private Button mButtonAllow;
     private Button mButtonNotAllow;
-    // Present for multiple devices association requests only.
+    // Present for multiple devices' association requests only.
     private Button mButtonNotAllowMultipleDevices;
 
     private LinearLayout mAssociationConfirmationDialog;
+    private LinearLayout mMultipleDeviceList;
     private RelativeLayout mVendorHeader;
 
     // The recycler view is only shown for multiple-device regular association request, after
@@ -130,6 +140,7 @@
     private @Nullable RecyclerView mDeviceListRecyclerView;
     private @Nullable DeviceListAdapter mDeviceAdapter;
 
+
     // The recycler view is only shown for selfManaged association request.
     private @Nullable RecyclerView mPermissionListRecyclerView;
     private @Nullable PermissionListAdapter mPermissionListAdapter;
@@ -202,7 +213,7 @@
 
         // TODO: handle config changes without cancelling.
         if (!isDone()) {
-            cancel(false); // will finish()
+            cancel(/* discoveryTimeOut */ false, /* userRejected */ false); // will finish()
         }
     }
 
@@ -243,17 +254,22 @@
 
         setContentView(R.layout.activity_confirmation);
 
+        mMultipleDeviceList = findViewById(R.id.multiple_device_list);
         mAssociationConfirmationDialog = findViewById(R.id.activity_confirmation);
         mVendorHeader = findViewById(R.id.vendor_header);
 
         mTitle = findViewById(R.id.title);
         mSummary = findViewById(R.id.summary);
 
+        mProfileIcon = findViewById(R.id.profile_icon);
+
         mVendorHeaderImage = findViewById(R.id.vendor_header_image);
         mVendorHeaderName = findViewById(R.id.vendor_header_name);
         mVendorHeaderButton = findViewById(R.id.vendor_header_button);
 
         mDeviceListRecyclerView = findViewById(R.id.device_list);
+
+        mProgressIndicator = findViewById(R.id.spinner);
         mDeviceAdapter = new DeviceListAdapter(this, this::onListItemClick);
 
         mPermissionListRecyclerView = findViewById(R.id.permission_list);
@@ -270,7 +286,7 @@
         mVendorHeaderButton.setOnClickListener(this::onShowHelperDialog);
 
         if (mRequest.isSelfManaged()) {
-            initUiForSelfManagedAssociation(appLabel);
+            initUiForSelfManagedAssociation();
         } else if (mRequest.isSingleDevice()) {
             initUiForSingleDevice(appLabel);
         } else {
@@ -281,7 +297,7 @@
     private void onDiscoveryStateChanged(DiscoveryState newState) {
         if (newState == FINISHED_TIMEOUT
                 && CompanionDeviceDiscoveryService.getScanResult().getValue().isEmpty()) {
-            cancel(true);
+            cancel(/* discoveryTimeOut */ true, /* userRejected */ false);
         }
     }
 
@@ -324,10 +340,12 @@
         setResultAndFinish(association, RESULT_OK);
     }
 
-    private void cancel(boolean discoveryTimeout) {
+    private void cancel(boolean discoveryTimeout, boolean userRejected) {
         if (DEBUG) {
-            Log.i(TAG, "cancel(), discoveryTimeout=" + discoveryTimeout,
-                    new Exception("Stack Trace Dump"));
+            Log.i(TAG, "cancel(), discoveryTimeout="
+                    + discoveryTimeout
+                    + ", userRejected="
+                    + userRejected, new Exception("Stack Trace Dump"));
         }
 
         if (isDone()) {
@@ -341,14 +359,27 @@
             CompanionDeviceDiscoveryService.stop(this);
         }
 
+        final String cancelReason;
+        final int resultCode;
+        if (userRejected) {
+            cancelReason = REASON_USER_REJECTED;
+            resultCode = RESULT_USER_REJECTED;
+        } else if (discoveryTimeout) {
+            cancelReason = REASON_DISCOVERY_TIMEOUT;
+            resultCode = RESULT_DISCOVERY_TIMEOUT;
+        } else {
+            cancelReason = REASON_CANCELED;
+            resultCode = RESULT_CANCELED;
+        }
+
         // First send callback to the app directly...
         try {
-            mAppCallback.onFailure(discoveryTimeout ? "Timeout." : "Cancelled.");
+            mAppCallback.onFailure(cancelReason);
         } catch (RemoteException ignore) {
         }
 
         // ... then set result and finish ("sending" onActivityResult()).
-        setResultAndFinish(null, RESULT_CANCELED);
+        setResultAndFinish(null, resultCode);
     }
 
     private void setResultAndFinish(@Nullable AssociationInfo association, int resultCode) {
@@ -366,7 +397,7 @@
         finish();
     }
 
-    private void initUiForSelfManagedAssociation(CharSequence appLabel) {
+    private void initUiForSelfManagedAssociation() {
         if (DEBUG) Log.i(TAG, "initUiFor_SelfManaged_Association()");
 
         final CharSequence deviceName = mRequest.getDisplayName();
@@ -382,6 +413,12 @@
         try {
             vendorIcon = getVendorHeaderIcon(this, packageName, userId);
             vendorName = getVendorHeaderName(this, packageName, userId);
+
+            mVendorHeaderImage.setImageDrawable(vendorIcon);
+            if (hasVendorIcon(this, packageName, userId)) {
+                mVendorHeaderImage.setColorFilter(getResources().getColor(
+                                android.R.color.system_accent1_600, /* Theme= */null));
+            }
         } catch (PackageManager.NameNotFoundException e) {
             Log.e(TAG, "Package u" + userId + "/" + packageName + " not found.");
             setResultAndFinish(null, RESULT_INTERNAL_ERROR);
@@ -416,10 +453,9 @@
         mPermissionListRecyclerView.setLayoutManager(new LinearLayoutManager(this));
 
         mTitle.setText(title);
-        mVendorHeaderImage.setImageDrawable(vendorIcon);
         mVendorHeaderName.setText(vendorName);
-
         mDeviceListRecyclerView.setVisibility(View.GONE);
+        mProfileIcon.setVisibility(View.GONE);
         mVendorHeader.setVisibility(View.VISIBLE);
     }
 
@@ -447,17 +483,22 @@
         final Spanned title = getHtmlFromResources(
                 this, R.string.confirmation_title, appLabel, deviceName);
         final Spanned summary;
+        final Drawable profileIcon;
 
         if (deviceProfile == null) {
             summary = getHtmlFromResources(this, R.string.summary_generic);
+            profileIcon = getIcon(this, R.drawable.ic_device_other);
+            mSummary.setVisibility(View.GONE);
         } else if (deviceProfile.equals(DEVICE_PROFILE_WATCH)) {
             summary = getHtmlFromResources(this, R.string.summary_watch, appLabel, deviceName);
+            profileIcon = getIcon(this, R.drawable.ic_watch);
         } else {
             throw new RuntimeException("Unsupported profile " + deviceProfile);
         }
 
         mTitle.setText(title);
         mSummary.setText(summary);
+        mProfileIcon.setImageDrawable(profileIcon);
     }
 
     private void initUiForMultipleDevices(CharSequence appLabel) {
@@ -467,12 +508,16 @@
 
         final String profileName;
         final Spanned summary;
+        final Drawable profileIcon;
         if (deviceProfile == null) {
             profileName = getString(R.string.profile_name_generic);
             summary = getHtmlFromResources(this, R.string.summary_generic);
+            profileIcon = getIcon(this, R.drawable.ic_device_other);
+            mSummary.setVisibility(View.GONE);
         } else if (deviceProfile.equals(DEVICE_PROFILE_WATCH)) {
             profileName = getString(R.string.profile_name_watch);
             summary = getHtmlFromResources(this, R.string.summary_watch, appLabel);
+            profileIcon = getIcon(this, R.drawable.ic_watch);
         } else {
             throw new RuntimeException("Unsupported profile " + deviceProfile);
         }
@@ -481,21 +526,27 @@
 
         mTitle.setText(title);
         mSummary.setText(summary);
+        mProfileIcon.setImageDrawable(profileIcon);
 
-        mDeviceAdapter = new DeviceListAdapter(this, this::onListItemClick);
-
-        // TODO: hide the list and show a spinner until a first device matching device is found.
         mDeviceListRecyclerView.setAdapter(mDeviceAdapter);
         mDeviceListRecyclerView.setLayoutManager(new LinearLayoutManager(this));
 
-        CompanionDeviceDiscoveryService.getScanResult().observe(
-                /* lifecycleOwner */ this,
-                /* observer */ mDeviceAdapter);
+        CompanionDeviceDiscoveryService.getScanResult().observe(this,
+                deviceFilterPairs -> {
+                    // Dismiss the progress bar once there's one device found for multiple devices.
+                    if (deviceFilterPairs.size() >= 1) {
+                        mProgressIndicator.setVisibility(View.GONE);
+                    }
+
+                    mDeviceAdapter.setDevices(deviceFilterPairs);
+                });
 
         // "Remove" consent button: users would need to click on the list item.
         mButtonAllow.setVisibility(View.GONE);
         mButtonNotAllow.setVisibility(View.GONE);
         mButtonNotAllowMultipleDevices.setVisibility(View.VISIBLE);
+        mMultipleDeviceList.setVisibility(View.VISIBLE);
+        mProgressIndicator.setVisibility(View.VISIBLE);
     }
 
     private void onListItemClick(int position) {
@@ -534,16 +585,15 @@
         // Disable the button, to prevent more clicks.
         v.setEnabled(false);
 
-        cancel(false);
+        cancel(/* discoveryTimeout */ false, /* userRejected */ true);
     }
 
     private void onShowHelperDialog(View view) {
         FragmentManager fragmentManager = getSupportFragmentManager();
         CompanionVendorHelperDialogFragment fragmentDialog =
-                CompanionVendorHelperDialogFragment.newInstance(mRequest.getPackageName(),
-                        mRequest.getUserId(), mRequest.getDeviceProfile());
+                CompanionVendorHelperDialogFragment.newInstance(mRequest);
 
-        mAssociationConfirmationDialog.setVisibility(View.GONE);
+        mAssociationConfirmationDialog.setVisibility(View.INVISIBLE);
 
         fragmentDialog.show(fragmentManager, /* Tag */ FRAGMENT_DIALOG_TAG);
     }
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
index 5f07fcf..e8a1a5c 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
@@ -150,6 +150,8 @@
         mBtAdapter = mBtManager.getAdapter();
         mBleScanner = mBtAdapter.getBluetoothLeScanner();
         mWifiManager = getSystemService(WifiManager.class);
+
+        sScanResultsLiveData.setValue(Collections.emptyList());
     }
 
     @Override
@@ -186,7 +188,6 @@
         mStopAfterFirstMatch = request.isSingleDevice();
         mDiscoveryStarted = true;
         sStateLiveData.setValue(DiscoveryState.DISCOVERY_IN_PROGRESS);
-        sScanResultsLiveData.setValue(Collections.emptyList());
 
         final List<DeviceFilter<?>> allFilters = request.getDeviceFilters();
         final List<BluetoothDeviceFilter> btFilters =
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java
index 728e5e5..f2f6cb0 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java
@@ -23,6 +23,7 @@
 import static com.android.companiondevicemanager.Utils.getHtmlFromResources;
 
 import android.annotation.Nullable;
+import android.companion.AssociationRequest;
 import android.content.DialogInterface;
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
@@ -44,10 +45,7 @@
  */
 public class CompanionVendorHelperDialogFragment extends DialogFragment {
     private static final String TAG = CompanionVendorHelperDialogFragment.class.getSimpleName();
-
-    private static final String PACKAGE_NAME_EXTRA = "packageName";
-    private static final String DEVICE_PROFILE_EXTRA = "deviceProfile";
-    private static final String USER_ID_EXTRA = "userId";
+    private static final String ASSOCIATION_REQUEST_EXTRA = "association_request";
 
     private CompanionVendorHelperDialogListener mListener;
     // Only present for selfManaged devices.
@@ -63,15 +61,12 @@
 
     private CompanionVendorHelperDialogFragment() {}
 
-    static CompanionVendorHelperDialogFragment newInstance(String packageName,
-            int userId, String deviceProfile) {
+    static CompanionVendorHelperDialogFragment newInstance(AssociationRequest request) {
         CompanionVendorHelperDialogFragment fragmentDialog =
                 new CompanionVendorHelperDialogFragment();
 
         Bundle bundle = new Bundle();
-        bundle.putString(PACKAGE_NAME_EXTRA, packageName);
-        bundle.putInt(USER_ID_EXTRA, userId);
-        bundle.putString(DEVICE_PROFILE_EXTRA, deviceProfile);
+        bundle.putParcelable(ASSOCIATION_REQUEST_EXTRA, request);
         fragmentDialog.setArguments(bundle);
 
         return fragmentDialog;
@@ -102,9 +97,13 @@
         super.onViewCreated(view, savedInstanceState);
 
         Drawable applicationIcon;
-        String packageName = getArguments().getString(PACKAGE_NAME_EXTRA);
-        String deviceProfile = getArguments().getString(DEVICE_PROFILE_EXTRA);
-        int userId = getArguments().getInt(USER_ID_EXTRA);
+        AssociationRequest request = getArguments().getParcelable(
+                ASSOCIATION_REQUEST_EXTRA, AssociationRequest.class);
+
+        final String deviceProfile = request.getDeviceProfile();
+        final String packageName = request.getPackageName();
+        final CharSequence displayName = request.getDisplayName();
+        final int userId = request.getUserId();
 
         try {
             applicationIcon = getApplicationIcon(getContext(), packageName);
@@ -117,7 +116,7 @@
         mTitle = view.findViewById(R.id.helper_title);
         mSummary = view.findViewById(R.id.helper_summary);
         mAppIcon = view.findViewById(R.id.app_icon);
-        mButton = view.findViewById(R.id.btn_ok);
+        mButton = view.findViewById(R.id.btn_back);
 
         final Spanned title;
         final Spanned summary;
@@ -125,12 +124,14 @@
         switch (deviceProfile) {
             case DEVICE_PROFILE_APP_STREAMING:
                 title = getHtmlFromResources(getContext(), R.string.helper_title_app_streaming);
-                summary = getHtmlFromResources(getContext(), R.string.helper_summary_app_streaming);
+                summary = getHtmlFromResources(
+                        getContext(), R.string.helper_summary_app_streaming, title, displayName);
                 break;
 
             case DEVICE_PROFILE_COMPUTER:
                 title = getHtmlFromResources(getContext(), R.string.helper_title_computer);
-                summary = getHtmlFromResources(getContext(), R.string.helper_summary_computer);
+                summary = getHtmlFromResources(
+                        getContext(), R.string.helper_summary_computer, title, displayName);
                 break;
 
             default:
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java
index 8babd3a..328c67e 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java
@@ -25,15 +25,13 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
-import androidx.lifecycle.Observer;
 import androidx.recyclerview.widget.RecyclerView;
 
 import java.util.List;
 /**
  * Adapter for the list of "found" devices.
  */
-class DeviceListAdapter extends RecyclerView.Adapter<DeviceListAdapter.ViewHolder> implements
-        Observer<List<DeviceFilterPair<?>>> {
+class DeviceListAdapter extends RecyclerView.Adapter<DeviceListAdapter.ViewHolder> {
     public int mSelectedPosition = RecyclerView.NO_POSITION;
 
     private final Context mContext;
@@ -96,9 +94,8 @@
         mSelectedPosition = position;
     }
 
-    @Override
-    public void onChanged(List<DeviceFilterPair<?>> deviceFilterPairs) {
-        mDevices = deviceFilterPairs;
+    void setDevices(List<DeviceFilterPair<?>> devices) {
+        mDevices = devices;
         notifyDataSetChanged();
     }
 
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java
index d5b2f0a..fceca91 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java
@@ -22,7 +22,6 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.ApplicationInfoFlags;
-import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Handler;
@@ -109,6 +108,18 @@
         return appInfo.metaData.getCharSequence(COMPANION_DEVICE_ACTIVITY_VENDOR_NAME, "");
     }
 
+    static boolean hasVendorIcon(@NonNull Context context,
+            @NonNull String packageName, int userId) throws PackageManager.NameNotFoundException {
+        final ApplicationInfo appInfo = getApplicationInfo(context, packageName, userId);
+        final Bundle bundle = appInfo.metaData;
+
+        if (bundle == null) {
+            return false;
+        } else {
+            return bundle.getInt(COMPANION_DEVICE_ACTIVITY_VENDOR_ICON) != 0;
+        }
+    }
+
     /**
      * Getting ApplicationInfo from meta-data.
      */
@@ -124,7 +135,6 @@
 
     static @NonNull Drawable getIcon(@NonNull Context context, int resId) {
         Drawable icon = context.getResources().getDrawable(resId, null);
-        icon.setTint(Color.DKGRAY);
         return icon;
     }
 
diff --git a/packages/ConnectivityT/OWNERS b/packages/ConnectivityT/OWNERS
deleted file mode 100644
index e267d19..0000000
--- a/packages/ConnectivityT/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
-per-file **IpSec* = file:/services/core/java/com/android/server/vcn/OWNERS
diff --git a/packages/ConnectivityT/framework-t/Android.bp b/packages/ConnectivityT/framework-t/Android.bp
deleted file mode 100644
index 6652780..0000000
--- a/packages/ConnectivityT/framework-t/Android.bp
+++ /dev/null
@@ -1,205 +0,0 @@
-//
-// Copyright (C) 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-package {
-    // See: http://go/android-license-faq
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-// NetworkStats related libraries.
-
-filegroup {
-    name: "framework-connectivity-netstats-internal-sources",
-    srcs: [
-        "src/android/app/usage/*.java",
-        "src/android/net/DataUsageRequest.*",
-        "src/android/net/INetworkStatsService.aidl",
-        "src/android/net/INetworkStatsSession.aidl",
-        "src/android/net/NetworkIdentity.java",
-        "src/android/net/NetworkIdentitySet.java",
-        "src/android/net/NetworkStateSnapshot.*",
-        "src/android/net/NetworkStats.*",
-        "src/android/net/NetworkStatsAccess.*",
-        "src/android/net/NetworkStatsCollection.*",
-        "src/android/net/NetworkStatsHistory.*",
-        "src/android/net/NetworkTemplate.*",
-        "src/android/net/TrafficStats.java",
-        "src/android/net/UnderlyingNetworkInfo.*",
-        "src/android/net/netstats/**/*.*",
-    ],
-    path: "src",
-    visibility: [
-        "//visibility:private",
-    ],
-}
-
-filegroup {
-    name: "framework-connectivity-netstats-aidl-export-sources",
-    srcs: [
-        "aidl-export/android/net/NetworkStats.aidl",
-        "aidl-export/android/net/NetworkTemplate.aidl",
-    ],
-    path: "aidl-export",
-    visibility: [
-        "//visibility:private",
-    ],
-}
-
-filegroup {
-    name: "framework-connectivity-netstats-sources",
-    srcs: [
-        ":framework-connectivity-netstats-internal-sources",
-        ":framework-connectivity-netstats-aidl-export-sources",
-    ],
-    visibility: [
-        "//visibility:private",
-    ],
-}
-
-// Nsd related libraries.
-
-filegroup {
-    name: "framework-connectivity-nsd-internal-sources",
-    srcs: [
-        "src/android/net/nsd/*.aidl",
-        "src/android/net/nsd/*.java",
-    ],
-    path: "src",
-    visibility: [
-        "//visibility:private",
-    ],
-}
-
-filegroup {
-    name: "framework-connectivity-nsd-aidl-export-sources",
-    srcs: [
-        "aidl-export/android/net/nsd/*.aidl",
-    ],
-    path: "aidl-export",
-    visibility: [
-        "//visibility:private",
-    ],
-}
-
-filegroup {
-    name: "framework-connectivity-nsd-sources",
-    srcs: [
-        ":framework-connectivity-nsd-internal-sources",
-        ":framework-connectivity-nsd-aidl-export-sources",
-    ],
-    visibility: [
-        "//visibility:private",
-    ],
-}
-
-// IpSec related libraries.
-
-filegroup {
-    name: "framework-connectivity-ipsec-sources",
-    srcs: [
-        "src/android/net/IIpSecService.aidl",
-        "src/android/net/IpSec*.*",
-    ],
-    path: "src",
-    visibility: [
-        "//visibility:private",
-    ],
-}
-
-// Ethernet related libraries.
-
-filegroup {
-    name: "framework-connectivity-ethernet-sources",
-    srcs: [
-        "src/android/net/EthernetManager.java",
-        "src/android/net/EthernetNetworkManagementException.java",
-        "src/android/net/EthernetNetworkManagementException.aidl",
-        "src/android/net/EthernetNetworkSpecifier.java",
-        "src/android/net/EthernetNetworkUpdateRequest.java",
-        "src/android/net/EthernetNetworkUpdateRequest.aidl",
-        "src/android/net/IEthernetManager.aidl",
-        "src/android/net/IEthernetNetworkManagementListener.aidl",
-        "src/android/net/IEthernetServiceListener.aidl",
-        "src/android/net/ITetheredInterfaceCallback.aidl",
-    ],
-    path: "src",
-    visibility: [
-        "//visibility:private",
-    ],
-}
-
-// Connectivity-T common libraries.
-
-filegroup {
-    name: "framework-connectivity-tiramisu-internal-sources",
-    srcs: [
-        "src/android/net/ConnectivityFrameworkInitializerTiramisu.java",
-    ],
-    path: "src",
-    visibility: [
-        "//visibility:private",
-    ],
-}
-
-filegroup {
-    name: "framework-connectivity-tiramisu-sources",
-    srcs: [
-        ":framework-connectivity-ethernet-sources",
-    ],
-    visibility: ["//frameworks/base"],
-}
-
-filegroup {
-    name: "framework-connectivity-tiramisu-updatable-sources",
-    srcs: [
-        ":framework-connectivity-ipsec-sources",
-        ":framework-connectivity-netstats-sources",
-        ":framework-connectivity-nsd-sources",
-        ":framework-connectivity-tiramisu-internal-sources",
-    ],
-    visibility: [
-        "//frameworks/base",
-        "//packages/modules/Connectivity:__subpackages__",
-    ],
-}
-
-cc_library_shared {
-    name: "libframework-connectivity-tiramisu-jni",
-    min_sdk_version: "30",
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wno-unused-parameter",
-        // Don't warn about S API usage even with
-        // min_sdk 30: the library is only loaded
-        // on S+ devices
-        "-Wno-unguarded-availability",
-        "-Wthread-safety",
-    ],
-    srcs: [
-        "jni/android_net_TrafficStats.cpp",
-        "jni/onload.cpp",
-    ],
-    shared_libs: [
-        "libandroid",
-        "liblog",
-        "libnativehelper",
-    ],
-    stl: "none",
-    apex_available: [
-        "com.android.tethering",
-    ],
-}
diff --git a/packages/ConnectivityT/framework-t/aidl-export/android/net/NetworkTemplate.aidl b/packages/ConnectivityT/framework-t/aidl-export/android/net/NetworkTemplate.aidl
deleted file mode 100644
index 3d37488..0000000
--- a/packages/ConnectivityT/framework-t/aidl-export/android/net/NetworkTemplate.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2011, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-parcelable NetworkTemplate;
diff --git a/packages/ConnectivityT/framework-t/aidl-export/android/net/nsd/NsdServiceInfo.aidl b/packages/ConnectivityT/framework-t/aidl-export/android/net/nsd/NsdServiceInfo.aidl
deleted file mode 100644
index 657bdd1..0000000
--- a/packages/ConnectivityT/framework-t/aidl-export/android/net/nsd/NsdServiceInfo.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.nsd;
-
-@JavaOnlyStableParcelable parcelable NsdServiceInfo;
\ No newline at end of file
diff --git a/packages/ConnectivityT/framework-t/jni/android_net_TrafficStats.cpp b/packages/ConnectivityT/framework-t/jni/android_net_TrafficStats.cpp
deleted file mode 100644
index f3c58b1..0000000
--- a/packages/ConnectivityT/framework-t/jni/android_net_TrafficStats.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.
- */
-
-#include <android/file_descriptor_jni.h>
-#include <android/multinetwork.h>
-#include <nativehelper/JNIHelp.h>
-
-namespace android {
-
-static jint tagSocketFd(JNIEnv* env, jclass, jobject fileDescriptor, jint tag, jint uid) {
-  int fd = AFileDescriptor_getFd(env, fileDescriptor);
-  if (fd == -1) return -EBADF;
-  return android_tag_socket_with_uid(fd, tag, uid);
-}
-
-static jint untagSocketFd(JNIEnv* env, jclass, jobject fileDescriptor) {
-  int fd = AFileDescriptor_getFd(env, fileDescriptor);
-  if (fd == -1) return -EBADF;
-  return android_untag_socket(fd);
-}
-
-static const JNINativeMethod gMethods[] = {
-    /* name, signature, funcPtr */
-    { "native_tagSocketFd", "(Ljava/io/FileDescriptor;II)I", (void*) tagSocketFd },
-    { "native_untagSocketFd", "(Ljava/io/FileDescriptor;)I", (void*) untagSocketFd },
-};
-
-int register_android_net_TrafficStats(JNIEnv* env) {
-    return jniRegisterNativeMethods(env, "android/net/TrafficStats", gMethods, NELEM(gMethods));
-}
-
-};  // namespace android
-
diff --git a/packages/ConnectivityT/framework-t/jni/onload.cpp b/packages/ConnectivityT/framework-t/jni/onload.cpp
deleted file mode 100644
index 1fb42c6..0000000
--- a/packages/ConnectivityT/framework-t/jni/onload.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "FrameworkConnectivityJNI"
-
-#include <log/log.h>
-#include <nativehelper/JNIHelp.h>
-
-namespace android {
-
-int register_android_net_TrafficStats(JNIEnv* env);
-
-extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
-    JNIEnv *env;
-    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
-        __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "ERROR: GetEnv failed");
-        return JNI_ERR;
-    }
-
-    if (register_android_net_TrafficStats(env) < 0) return JNI_ERR;
-
-    return JNI_VERSION_1_6;
-}
-
-};  // namespace android
-
diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java
deleted file mode 100644
index 2b6570a..0000000
--- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java
+++ /dev/null
@@ -1,742 +0,0 @@
-/**
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy
- * of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-
-package android.app.usage;
-
-import android.annotation.IntDef;
-import android.content.Context;
-import android.net.INetworkStatsService;
-import android.net.INetworkStatsSession;
-import android.net.NetworkStatsHistory;
-import android.net.NetworkTemplate;
-import android.net.TrafficStats;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.net.module.util.CollectionUtils;
-
-import dalvik.system.CloseGuard;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-
-/**
- * Class providing enumeration over buckets of network usage statistics. {@link NetworkStats} objects
- * are returned as results to various queries in {@link NetworkStatsManager}.
- */
-public final class NetworkStats implements AutoCloseable {
-    private final static String TAG = "NetworkStats";
-
-    private final CloseGuard mCloseGuard = CloseGuard.get();
-
-    /**
-     * Start timestamp of stats collected
-     */
-    private final long mStartTimeStamp;
-
-    /**
-     * End timestamp of stats collected
-     */
-    private final long mEndTimeStamp;
-
-    /**
-     * Non-null array indicates the query enumerates over uids.
-     */
-    private int[] mUids;
-
-    /**
-     * Index of the current uid in mUids when doing uid enumeration or a single uid value,
-     * depending on query type.
-     */
-    private int mUidOrUidIndex;
-
-    /**
-     * Tag id in case if was specified in the query.
-     */
-    private int mTag = android.net.NetworkStats.TAG_NONE;
-
-    /**
-     * State in case it was not specified in the query.
-     */
-    private int mState = Bucket.STATE_ALL;
-
-    /**
-     * The session while the query requires it, null if all the stats have been collected or close()
-     * has been called.
-     */
-    private INetworkStatsSession mSession;
-    private NetworkTemplate mTemplate;
-
-    /**
-     * Results of a summary query.
-     */
-    private android.net.NetworkStats mSummary = null;
-
-    /**
-     * Results of detail queries.
-     */
-    private NetworkStatsHistory mHistory = null;
-
-    /**
-     * Where we are in enumerating over the current result.
-     */
-    private int mEnumerationIndex = 0;
-
-    /**
-     * Recycling entry objects to prevent heap fragmentation.
-     */
-    private android.net.NetworkStats.Entry mRecycledSummaryEntry = null;
-    private NetworkStatsHistory.Entry mRecycledHistoryEntry = null;
-
-    /** @hide */
-    NetworkStats(Context context, NetworkTemplate template, int flags, long startTimestamp,
-            long endTimestamp, INetworkStatsService statsService)
-            throws RemoteException, SecurityException {
-        // Open network stats session
-        mSession = statsService.openSessionForUsageStats(flags, context.getOpPackageName());
-        mCloseGuard.open("close");
-        mTemplate = template;
-        mStartTimeStamp = startTimestamp;
-        mEndTimeStamp = endTimestamp;
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        try {
-            if (mCloseGuard != null) {
-                mCloseGuard.warnIfOpen();
-            }
-            close();
-        } finally {
-            super.finalize();
-        }
-    }
-
-    // -------------------------BEGINNING OF PUBLIC API-----------------------------------
-
-    /**
-     * Buckets are the smallest elements of a query result. As some dimensions of a result may be
-     * aggregated (e.g. time or state) some values may be equal across all buckets.
-     */
-    public static class Bucket {
-        /** @hide */
-        @IntDef(prefix = { "STATE_" }, value = {
-                STATE_ALL,
-                STATE_DEFAULT,
-                STATE_FOREGROUND
-        })
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface State {}
-
-        /**
-         * Combined usage across all states.
-         */
-        public static final int STATE_ALL = -1;
-
-        /**
-         * Usage not accounted for in any other state.
-         */
-        public static final int STATE_DEFAULT = 0x1;
-
-        /**
-         * Foreground usage.
-         */
-        public static final int STATE_FOREGROUND = 0x2;
-
-        /**
-         * Special UID value for aggregate/unspecified.
-         */
-        public static final int UID_ALL = android.net.NetworkStats.UID_ALL;
-
-        /**
-         * Special UID value for removed apps.
-         */
-        public static final int UID_REMOVED = TrafficStats.UID_REMOVED;
-
-        /**
-         * Special UID value for data usage by tethering.
-         */
-        public static final int UID_TETHERING = TrafficStats.UID_TETHERING;
-
-        /** @hide */
-        @IntDef(prefix = { "METERED_" }, value = {
-                METERED_ALL,
-                METERED_NO,
-                METERED_YES
-        })
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface Metered {}
-
-        /**
-         * Combined usage across all metered states. Covers metered and unmetered usage.
-         */
-        public static final int METERED_ALL = -1;
-
-        /**
-         * Usage that occurs on an unmetered network.
-         */
-        public static final int METERED_NO = 0x1;
-
-        /**
-         * Usage that occurs on a metered network.
-         *
-         * <p>A network is classified as metered when the user is sensitive to heavy data usage on
-         * that connection.
-         */
-        public static final int METERED_YES = 0x2;
-
-        /** @hide */
-        @IntDef(prefix = { "ROAMING_" }, value = {
-                ROAMING_ALL,
-                ROAMING_NO,
-                ROAMING_YES
-        })
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface Roaming {}
-
-        /**
-         * Combined usage across all roaming states. Covers both roaming and non-roaming usage.
-         */
-        public static final int ROAMING_ALL = -1;
-
-        /**
-         * Usage that occurs on a home, non-roaming network.
-         *
-         * <p>Any cellular usage in this bucket was incurred while the device was connected to a
-         * tower owned or operated by the user's wireless carrier, or a tower that the user's
-         * wireless carrier has indicated should be treated as a home network regardless.
-         *
-         * <p>This is also the default value for network types that do not support roaming.
-         */
-        public static final int ROAMING_NO = 0x1;
-
-        /**
-         * Usage that occurs on a roaming network.
-         *
-         * <p>Any cellular usage in this bucket as incurred while the device was roaming on another
-         * carrier's network, for which additional charges may apply.
-         */
-        public static final int ROAMING_YES = 0x2;
-
-        /** @hide */
-        @IntDef(prefix = { "DEFAULT_NETWORK_" }, value = {
-                DEFAULT_NETWORK_ALL,
-                DEFAULT_NETWORK_NO,
-                DEFAULT_NETWORK_YES
-        })
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface DefaultNetworkStatus {}
-
-        /**
-         * Combined usage for this network regardless of default network status.
-         */
-        public static final int DEFAULT_NETWORK_ALL = -1;
-
-        /**
-         * Usage that occurs while this network is not a default network.
-         *
-         * <p>This implies that the app responsible for this usage requested that it occur on a
-         * specific network different from the one(s) the system would have selected for it.
-         */
-        public static final int DEFAULT_NETWORK_NO = 0x1;
-
-        /**
-         * Usage that occurs while this network is a default network.
-         *
-         * <p>This implies that the app either did not select a specific network for this usage,
-         * or it selected a network that the system could have selected for app traffic.
-         */
-        public static final int DEFAULT_NETWORK_YES = 0x2;
-
-        /**
-         * Special TAG value for total data across all tags
-         */
-        public static final int TAG_NONE = android.net.NetworkStats.TAG_NONE;
-
-        private int mUid;
-        private int mTag;
-        private int mState;
-        private int mDefaultNetworkStatus;
-        private int mMetered;
-        private int mRoaming;
-        private long mBeginTimeStamp;
-        private long mEndTimeStamp;
-        private long mRxBytes;
-        private long mRxPackets;
-        private long mTxBytes;
-        private long mTxPackets;
-
-        private static int convertSet(@State int state) {
-            switch (state) {
-                case STATE_ALL: return android.net.NetworkStats.SET_ALL;
-                case STATE_DEFAULT: return android.net.NetworkStats.SET_DEFAULT;
-                case STATE_FOREGROUND: return android.net.NetworkStats.SET_FOREGROUND;
-            }
-            return 0;
-        }
-
-        private static @State int convertState(int networkStatsSet) {
-            switch (networkStatsSet) {
-                case android.net.NetworkStats.SET_ALL : return STATE_ALL;
-                case android.net.NetworkStats.SET_DEFAULT : return STATE_DEFAULT;
-                case android.net.NetworkStats.SET_FOREGROUND : return STATE_FOREGROUND;
-            }
-            return 0;
-        }
-
-        private static int convertUid(int uid) {
-            switch (uid) {
-                case TrafficStats.UID_REMOVED: return UID_REMOVED;
-                case TrafficStats.UID_TETHERING: return UID_TETHERING;
-            }
-            return uid;
-        }
-
-        private static int convertTag(int tag) {
-            switch (tag) {
-                case android.net.NetworkStats.TAG_NONE: return TAG_NONE;
-            }
-            return tag;
-        }
-
-        private static @Metered int convertMetered(int metered) {
-            switch (metered) {
-                case android.net.NetworkStats.METERED_ALL : return METERED_ALL;
-                case android.net.NetworkStats.METERED_NO: return METERED_NO;
-                case android.net.NetworkStats.METERED_YES: return METERED_YES;
-            }
-            return 0;
-        }
-
-        private static @Roaming int convertRoaming(int roaming) {
-            switch (roaming) {
-                case android.net.NetworkStats.ROAMING_ALL : return ROAMING_ALL;
-                case android.net.NetworkStats.ROAMING_NO: return ROAMING_NO;
-                case android.net.NetworkStats.ROAMING_YES: return ROAMING_YES;
-            }
-            return 0;
-        }
-
-        private static @DefaultNetworkStatus int convertDefaultNetworkStatus(
-                int defaultNetworkStatus) {
-            switch (defaultNetworkStatus) {
-                case android.net.NetworkStats.DEFAULT_NETWORK_ALL : return DEFAULT_NETWORK_ALL;
-                case android.net.NetworkStats.DEFAULT_NETWORK_NO: return DEFAULT_NETWORK_NO;
-                case android.net.NetworkStats.DEFAULT_NETWORK_YES: return DEFAULT_NETWORK_YES;
-            }
-            return 0;
-        }
-
-        public Bucket() {
-        }
-
-        /**
-         * Key of the bucket. Usually an app uid or one of the following special values:<p />
-         * <ul>
-         * <li>{@link #UID_REMOVED}</li>
-         * <li>{@link #UID_TETHERING}</li>
-         * <li>{@link android.os.Process#SYSTEM_UID}</li>
-         * </ul>
-         * @return Bucket key.
-         */
-        public int getUid() {
-            return mUid;
-        }
-
-        /**
-         * Tag of the bucket.<p />
-         * @return Bucket tag.
-         */
-        public int getTag() {
-            return mTag;
-        }
-
-        /**
-         * Usage state. One of the following values:<p/>
-         * <ul>
-         * <li>{@link #STATE_ALL}</li>
-         * <li>{@link #STATE_DEFAULT}</li>
-         * <li>{@link #STATE_FOREGROUND}</li>
-         * </ul>
-         * @return Usage state.
-         */
-        public @State int getState() {
-            return mState;
-        }
-
-        /**
-         * Metered state. One of the following values:<p/>
-         * <ul>
-         * <li>{@link #METERED_ALL}</li>
-         * <li>{@link #METERED_NO}</li>
-         * <li>{@link #METERED_YES}</li>
-         * </ul>
-         * <p>A network is classified as metered when the user is sensitive to heavy data usage on
-         * that connection. Apps may warn before using these networks for large downloads. The
-         * metered state can be set by the user within data usage network restrictions.
-         */
-        public @Metered int getMetered() {
-            return mMetered;
-        }
-
-        /**
-         * Roaming state. One of the following values:<p/>
-         * <ul>
-         * <li>{@link #ROAMING_ALL}</li>
-         * <li>{@link #ROAMING_NO}</li>
-         * <li>{@link #ROAMING_YES}</li>
-         * </ul>
-         */
-        public @Roaming int getRoaming() {
-            return mRoaming;
-        }
-
-        /**
-         * Default network status. One of the following values:<p/>
-         * <ul>
-         * <li>{@link #DEFAULT_NETWORK_ALL}</li>
-         * <li>{@link #DEFAULT_NETWORK_NO}</li>
-         * <li>{@link #DEFAULT_NETWORK_YES}</li>
-         * </ul>
-         */
-        public @DefaultNetworkStatus int getDefaultNetworkStatus() {
-            return mDefaultNetworkStatus;
-        }
-
-        /**
-         * Start timestamp of the bucket's time interval. Defined in terms of "Unix time", see
-         * {@link java.lang.System#currentTimeMillis}.
-         * @return Start of interval.
-         */
-        public long getStartTimeStamp() {
-            return mBeginTimeStamp;
-        }
-
-        /**
-         * End timestamp of the bucket's time interval. Defined in terms of "Unix time", see
-         * {@link java.lang.System#currentTimeMillis}.
-         * @return End of interval.
-         */
-        public long getEndTimeStamp() {
-            return mEndTimeStamp;
-        }
-
-        /**
-         * Number of bytes received during the bucket's time interval. Statistics are measured at
-         * the network layer, so they include both TCP and UDP usage.
-         * @return Number of bytes.
-         */
-        public long getRxBytes() {
-            return mRxBytes;
-        }
-
-        /**
-         * Number of bytes transmitted during the bucket's time interval. Statistics are measured at
-         * the network layer, so they include both TCP and UDP usage.
-         * @return Number of bytes.
-         */
-        public long getTxBytes() {
-            return mTxBytes;
-        }
-
-        /**
-         * Number of packets received during the bucket's time interval. Statistics are measured at
-         * the network layer, so they include both TCP and UDP usage.
-         * @return Number of packets.
-         */
-        public long getRxPackets() {
-            return mRxPackets;
-        }
-
-        /**
-         * Number of packets transmitted during the bucket's time interval. Statistics are measured
-         * at the network layer, so they include both TCP and UDP usage.
-         * @return Number of packets.
-         */
-        public long getTxPackets() {
-            return mTxPackets;
-        }
-    }
-
-    /**
-     * Fills the recycled bucket with data of the next bin in the enumeration.
-     * @param bucketOut Bucket to be filled with data.
-     * @return true if successfully filled the bucket, false otherwise.
-     */
-    public boolean getNextBucket(Bucket bucketOut) {
-        if (mSummary != null) {
-            return getNextSummaryBucket(bucketOut);
-        } else {
-            return getNextHistoryBucket(bucketOut);
-        }
-    }
-
-    /**
-     * Check if it is possible to ask for a next bucket in the enumeration.
-     * @return true if there is at least one more bucket.
-     */
-    public boolean hasNextBucket() {
-        if (mSummary != null) {
-            return mEnumerationIndex < mSummary.size();
-        } else if (mHistory != null) {
-            return mEnumerationIndex < mHistory.size()
-                    || hasNextUid();
-        }
-        return false;
-    }
-
-    /**
-     * Closes the enumeration. Call this method before this object gets out of scope.
-     */
-    @Override
-    public void close() {
-        if (mSession != null) {
-            try {
-                mSession.close();
-            } catch (RemoteException e) {
-                Log.w(TAG, e);
-                // Otherwise, meh
-            }
-        }
-        mSession = null;
-        if (mCloseGuard != null) {
-            mCloseGuard.close();
-        }
-    }
-
-    // -------------------------END OF PUBLIC API-----------------------------------
-
-    /**
-     * Collects device summary results into a Bucket.
-     * @throws RemoteException
-     */
-    Bucket getDeviceSummaryForNetwork() throws RemoteException {
-        mSummary = mSession.getDeviceSummaryForNetwork(mTemplate, mStartTimeStamp, mEndTimeStamp);
-
-        // Setting enumeration index beyond end to avoid accidental enumeration over data that does
-        // not belong to the calling user.
-        mEnumerationIndex = mSummary.size();
-
-        return getSummaryAggregate();
-    }
-
-    /**
-     * Collects summary results and sets summary enumeration mode.
-     * @throws RemoteException
-     */
-    void startSummaryEnumeration() throws RemoteException {
-        mSummary = mSession.getSummaryForAllUid(mTemplate, mStartTimeStamp, mEndTimeStamp,
-                false /* includeTags */);
-        mEnumerationIndex = 0;
-    }
-
-    /**
-     * Collects tagged summary results and sets summary enumeration mode.
-     * @throws RemoteException
-     */
-    void startTaggedSummaryEnumeration() throws RemoteException {
-        mSummary = mSession.getTaggedSummaryForAllUid(mTemplate, mStartTimeStamp, mEndTimeStamp);
-        mEnumerationIndex = 0;
-    }
-
-    /**
-     * Collects history results for uid and resets history enumeration index.
-     */
-    void startHistoryUidEnumeration(int uid, int tag, int state) {
-        mHistory = null;
-        try {
-            mHistory = mSession.getHistoryIntervalForUid(mTemplate, uid,
-                    Bucket.convertSet(state), tag, NetworkStatsHistory.FIELD_ALL,
-                    mStartTimeStamp, mEndTimeStamp);
-            setSingleUidTagState(uid, tag, state);
-        } catch (RemoteException e) {
-            Log.w(TAG, e);
-            // Leaving mHistory null
-        }
-        mEnumerationIndex = 0;
-    }
-
-    /**
-     * Collects history results for network and resets history enumeration index.
-     */
-    void startHistoryDeviceEnumeration() {
-        try {
-            mHistory = mSession.getHistoryIntervalForNetwork(
-                    mTemplate, NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp);
-        } catch (RemoteException e) {
-            Log.w(TAG, e);
-            mHistory = null;
-        }
-        mEnumerationIndex = 0;
-    }
-
-    /**
-     * Starts uid enumeration for current user.
-     * @throws RemoteException
-     */
-    void startUserUidEnumeration() throws RemoteException {
-        // TODO: getRelevantUids should be sensitive to time interval. When that's done,
-        //       the filtering logic below can be removed.
-        int[] uids = mSession.getRelevantUids();
-        // Filtering of uids with empty history.
-        final ArrayList<Integer> filteredUids = new ArrayList<>();
-        for (int uid : uids) {
-            try {
-                NetworkStatsHistory history = mSession.getHistoryIntervalForUid(mTemplate, uid,
-                        android.net.NetworkStats.SET_ALL, android.net.NetworkStats.TAG_NONE,
-                        NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp);
-                if (history != null && history.size() > 0) {
-                    filteredUids.add(uid);
-                }
-            } catch (RemoteException e) {
-                Log.w(TAG, "Error while getting history of uid " + uid, e);
-            }
-        }
-        mUids = CollectionUtils.toIntArray(filteredUids);
-        mUidOrUidIndex = -1;
-        stepHistory();
-    }
-
-    /**
-     * Steps to next uid in enumeration and collects history for that.
-     */
-    private void stepHistory(){
-        if (hasNextUid()) {
-            stepUid();
-            mHistory = null;
-            try {
-                mHistory = mSession.getHistoryIntervalForUid(mTemplate, getUid(),
-                        android.net.NetworkStats.SET_ALL, android.net.NetworkStats.TAG_NONE,
-                        NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp);
-            } catch (RemoteException e) {
-                Log.w(TAG, e);
-                // Leaving mHistory null
-            }
-            mEnumerationIndex = 0;
-        }
-    }
-
-    private void fillBucketFromSummaryEntry(Bucket bucketOut) {
-        bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid);
-        bucketOut.mTag = Bucket.convertTag(mRecycledSummaryEntry.tag);
-        bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set);
-        bucketOut.mDefaultNetworkStatus = Bucket.convertDefaultNetworkStatus(
-                mRecycledSummaryEntry.defaultNetwork);
-        bucketOut.mMetered = Bucket.convertMetered(mRecycledSummaryEntry.metered);
-        bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming);
-        bucketOut.mBeginTimeStamp = mStartTimeStamp;
-        bucketOut.mEndTimeStamp = mEndTimeStamp;
-        bucketOut.mRxBytes = mRecycledSummaryEntry.rxBytes;
-        bucketOut.mRxPackets = mRecycledSummaryEntry.rxPackets;
-        bucketOut.mTxBytes = mRecycledSummaryEntry.txBytes;
-        bucketOut.mTxPackets = mRecycledSummaryEntry.txPackets;
-    }
-
-    /**
-     * Getting the next item in summary enumeration.
-     * @param bucketOut Next item will be set here.
-     * @return true if a next item could be set.
-     */
-    private boolean getNextSummaryBucket(Bucket bucketOut) {
-        if (bucketOut != null && mEnumerationIndex < mSummary.size()) {
-            mRecycledSummaryEntry = mSummary.getValues(mEnumerationIndex++, mRecycledSummaryEntry);
-            fillBucketFromSummaryEntry(bucketOut);
-            return true;
-        }
-        return false;
-    }
-
-    Bucket getSummaryAggregate() {
-        if (mSummary == null) {
-            return null;
-        }
-        Bucket bucket = new Bucket();
-        if (mRecycledSummaryEntry == null) {
-            mRecycledSummaryEntry = new android.net.NetworkStats.Entry();
-        }
-        mSummary.getTotal(mRecycledSummaryEntry);
-        fillBucketFromSummaryEntry(bucket);
-        return bucket;
-    }
-
-    /**
-     * Getting the next item in a history enumeration.
-     * @param bucketOut Next item will be set here.
-     * @return true if a next item could be set.
-     */
-    private boolean getNextHistoryBucket(Bucket bucketOut) {
-        if (bucketOut != null && mHistory != null) {
-            if (mEnumerationIndex < mHistory.size()) {
-                mRecycledHistoryEntry = mHistory.getValues(mEnumerationIndex++,
-                        mRecycledHistoryEntry);
-                bucketOut.mUid = Bucket.convertUid(getUid());
-                bucketOut.mTag = Bucket.convertTag(mTag);
-                bucketOut.mState = mState;
-                bucketOut.mDefaultNetworkStatus = Bucket.DEFAULT_NETWORK_ALL;
-                bucketOut.mMetered = Bucket.METERED_ALL;
-                bucketOut.mRoaming = Bucket.ROAMING_ALL;
-                bucketOut.mBeginTimeStamp = mRecycledHistoryEntry.bucketStart;
-                bucketOut.mEndTimeStamp = mRecycledHistoryEntry.bucketStart +
-                        mRecycledHistoryEntry.bucketDuration;
-                bucketOut.mRxBytes = mRecycledHistoryEntry.rxBytes;
-                bucketOut.mRxPackets = mRecycledHistoryEntry.rxPackets;
-                bucketOut.mTxBytes = mRecycledHistoryEntry.txBytes;
-                bucketOut.mTxPackets = mRecycledHistoryEntry.txPackets;
-                return true;
-            } else if (hasNextUid()) {
-                stepHistory();
-                return getNextHistoryBucket(bucketOut);
-            }
-        }
-        return false;
-    }
-
-    // ------------------ UID LOGIC------------------------
-
-    private boolean isUidEnumeration() {
-        return mUids != null;
-    }
-
-    private boolean hasNextUid() {
-        return isUidEnumeration() && (mUidOrUidIndex + 1) < mUids.length;
-    }
-
-    private int getUid() {
-        // Check if uid enumeration.
-        if (isUidEnumeration()) {
-            if (mUidOrUidIndex < 0 || mUidOrUidIndex >= mUids.length) {
-                throw new IndexOutOfBoundsException(
-                        "Index=" + mUidOrUidIndex + " mUids.length=" + mUids.length);
-            }
-            return mUids[mUidOrUidIndex];
-        }
-        // Single uid mode.
-        return mUidOrUidIndex;
-    }
-
-    private void setSingleUidTagState(int uid, int tag, int state) {
-        mUidOrUidIndex = uid;
-        mTag = tag;
-        mState = state;
-    }
-
-    private void stepUid() {
-        if (mUids != null) {
-            ++mUidOrUidIndex;
-        }
-    }
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
deleted file mode 100644
index ca080ce..0000000
--- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
+++ /dev/null
@@ -1,1181 +0,0 @@
-/**
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy
- * of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-
-package android.app.usage;
-
-import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-
-import android.Manifest;
-import android.annotation.CallbackExecutor;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
-import android.annotation.SystemService;
-import android.annotation.WorkerThread;
-import android.app.usage.NetworkStats.Bucket;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.DataUsageRequest;
-import android.net.INetworkStatsService;
-import android.net.Network;
-import android.net.NetworkStack;
-import android.net.NetworkStateSnapshot;
-import android.net.NetworkTemplate;
-import android.net.UnderlyingNetworkInfo;
-import android.net.netstats.IUsageCallback;
-import android.net.netstats.NetworkStatsDataMigrationUtils;
-import android.net.netstats.provider.INetworkStatsProviderCallback;
-import android.net.netstats.provider.NetworkStatsProvider;
-import android.os.Build;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.net.module.util.NetworkIdentityUtils;
-
-import java.util.List;
-import java.util.Objects;
-import java.util.concurrent.Executor;
-
-/**
- * Provides access to network usage history and statistics. Usage data is collected in
- * discrete bins of time called 'Buckets'. See {@link NetworkStats.Bucket} for details.
- * <p />
- * Queries can define a time interval in the form of start and end timestamps (Long.MIN_VALUE and
- * Long.MAX_VALUE can be used to simulate open ended intervals). By default, apps can only obtain
- * data about themselves. See the below note for special cases in which apps can obtain data about
- * other applications.
- * <h3>
- * Summary queries
- * </h3>
- * {@link #querySummaryForDevice} <p />
- * {@link #querySummaryForUser} <p />
- * {@link #querySummary} <p />
- * These queries aggregate network usage across the whole interval. Therefore there will be only one
- * bucket for a particular key, state, metered and roaming combination. In case of the user-wide
- * and device-wide summaries a single bucket containing the totalised network usage is returned.
- * <h3>
- * History queries
- * </h3>
- * {@link #queryDetailsForUid} <p />
- * {@link #queryDetails} <p />
- * These queries do not aggregate over time but do aggregate over state, metered and roaming.
- * Therefore there can be multiple buckets for a particular key. However, all Buckets will have
- * {@code state} {@link NetworkStats.Bucket#STATE_ALL},
- * {@code defaultNetwork} {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
- * {@code metered } {@link NetworkStats.Bucket#METERED_ALL},
- * {@code roaming} {@link NetworkStats.Bucket#ROAMING_ALL}.
- * <p />
- * <b>NOTE:</b> Calling {@link #querySummaryForDevice} or accessing stats for apps other than the
- * calling app requires the permission {@link android.Manifest.permission#PACKAGE_USAGE_STATS},
- * which is a system-level permission and will not be granted to third-party apps. However,
- * declaring the permission implies intention to use the API and the user of the device can grant
- * permission through the Settings application.
- * <p />
- * Profile owner apps are automatically granted permission to query data on the profile they manage
- * (that is, for any query except {@link #querySummaryForDevice}). Device owner apps and carrier-
- * privileged apps likewise get access to usage data for all users on the device.
- * <p />
- * In addition to tethering usage, usage by removed users and apps, and usage by the system
- * is also included in the results for callers with one of these higher levels of access.
- * <p />
- * <b>NOTE:</b> Prior to API level {@value android.os.Build.VERSION_CODES#N}, all calls to these APIs required
- * the above permission, even to access an app's own data usage, and carrier-privileged apps were
- * not included.
- */
-@SystemService(Context.NETWORK_STATS_SERVICE)
-public class NetworkStatsManager {
-    private static final String TAG = "NetworkStatsManager";
-    private static final boolean DBG = false;
-
-    /** @hide */
-    public static final int CALLBACK_LIMIT_REACHED = 0;
-    /** @hide */
-    public static final int CALLBACK_RELEASED = 1;
-
-    /**
-     * Minimum data usage threshold for registering usage callbacks.
-     *
-     * Requests registered with a threshold lower than this will only be triggered once this minimum
-     * is reached.
-     * @hide
-     */
-    public static final long MIN_THRESHOLD_BYTES = 2 * 1_048_576L; // 2MiB
-
-    private final Context mContext;
-    private final INetworkStatsService mService;
-
-    /**
-     * @deprecated Use {@link NetworkStatsDataMigrationUtils#PREFIX_XT}
-     * instead.
-     * @hide
-     */
-    @Deprecated
-    public static final String PREFIX_DEV = "dev";
-
-    /** @hide */
-    public static final int FLAG_POLL_ON_OPEN = 1 << 0;
-    /** @hide */
-    public static final int FLAG_POLL_FORCE = 1 << 1;
-    /** @hide */
-    public static final int FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN = 1 << 2;
-
-    /**
-     * Virtual RAT type to represent 5G NSA (Non Stand Alone) mode, where the primary cell is
-     * still LTE and network allocates a secondary 5G cell so telephony reports RAT = LTE along
-     * with NR state as connected. This is a concept added by NetworkStats on top of the telephony
-     * constants for backward compatibility of metrics so this should not be overlapped with any of
-     * the {@code TelephonyManager.NETWORK_TYPE_*} constants.
-     *
-     * @hide
-     */
-    @SystemApi(client = MODULE_LIBRARIES)
-    public static final int NETWORK_TYPE_5G_NSA = -2;
-
-    private int mFlags;
-
-    /** @hide */
-    @VisibleForTesting
-    public NetworkStatsManager(Context context, INetworkStatsService service) {
-        mContext = context;
-        mService = service;
-        setPollOnOpen(true);
-        setAugmentWithSubscriptionPlan(true);
-    }
-
-    /** @hide */
-    public INetworkStatsService getBinder() {
-        return mService;
-    }
-
-    /**
-     * Set poll on open flag to indicate the poll is needed before service gets statistics
-     * result. This is default enabled. However, for any non-privileged caller, the poll might
-     * be omitted in case of rate limiting.
-     *
-     * @param pollOnOpen true if poll is needed.
-     * @hide
-     */
-    // The system will ignore any non-default values for non-privileged
-    // processes, so processes that don't hold the appropriate permissions
-    // can make no use of this API.
-    @SystemApi(client = MODULE_LIBRARIES)
-    @RequiresPermission(anyOf = {
-            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
-            android.Manifest.permission.NETWORK_STACK})
-    public void setPollOnOpen(boolean pollOnOpen) {
-        if (pollOnOpen) {
-            mFlags |= FLAG_POLL_ON_OPEN;
-        } else {
-            mFlags &= ~FLAG_POLL_ON_OPEN;
-        }
-    }
-
-    /**
-     * Set poll force flag to indicate that calling any subsequent query method will force a stats
-     * poll.
-     * @hide
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    @SystemApi(client = MODULE_LIBRARIES)
-    public void setPollForce(boolean pollForce) {
-        if (pollForce) {
-            mFlags |= FLAG_POLL_FORCE;
-        } else {
-            mFlags &= ~FLAG_POLL_FORCE;
-        }
-    }
-
-    /** @hide */
-    public void setAugmentWithSubscriptionPlan(boolean augmentWithSubscriptionPlan) {
-        if (augmentWithSubscriptionPlan) {
-            mFlags |= FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN;
-        } else {
-            mFlags &= ~FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN;
-        }
-    }
-
-    /**
-     * Query network usage statistics summaries.
-     *
-     * Result is summarised data usage for the whole
-     * device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and
-     * roaming. This means the bucket's start and end timestamp will be the same as the
-     * 'startTime' and 'endTime' arguments. State is going to be
-     * {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL},
-     * tag {@link NetworkStats.Bucket#TAG_NONE},
-     * default network {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
-     * metered {@link NetworkStats.Bucket#METERED_ALL},
-     * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}.
-     * This may take a long time, and apps should avoid calling this on their main thread.
-     *
-     * @param template Template used to match networks. See {@link NetworkTemplate}.
-     * @param startTime Start of period, in milliseconds since the Unix epoch, see
-     *            {@link java.lang.System#currentTimeMillis}.
-     * @param endTime End of period, in milliseconds since the Unix epoch, see
-     *            {@link java.lang.System#currentTimeMillis}.
-     * @return Bucket Summarised data usage.
-     *
-     * @hide
-     */
-    @NonNull
-    @WorkerThread
-    @SystemApi(client = MODULE_LIBRARIES)
-    public Bucket querySummaryForDevice(@NonNull NetworkTemplate template,
-            long startTime, long endTime) {
-        Objects.requireNonNull(template);
-        try {
-            NetworkStats stats =
-                    new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
-            Bucket bucket = stats.getDeviceSummaryForNetwork();
-            stats.close();
-            return bucket;
-        } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-        }
-        return null; // To make the compiler happy.
-    }
-
-    /**
-     * Query network usage statistics summaries. Result is summarised data usage for the whole
-     * device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and
-     * roaming. This means the bucket's start and end timestamp are going to be the same as the
-     * 'startTime' and 'endTime' parameters. State is going to be
-     * {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL},
-     * tag {@link NetworkStats.Bucket#TAG_NONE},
-     * default network {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
-     * metered {@link NetworkStats.Bucket#METERED_ALL},
-     * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}.
-     * This may take a long time, and apps should avoid calling this on their main thread.
-     *
-     * @param networkType As defined in {@link ConnectivityManager}, e.g.
-     *            {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
-     *            etc.
-     * @param subscriberId If applicable, the subscriber id of the network interface.
-     *                     <p>Starting with API level 29, the {@code subscriberId} is guarded by
-     *                     additional restrictions. Calling apps that do not meet the new
-     *                     requirements to access the {@code subscriberId} can provide a {@code
-     *                     null} value when querying for the mobile network type to receive usage
-     *                     for all mobile networks. For additional details see {@link
-     *                     TelephonyManager#getSubscriberId()}.
-     *                     <p>Starting with API level 31, calling apps can provide a
-     *                     {@code subscriberId} with wifi network type to receive usage for
-     *                     wifi networks which is under the given subscription if applicable.
-     *                     Otherwise, pass {@code null} when querying all wifi networks.
-     * @param startTime Start of period. Defined in terms of "Unix time", see
-     *            {@link java.lang.System#currentTimeMillis}.
-     * @param endTime End of period. Defined in terms of "Unix time", see
-     *            {@link java.lang.System#currentTimeMillis}.
-     * @return Bucket object or null if permissions are insufficient or error happened during
-     *         statistics collection.
-     */
-    @WorkerThread
-    public Bucket querySummaryForDevice(int networkType, String subscriberId,
-            long startTime, long endTime) throws SecurityException, RemoteException {
-        NetworkTemplate template;
-        try {
-            template = createTemplate(networkType, subscriberId);
-        } catch (IllegalArgumentException e) {
-            if (DBG) Log.e(TAG, "Cannot create template", e);
-            return null;
-        }
-
-        return querySummaryForDevice(template, startTime, endTime);
-    }
-
-    /**
-     * Query network usage statistics summaries. Result is summarised data usage for all uids
-     * belonging to calling user. Result is a single Bucket aggregated over time, state and uid.
-     * This means the bucket's start and end timestamp are going to be the same as the 'startTime'
-     * and 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL},
-     * uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE},
-     * metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming
-     * {@link NetworkStats.Bucket#ROAMING_ALL}.
-     * This may take a long time, and apps should avoid calling this on their main thread.
-     *
-     * @param networkType As defined in {@link ConnectivityManager}, e.g.
-     *            {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
-     *            etc.
-     * @param subscriberId If applicable, the subscriber id of the network interface.
-     *                     <p>Starting with API level 29, the {@code subscriberId} is guarded by
-     *                     additional restrictions. Calling apps that do not meet the new
-     *                     requirements to access the {@code subscriberId} can provide a {@code
-     *                     null} value when querying for the mobile network type to receive usage
-     *                     for all mobile networks. For additional details see {@link
-     *                     TelephonyManager#getSubscriberId()}.
-     *                     <p>Starting with API level 31, calling apps can provide a
-     *                     {@code subscriberId} with wifi network type to receive usage for
-     *                     wifi networks which is under the given subscription if applicable.
-     *                     Otherwise, pass {@code null} when querying all wifi networks.
-     * @param startTime Start of period. Defined in terms of "Unix time", see
-     *            {@link java.lang.System#currentTimeMillis}.
-     * @param endTime End of period. Defined in terms of "Unix time", see
-     *            {@link java.lang.System#currentTimeMillis}.
-     * @return Bucket object or null if permissions are insufficient or error happened during
-     *         statistics collection.
-     */
-    @WorkerThread
-    public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime,
-            long endTime) throws SecurityException, RemoteException {
-        NetworkTemplate template;
-        try {
-            template = createTemplate(networkType, subscriberId);
-        } catch (IllegalArgumentException e) {
-            if (DBG) Log.e(TAG, "Cannot create template", e);
-            return null;
-        }
-
-        NetworkStats stats;
-        stats = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
-        stats.startSummaryEnumeration();
-
-        stats.close();
-        return stats.getSummaryAggregate();
-    }
-
-    /**
-     * Query network usage statistics summaries. Result filtered to include only uids belonging to
-     * calling user. Result is aggregated over time, hence all buckets will have the same start and
-     * end timestamps. Not aggregated over state, uid, default network, metered, or roaming. This
-     * means buckets' start and end timestamps are going to be the same as the 'startTime' and
-     * 'endTime' parameters. State, uid, metered, and roaming are going to vary, and tag is going to
-     * be the same.
-     * This may take a long time, and apps should avoid calling this on their main thread.
-     *
-     * @param networkType As defined in {@link ConnectivityManager}, e.g.
-     *            {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
-     *            etc.
-     * @param subscriberId If applicable, the subscriber id of the network interface.
-     *                     <p>Starting with API level 29, the {@code subscriberId} is guarded by
-     *                     additional restrictions. Calling apps that do not meet the new
-     *                     requirements to access the {@code subscriberId} can provide a {@code
-     *                     null} value when querying for the mobile network type to receive usage
-     *                     for all mobile networks. For additional details see {@link
-     *                     TelephonyManager#getSubscriberId()}.
-     *                     <p>Starting with API level 31, calling apps can provide a
-     *                     {@code subscriberId} with wifi network type to receive usage for
-     *                     wifi networks which is under the given subscription if applicable.
-     *                     Otherwise, pass {@code null} when querying all wifi networks.
-     * @param startTime Start of period. Defined in terms of "Unix time", see
-     *            {@link java.lang.System#currentTimeMillis}.
-     * @param endTime End of period. Defined in terms of "Unix time", see
-     *            {@link java.lang.System#currentTimeMillis}.
-     * @return Statistics object or null if permissions are insufficient or error happened during
-     *         statistics collection.
-     */
-    @WorkerThread
-    public NetworkStats querySummary(int networkType, String subscriberId, long startTime,
-            long endTime) throws SecurityException, RemoteException {
-        NetworkTemplate template;
-        try {
-            template = createTemplate(networkType, subscriberId);
-        } catch (IllegalArgumentException e) {
-            if (DBG) Log.e(TAG, "Cannot create template", e);
-            return null;
-        }
-
-        return querySummary(template, startTime, endTime);
-    }
-
-    /**
-     * Query network usage statistics summaries.
-     *
-     * The results will only include traffic made by UIDs belonging to the calling user profile.
-     * The results are aggregated over time, so that all buckets will have the same start and
-     * end timestamps as the passed arguments. Not aggregated over state, uid, default network,
-     * metered, or roaming.
-     * This may take a long time, and apps should avoid calling this on their main thread.
-     *
-     * @param template Template used to match networks. See {@link NetworkTemplate}.
-     * @param startTime Start of period, in milliseconds since the Unix epoch, see
-     *            {@link java.lang.System#currentTimeMillis}.
-     * @param endTime End of period, in milliseconds since the Unix epoch, see
-     *            {@link java.lang.System#currentTimeMillis}.
-     * @return Statistics which is described above.
-     * @hide
-     */
-    @NonNull
-    @SystemApi(client = MODULE_LIBRARIES)
-    @WorkerThread
-    public NetworkStats querySummary(@NonNull NetworkTemplate template, long startTime,
-            long endTime) throws SecurityException {
-        Objects.requireNonNull(template);
-        try {
-            NetworkStats result =
-                    new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
-            result.startSummaryEnumeration();
-            return result;
-        } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-        }
-        return null; // To make the compiler happy.
-    }
-
-    /**
-     * Query tagged network usage statistics summaries.
-     *
-     * The results will only include tagged traffic made by UIDs belonging to the calling user
-     * profile. The results are aggregated over time, so that all buckets will have the same
-     * start and end timestamps as the passed arguments. Not aggregated over state, uid,
-     * default network, metered, or roaming.
-     * This may take a long time, and apps should avoid calling this on their main thread.
-     *
-     * @param template Template used to match networks. See {@link NetworkTemplate}.
-     * @param startTime Start of period, in milliseconds since the Unix epoch, see
-     *            {@link System#currentTimeMillis}.
-     * @param endTime End of period, in milliseconds since the Unix epoch, see
-     *            {@link System#currentTimeMillis}.
-     * @return Statistics which is described above.
-     * @hide
-     */
-    @NonNull
-    @SystemApi(client = MODULE_LIBRARIES)
-    @WorkerThread
-    public NetworkStats queryTaggedSummary(@NonNull NetworkTemplate template, long startTime,
-            long endTime) throws SecurityException {
-        Objects.requireNonNull(template);
-        try {
-            NetworkStats result =
-                    new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
-            result.startTaggedSummaryEnumeration();
-            return result;
-        } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-        }
-        return null; // To make the compiler happy.
-    }
-
-    /**
-     * Query usage statistics details for networks matching a given {@link NetworkTemplate}.
-     *
-     * Result is not aggregated over time. This means buckets' start and
-     * end timestamps will be between 'startTime' and 'endTime' parameters.
-     * <p>Only includes buckets whose entire time period is included between
-     * startTime and endTime. Doesn't interpolate or return partial buckets.
-     * Since bucket length is in the order of hours, this
-     * method cannot be used to measure data usage on a fine grained time scale.
-     * This may take a long time, and apps should avoid calling this on their main thread.
-     *
-     * @param template Template used to match networks. See {@link NetworkTemplate}.
-     * @param startTime Start of period, in milliseconds since the Unix epoch, see
-     *                  {@link java.lang.System#currentTimeMillis}.
-     * @param endTime End of period, in milliseconds since the Unix epoch, see
-     *                {@link java.lang.System#currentTimeMillis}.
-     * @return Statistics which is described above.
-     * @hide
-     */
-    @NonNull
-    @SystemApi(client = MODULE_LIBRARIES)
-    @WorkerThread
-    public NetworkStats queryDetailsForDevice(@NonNull NetworkTemplate template,
-            long startTime, long endTime) {
-        Objects.requireNonNull(template);
-        try {
-            final NetworkStats result =
-                    new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
-            result.startHistoryDeviceEnumeration();
-            return result;
-        } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-        }
-
-        return null; // To make the compiler happy.
-    }
-
-    /**
-     * Query network usage statistics details for a given uid.
-     * This may take a long time, and apps should avoid calling this on their main thread.
-     *
-     * @see #queryDetailsForUidTagState(int, String, long, long, int, int, int)
-     */
-    @WorkerThread
-    public NetworkStats queryDetailsForUid(int networkType, String subscriberId,
-            long startTime, long endTime, int uid) throws SecurityException {
-        return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid,
-            NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL);
-    }
-
-    /** @hide */
-    public NetworkStats queryDetailsForUid(NetworkTemplate template,
-            long startTime, long endTime, int uid) throws SecurityException {
-        return queryDetailsForUidTagState(template, startTime, endTime, uid,
-                NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL);
-    }
-
-    /**
-     * Query network usage statistics details for a given uid and tag.
-     * This may take a long time, and apps should avoid calling this on their main thread.
-     *
-     * @see #queryDetailsForUidTagState(int, String, long, long, int, int, int)
-     */
-    @WorkerThread
-    public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId,
-            long startTime, long endTime, int uid, int tag) throws SecurityException {
-        return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid,
-            tag, NetworkStats.Bucket.STATE_ALL);
-    }
-
-    /**
-     * Query network usage statistics details for a given uid, tag, and state. Only usable for uids
-     * belonging to calling user. Result is not aggregated over time. This means buckets' start and
-     * end timestamps are going to be between 'startTime' and 'endTime' parameters. The uid is going
-     * to be the same as the 'uid' parameter, the tag the same as the 'tag' parameter, and the state
-     * the same as the 'state' parameter.
-     * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
-     * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and
-     * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}.
-     * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't
-     * interpolate across partial buckets. Since bucket length is in the order of hours, this
-     * method cannot be used to measure data usage on a fine grained time scale.
-     * This may take a long time, and apps should avoid calling this on their main thread.
-     *
-     * @param networkType As defined in {@link ConnectivityManager}, e.g.
-     *            {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
-     *            etc.
-     * @param subscriberId If applicable, the subscriber id of the network interface.
-     *                     <p>Starting with API level 29, the {@code subscriberId} is guarded by
-     *                     additional restrictions. Calling apps that do not meet the new
-     *                     requirements to access the {@code subscriberId} can provide a {@code
-     *                     null} value when querying for the mobile network type to receive usage
-     *                     for all mobile networks. For additional details see {@link
-     *                     TelephonyManager#getSubscriberId()}.
-     *                     <p>Starting with API level 31, calling apps can provide a
-     *                     {@code subscriberId} with wifi network type to receive usage for
-     *                     wifi networks which is under the given subscription if applicable.
-     *                     Otherwise, pass {@code null} when querying all wifi networks.
-     * @param startTime Start of period. Defined in terms of "Unix time", see
-     *            {@link java.lang.System#currentTimeMillis}.
-     * @param endTime End of period. Defined in terms of "Unix time", see
-     *            {@link java.lang.System#currentTimeMillis}.
-     * @param uid UID of app
-     * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for aggregated data
-     *            across all the tags.
-     * @param state state of interest. Use {@link NetworkStats.Bucket#STATE_ALL} to aggregate
-     *            traffic from all states.
-     * @return Statistics object or null if an error happened during statistics collection.
-     * @throws SecurityException if permissions are insufficient to read network statistics.
-     */
-    @WorkerThread
-    public NetworkStats queryDetailsForUidTagState(int networkType, String subscriberId,
-            long startTime, long endTime, int uid, int tag, int state) throws SecurityException {
-        NetworkTemplate template;
-        template = createTemplate(networkType, subscriberId);
-
-        return queryDetailsForUidTagState(template, startTime, endTime, uid, tag, state);
-    }
-
-    /**
-     * Query network usage statistics details for a given template, uid, tag, and state.
-     *
-     * Only usable for uids belonging to calling user. Result is not aggregated over time.
-     * This means buckets' start and end timestamps are going to be between 'startTime' and
-     * 'endTime' parameters. The uid is going to be the same as the 'uid' parameter, the tag
-     * the same as the 'tag' parameter, and the state the same as the 'state' parameter.
-     * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
-     * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and
-     * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}.
-     * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't
-     * interpolate across partial buckets. Since bucket length is in the order of hours, this
-     * method cannot be used to measure data usage on a fine grained time scale.
-     * This may take a long time, and apps should avoid calling this on their main thread.
-     *
-     * @param template Template used to match networks. See {@link NetworkTemplate}.
-     * @param startTime Start of period, in milliseconds since the Unix epoch, see
-     *                  {@link java.lang.System#currentTimeMillis}.
-     * @param endTime End of period, in milliseconds since the Unix epoch, see
-     *                {@link java.lang.System#currentTimeMillis}.
-     * @param uid UID of app
-     * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for aggregated data
-     *            across all the tags.
-     * @param state state of interest. Use {@link NetworkStats.Bucket#STATE_ALL} to aggregate
-     *            traffic from all states.
-     * @return Statistics which is described above.
-     * @hide
-     */
-    @NonNull
-    @SystemApi(client = MODULE_LIBRARIES)
-    @WorkerThread
-    public NetworkStats queryDetailsForUidTagState(@NonNull NetworkTemplate template,
-            long startTime, long endTime, int uid, int tag, int state) throws SecurityException {
-        Objects.requireNonNull(template);
-        try {
-            final NetworkStats result = new NetworkStats(
-                    mContext, template, mFlags, startTime, endTime, mService);
-            result.startHistoryUidEnumeration(uid, tag, state);
-            return result;
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag
-                    + " state=" + state, e);
-            e.rethrowFromSystemServer();
-        }
-
-        return null; // To make the compiler happy.
-    }
-
-    /**
-     * Query network usage statistics details. Result filtered to include only uids belonging to
-     * calling user. Result is aggregated over state but not aggregated over time, uid, tag,
-     * metered, nor roaming. This means buckets' start and end timestamps are going to be between
-     * 'startTime' and 'endTime' parameters. State is going to be
-     * {@link NetworkStats.Bucket#STATE_ALL}, uid will vary,
-     * tag {@link NetworkStats.Bucket#TAG_NONE},
-     * default network is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
-     * metered is going to be {@link NetworkStats.Bucket#METERED_ALL},
-     * and roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}.
-     * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't
-     * interpolate across partial buckets. Since bucket length is in the order of hours, this
-     * method cannot be used to measure data usage on a fine grained time scale.
-     * This may take a long time, and apps should avoid calling this on their main thread.
-     *
-     * @param networkType As defined in {@link ConnectivityManager}, e.g.
-     *            {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
-     *            etc.
-     * @param subscriberId If applicable, the subscriber id of the network interface.
-     *                     <p>Starting with API level 29, the {@code subscriberId} is guarded by
-     *                     additional restrictions. Calling apps that do not meet the new
-     *                     requirements to access the {@code subscriberId} can provide a {@code
-     *                     null} value when querying for the mobile network type to receive usage
-     *                     for all mobile networks. For additional details see {@link
-     *                     TelephonyManager#getSubscriberId()}.
-     *                     <p>Starting with API level 31, calling apps can provide a
-     *                     {@code subscriberId} with wifi network type to receive usage for
-     *                     wifi networks which is under the given subscription if applicable.
-     *                     Otherwise, pass {@code null} when querying all wifi networks.
-     * @param startTime Start of period. Defined in terms of "Unix time", see
-     *            {@link java.lang.System#currentTimeMillis}.
-     * @param endTime End of period. Defined in terms of "Unix time", see
-     *            {@link java.lang.System#currentTimeMillis}.
-     * @return Statistics object or null if permissions are insufficient or error happened during
-     *         statistics collection.
-     */
-    @WorkerThread
-    public NetworkStats queryDetails(int networkType, String subscriberId, long startTime,
-            long endTime) throws SecurityException, RemoteException {
-        NetworkTemplate template;
-        try {
-            template = createTemplate(networkType, subscriberId);
-        } catch (IllegalArgumentException e) {
-            if (DBG) Log.e(TAG, "Cannot create template", e);
-            return null;
-        }
-
-        NetworkStats result;
-        result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
-        result.startUserUidEnumeration();
-        return result;
-    }
-
-    /**
-     * Query realtime mobile network usage statistics.
-     *
-     * Return a snapshot of current UID network statistics, as it applies
-     * to the mobile radios of the device. The snapshot will include any
-     * tethering traffic, video calling data usage and count of
-     * network operations set by {@link TrafficStats#incrementOperationCount}
-     * made over a mobile radio.
-     * The snapshot will not include any statistics that cannot be seen by
-     * the kernel, e.g. statistics reported by {@link NetworkStatsProvider}s.
-     *
-     * @hide
-     */
-    @SystemApi
-    @RequiresPermission(anyOf = {
-            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
-            android.Manifest.permission.NETWORK_STACK})
-    @NonNull public android.net.NetworkStats getMobileUidStats() {
-        try {
-            return mService.getUidStatsForTransport(TRANSPORT_CELLULAR);
-        } catch (RemoteException e) {
-            if (DBG) Log.d(TAG, "Remote exception when get Mobile uid stats");
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Query realtime Wi-Fi network usage statistics.
-     *
-     * Return a snapshot of current UID network statistics, as it applies
-     * to the Wi-Fi radios of the device. The snapshot will include any
-     * tethering traffic, video calling data usage and count of
-     * network operations set by {@link TrafficStats#incrementOperationCount}
-     * made over a Wi-Fi radio.
-     * The snapshot will not include any statistics that cannot be seen by
-     * the kernel, e.g. statistics reported by {@link NetworkStatsProvider}s.
-     *
-     * @hide
-     */
-    @SystemApi
-    @RequiresPermission(anyOf = {
-            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
-            android.Manifest.permission.NETWORK_STACK})
-    @NonNull public android.net.NetworkStats getWifiUidStats() {
-        try {
-            return mService.getUidStatsForTransport(TRANSPORT_WIFI);
-        } catch (RemoteException e) {
-            if (DBG) Log.d(TAG, "Remote exception when get WiFi uid stats");
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Registers to receive notifications about data usage on specified networks.
-     *
-     * <p>The callbacks will continue to be called as long as the process is alive or
-     * {@link #unregisterUsageCallback} is called.
-     *
-     * @param template Template used to match networks. See {@link NetworkTemplate}.
-     * @param thresholdBytes Threshold in bytes to be notified on. Provided values lower than 2MiB
-     *                       will be clamped for callers except callers with the NETWORK_STACK
-     *                       permission.
-     * @param executor The executor on which callback will be invoked. The provided {@link Executor}
-     *                 must run callback sequentially, otherwise the order of callbacks cannot be
-     *                 guaranteed.
-     * @param callback The {@link UsageCallback} that the system will call when data usage
-     *                 has exceeded the specified threshold.
-     * @hide
-     */
-    @SystemApi(client = MODULE_LIBRARIES)
-    @RequiresPermission(anyOf = {
-            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
-            android.Manifest.permission.NETWORK_STACK}, conditional = true)
-    public void registerUsageCallback(@NonNull NetworkTemplate template, long thresholdBytes,
-            @NonNull @CallbackExecutor Executor executor, @NonNull UsageCallback callback) {
-        Objects.requireNonNull(template, "NetworkTemplate cannot be null");
-        Objects.requireNonNull(callback, "UsageCallback cannot be null");
-        Objects.requireNonNull(executor, "Executor cannot be null");
-
-        final DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET,
-                template, thresholdBytes);
-        try {
-            final UsageCallbackWrapper callbackWrapper =
-                    new UsageCallbackWrapper(executor, callback);
-            callback.request = mService.registerUsageCallback(
-                    mContext.getOpPackageName(), request, callbackWrapper);
-            if (DBG) Log.d(TAG, "registerUsageCallback returned " + callback.request);
-
-            if (callback.request == null) {
-                Log.e(TAG, "Request from callback is null; should not happen");
-            }
-        } catch (RemoteException e) {
-            if (DBG) Log.d(TAG, "Remote exception when registering callback");
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Registers to receive notifications about data usage on specified networks.
-     *
-     * @see #registerUsageCallback(int, String, long, UsageCallback, Handler)
-     */
-    public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes,
-            UsageCallback callback) {
-        registerUsageCallback(networkType, subscriberId, thresholdBytes, callback,
-                null /* handler */);
-    }
-
-    /**
-     * Registers to receive notifications about data usage on specified networks.
-     *
-     * <p>The callbacks will continue to be called as long as the process is live or
-     * {@link #unregisterUsageCallback} is called.
-     *
-     * @param networkType Type of network to monitor. Either
-                  {@link ConnectivityManager#TYPE_MOBILE} or {@link ConnectivityManager#TYPE_WIFI}.
-     * @param subscriberId If applicable, the subscriber id of the network interface.
-     *                     <p>Starting with API level 29, the {@code subscriberId} is guarded by
-     *                     additional restrictions. Calling apps that do not meet the new
-     *                     requirements to access the {@code subscriberId} can provide a {@code
-     *                     null} value when registering for the mobile network type to receive
-     *                     notifications for all mobile networks. For additional details see {@link
-     *                     TelephonyManager#getSubscriberId()}.
-     *                     <p>Starting with API level 31, calling apps can provide a
-     *                     {@code subscriberId} with wifi network type to receive usage for
-     *                     wifi networks which is under the given subscription if applicable.
-     *                     Otherwise, pass {@code null} when querying all wifi networks.
-     * @param thresholdBytes Threshold in bytes to be notified on.
-     * @param callback The {@link UsageCallback} that the system will call when data usage
-     *            has exceeded the specified threshold.
-     * @param handler to dispatch callback events through, otherwise if {@code null} it uses
-     *            the calling thread.
-     */
-    public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes,
-            UsageCallback callback, @Nullable Handler handler) {
-        NetworkTemplate template = createTemplate(networkType, subscriberId);
-        if (DBG) {
-            Log.d(TAG, "registerUsageCallback called with: {"
-                    + " networkType=" + networkType
-                    + " subscriberId=" + subscriberId
-                    + " thresholdBytes=" + thresholdBytes
-                    + " }");
-        }
-
-        final Executor executor = handler == null ? r -> r.run() : r -> handler.post(r);
-
-        registerUsageCallback(template, thresholdBytes, executor, callback);
-    }
-
-    /**
-     * Unregisters callbacks on data usage.
-     *
-     * @param callback The {@link UsageCallback} used when registering.
-     */
-    public void unregisterUsageCallback(UsageCallback callback) {
-        if (callback == null || callback.request == null
-                || callback.request.requestId == DataUsageRequest.REQUEST_ID_UNSET) {
-            throw new IllegalArgumentException("Invalid UsageCallback");
-        }
-        try {
-            mService.unregisterUsageRequest(callback.request);
-        } catch (RemoteException e) {
-            if (DBG) Log.d(TAG, "Remote exception when unregistering callback");
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Base class for usage callbacks. Should be extended by applications wanting notifications.
-     */
-    public static abstract class UsageCallback {
-        /**
-         * Called when data usage has reached the given threshold.
-         *
-         * Called by {@code NetworkStatsService} when the registered threshold is reached.
-         * If a caller implements {@link #onThresholdReached(NetworkTemplate)}, the system
-         * will not call {@link #onThresholdReached(int, String)}.
-         *
-         * @param template The {@link NetworkTemplate} that associated with this callback.
-         * @hide
-         */
-        @SystemApi(client = MODULE_LIBRARIES)
-        public void onThresholdReached(@NonNull NetworkTemplate template) {
-            // Backward compatibility for those who didn't override this function.
-            final int networkType = networkTypeForTemplate(template);
-            if (networkType != ConnectivityManager.TYPE_NONE) {
-                final String subscriberId = template.getSubscriberIds().isEmpty() ? null
-                        : template.getSubscriberIds().iterator().next();
-                onThresholdReached(networkType, subscriberId);
-            }
-        }
-
-        /**
-         * Called when data usage has reached the given threshold.
-         */
-        public abstract void onThresholdReached(int networkType, String subscriberId);
-
-        /**
-         * @hide used for internal bookkeeping
-         */
-        private DataUsageRequest request;
-
-        /**
-         * Get network type from a template if feasible.
-         *
-         * @param template the target {@link NetworkTemplate}.
-         * @return legacy network type, only supports for the types which is already supported in
-         *         {@link #registerUsageCallback(int, String, long, UsageCallback, Handler)}.
-         *         {@link ConnectivityManager#TYPE_NONE} for other types.
-         */
-        private static int networkTypeForTemplate(@NonNull NetworkTemplate template) {
-            switch (template.getMatchRule()) {
-                case NetworkTemplate.MATCH_MOBILE:
-                    return ConnectivityManager.TYPE_MOBILE;
-                case NetworkTemplate.MATCH_WIFI:
-                    return ConnectivityManager.TYPE_WIFI;
-                default:
-                    return ConnectivityManager.TYPE_NONE;
-            }
-        }
-    }
-
-    /**
-     * Registers a custom provider of {@link android.net.NetworkStats} to provide network statistics
-     * to the system. To unregister, invoke {@link #unregisterNetworkStatsProvider}.
-     * Note that no de-duplication of statistics between providers is performed, so each provider
-     * must only report network traffic that is not being reported by any other provider. Also note
-     * that the provider cannot be re-registered after unregistering.
-     *
-     * @param tag a human readable identifier of the custom network stats provider. This is only
-     *            used for debugging.
-     * @param provider the subclass of {@link NetworkStatsProvider} that needs to be
-     *                 registered to the system.
-     * @hide
-     */
-    @SystemApi
-    @RequiresPermission(anyOf = {
-            android.Manifest.permission.NETWORK_STATS_PROVIDER,
-            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
-    @NonNull public void registerNetworkStatsProvider(
-            @NonNull String tag,
-            @NonNull NetworkStatsProvider provider) {
-        try {
-            if (provider.getProviderCallbackBinder() != null) {
-                throw new IllegalArgumentException("provider is already registered");
-            }
-            final INetworkStatsProviderCallback cbBinder =
-                    mService.registerNetworkStatsProvider(tag, provider.getProviderBinder());
-            provider.setProviderCallbackBinder(cbBinder);
-        } catch (RemoteException e) {
-            e.rethrowAsRuntimeException();
-        }
-    }
-
-    /**
-     * Unregisters an instance of {@link NetworkStatsProvider}.
-     *
-     * @param provider the subclass of {@link NetworkStatsProvider} that needs to be
-     *                 unregistered to the system.
-     * @hide
-     */
-    @SystemApi
-    @RequiresPermission(anyOf = {
-            android.Manifest.permission.NETWORK_STATS_PROVIDER,
-            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
-    @NonNull public void unregisterNetworkStatsProvider(@NonNull NetworkStatsProvider provider) {
-        try {
-            provider.getProviderCallbackBinderOrThrow().unregister();
-        } catch (RemoteException e) {
-            e.rethrowAsRuntimeException();
-        }
-    }
-
-    private static NetworkTemplate createTemplate(int networkType, String subscriberId) {
-        final NetworkTemplate template;
-        switch (networkType) {
-            case ConnectivityManager.TYPE_MOBILE:
-                template = subscriberId == null
-                        ? NetworkTemplate.buildTemplateMobileWildcard()
-                        : NetworkTemplate.buildTemplateMobileAll(subscriberId);
-                break;
-            case ConnectivityManager.TYPE_WIFI:
-                template = TextUtils.isEmpty(subscriberId)
-                        ? NetworkTemplate.buildTemplateWifiWildcard()
-                        : NetworkTemplate.buildTemplateWifi(NetworkTemplate.WIFI_NETWORKID_ALL,
-                                subscriberId);
-                break;
-            default:
-                throw new IllegalArgumentException("Cannot create template for network type "
-                        + networkType + ", subscriberId '"
-                        + NetworkIdentityUtils.scrubSubscriberId(subscriberId) + "'.");
-        }
-        return template;
-    }
-
-    /**
-     * Notify {@code NetworkStatsService} about network status changed.
-     *
-     * Notifies NetworkStatsService of network state changes for data usage accounting purposes.
-     *
-     * To avoid races that attribute data usage to wrong network, such as new network with
-     * the same interface after SIM hot-swap, this function will not return until
-     * {@code NetworkStatsService} finishes its work of retrieving traffic statistics from
-     * all data sources.
-     *
-     * @param defaultNetworks the list of all networks that could be used by network traffic that
-     *                        does not explicitly select a network.
-     * @param networkStateSnapshots a list of {@link NetworkStateSnapshot}s, one for
-     *                              each network that is currently connected.
-     * @param activeIface the active (i.e., connected) default network interface for the calling
-     *                    uid. Used to determine on which network future calls to
-     *                    {@link android.net.TrafficStats#incrementOperationCount} applies to.
-     * @param underlyingNetworkInfos the list of underlying network information for all
-     *                               currently-connected VPNs.
-     *
-     * @hide
-     */
-    @SystemApi(client = MODULE_LIBRARIES)
-    @RequiresPermission(anyOf = {
-            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
-            android.Manifest.permission.NETWORK_STACK})
-    public void notifyNetworkStatus(
-            @NonNull List<Network> defaultNetworks,
-            @NonNull List<NetworkStateSnapshot> networkStateSnapshots,
-            @Nullable String activeIface,
-            @NonNull List<UnderlyingNetworkInfo> underlyingNetworkInfos) {
-        try {
-            Objects.requireNonNull(defaultNetworks);
-            Objects.requireNonNull(networkStateSnapshots);
-            Objects.requireNonNull(underlyingNetworkInfos);
-            mService.notifyNetworkStatus(defaultNetworks.toArray(new Network[0]),
-                    networkStateSnapshots.toArray(new NetworkStateSnapshot[0]), activeIface,
-                    underlyingNetworkInfos.toArray(new UnderlyingNetworkInfo[0]));
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    private static class UsageCallbackWrapper extends IUsageCallback.Stub {
-        // Null if unregistered.
-        private volatile UsageCallback mCallback;
-
-        private final Executor mExecutor;
-
-        UsageCallbackWrapper(@NonNull Executor executor, @NonNull UsageCallback callback) {
-            mCallback = callback;
-            mExecutor = executor;
-        }
-
-        @Override
-        public void onThresholdReached(DataUsageRequest request) {
-            // Copy it to a local variable in case mCallback changed inside the if condition.
-            final UsageCallback callback = mCallback;
-            if (callback != null) {
-                mExecutor.execute(() -> callback.onThresholdReached(request.template));
-            } else {
-                Log.e(TAG, "onThresholdReached with released callback for " + request);
-            }
-        }
-
-        @Override
-        public void onCallbackReleased(DataUsageRequest request) {
-            if (DBG) Log.d(TAG, "callback released for " + request);
-            mCallback = null;
-        }
-    }
-
-    /**
-     * Mark given UID as being in foreground for stats purposes.
-     *
-     * @hide
-     */
-    @SystemApi(client = MODULE_LIBRARIES)
-    @RequiresPermission(anyOf = {
-            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
-            android.Manifest.permission.NETWORK_STACK})
-    public void setUidForeground(int uid, boolean uidForeground) {
-        try {
-            mService.setUidForeground(uid, uidForeground);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Set default value of global alert bytes, the value will be clamped to [128kB, 2MB].
-     *
-     * @hide
-     */
-    @SystemApi(client = MODULE_LIBRARIES)
-    @RequiresPermission(anyOf = {
-            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
-            Manifest.permission.NETWORK_STACK})
-    public void setDefaultGlobalAlert(long alertBytes) {
-        try {
-            // TODO: Sync internal naming with the API surface.
-            mService.advisePersistThreshold(alertBytes);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Force update of statistics.
-     *
-     * @hide
-     */
-    @SystemApi(client = MODULE_LIBRARIES)
-    @RequiresPermission(anyOf = {
-            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
-            android.Manifest.permission.NETWORK_STACK})
-    public void forceUpdate() {
-        try {
-            mService.forceUpdate();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Set the warning and limit to all registered custom network stats providers.
-     * Note that invocation of any interface will be sent to all providers.
-     *
-     * Asynchronicity notes : because traffic may be happening on the device at the same time, it
-     * doesn't make sense to wait for the warning and limit to be set – a caller still wouldn't
-     * know when exactly it was effective. All that can matter is that it's done quickly. Also,
-     * this method can't fail, so there is no status to return. All providers will see the new
-     * values soon.
-     * As such, this method returns immediately and sends the warning and limit to all providers
-     * as soon as possible through a one-way binder call.
-     *
-     * @hide
-     */
-    @SystemApi(client = MODULE_LIBRARIES)
-    @RequiresPermission(anyOf = {
-            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
-            android.Manifest.permission.NETWORK_STACK})
-    public void setStatsProviderWarningAndLimitAsync(@NonNull String iface, long warning,
-            long limit) {
-        try {
-            mService.setStatsProviderWarningAndLimitAsync(iface, warning, limit);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Get a RAT type representative of a group of RAT types for network statistics.
-     *
-     * Collapse the given Radio Access Technology (RAT) type into a bucket that
-     * is representative of the original RAT type for network statistics. The
-     * mapping mostly corresponds to {@code TelephonyManager#NETWORK_CLASS_BIT_MASK_*}
-     * but with adaptations specific to the virtual types introduced by
-     * networks stats.
-     *
-     * @param ratType An integer defined in {@code TelephonyManager#NETWORK_TYPE_*}.
-     *
-     * @hide
-     */
-    @SystemApi(client = MODULE_LIBRARIES)
-    public static int getCollapsedRatType(int ratType) {
-        switch (ratType) {
-            case TelephonyManager.NETWORK_TYPE_GPRS:
-            case TelephonyManager.NETWORK_TYPE_GSM:
-            case TelephonyManager.NETWORK_TYPE_EDGE:
-            case TelephonyManager.NETWORK_TYPE_IDEN:
-            case TelephonyManager.NETWORK_TYPE_CDMA:
-            case TelephonyManager.NETWORK_TYPE_1xRTT:
-                return TelephonyManager.NETWORK_TYPE_GSM;
-            case TelephonyManager.NETWORK_TYPE_EVDO_0:
-            case TelephonyManager.NETWORK_TYPE_EVDO_A:
-            case TelephonyManager.NETWORK_TYPE_EVDO_B:
-            case TelephonyManager.NETWORK_TYPE_EHRPD:
-            case TelephonyManager.NETWORK_TYPE_UMTS:
-            case TelephonyManager.NETWORK_TYPE_HSDPA:
-            case TelephonyManager.NETWORK_TYPE_HSUPA:
-            case TelephonyManager.NETWORK_TYPE_HSPA:
-            case TelephonyManager.NETWORK_TYPE_HSPAP:
-            case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
-                return TelephonyManager.NETWORK_TYPE_UMTS;
-            case TelephonyManager.NETWORK_TYPE_LTE:
-            case TelephonyManager.NETWORK_TYPE_IWLAN:
-                return TelephonyManager.NETWORK_TYPE_LTE;
-            case TelephonyManager.NETWORK_TYPE_NR:
-                return TelephonyManager.NETWORK_TYPE_NR;
-            // Virtual RAT type for 5G NSA mode, see
-            // {@link NetworkStatsManager#NETWORK_TYPE_5G_NSA}.
-            case NetworkStatsManager.NETWORK_TYPE_5G_NSA:
-                return NetworkStatsManager.NETWORK_TYPE_5G_NSA;
-            default:
-                return TelephonyManager.NETWORK_TYPE_UNKNOWN;
-        }
-    }
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java b/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java
deleted file mode 100644
index 9bffbfb..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.SystemApi;
-import android.app.SystemServiceRegistry;
-import android.app.usage.NetworkStatsManager;
-import android.content.Context;
-import android.net.nsd.INsdManager;
-import android.net.nsd.NsdManager;
-
-/**
- * Class for performing registration for Connectivity services which are exposed via updatable APIs
- * since Android T.
- *
- * @hide
- */
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-public final class ConnectivityFrameworkInitializerTiramisu {
-    private ConnectivityFrameworkInitializerTiramisu() {}
-
-    /**
-     * Called by {@link SystemServiceRegistry}'s static initializer and registers nsd services to
-     * {@link Context}, so that {@link Context#getSystemService} can return them.
-     *
-     * @throws IllegalStateException if this is called anywhere besides
-     * {@link SystemServiceRegistry}.
-     */
-    public static void registerServiceWrappers() {
-        SystemServiceRegistry.registerContextAwareService(
-                Context.NSD_SERVICE,
-                NsdManager.class,
-                (context, serviceBinder) -> {
-                    INsdManager service = INsdManager.Stub.asInterface(serviceBinder);
-                    return new NsdManager(context, service);
-                }
-        );
-
-        SystemServiceRegistry.registerContextAwareService(
-                Context.IPSEC_SERVICE,
-                IpSecManager.class,
-                (context, serviceBinder) -> {
-                    IIpSecService service = IIpSecService.Stub.asInterface(serviceBinder);
-                    return new IpSecManager(context, service);
-                }
-        );
-
-        SystemServiceRegistry.registerContextAwareService(
-                Context.NETWORK_STATS_SERVICE,
-                NetworkStatsManager.class,
-                (context, serviceBinder) -> {
-                    INetworkStatsService service =
-                            INetworkStatsService.Stub.asInterface(serviceBinder);
-                    return new NetworkStatsManager(context, service);
-                }
-        );
-    }
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/DataUsageRequest.aidl b/packages/ConnectivityT/framework-t/src/android/net/DataUsageRequest.aidl
deleted file mode 100644
index d1937c7..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/DataUsageRequest.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-parcelable DataUsageRequest;
diff --git a/packages/ConnectivityT/framework-t/src/android/net/DataUsageRequest.java b/packages/ConnectivityT/framework-t/src/android/net/DataUsageRequest.java
deleted file mode 100644
index f0ff465..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/DataUsageRequest.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/**
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy
- * of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-
-package android.net;
-
-import android.annotation.Nullable;
-import android.net.NetworkTemplate;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Objects;
-
-/**
- * Defines a request to register a callbacks. Used to be notified on data usage via
- * {@link android.app.usage.NetworkStatsManager#registerDataUsageCallback}.
- * If no {@code uid}s are set, callbacks are restricted to device-owners,
- * carrier-privileged apps, or system apps.
- *
- * @hide
- */
-public final class DataUsageRequest implements Parcelable {
-
-    public static final String PARCELABLE_KEY = "DataUsageRequest";
-    public static final int REQUEST_ID_UNSET = 0;
-
-    /**
-     * Identifies the request.  {@link DataUsageRequest}s should only be constructed by
-     * the Framework and it is used internally to identify the request.
-     */
-    public final int requestId;
-
-    /**
-     * {@link NetworkTemplate} describing the network to monitor.
-     */
-    public final NetworkTemplate template;
-
-    /**
-     * Threshold in bytes to be notified on.
-     */
-    public final long thresholdInBytes;
-
-    public DataUsageRequest(int requestId, NetworkTemplate template, long thresholdInBytes) {
-        this.requestId = requestId;
-        this.template = template;
-        this.thresholdInBytes = thresholdInBytes;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(requestId);
-        dest.writeParcelable(template, flags);
-        dest.writeLong(thresholdInBytes);
-    }
-
-    public static final @android.annotation.NonNull Creator<DataUsageRequest> CREATOR =
-            new Creator<DataUsageRequest>() {
-                @Override
-                public DataUsageRequest createFromParcel(Parcel in) {
-                    int requestId = in.readInt();
-                    NetworkTemplate template = in.readParcelable(null, android.net.NetworkTemplate.class);
-                    long thresholdInBytes = in.readLong();
-                    DataUsageRequest result = new DataUsageRequest(requestId, template,
-                            thresholdInBytes);
-                    return result;
-                }
-
-                @Override
-                public DataUsageRequest[] newArray(int size) {
-                    return new DataUsageRequest[size];
-                }
-            };
-
-    @Override
-    public String toString() {
-        return "DataUsageRequest [ requestId=" + requestId
-                + ", networkTemplate=" + template
-                + ", thresholdInBytes=" + thresholdInBytes + " ]";
-    }
-
-    @Override
-    public boolean equals(@Nullable Object obj) {
-        if (obj instanceof DataUsageRequest == false) return false;
-        DataUsageRequest that = (DataUsageRequest) obj;
-        return that.requestId == this.requestId
-                && Objects.equals(that.template, this.template)
-                && that.thresholdInBytes == this.thresholdInBytes;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(requestId, template, thresholdInBytes);
-   }
-
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
deleted file mode 100644
index 72243f9..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
+++ /dev/null
@@ -1,603 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-
-import android.annotation.CallbackExecutor;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresFeature;
-import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
-import android.annotation.SystemService;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Build;
-import android.os.RemoteException;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.os.BackgroundThread;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.Objects;
-import java.util.concurrent.Executor;
-import java.util.function.BiConsumer;
-
-/**
- * A class that manages and configures Ethernet interfaces.
- *
- * @hide
- */
-@SystemApi
-@SystemService(Context.ETHERNET_SERVICE)
-public class EthernetManager {
-    private static final String TAG = "EthernetManager";
-
-    private final IEthernetManager mService;
-    @GuardedBy("mListeners")
-    private final ArrayList<ListenerInfo> mListeners = new ArrayList<>();
-    private final IEthernetServiceListener.Stub mServiceListener =
-            new IEthernetServiceListener.Stub() {
-                @Override
-                public void onInterfaceStateChanged(String iface, int state, int role,
-                        IpConfiguration configuration) {
-                    synchronized (mListeners) {
-                        for (ListenerInfo li : mListeners) {
-                            li.executor.execute(() ->
-                                    li.listener.onInterfaceStateChanged(iface, state, role,
-                                            configuration));
-                        }
-                    }
-                }
-            };
-
-    private static class ListenerInfo {
-        @NonNull
-        public final Executor executor;
-        @NonNull
-        public final InterfaceStateListener listener;
-
-        private ListenerInfo(@NonNull Executor executor, @NonNull InterfaceStateListener listener) {
-            this.executor = executor;
-            this.listener = listener;
-        }
-    }
-
-    /**
-     * The interface is absent.
-     * @hide
-     */
-    @SystemApi(client = MODULE_LIBRARIES)
-    public static final int STATE_ABSENT = 0;
-
-    /**
-     * The interface is present but link is down.
-     * @hide
-     */
-    @SystemApi(client = MODULE_LIBRARIES)
-    public static final int STATE_LINK_DOWN = 1;
-
-    /**
-     * The interface is present and link is up.
-     * @hide
-     */
-    @SystemApi(client = MODULE_LIBRARIES)
-    public static final int STATE_LINK_UP = 2;
-
-    /** @hide */
-    @IntDef(prefix = "STATE_", value = {STATE_ABSENT, STATE_LINK_DOWN, STATE_LINK_UP})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface InterfaceState {}
-
-    /**
-     * The interface currently does not have any specific role.
-     * @hide
-     */
-    @SystemApi(client = MODULE_LIBRARIES)
-    public static final int ROLE_NONE = 0;
-
-    /**
-     * The interface is in client mode (e.g., connected to the Internet).
-     * @hide
-     */
-    @SystemApi(client = MODULE_LIBRARIES)
-    public static final int ROLE_CLIENT = 1;
-
-    /**
-     * Ethernet interface is in server mode (e.g., providing Internet access to tethered devices).
-     * @hide
-     */
-    @SystemApi(client = MODULE_LIBRARIES)
-    public static final int ROLE_SERVER = 2;
-
-    /** @hide */
-    @IntDef(prefix = "ROLE_", value = {ROLE_NONE, ROLE_CLIENT, ROLE_SERVER})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Role {}
-
-    /**
-     * A listener that receives notifications about the state of Ethernet interfaces on the system.
-     * @hide
-     */
-    @SystemApi(client = MODULE_LIBRARIES)
-    public interface InterfaceStateListener {
-        /**
-         * Called when an Ethernet interface changes state.
-         *
-         * @param iface the name of the interface.
-         * @param state the current state of the interface, or {@link #STATE_ABSENT} if the
-         *              interface was removed.
-         * @param role whether the interface is in client mode or server mode.
-         * @param configuration the current IP configuration of the interface.
-         * @hide
-         */
-        @SystemApi(client = MODULE_LIBRARIES)
-        void onInterfaceStateChanged(@NonNull String iface, @InterfaceState int state,
-                @Role int role, @Nullable IpConfiguration configuration);
-    }
-
-    /**
-     * A listener interface to receive notification on changes in Ethernet.
-     * This has never been a supported API. Use {@link InterfaceStateListener} instead.
-     * @hide
-     */
-    public interface Listener extends InterfaceStateListener {
-        /**
-         * Called when Ethernet port's availability is changed.
-         * @param iface Ethernet interface name
-         * @param isAvailable {@code true} if Ethernet port exists.
-         * @hide
-         */
-        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-        void onAvailabilityChanged(String iface, boolean isAvailable);
-
-        /** Default implementation for backwards compatibility. Only calls the legacy listener. */
-        default void onInterfaceStateChanged(@NonNull String iface, @InterfaceState int state,
-                @Role int role, @Nullable IpConfiguration configuration) {
-            onAvailabilityChanged(iface, (state >= STATE_LINK_UP));
-        }
-
-    }
-
-    /**
-     * Create a new EthernetManager instance.
-     * Applications will almost always want to use
-     * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
-     * the standard {@link android.content.Context#ETHERNET_SERVICE Context.ETHERNET_SERVICE}.
-     * @hide
-     */
-    public EthernetManager(Context context, IEthernetManager service) {
-        mService = service;
-    }
-
-    /**
-     * Get Ethernet configuration.
-     * @return the Ethernet Configuration, contained in {@link IpConfiguration}.
-     * @hide
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public IpConfiguration getConfiguration(String iface) {
-        try {
-            return mService.getConfiguration(iface);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Set Ethernet configuration.
-     * @hide
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public void setConfiguration(@NonNull String iface, @NonNull IpConfiguration config) {
-        try {
-            mService.setConfiguration(iface, config);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Indicates whether the system currently has one or more Ethernet interfaces.
-     * @hide
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public boolean isAvailable() {
-        return getAvailableInterfaces().length > 0;
-    }
-
-    /**
-     * Indicates whether the system has given interface.
-     *
-     * @param iface Ethernet interface name
-     * @hide
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public boolean isAvailable(String iface) {
-        try {
-            return mService.isAvailable(iface);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Adds a listener.
-     * This has never been a supported API. Use {@link #addInterfaceStateListener} instead.
-     *
-     * @param listener A {@link Listener} to add.
-     * @throws IllegalArgumentException If the listener is null.
-     * @hide
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public void addListener(@NonNull Listener listener) {
-        addListener(listener, BackgroundThread.getExecutor());
-    }
-
-    /**
-     * Adds a listener.
-     * This has never been a supported API. Use {@link #addInterfaceStateListener} instead.
-     *
-     * @param listener A {@link Listener} to add.
-     * @param executor Executor to run callbacks on.
-     * @throws IllegalArgumentException If the listener or executor is null.
-     * @hide
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public void addListener(@NonNull Listener listener, @NonNull Executor executor) {
-        addInterfaceStateListener(executor, listener);
-    }
-
-    /**
-     * Listen to changes in the state of Ethernet interfaces.
-     *
-     * Adds a listener to receive notification for any state change of all existing Ethernet
-     * interfaces.
-     * <p>{@link Listener#onInterfaceStateChanged} will be triggered immediately for all
-     * existing interfaces upon adding a listener. The same method will be called on the
-     * listener every time any of the interface changes state. In particular, if an
-     * interface is removed, it will be called with state {@link #STATE_ABSENT}.
-     * <p>Use {@link #removeInterfaceStateListener} with the same object to stop listening.
-     *
-     * @param executor Executor to run callbacks on.
-     * @param listener A {@link Listener} to add.
-     * @hide
-     */
-    @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
-    @SystemApi(client = MODULE_LIBRARIES)
-    public void addInterfaceStateListener(@NonNull Executor executor,
-            @NonNull InterfaceStateListener listener) {
-        if (listener == null || executor == null) {
-            throw new NullPointerException("listener and executor must not be null");
-        }
-        synchronized (mListeners) {
-            mListeners.add(new ListenerInfo(executor, listener));
-            if (mListeners.size() == 1) {
-                try {
-                    mService.addListener(mServiceListener);
-                } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
-                }
-            }
-        }
-    }
-
-    /**
-     * Returns an array of available Ethernet interface names.
-     * @hide
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public String[] getAvailableInterfaces() {
-        try {
-            return mService.getAvailableInterfaces();
-        } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
-        }
-    }
-
-    /**
-     * Removes a listener.
-     *
-     * @param listener A {@link Listener} to remove.
-     * @hide
-     */
-    @SystemApi(client = MODULE_LIBRARIES)
-    public void removeInterfaceStateListener(@NonNull InterfaceStateListener listener) {
-        Objects.requireNonNull(listener);
-        synchronized (mListeners) {
-            mListeners.removeIf(l -> l.listener == listener);
-            if (mListeners.isEmpty()) {
-                try {
-                    mService.removeListener(mServiceListener);
-                } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
-                }
-            }
-        }
-    }
-
-    /**
-     * Removes a listener.
-     * This has never been a supported API. Use {@link #removeInterfaceStateListener} instead.
-     * @param listener A {@link Listener} to remove.
-     * @hide
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public void removeListener(@NonNull Listener listener) {
-        if (listener == null) {
-            throw new IllegalArgumentException("listener must not be null");
-        }
-        removeInterfaceStateListener(listener);
-    }
-
-    /**
-     * Whether to treat interfaces created by {@link TestNetworkManager#createTapInterface}
-     * as Ethernet interfaces. The effects of this method apply to any test interfaces that are
-     * already present on the system.
-     * @hide
-     */
-    @SystemApi(client = MODULE_LIBRARIES)
-    public void setIncludeTestInterfaces(boolean include) {
-        try {
-            mService.setIncludeTestInterfaces(include);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * A request for a tethered interface.
-     */
-    public static class TetheredInterfaceRequest {
-        private final IEthernetManager mService;
-        private final ITetheredInterfaceCallback mCb;
-
-        private TetheredInterfaceRequest(@NonNull IEthernetManager service,
-                @NonNull ITetheredInterfaceCallback cb) {
-            this.mService = service;
-            this.mCb = cb;
-        }
-
-        /**
-         * Release the request, causing the interface to revert back from tethering mode if there
-         * is no other requestor.
-         */
-        public void release() {
-            try {
-                mService.releaseTetheredInterface(mCb);
-            } catch (RemoteException e) {
-                e.rethrowFromSystemServer();
-            }
-        }
-    }
-
-    /**
-     * Callback for {@link #requestTetheredInterface(TetheredInterfaceCallback)}.
-     */
-    public interface TetheredInterfaceCallback {
-        /**
-         * Called when the tethered interface is available.
-         * @param iface The name of the interface.
-         */
-        void onAvailable(@NonNull String iface);
-
-        /**
-         * Called when the tethered interface is now unavailable.
-         */
-        void onUnavailable();
-    }
-
-    /**
-     * Request a tethered interface in tethering mode.
-     *
-     * <p>When this method is called and there is at least one ethernet interface available, the
-     * system will designate one to act as a tethered interface. If there is already a tethered
-     * interface, the existing interface will be used.
-     * @param callback A callback to be called once the request has been fulfilled.
-     */
-    @RequiresPermission(anyOf = {
-            android.Manifest.permission.NETWORK_STACK,
-            android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
-    })
-    @NonNull
-    public TetheredInterfaceRequest requestTetheredInterface(@NonNull final Executor executor,
-            @NonNull final TetheredInterfaceCallback callback) {
-        Objects.requireNonNull(callback, "Callback must be non-null");
-        Objects.requireNonNull(executor, "Executor must be non-null");
-        final ITetheredInterfaceCallback cbInternal = new ITetheredInterfaceCallback.Stub() {
-            @Override
-            public void onAvailable(String iface) {
-                executor.execute(() -> callback.onAvailable(iface));
-            }
-
-            @Override
-            public void onUnavailable() {
-                executor.execute(() -> callback.onUnavailable());
-            }
-        };
-
-        try {
-            mService.requestTetheredInterface(cbInternal);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-        return new TetheredInterfaceRequest(mService, cbInternal);
-    }
-
-    private static final class InternalNetworkManagementListener
-            extends IEthernetNetworkManagementListener.Stub {
-        @NonNull
-        private final Executor mExecutor;
-        @NonNull
-        private final BiConsumer<Network, EthernetNetworkManagementException> mListener;
-
-        InternalNetworkManagementListener(
-                @NonNull final Executor executor,
-                @NonNull final BiConsumer<Network, EthernetNetworkManagementException> listener) {
-            Objects.requireNonNull(executor, "Pass a non-null executor");
-            Objects.requireNonNull(listener, "Pass a non-null listener");
-            mExecutor = executor;
-            mListener = listener;
-        }
-
-        @Override
-        public void onComplete(
-                @Nullable final Network network,
-                @Nullable final EthernetNetworkManagementException e) {
-            mExecutor.execute(() -> mListener.accept(network, e));
-        }
-    }
-
-    private InternalNetworkManagementListener getInternalNetworkManagementListener(
-            @Nullable final Executor executor,
-            @Nullable final BiConsumer<Network, EthernetNetworkManagementException> listener) {
-        if (null != listener) {
-            Objects.requireNonNull(executor, "Pass a non-null executor, or a null listener");
-        }
-        final InternalNetworkManagementListener proxy;
-        if (null == listener) {
-            proxy = null;
-        } else {
-            proxy = new InternalNetworkManagementListener(executor, listener);
-        }
-        return proxy;
-    }
-
-    /**
-     * Updates the configuration of an automotive device's ethernet network.
-     *
-     * The {@link EthernetNetworkUpdateRequest} {@code request} argument describes how to update the
-     * configuration for this network.
-     * Use {@link StaticIpConfiguration.Builder} to build a {@code StaticIpConfiguration} object for
-     * this network to put inside the {@code request}.
-     * Similarly, use {@link NetworkCapabilities.Builder} to build a {@code NetworkCapabilities}
-     * object for this network to put inside the {@code request}.
-     *
-     * If non-null, the listener will be called exactly once after this is called, unless
-     * a synchronous exception was thrown.
-     *
-     * @param iface the name of the interface to act upon.
-     * @param request the {@link EthernetNetworkUpdateRequest} used to set an ethernet network's
-     *                {@link StaticIpConfiguration} and {@link NetworkCapabilities} values.
-     * @param executor an {@link Executor} to execute the listener on. Optional if listener is null.
-     * @param listener an optional {@link BiConsumer} to listen for completion of the operation.
-     * @throws SecurityException if the process doesn't hold
-     *                          {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}.
-     * @throws UnsupportedOperationException if called on a non-automotive device or on an
-     *                                       unsupported interface.
-     * @hide
-     */
-    @SystemApi
-    @RequiresPermission(anyOf = {
-            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
-            android.Manifest.permission.NETWORK_STACK,
-            android.Manifest.permission.MANAGE_ETHERNET_NETWORKS})
-    @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
-    public void updateConfiguration(
-            @NonNull String iface,
-            @NonNull EthernetNetworkUpdateRequest request,
-            @Nullable @CallbackExecutor Executor executor,
-            @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) {
-        Objects.requireNonNull(iface, "iface must be non-null");
-        Objects.requireNonNull(request, "request must be non-null");
-        final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
-                executor, listener);
-        try {
-            mService.updateConfiguration(iface, request, proxy);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Set an ethernet network's link state up.
-     *
-     * When the link is successfully turned up, the listener will be called with the resulting
-     * network. If any error or unexpected condition happens while the system tries to turn the
-     * interface up, the listener will be called with an appropriate exception.
-     * The listener is guaranteed to be called exactly once for each call to this method, but this
-     * may take an unbounded amount of time depending on the actual network conditions.
-     *
-     * @param iface the name of the interface to act upon.
-     * @param executor an {@link Executor} to execute the listener on. Optional if listener is null.
-     * @param listener an optional {@link BiConsumer} to listen for completion of the operation.
-     * @throws SecurityException if the process doesn't hold
-     *                          {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}.
-     * @throws UnsupportedOperationException if called on a non-automotive device.
-     * @hide
-     */
-    @SystemApi
-    @RequiresPermission(anyOf = {
-            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
-            android.Manifest.permission.NETWORK_STACK,
-            android.Manifest.permission.MANAGE_ETHERNET_NETWORKS})
-    @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
-    public void connectNetwork(
-            @NonNull String iface,
-            @Nullable @CallbackExecutor Executor executor,
-            @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) {
-        Objects.requireNonNull(iface, "iface must be non-null");
-        final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
-                executor, listener);
-        try {
-            mService.connectNetwork(iface, proxy);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Set an ethernet network's link state down.
-     *
-     * When the link is successfully turned down, the listener will be called with the network that
-     * was torn down, if any. If any error or unexpected condition happens while the system tries to
-     * turn the interface down, the listener will be called with an appropriate exception.
-     * The listener is guaranteed to be called exactly once for each call to this method.
-     *
-     * @param iface the name of the interface to act upon.
-     * @param executor an {@link Executor} to execute the listener on. Optional if listener is null.
-     * @param listener an optional {@link BiConsumer} to listen for completion of the operation.
-     * @throws SecurityException if the process doesn't hold
-     *                          {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}.
-     * @throws UnsupportedOperationException if called on a non-automotive device.
-     * @hide
-     */
-    @SystemApi
-    @RequiresPermission(anyOf = {
-            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
-            android.Manifest.permission.NETWORK_STACK,
-            android.Manifest.permission.MANAGE_ETHERNET_NETWORKS})
-    @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
-    public void disconnectNetwork(
-            @NonNull String iface,
-            @Nullable @CallbackExecutor Executor executor,
-            @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) {
-        Objects.requireNonNull(iface, "iface must be non-null");
-        final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
-                executor, listener);
-        try {
-            mService.disconnectNetwork(iface, proxy);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.aidl b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.aidl
deleted file mode 100644
index adf9e5a..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- package android.net;
-
- parcelable EthernetNetworkManagementException;
\ No newline at end of file
diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.java
deleted file mode 100644
index a69cc55..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Objects;
-
-/** @hide */
-@SystemApi
-public final class EthernetNetworkManagementException
-        extends RuntimeException implements Parcelable {
-
-    /* @hide */
-    public EthernetNetworkManagementException(@NonNull final String errorMessage) {
-        super(errorMessage);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(getMessage());
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) return true;
-        if (obj == null || getClass() != obj.getClass()) return false;
-        final EthernetNetworkManagementException that = (EthernetNetworkManagementException) obj;
-
-        return Objects.equals(getMessage(), that.getMessage());
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeString(getMessage());
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @NonNull
-    public static final Parcelable.Creator<EthernetNetworkManagementException> CREATOR =
-            new Parcelable.Creator<EthernetNetworkManagementException>() {
-                @Override
-                public EthernetNetworkManagementException[] newArray(int size) {
-                    return new EthernetNetworkManagementException[size];
-                }
-
-                @Override
-                public EthernetNetworkManagementException createFromParcel(@NonNull Parcel source) {
-                    return new EthernetNetworkManagementException(source.readString());
-                }
-            };
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkSpecifier.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkSpecifier.java
deleted file mode 100644
index e4d6e24..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkSpecifier.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-
-import java.util.Objects;
-
-/**
- * A {@link NetworkSpecifier} used to identify ethernet interfaces.
- *
- * @see EthernetManager
- */
-public final class EthernetNetworkSpecifier extends NetworkSpecifier implements Parcelable {
-
-    /**
-     * Name of the network interface.
-     */
-    @NonNull
-    private final String mInterfaceName;
-
-    /**
-     * Create a new EthernetNetworkSpecifier.
-     * @param interfaceName Name of the ethernet interface the specifier refers to.
-     */
-    public EthernetNetworkSpecifier(@NonNull String interfaceName) {
-        if (TextUtils.isEmpty(interfaceName)) {
-            throw new IllegalArgumentException();
-        }
-        mInterfaceName = interfaceName;
-    }
-
-    /**
-     * Get the name of the ethernet interface the specifier refers to.
-     */
-    @Nullable
-    public String getInterfaceName() {
-        // This may be null in the future to support specifiers based on data other than the
-        // interface name.
-        return mInterfaceName;
-    }
-
-    /** @hide */
-    @Override
-    public boolean canBeSatisfiedBy(@Nullable NetworkSpecifier other) {
-        return equals(other);
-    }
-
-    @Override
-    public boolean equals(@Nullable Object o) {
-        if (!(o instanceof EthernetNetworkSpecifier)) return false;
-        return TextUtils.equals(mInterfaceName, ((EthernetNetworkSpecifier) o).mInterfaceName);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(mInterfaceName);
-    }
-
-    @Override
-    public String toString() {
-        return "EthernetNetworkSpecifier (" + mInterfaceName + ")";
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeString(mInterfaceName);
-    }
-
-    public static final @NonNull Parcelable.Creator<EthernetNetworkSpecifier> CREATOR =
-            new Parcelable.Creator<EthernetNetworkSpecifier>() {
-        public EthernetNetworkSpecifier createFromParcel(Parcel in) {
-            return new EthernetNetworkSpecifier(in.readString());
-        }
-        public EthernetNetworkSpecifier[] newArray(int size) {
-            return new EthernetNetworkSpecifier[size];
-        }
-    };
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.aidl b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.aidl
deleted file mode 100644
index debc348..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- package android.net;
-
- parcelable EthernetNetworkUpdateRequest;
\ No newline at end of file
diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java
deleted file mode 100644
index 43f4c40f..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Objects;
-
-/**
- * Represents a request to update an existing Ethernet interface.
- *
- * @see EthernetManager#updateConfiguration
- *
- * @hide
- */
-@SystemApi
-public final class EthernetNetworkUpdateRequest implements Parcelable {
-    @NonNull
-    private final IpConfiguration mIpConfig;
-    @Nullable
-    private final NetworkCapabilities mNetworkCapabilities;
-
-    /**
-     * @return the new {@link IpConfiguration}.
-     */
-    @NonNull
-    public IpConfiguration getIpConfiguration() {
-        return new IpConfiguration(mIpConfig);
-    }
-
-    /**
-     * Setting the {@link NetworkCapabilities} is optional in {@link EthernetNetworkUpdateRequest}.
-     * When set to null, the existing NetworkCapabilities are not updated.
-     *
-     * @return the new {@link NetworkCapabilities} or null.
-     */
-    @Nullable
-    public NetworkCapabilities getNetworkCapabilities() {
-        return mNetworkCapabilities == null ? null : new NetworkCapabilities(mNetworkCapabilities);
-    }
-
-    private EthernetNetworkUpdateRequest(@NonNull final IpConfiguration ipConfig,
-            @Nullable final NetworkCapabilities networkCapabilities) {
-        Objects.requireNonNull(ipConfig);
-        mIpConfig = ipConfig;
-        mNetworkCapabilities = networkCapabilities;
-    }
-
-    private EthernetNetworkUpdateRequest(@NonNull final Parcel source) {
-        Objects.requireNonNull(source);
-        mIpConfig = source.readParcelable(IpConfiguration.class.getClassLoader(),
-                IpConfiguration.class);
-        mNetworkCapabilities = source.readParcelable(NetworkCapabilities.class.getClassLoader(),
-                NetworkCapabilities.class);
-    }
-
-    /**
-     * Builder used to create {@link EthernetNetworkUpdateRequest} objects.
-     */
-    public static final class Builder {
-        @Nullable
-        private IpConfiguration mBuilderIpConfig;
-        @Nullable
-        private NetworkCapabilities mBuilderNetworkCapabilities;
-
-        public Builder(){}
-
-        /**
-         * Constructor to populate the builder's values with an already built
-         * {@link EthernetNetworkUpdateRequest}.
-         * @param request the {@link EthernetNetworkUpdateRequest} to populate with.
-         */
-        public Builder(@NonNull final EthernetNetworkUpdateRequest request) {
-            Objects.requireNonNull(request);
-            mBuilderIpConfig = new IpConfiguration(request.mIpConfig);
-            mBuilderNetworkCapabilities = null == request.mNetworkCapabilities
-                    ? null : new NetworkCapabilities(request.mNetworkCapabilities);
-        }
-
-        /**
-         * Set the {@link IpConfiguration} to be used with the {@code Builder}.
-         * @param ipConfig the {@link IpConfiguration} to set.
-         * @return The builder to facilitate chaining.
-         */
-        @NonNull
-        public Builder setIpConfiguration(@NonNull final IpConfiguration ipConfig) {
-            mBuilderIpConfig = new IpConfiguration(ipConfig);
-            return this;
-        }
-
-        /**
-         * Set the {@link NetworkCapabilities} to be used with the {@code Builder}.
-         * @param nc the {@link NetworkCapabilities} to set.
-         * @return The builder to facilitate chaining.
-         */
-        @NonNull
-        public Builder setNetworkCapabilities(@Nullable final NetworkCapabilities nc) {
-            mBuilderNetworkCapabilities = nc == null ? null : new NetworkCapabilities(nc);
-            return this;
-        }
-
-        /**
-         * Build {@link EthernetNetworkUpdateRequest} return the current update request.
-         */
-        @NonNull
-        public EthernetNetworkUpdateRequest build() {
-            return new EthernetNetworkUpdateRequest(mBuilderIpConfig, mBuilderNetworkCapabilities);
-        }
-    }
-
-    @Override
-    public String toString() {
-        return "EthernetNetworkUpdateRequest{"
-                + "mIpConfig=" + mIpConfig
-                + ", mNetworkCapabilities=" + mNetworkCapabilities + '}';
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-        EthernetNetworkUpdateRequest that = (EthernetNetworkUpdateRequest) o;
-
-        return Objects.equals(that.getIpConfiguration(), mIpConfig)
-                && Objects.equals(that.getNetworkCapabilities(), mNetworkCapabilities);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mIpConfig, mNetworkCapabilities);
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeParcelable(mIpConfig, flags);
-        dest.writeParcelable(mNetworkCapabilities, flags);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @NonNull
-    public static final Parcelable.Creator<EthernetNetworkUpdateRequest> CREATOR =
-            new Parcelable.Creator<EthernetNetworkUpdateRequest>() {
-                @Override
-                public EthernetNetworkUpdateRequest[] newArray(int size) {
-                    return new EthernetNetworkUpdateRequest[size];
-                }
-
-                @Override
-                public EthernetNetworkUpdateRequest createFromParcel(@NonNull Parcel source) {
-                    return new EthernetNetworkUpdateRequest(source);
-                }
-            };
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl
deleted file mode 100644
index 544d02b..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.net.IpConfiguration;
-import android.net.IEthernetServiceListener;
-import android.net.IEthernetNetworkManagementListener;
-import android.net.EthernetNetworkUpdateRequest;
-import android.net.ITetheredInterfaceCallback;
-
-/**
- * Interface that answers queries about, and allows changing
- * ethernet configuration.
- */
-/** {@hide} */
-interface IEthernetManager
-{
-    String[] getAvailableInterfaces();
-    IpConfiguration getConfiguration(String iface);
-    void setConfiguration(String iface, in IpConfiguration config);
-    boolean isAvailable(String iface);
-    void addListener(in IEthernetServiceListener listener);
-    void removeListener(in IEthernetServiceListener listener);
-    void setIncludeTestInterfaces(boolean include);
-    void requestTetheredInterface(in ITetheredInterfaceCallback callback);
-    void releaseTetheredInterface(in ITetheredInterfaceCallback callback);
-    void updateConfiguration(String iface, in EthernetNetworkUpdateRequest request,
-        in IEthernetNetworkManagementListener listener);
-    void connectNetwork(String iface, in IEthernetNetworkManagementListener listener);
-    void disconnectNetwork(String iface, in IEthernetNetworkManagementListener listener);
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl
deleted file mode 100644
index 93edccf..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.net.EthernetNetworkManagementException;
-import android.net.Network;
-
-/** @hide */
-oneway interface IEthernetNetworkManagementListener {
-    void onComplete(in Network network, in EthernetNetworkManagementException exception);
-}
\ No newline at end of file
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl
deleted file mode 100644
index 6d2ba03..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.net.IpConfiguration;
-
-/** @hide */
-oneway interface IEthernetServiceListener
-{
-    void onInterfaceStateChanged(String iface, int state, int role,
-            in IpConfiguration configuration);
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IIpSecService.aidl b/packages/ConnectivityT/framework-t/src/android/net/IIpSecService.aidl
deleted file mode 100644
index 933256a..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/IIpSecService.aidl
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.net;
-
-import android.net.LinkAddress;
-import android.net.Network;
-import android.net.IpSecConfig;
-import android.net.IpSecUdpEncapResponse;
-import android.net.IpSecSpiResponse;
-import android.net.IpSecTransformResponse;
-import android.net.IpSecTunnelInterfaceResponse;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
-
-/**
- * @hide
- */
-interface IIpSecService
-{
-    IpSecSpiResponse allocateSecurityParameterIndex(
-            in String destinationAddress, int requestedSpi, in IBinder binder);
-
-    void releaseSecurityParameterIndex(int resourceId);
-
-    IpSecUdpEncapResponse openUdpEncapsulationSocket(int port, in IBinder binder);
-
-    void closeUdpEncapsulationSocket(int resourceId);
-
-    IpSecTunnelInterfaceResponse createTunnelInterface(
-            in String localAddr,
-            in String remoteAddr,
-            in Network underlyingNetwork,
-            in IBinder binder,
-            in String callingPackage);
-
-    void addAddressToTunnelInterface(
-            int tunnelResourceId,
-            in LinkAddress localAddr,
-            in String callingPackage);
-
-    void removeAddressFromTunnelInterface(
-            int tunnelResourceId,
-            in LinkAddress localAddr,
-            in String callingPackage);
-
-    void setNetworkForTunnelInterface(
-            int tunnelResourceId, in Network underlyingNetwork, in String callingPackage);
-
-    void deleteTunnelInterface(int resourceId, in String callingPackage);
-
-    IpSecTransformResponse createTransform(
-            in IpSecConfig c, in IBinder binder, in String callingPackage);
-
-    void deleteTransform(int transformId);
-
-    void applyTransportModeTransform(
-            in ParcelFileDescriptor socket, int direction, int transformId);
-
-    void applyTunnelModeTransform(
-            int tunnelResourceId, int direction, int transformResourceId, in String callingPackage);
-
-    void removeTransportModeTransforms(in ParcelFileDescriptor socket);
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl b/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl
deleted file mode 100644
index efe626d..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.net.DataUsageRequest;
-import android.net.INetworkStatsSession;
-import android.net.Network;
-import android.net.NetworkStateSnapshot;
-import android.net.NetworkStats;
-import android.net.NetworkStatsHistory;
-import android.net.NetworkTemplate;
-import android.net.UnderlyingNetworkInfo;
-import android.net.netstats.IUsageCallback;
-import android.net.netstats.provider.INetworkStatsProvider;
-import android.net.netstats.provider.INetworkStatsProviderCallback;
-import android.os.IBinder;
-import android.os.Messenger;
-
-/** {@hide} */
-interface INetworkStatsService {
-
-    /** Start a statistics query session. */
-    @UnsupportedAppUsage
-    INetworkStatsSession openSession();
-
-    /** Start a statistics query session. If calling package is profile or device owner then it is
-     *  granted automatic access if apiLevel is NetworkStatsManager.API_LEVEL_DPC_ALLOWED. If
-     *  apiLevel is at least NetworkStatsManager.API_LEVEL_REQUIRES_PACKAGE_USAGE_STATS then
-     *  PACKAGE_USAGE_STATS permission is always checked. If PACKAGE_USAGE_STATS is not granted
-     *  READ_NETWORK_USAGE_STATS is checked for.
-     */
-    @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
-    INetworkStatsSession openSessionForUsageStats(int flags, String callingPackage);
-
-    /** Return data layer snapshot of UID network usage. */
-    @UnsupportedAppUsage
-    NetworkStats getDataLayerSnapshotForUid(int uid);
-
-    /** Get the transport NetworkStats for all UIDs since boot. */
-    NetworkStats getUidStatsForTransport(int transport);
-
-    /** Return set of any ifaces associated with mobile networks since boot. */
-    @UnsupportedAppUsage
-    String[] getMobileIfaces();
-
-    /** Increment data layer count of operations performed for UID and tag. */
-    void incrementOperationCount(int uid, int tag, int operationCount);
-
-    /**  Notify {@code NetworkStatsService} about network status changed. */
-    void notifyNetworkStatus(
-         in Network[] defaultNetworks,
-         in NetworkStateSnapshot[] snapshots,
-         in String activeIface,
-         in UnderlyingNetworkInfo[] underlyingNetworkInfos);
-    /** Force update of statistics. */
-    @UnsupportedAppUsage
-    void forceUpdate();
-
-    /** Registers a callback on data usage. */
-    DataUsageRequest registerUsageCallback(String callingPackage,
-            in DataUsageRequest request, in IUsageCallback callback);
-
-    /** Unregisters a callback on data usage. */
-    void unregisterUsageRequest(in DataUsageRequest request);
-
-    /** Get the uid stats information since boot */
-    long getUidStats(int uid, int type);
-
-    /** Get the iface stats information since boot */
-    long getIfaceStats(String iface, int type);
-
-    /** Get the total network stats information since boot */
-    long getTotalStats(int type);
-
-    /** Registers a network stats provider */
-    INetworkStatsProviderCallback registerNetworkStatsProvider(String tag,
-            in INetworkStatsProvider provider);
-
-    /** Mark given UID as being in foreground for stats purposes. */
-    void setUidForeground(int uid, boolean uidForeground);
-
-    /** Advise persistence threshold; may be overridden internally. */
-    void advisePersistThreshold(long thresholdBytes);
-
-    /**
-     * Set the warning and limit to all registered custom network stats providers.
-     * Note that invocation of any interface will be sent to all providers.
-     */
-     void setStatsProviderWarningAndLimitAsync(String iface, long warning, long limit);
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsSession.aidl b/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsSession.aidl
deleted file mode 100644
index ab70be8..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsSession.aidl
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.net.NetworkStats;
-import android.net.NetworkStatsHistory;
-import android.net.NetworkTemplate;
-
-/** {@hide} */
-interface INetworkStatsSession {
-
-    /** Return device aggregated network layer usage summary for traffic that matches template. */
-    NetworkStats getDeviceSummaryForNetwork(in NetworkTemplate template, long start, long end);
-
-    /** Return network layer usage summary for traffic that matches template. */
-    @UnsupportedAppUsage
-    NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end);
-    /** Return historical network layer stats for traffic that matches template. */
-    @UnsupportedAppUsage
-    NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template, int fields);
-    /**
-     * Return historical network layer stats for traffic that matches template, start and end
-     * timestamp.
-     */
-    NetworkStatsHistory getHistoryIntervalForNetwork(in NetworkTemplate template, int fields, long start, long end);
-
-    /**
-     * Return network layer usage summary per UID for traffic that matches template.
-     *
-     * <p>The resulting {@code NetworkStats#getElapsedRealtime()} contains time delta between
-     * {@code start} and {@code end}.
-     *
-     * @param template - a predicate to filter netstats.
-     * @param start - start of the range, timestamp in milliseconds since the epoch.
-     * @param end - end of the range, timestamp in milliseconds since the epoch.
-     * @param includeTags - includes data usage tags if true.
-     */
-    @UnsupportedAppUsage
-    NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags);
-
-    /** Return network layer usage summary per UID for tagged traffic that matches template. */
-    NetworkStats getTaggedSummaryForAllUid(in NetworkTemplate template, long start, long end);
-
-    /** Return historical network layer stats for specific UID traffic that matches template. */
-    @UnsupportedAppUsage
-    NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int set, int tag, int fields);
-    /** Return historical network layer stats for specific UID traffic that matches template. */
-    NetworkStatsHistory getHistoryIntervalForUid(in NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end);
-
-    /** Return array of uids that have stats and are accessible to the calling user */
-    int[] getRelevantUids();
-
-    @UnsupportedAppUsage
-    void close();
-
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/ITetheredInterfaceCallback.aidl b/packages/ConnectivityT/framework-t/src/android/net/ITetheredInterfaceCallback.aidl
deleted file mode 100644
index 14aa023..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/ITetheredInterfaceCallback.aidl
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-/** @hide */
-oneway interface ITetheredInterfaceCallback {
-    void onAvailable(in String iface);
-    void onUnavailable();
-}
\ No newline at end of file
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecAlgorithm.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecAlgorithm.java
deleted file mode 100644
index 10a22ac..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/IpSecAlgorithm.java
+++ /dev/null
@@ -1,491 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net;
-
-import android.annotation.NonNull;
-import android.annotation.StringDef;
-import android.content.res.Resources;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-/**
- * This class represents a single algorithm that can be used by an {@link IpSecTransform}.
- *
- * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the
- * Internet Protocol</a>
- */
-public final class IpSecAlgorithm implements Parcelable {
-    private static final String TAG = "IpSecAlgorithm";
-
-    /**
-     * Null cipher.
-     *
-     * @hide
-     */
-    public static final String CRYPT_NULL = "ecb(cipher_null)";
-
-    /**
-     * AES-CBC Encryption/Ciphering Algorithm.
-     *
-     * <p>Valid lengths for this key are {128, 192, 256}.
-     */
-    public static final String CRYPT_AES_CBC = "cbc(aes)";
-
-    /**
-     * AES-CTR Encryption/Ciphering Algorithm.
-     *
-     * <p>Valid lengths for keying material are {160, 224, 288}.
-     *
-     * <p>As per <a href="https://tools.ietf.org/html/rfc3686#section-5.1">RFC3686 (Section
-     * 5.1)</a>, keying material consists of a 128, 192, or 256 bit AES key followed by a 32-bit
-     * nonce. RFC compliance requires that the nonce must be unique per security association.
-     *
-     * <p>This algorithm may be available on the device. Caller MUST check if it is supported before
-     * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is
-     * included in the returned algorithm set. The returned algorithm set will not change unless the
-     * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is
-     * requested on an unsupported device.
-     *
-     * <p>@see {@link #getSupportedAlgorithms()}
-     */
-    // This algorithm may be available on devices released before Android 12, and is guaranteed
-    // to be available on devices first shipped with Android 12 or later.
-    public static final String CRYPT_AES_CTR = "rfc3686(ctr(aes))";
-
-    /**
-     * MD5 HMAC Authentication/Integrity Algorithm. <b>This algorithm is not recommended for use in
-     * new applications and is provided for legacy compatibility with 3gpp infrastructure.</b>
-     *
-     * <p>Keys for this algorithm must be 128 bits in length.
-     *
-     * <p>Valid truncation lengths are multiples of 8 bits from 96 to 128.
-     */
-    public static final String AUTH_HMAC_MD5 = "hmac(md5)";
-
-    /**
-     * SHA1 HMAC Authentication/Integrity Algorithm. <b>This algorithm is not recommended for use in
-     * new applications and is provided for legacy compatibility with 3gpp infrastructure.</b>
-     *
-     * <p>Keys for this algorithm must be 160 bits in length.
-     *
-     * <p>Valid truncation lengths are multiples of 8 bits from 96 to 160.
-     */
-    public static final String AUTH_HMAC_SHA1 = "hmac(sha1)";
-
-    /**
-     * SHA256 HMAC Authentication/Integrity Algorithm.
-     *
-     * <p>Keys for this algorithm must be 256 bits in length.
-     *
-     * <p>Valid truncation lengths are multiples of 8 bits from 96 to 256.
-     */
-    public static final String AUTH_HMAC_SHA256 = "hmac(sha256)";
-
-    /**
-     * SHA384 HMAC Authentication/Integrity Algorithm.
-     *
-     * <p>Keys for this algorithm must be 384 bits in length.
-     *
-     * <p>Valid truncation lengths are multiples of 8 bits from 192 to 384.
-     */
-    public static final String AUTH_HMAC_SHA384 = "hmac(sha384)";
-
-    /**
-     * SHA512 HMAC Authentication/Integrity Algorithm.
-     *
-     * <p>Keys for this algorithm must be 512 bits in length.
-     *
-     * <p>Valid truncation lengths are multiples of 8 bits from 256 to 512.
-     */
-    public static final String AUTH_HMAC_SHA512 = "hmac(sha512)";
-
-    /**
-     * AES-XCBC Authentication/Integrity Algorithm.
-     *
-     * <p>Keys for this algorithm must be 128 bits in length.
-     *
-     * <p>The only valid truncation length is 96 bits.
-     *
-     * <p>This algorithm may be available on the device. Caller MUST check if it is supported before
-     * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is
-     * included in the returned algorithm set. The returned algorithm set will not change unless the
-     * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is
-     * requested on an unsupported device.
-     *
-     * <p>@see {@link #getSupportedAlgorithms()}
-     */
-    // This algorithm may be available on devices released before Android 12, and is guaranteed
-    // to be available on devices first shipped with Android 12 or later.
-    public static final String AUTH_AES_XCBC = "xcbc(aes)";
-
-    /**
-     * AES-CMAC Authentication/Integrity Algorithm.
-     *
-     * <p>Keys for this algorithm must be 128 bits in length.
-     *
-     * <p>The only valid truncation length is 96 bits.
-     *
-     * <p>This algorithm may be available on the device. Caller MUST check if it is supported before
-     * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is
-     * included in the returned algorithm set. The returned algorithm set will not change unless the
-     * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is
-     * requested on an unsupported device.
-     *
-     * <p>@see {@link #getSupportedAlgorithms()}
-     */
-    // This algorithm may be available on devices released before Android 12, and is guaranteed
-    // to be available on devices first shipped with Android 12 or later.
-    public static final String AUTH_AES_CMAC = "cmac(aes)";
-
-    /**
-     * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm.
-     *
-     * <p>Valid lengths for keying material are {160, 224, 288}.
-     *
-     * <p>As per <a href="https://tools.ietf.org/html/rfc4106#section-8.1">RFC4106 (Section
-     * 8.1)</a>, keying material consists of a 128, 192, or 256 bit AES key followed by a 32-bit
-     * salt. RFC compliance requires that the salt must be unique per invocation with the same key.
-     *
-     * <p>Valid ICV (truncation) lengths are {64, 96, 128}.
-     */
-    public static final String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))";
-
-    /**
-     * ChaCha20-Poly1305 Authentication/Integrity + Encryption/Ciphering Algorithm.
-     *
-     * <p>Keys for this algorithm must be 288 bits in length.
-     *
-     * <p>As per <a href="https://tools.ietf.org/html/rfc7634#section-2">RFC7634 (Section 2)</a>,
-     * keying material consists of a 256 bit key followed by a 32-bit salt. The salt is fixed per
-     * security association.
-     *
-     * <p>The only valid ICV (truncation) length is 128 bits.
-     *
-     * <p>This algorithm may be available on the device. Caller MUST check if it is supported before
-     * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is
-     * included in the returned algorithm set. The returned algorithm set will not change unless the
-     * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is
-     * requested on an unsupported device.
-     *
-     * <p>@see {@link #getSupportedAlgorithms()}
-     */
-    // This algorithm may be available on devices released before Android 12, and is guaranteed
-    // to be available on devices first shipped with Android 12 or later.
-    public static final String AUTH_CRYPT_CHACHA20_POLY1305 = "rfc7539esp(chacha20,poly1305)";
-
-    /** @hide */
-    @StringDef({
-        CRYPT_AES_CBC,
-        CRYPT_AES_CTR,
-        AUTH_HMAC_MD5,
-        AUTH_HMAC_SHA1,
-        AUTH_HMAC_SHA256,
-        AUTH_HMAC_SHA384,
-        AUTH_HMAC_SHA512,
-        AUTH_AES_XCBC,
-        AUTH_AES_CMAC,
-        AUTH_CRYPT_AES_GCM,
-        AUTH_CRYPT_CHACHA20_POLY1305
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface AlgorithmName {}
-
-    /** @hide */
-    @VisibleForTesting
-    public static final Map<String, Integer> ALGO_TO_REQUIRED_FIRST_SDK = new HashMap<>();
-
-    private static final int SDK_VERSION_ZERO = 0;
-
-    static {
-        ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CBC, SDK_VERSION_ZERO);
-        ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_MD5, SDK_VERSION_ZERO);
-        ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA1, SDK_VERSION_ZERO);
-        ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA256, SDK_VERSION_ZERO);
-        ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA384, SDK_VERSION_ZERO);
-        ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA512, SDK_VERSION_ZERO);
-        ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_AES_GCM, SDK_VERSION_ZERO);
-
-        ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.S);
-        ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.S);
-        ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_CMAC, Build.VERSION_CODES.S);
-        ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.S);
-    }
-
-    private static final Set<String> ENABLED_ALGOS =
-            Collections.unmodifiableSet(loadAlgos(Resources.getSystem()));
-
-    private final String mName;
-    private final byte[] mKey;
-    private final int mTruncLenBits;
-
-    /**
-     * Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are
-     * defined as constants in this class.
-     *
-     * <p>For algorithms that produce an integrity check value, the truncation length is a required
-     * parameter. See {@link #IpSecAlgorithm(String algorithm, byte[] key, int truncLenBits)}
-     *
-     * @param algorithm name of the algorithm.
-     * @param key key padded to a multiple of 8 bits.
-     * @throws IllegalArgumentException if algorithm or key length is invalid.
-     */
-    public IpSecAlgorithm(@NonNull @AlgorithmName String algorithm, @NonNull byte[] key) {
-        this(algorithm, key, 0);
-    }
-
-    /**
-     * Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are
-     * defined as constants in this class.
-     *
-     * <p>This constructor only supports algorithms that use a truncation length. i.e.
-     * Authentication and Authenticated Encryption algorithms.
-     *
-     * @param algorithm name of the algorithm.
-     * @param key key padded to a multiple of 8 bits.
-     * @param truncLenBits number of bits of output hash to use.
-     * @throws IllegalArgumentException if algorithm, key length or truncation length is invalid.
-     */
-    public IpSecAlgorithm(
-            @NonNull @AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) {
-        mName = algorithm;
-        mKey = key.clone();
-        mTruncLenBits = truncLenBits;
-        checkValidOrThrow(mName, mKey.length * 8, mTruncLenBits);
-    }
-
-    /** Get the algorithm name */
-    @NonNull
-    public String getName() {
-        return mName;
-    }
-
-    /** Get the key for this algorithm */
-    @NonNull
-    public byte[] getKey() {
-        return mKey.clone();
-    }
-
-    /** Get the truncation length of this algorithm, in bits */
-    public int getTruncationLengthBits() {
-        return mTruncLenBits;
-    }
-
-    /** Parcelable Implementation */
-    public int describeContents() {
-        return 0;
-    }
-
-    /** Write to parcel */
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeString(mName);
-        out.writeByteArray(mKey);
-        out.writeInt(mTruncLenBits);
-    }
-
-    /** Parcelable Creator */
-    public static final @android.annotation.NonNull Parcelable.Creator<IpSecAlgorithm> CREATOR =
-            new Parcelable.Creator<IpSecAlgorithm>() {
-                public IpSecAlgorithm createFromParcel(Parcel in) {
-                    final String name = in.readString();
-                    final byte[] key = in.createByteArray();
-                    final int truncLenBits = in.readInt();
-
-                    return new IpSecAlgorithm(name, key, truncLenBits);
-                }
-
-                public IpSecAlgorithm[] newArray(int size) {
-                    return new IpSecAlgorithm[size];
-                }
-            };
-
-    /**
-     * Returns supported IPsec algorithms for the current device.
-     *
-     * <p>Some algorithms may not be supported on old devices. Callers MUST check if an algorithm is
-     * supported before using it.
-     */
-    @NonNull
-    public static Set<String> getSupportedAlgorithms() {
-        return ENABLED_ALGOS;
-    }
-
-    /** @hide */
-    @VisibleForTesting
-    public static Set<String> loadAlgos(Resources systemResources) {
-        final Set<String> enabledAlgos = new HashSet<>();
-
-        // Load and validate the optional algorithm resource. Undefined or duplicate algorithms in
-        // the resource are not allowed.
-        final String[] resourceAlgos = systemResources.getStringArray(
-                android.R.array.config_optionalIpSecAlgorithms);
-        for (String str : resourceAlgos) {
-            if (!ALGO_TO_REQUIRED_FIRST_SDK.containsKey(str) || !enabledAlgos.add(str)) {
-                // This error should be caught by CTS and never be thrown to API callers
-                throw new IllegalArgumentException("Invalid or repeated algorithm " + str);
-            }
-        }
-
-        for (Entry<String, Integer> entry : ALGO_TO_REQUIRED_FIRST_SDK.entrySet()) {
-            if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= entry.getValue()) {
-                enabledAlgos.add(entry.getKey());
-            }
-        }
-
-        return enabledAlgos;
-    }
-
-    private static void checkValidOrThrow(String name, int keyLen, int truncLen) {
-        final boolean isValidLen;
-        final boolean isValidTruncLen;
-
-        if (!getSupportedAlgorithms().contains(name)) {
-            throw new IllegalArgumentException("Unsupported algorithm: " + name);
-        }
-
-        switch (name) {
-            case CRYPT_AES_CBC:
-                isValidLen = keyLen == 128 || keyLen == 192 || keyLen == 256;
-                isValidTruncLen = true;
-                break;
-            case CRYPT_AES_CTR:
-                // The keying material for AES-CTR is a key plus a 32-bit salt
-                isValidLen = keyLen == 128 + 32 || keyLen == 192 + 32 || keyLen == 256 + 32;
-                isValidTruncLen = true;
-                break;
-            case AUTH_HMAC_MD5:
-                isValidLen = keyLen == 128;
-                isValidTruncLen = truncLen >= 96 && truncLen <= 128;
-                break;
-            case AUTH_HMAC_SHA1:
-                isValidLen = keyLen == 160;
-                isValidTruncLen = truncLen >= 96 && truncLen <= 160;
-                break;
-            case AUTH_HMAC_SHA256:
-                isValidLen = keyLen == 256;
-                isValidTruncLen = truncLen >= 96 && truncLen <= 256;
-                break;
-            case AUTH_HMAC_SHA384:
-                isValidLen = keyLen == 384;
-                isValidTruncLen = truncLen >= 192 && truncLen <= 384;
-                break;
-            case AUTH_HMAC_SHA512:
-                isValidLen = keyLen == 512;
-                isValidTruncLen = truncLen >= 256 && truncLen <= 512;
-                break;
-            case AUTH_AES_XCBC:
-                isValidLen = keyLen == 128;
-                isValidTruncLen = truncLen == 96;
-                break;
-            case AUTH_AES_CMAC:
-                isValidLen = keyLen == 128;
-                isValidTruncLen = truncLen == 96;
-                break;
-            case AUTH_CRYPT_AES_GCM:
-                // The keying material for GCM is a key plus a 32-bit salt
-                isValidLen = keyLen == 128 + 32 || keyLen == 192 + 32 || keyLen == 256 + 32;
-                isValidTruncLen = truncLen == 64 || truncLen == 96 || truncLen == 128;
-                break;
-            case AUTH_CRYPT_CHACHA20_POLY1305:
-                // The keying material for ChaCha20Poly1305 is a key plus a 32-bit salt
-                isValidLen = keyLen == 256 + 32;
-                isValidTruncLen = truncLen == 128;
-                break;
-            default:
-                // Should never hit here.
-                throw new IllegalArgumentException("Couldn't find an algorithm: " + name);
-        }
-
-        if (!isValidLen) {
-            throw new IllegalArgumentException("Invalid key material keyLength: " + keyLen);
-        }
-        if (!isValidTruncLen) {
-            throw new IllegalArgumentException("Invalid truncation keyLength: " + truncLen);
-        }
-    }
-
-    /** @hide */
-    public boolean isAuthentication() {
-        switch (getName()) {
-            // Fallthrough
-            case AUTH_HMAC_MD5:
-            case AUTH_HMAC_SHA1:
-            case AUTH_HMAC_SHA256:
-            case AUTH_HMAC_SHA384:
-            case AUTH_HMAC_SHA512:
-            case AUTH_AES_XCBC:
-            case AUTH_AES_CMAC:
-                return true;
-            default:
-                return false;
-        }
-    }
-
-    /** @hide */
-    public boolean isEncryption() {
-        switch (getName()) {
-            case CRYPT_AES_CBC: // fallthrough
-            case CRYPT_AES_CTR:
-                return true;
-            default:
-                return false;
-        }
-    }
-
-    /** @hide */
-    public boolean isAead() {
-        switch (getName()) {
-            case AUTH_CRYPT_AES_GCM: // fallthrough
-            case AUTH_CRYPT_CHACHA20_POLY1305:
-                return true;
-            default:
-                return false;
-        }
-    }
-
-    @Override
-    @NonNull
-    public String toString() {
-        return new StringBuilder()
-                .append("{mName=")
-                .append(mName)
-                .append(", mTruncLenBits=")
-                .append(mTruncLenBits)
-                .append("}")
-                .toString();
-    }
-
-    /** @hide */
-    @VisibleForTesting
-    public static boolean equals(IpSecAlgorithm lhs, IpSecAlgorithm rhs) {
-        if (lhs == null || rhs == null) return (lhs == rhs);
-        return (lhs.mName.equals(rhs.mName)
-                && Arrays.equals(lhs.mKey, rhs.mKey)
-                && lhs.mTruncLenBits == rhs.mTruncLenBits);
-    }
-};
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecConfig.aidl b/packages/ConnectivityT/framework-t/src/android/net/IpSecConfig.aidl
deleted file mode 100644
index eaefca7..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/IpSecConfig.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-/** @hide */
-parcelable IpSecConfig;
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecConfig.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecConfig.java
deleted file mode 100644
index 03bb187..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/IpSecConfig.java
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net;
-
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * This class encapsulates all the configuration parameters needed to create IPsec transforms and
- * policies.
- *
- * @hide
- */
-public final class IpSecConfig implements Parcelable {
-    private static final String TAG = "IpSecConfig";
-
-    // MODE_TRANSPORT or MODE_TUNNEL
-    private int mMode = IpSecTransform.MODE_TRANSPORT;
-
-    // Preventing this from being null simplifies Java->Native binder
-    private String mSourceAddress = "";
-
-    // Preventing this from being null simplifies Java->Native binder
-    private String mDestinationAddress = "";
-
-    // The underlying Network that represents the "gateway" Network
-    // for outbound packets. It may also be used to select packets.
-    private Network mNetwork;
-
-    // Minimum requirements for identifying a transform
-    // SPI identifying the IPsec SA in packet processing
-    // and a destination IP address
-    private int mSpiResourceId = IpSecManager.INVALID_RESOURCE_ID;
-
-    // Encryption Algorithm
-    private IpSecAlgorithm mEncryption;
-
-    // Authentication Algorithm
-    private IpSecAlgorithm mAuthentication;
-
-    // Authenticated Encryption Algorithm
-    private IpSecAlgorithm mAuthenticatedEncryption;
-
-    // For tunnel mode IPv4 UDP Encapsulation
-    // IpSecTransform#ENCAP_ESP_*, such as ENCAP_ESP_OVER_UDP_IKE
-    private int mEncapType = IpSecTransform.ENCAP_NONE;
-    private int mEncapSocketResourceId = IpSecManager.INVALID_RESOURCE_ID;
-    private int mEncapRemotePort;
-
-    // An interval, in seconds between the NattKeepalive packets
-    private int mNattKeepaliveInterval;
-
-    // XFRM mark and mask; defaults to 0 (no mark/mask)
-    private int mMarkValue;
-    private int mMarkMask;
-
-    // XFRM interface id
-    private int mXfrmInterfaceId;
-
-    /** Set the mode for this IPsec transform */
-    public void setMode(int mode) {
-        mMode = mode;
-    }
-
-    /** Set the source IP addres for this IPsec transform */
-    public void setSourceAddress(String sourceAddress) {
-        mSourceAddress = sourceAddress;
-    }
-
-    /** Set the destination IP address for this IPsec transform */
-    public void setDestinationAddress(String destinationAddress) {
-        mDestinationAddress = destinationAddress;
-    }
-
-    /** Set the SPI by resource ID */
-    public void setSpiResourceId(int resourceId) {
-        mSpiResourceId = resourceId;
-    }
-
-    /** Set the encryption algorithm */
-    public void setEncryption(IpSecAlgorithm encryption) {
-        mEncryption = encryption;
-    }
-
-    /** Set the authentication algorithm */
-    public void setAuthentication(IpSecAlgorithm authentication) {
-        mAuthentication = authentication;
-    }
-
-    /** Set the authenticated encryption algorithm */
-    public void setAuthenticatedEncryption(IpSecAlgorithm authenticatedEncryption) {
-        mAuthenticatedEncryption = authenticatedEncryption;
-    }
-
-    /** Set the underlying network that will carry traffic for this transform */
-    public void setNetwork(Network network) {
-        mNetwork = network;
-    }
-
-    public void setEncapType(int encapType) {
-        mEncapType = encapType;
-    }
-
-    public void setEncapSocketResourceId(int resourceId) {
-        mEncapSocketResourceId = resourceId;
-    }
-
-    public void setEncapRemotePort(int port) {
-        mEncapRemotePort = port;
-    }
-
-    public void setNattKeepaliveInterval(int interval) {
-        mNattKeepaliveInterval = interval;
-    }
-
-    /**
-     * Sets the mark value
-     *
-     * <p>Internal (System server) use only. Marks passed in by users will be overwritten or
-     * ignored.
-     */
-    public void setMarkValue(int mark) {
-        mMarkValue = mark;
-    }
-
-    /**
-     * Sets the mark mask
-     *
-     * <p>Internal (System server) use only. Marks passed in by users will be overwritten or
-     * ignored.
-     */
-    public void setMarkMask(int mask) {
-        mMarkMask = mask;
-    }
-
-    public void setXfrmInterfaceId(int xfrmInterfaceId) {
-        mXfrmInterfaceId = xfrmInterfaceId;
-    }
-
-    // Transport or Tunnel
-    public int getMode() {
-        return mMode;
-    }
-
-    public String getSourceAddress() {
-        return mSourceAddress;
-    }
-
-    public int getSpiResourceId() {
-        return mSpiResourceId;
-    }
-
-    public String getDestinationAddress() {
-        return mDestinationAddress;
-    }
-
-    public IpSecAlgorithm getEncryption() {
-        return mEncryption;
-    }
-
-    public IpSecAlgorithm getAuthentication() {
-        return mAuthentication;
-    }
-
-    public IpSecAlgorithm getAuthenticatedEncryption() {
-        return mAuthenticatedEncryption;
-    }
-
-    public Network getNetwork() {
-        return mNetwork;
-    }
-
-    public int getEncapType() {
-        return mEncapType;
-    }
-
-    public int getEncapSocketResourceId() {
-        return mEncapSocketResourceId;
-    }
-
-    public int getEncapRemotePort() {
-        return mEncapRemotePort;
-    }
-
-    public int getNattKeepaliveInterval() {
-        return mNattKeepaliveInterval;
-    }
-
-    public int getMarkValue() {
-        return mMarkValue;
-    }
-
-    public int getMarkMask() {
-        return mMarkMask;
-    }
-
-    public int getXfrmInterfaceId() {
-        return mXfrmInterfaceId;
-    }
-
-    // Parcelable Methods
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeInt(mMode);
-        out.writeString(mSourceAddress);
-        out.writeString(mDestinationAddress);
-        out.writeParcelable(mNetwork, flags);
-        out.writeInt(mSpiResourceId);
-        out.writeParcelable(mEncryption, flags);
-        out.writeParcelable(mAuthentication, flags);
-        out.writeParcelable(mAuthenticatedEncryption, flags);
-        out.writeInt(mEncapType);
-        out.writeInt(mEncapSocketResourceId);
-        out.writeInt(mEncapRemotePort);
-        out.writeInt(mNattKeepaliveInterval);
-        out.writeInt(mMarkValue);
-        out.writeInt(mMarkMask);
-        out.writeInt(mXfrmInterfaceId);
-    }
-
-    @VisibleForTesting
-    public IpSecConfig() {}
-
-    /** Copy constructor */
-    @VisibleForTesting
-    public IpSecConfig(IpSecConfig c) {
-        mMode = c.mMode;
-        mSourceAddress = c.mSourceAddress;
-        mDestinationAddress = c.mDestinationAddress;
-        mNetwork = c.mNetwork;
-        mSpiResourceId = c.mSpiResourceId;
-        mEncryption = c.mEncryption;
-        mAuthentication = c.mAuthentication;
-        mAuthenticatedEncryption = c.mAuthenticatedEncryption;
-        mEncapType = c.mEncapType;
-        mEncapSocketResourceId = c.mEncapSocketResourceId;
-        mEncapRemotePort = c.mEncapRemotePort;
-        mNattKeepaliveInterval = c.mNattKeepaliveInterval;
-        mMarkValue = c.mMarkValue;
-        mMarkMask = c.mMarkMask;
-        mXfrmInterfaceId = c.mXfrmInterfaceId;
-    }
-
-    private IpSecConfig(Parcel in) {
-        mMode = in.readInt();
-        mSourceAddress = in.readString();
-        mDestinationAddress = in.readString();
-        mNetwork = (Network) in.readParcelable(Network.class.getClassLoader(), android.net.Network.class);
-        mSpiResourceId = in.readInt();
-        mEncryption =
-                (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader(), android.net.IpSecAlgorithm.class);
-        mAuthentication =
-                (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader(), android.net.IpSecAlgorithm.class);
-        mAuthenticatedEncryption =
-                (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader(), android.net.IpSecAlgorithm.class);
-        mEncapType = in.readInt();
-        mEncapSocketResourceId = in.readInt();
-        mEncapRemotePort = in.readInt();
-        mNattKeepaliveInterval = in.readInt();
-        mMarkValue = in.readInt();
-        mMarkMask = in.readInt();
-        mXfrmInterfaceId = in.readInt();
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder strBuilder = new StringBuilder();
-        strBuilder
-                .append("{mMode=")
-                .append(mMode == IpSecTransform.MODE_TUNNEL ? "TUNNEL" : "TRANSPORT")
-                .append(", mSourceAddress=")
-                .append(mSourceAddress)
-                .append(", mDestinationAddress=")
-                .append(mDestinationAddress)
-                .append(", mNetwork=")
-                .append(mNetwork)
-                .append(", mEncapType=")
-                .append(mEncapType)
-                .append(", mEncapSocketResourceId=")
-                .append(mEncapSocketResourceId)
-                .append(", mEncapRemotePort=")
-                .append(mEncapRemotePort)
-                .append(", mNattKeepaliveInterval=")
-                .append(mNattKeepaliveInterval)
-                .append("{mSpiResourceId=")
-                .append(mSpiResourceId)
-                .append(", mEncryption=")
-                .append(mEncryption)
-                .append(", mAuthentication=")
-                .append(mAuthentication)
-                .append(", mAuthenticatedEncryption=")
-                .append(mAuthenticatedEncryption)
-                .append(", mMarkValue=")
-                .append(mMarkValue)
-                .append(", mMarkMask=")
-                .append(mMarkMask)
-                .append(", mXfrmInterfaceId=")
-                .append(mXfrmInterfaceId)
-                .append("}");
-
-        return strBuilder.toString();
-    }
-
-    public static final @android.annotation.NonNull Parcelable.Creator<IpSecConfig> CREATOR =
-            new Parcelable.Creator<IpSecConfig>() {
-                public IpSecConfig createFromParcel(Parcel in) {
-                    return new IpSecConfig(in);
-                }
-
-                public IpSecConfig[] newArray(int size) {
-                    return new IpSecConfig[size];
-                }
-            };
-
-    @Override
-    public boolean equals(@Nullable Object other) {
-        if (!(other instanceof IpSecConfig)) return false;
-        final IpSecConfig rhs = (IpSecConfig) other;
-        return (mMode == rhs.mMode
-                && mSourceAddress.equals(rhs.mSourceAddress)
-                && mDestinationAddress.equals(rhs.mDestinationAddress)
-                && ((mNetwork != null && mNetwork.equals(rhs.mNetwork))
-                        || (mNetwork == rhs.mNetwork))
-                && mEncapType == rhs.mEncapType
-                && mEncapSocketResourceId == rhs.mEncapSocketResourceId
-                && mEncapRemotePort == rhs.mEncapRemotePort
-                && mNattKeepaliveInterval == rhs.mNattKeepaliveInterval
-                && mSpiResourceId == rhs.mSpiResourceId
-                && IpSecAlgorithm.equals(mEncryption, rhs.mEncryption)
-                && IpSecAlgorithm.equals(mAuthenticatedEncryption, rhs.mAuthenticatedEncryption)
-                && IpSecAlgorithm.equals(mAuthentication, rhs.mAuthentication)
-                && mMarkValue == rhs.mMarkValue
-                && mMarkMask == rhs.mMarkMask
-                && mXfrmInterfaceId == rhs.mXfrmInterfaceId);
-    }
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java
deleted file mode 100644
index 9cb0947..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java
+++ /dev/null
@@ -1,1065 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net;
-
-import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.RequiresFeature;
-import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
-import android.annotation.SystemService;
-import android.annotation.TestApi;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.os.ServiceSpecificException;
-import android.system.ErrnoException;
-import android.system.OsConstants;
-import android.util.AndroidException;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import dalvik.system.CloseGuard;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-import java.net.Socket;
-import java.util.Objects;
-
-/**
- * This class contains methods for managing IPsec sessions. Once configured, the kernel will apply
- * confidentiality (encryption) and integrity (authentication) to IP traffic.
- *
- * <p>Note that not all aspects of IPsec are permitted by this API. Applications may create
- * transport mode security associations and apply them to individual sockets. Applications looking
- * to create an IPsec VPN should use {@link VpnManager} and {@link Ikev2VpnProfile}.
- *
- * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the
- *     Internet Protocol</a>
- */
-@SystemService(Context.IPSEC_SERVICE)
-public class IpSecManager {
-    private static final String TAG = "IpSecManager";
-
-    /**
-     * Used when applying a transform to direct traffic through an {@link IpSecTransform}
-     * towards the host.
-     *
-     * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}.
-     */
-    public static final int DIRECTION_IN = 0;
-
-    /**
-     * Used when applying a transform to direct traffic through an {@link IpSecTransform}
-     * away from the host.
-     *
-     * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}.
-     */
-    public static final int DIRECTION_OUT = 1;
-
-    /**
-     * Used when applying a transform to direct traffic through an {@link IpSecTransform} for
-     * forwarding between interfaces.
-     *
-     * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}.
-     *
-     * @hide
-     */
-    @SystemApi(client = MODULE_LIBRARIES)
-    public static final int DIRECTION_FWD = 2;
-
-    /** @hide */
-    @IntDef(value = {DIRECTION_IN, DIRECTION_OUT})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface PolicyDirection {}
-
-    /**
-     * The Security Parameter Index (SPI) 0 indicates an unknown or invalid index.
-     *
-     * <p>No IPsec packet may contain an SPI of 0.
-     *
-     * @hide
-     */
-    @TestApi public static final int INVALID_SECURITY_PARAMETER_INDEX = 0;
-
-    /** @hide */
-    public interface Status {
-        int OK = 0;
-        int RESOURCE_UNAVAILABLE = 1;
-        int SPI_UNAVAILABLE = 2;
-    }
-
-    /** @hide */
-    public static final int INVALID_RESOURCE_ID = -1;
-
-    /**
-     * Thrown to indicate that a requested SPI is in use.
-     *
-     * <p>The combination of remote {@code InetAddress} and SPI must be unique across all apps on
-     * one device. If this error is encountered, a new SPI is required before a transform may be
-     * created. This error can be avoided by calling {@link
-     * IpSecManager#allocateSecurityParameterIndex}.
-     */
-    public static final class SpiUnavailableException extends AndroidException {
-        private final int mSpi;
-
-        /**
-         * Construct an exception indicating that a transform with the given SPI is already in use
-         * or otherwise unavailable.
-         *
-         * @param msg description indicating the colliding SPI
-         * @param spi the SPI that could not be used due to a collision
-         */
-        SpiUnavailableException(String msg, int spi) {
-            super(msg + " (spi: " + spi + ")");
-            mSpi = spi;
-        }
-
-        /** Get the SPI that caused a collision. */
-        public int getSpi() {
-            return mSpi;
-        }
-    }
-
-    /**
-     * Thrown to indicate that an IPsec resource is unavailable.
-     *
-     * <p>This could apply to resources such as sockets, {@link SecurityParameterIndex}, {@link
-     * IpSecTransform}, or other system resources. If this exception is thrown, users should release
-     * allocated objects of the type requested.
-     */
-    public static final class ResourceUnavailableException extends AndroidException {
-
-        ResourceUnavailableException(String msg) {
-            super(msg);
-        }
-    }
-
-    private final Context mContext;
-    private final IIpSecService mService;
-
-    /**
-     * This class represents a reserved SPI.
-     *
-     * <p>Objects of this type are used to track reserved security parameter indices. They can be
-     * obtained by calling {@link IpSecManager#allocateSecurityParameterIndex} and must be released
-     * by calling {@link #close()} when they are no longer needed.
-     */
-    public static final class SecurityParameterIndex implements AutoCloseable {
-        private final IIpSecService mService;
-        private final InetAddress mDestinationAddress;
-        private final CloseGuard mCloseGuard = CloseGuard.get();
-        private int mSpi = INVALID_SECURITY_PARAMETER_INDEX;
-        private int mResourceId = INVALID_RESOURCE_ID;
-
-        /** Get the underlying SPI held by this object. */
-        public int getSpi() {
-            return mSpi;
-        }
-
-        /**
-         * Release an SPI that was previously reserved.
-         *
-         * <p>Release an SPI for use by other users in the system. If a SecurityParameterIndex is
-         * applied to an IpSecTransform, it will become unusable for future transforms but should
-         * still be closed to ensure system resources are released.
-         */
-        @Override
-        public void close() {
-            try {
-                mService.releaseSecurityParameterIndex(mResourceId);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            } catch (Exception e) {
-                // On close we swallow all random exceptions since failure to close is not
-                // actionable by the user.
-                Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
-            } finally {
-                mResourceId = INVALID_RESOURCE_ID;
-                mCloseGuard.close();
-            }
-        }
-
-        /** Check that the SPI was closed properly. */
-        @Override
-        protected void finalize() throws Throwable {
-            if (mCloseGuard != null) {
-                mCloseGuard.warnIfOpen();
-            }
-
-            close();
-        }
-
-        private SecurityParameterIndex(
-                @NonNull IIpSecService service, InetAddress destinationAddress, int spi)
-                throws ResourceUnavailableException, SpiUnavailableException {
-            mService = service;
-            mDestinationAddress = destinationAddress;
-            try {
-                IpSecSpiResponse result =
-                        mService.allocateSecurityParameterIndex(
-                                destinationAddress.getHostAddress(), spi, new Binder());
-
-                if (result == null) {
-                    throw new NullPointerException("Received null response from IpSecService");
-                }
-
-                int status = result.status;
-                switch (status) {
-                    case Status.OK:
-                        break;
-                    case Status.RESOURCE_UNAVAILABLE:
-                        throw new ResourceUnavailableException(
-                                "No more SPIs may be allocated by this requester.");
-                    case Status.SPI_UNAVAILABLE:
-                        throw new SpiUnavailableException("Requested SPI is unavailable", spi);
-                    default:
-                        throw new RuntimeException(
-                                "Unknown status returned by IpSecService: " + status);
-                }
-                mSpi = result.spi;
-                mResourceId = result.resourceId;
-
-                if (mSpi == INVALID_SECURITY_PARAMETER_INDEX) {
-                    throw new RuntimeException("Invalid SPI returned by IpSecService: " + status);
-                }
-
-                if (mResourceId == INVALID_RESOURCE_ID) {
-                    throw new RuntimeException(
-                            "Invalid Resource ID returned by IpSecService: " + status);
-                }
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-            mCloseGuard.open("open");
-        }
-
-        /** @hide */
-        @VisibleForTesting
-        public int getResourceId() {
-            return mResourceId;
-        }
-
-        @Override
-        public String toString() {
-            return new StringBuilder()
-                .append("SecurityParameterIndex{spi=")
-                .append(mSpi)
-                .append(",resourceId=")
-                .append(mResourceId)
-                .append("}")
-                .toString();
-        }
-    }
-
-    /**
-     * Reserve a random SPI for traffic bound to or from the specified destination address.
-     *
-     * <p>If successful, this SPI is guaranteed available until released by a call to {@link
-     * SecurityParameterIndex#close()}.
-     *
-     * @param destinationAddress the destination address for traffic bearing the requested SPI.
-     *     For inbound traffic, the destination should be an address currently assigned on-device.
-     * @return the reserved SecurityParameterIndex
-     * @throws ResourceUnavailableException indicating that too many SPIs are
-     *     currently allocated for this user
-     */
-    @NonNull
-    public SecurityParameterIndex allocateSecurityParameterIndex(
-                @NonNull InetAddress destinationAddress) throws ResourceUnavailableException {
-        try {
-            return new SecurityParameterIndex(
-                    mService,
-                    destinationAddress,
-                    IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
-        } catch (ServiceSpecificException e) {
-            throw rethrowUncheckedExceptionFromServiceSpecificException(e);
-        } catch (SpiUnavailableException unlikely) {
-            // Because this function allocates a totally random SPI, it really shouldn't ever
-            // fail to allocate an SPI; we simply need this because the exception is checked.
-            throw new ResourceUnavailableException("No SPIs available");
-        }
-    }
-
-    /**
-     * Reserve the requested SPI for traffic bound to or from the specified destination address.
-     *
-     * <p>If successful, this SPI is guaranteed available until released by a call to {@link
-     * SecurityParameterIndex#close()}.
-     *
-     * @param destinationAddress the destination address for traffic bearing the requested SPI.
-     *     For inbound traffic, the destination should be an address currently assigned on-device.
-     * @param requestedSpi the requested SPI. The range 1-255 is reserved and may not be used. See
-     *     RFC 4303 Section 2.1.
-     * @return the reserved SecurityParameterIndex
-     * @throws ResourceUnavailableException indicating that too many SPIs are
-     *     currently allocated for this user
-     * @throws SpiUnavailableException indicating that the requested SPI could not be
-     *     reserved
-     */
-    @NonNull
-    public SecurityParameterIndex allocateSecurityParameterIndex(
-            @NonNull InetAddress destinationAddress, int requestedSpi)
-            throws SpiUnavailableException, ResourceUnavailableException {
-        if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) {
-            throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI");
-        }
-        try {
-            return new SecurityParameterIndex(mService, destinationAddress, requestedSpi);
-        } catch (ServiceSpecificException e) {
-            throw rethrowUncheckedExceptionFromServiceSpecificException(e);
-        }
-    }
-
-    /**
-     * Apply an IPsec transform to a stream socket.
-     *
-     * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
-     * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
-     * the transform is removed from the socket by calling {@link #removeTransportModeTransforms},
-     * unprotected traffic can resume on that socket.
-     *
-     * <p>For security reasons, the destination address of any traffic on the socket must match the
-     * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
-     * other IP address will result in an IOException. In addition, reads and writes on the socket
-     * will throw IOException if the user deactivates the transform (by calling {@link
-     * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}.
-     *
-     * <p>Note that when applied to TCP sockets, calling {@link IpSecTransform#close()} on an
-     * applied transform before completion of graceful shutdown may result in the shutdown sequence
-     * failing to complete. As such, applications requiring graceful shutdown MUST close the socket
-     * prior to deactivating the applied transform. Socket closure may be performed asynchronously
-     * (in batches), so the returning of a close function does not guarantee shutdown of a socket.
-     * Setting an SO_LINGER timeout results in socket closure being performed synchronously, and is
-     * sufficient to ensure shutdown.
-     *
-     * Specifically, if the transform is deactivated (by calling {@link IpSecTransform#close()}),
-     * prior to the socket being closed, the standard [FIN - FIN/ACK - ACK], or the reset [RST]
-     * packets are dropped due to the lack of a valid Transform. Similarly, if a socket without the
-     * SO_LINGER option set is closed, the delayed/batched FIN packets may be dropped.
-     *
-     * <h4>Rekey Procedure</h4>
-     *
-     * <p>When applying a new tranform to a socket in the outbound direction, the previous transform
-     * will be removed and the new transform will take effect immediately, sending all traffic on
-     * the new transform; however, when applying a transform in the inbound direction, traffic
-     * on the old transform will continue to be decrypted and delivered until that transform is
-     * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey
-     * procedures where both transforms are valid until both endpoints are using the new transform
-     * and all in-flight packets have been received.
-     *
-     * @param socket a stream socket
-     * @param direction the direction in which the transform should be applied
-     * @param transform a transport mode {@code IpSecTransform}
-     * @throws IOException indicating that the transform could not be applied
-     */
-    public void applyTransportModeTransform(@NonNull Socket socket,
-            @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
-        // Ensure creation of FD. See b/77548890 for more details.
-        socket.getSoLinger();
-
-        applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform);
-    }
-
-    /**
-     * Apply an IPsec transform to a datagram socket.
-     *
-     * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
-     * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
-     * the transform is removed from the socket by calling {@link #removeTransportModeTransforms},
-     * unprotected traffic can resume on that socket.
-     *
-     * <p>For security reasons, the destination address of any traffic on the socket must match the
-     * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
-     * other IP address will result in an IOException. In addition, reads and writes on the socket
-     * will throw IOException if the user deactivates the transform (by calling {@link
-     * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}.
-     *
-     * <h4>Rekey Procedure</h4>
-     *
-     * <p>When applying a new tranform to a socket in the outbound direction, the previous transform
-     * will be removed and the new transform will take effect immediately, sending all traffic on
-     * the new transform; however, when applying a transform in the inbound direction, traffic
-     * on the old transform will continue to be decrypted and delivered until that transform is
-     * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey
-     * procedures where both transforms are valid until both endpoints are using the new transform
-     * and all in-flight packets have been received.
-     *
-     * @param socket a datagram socket
-     * @param direction the direction in which the transform should be applied
-     * @param transform a transport mode {@code IpSecTransform}
-     * @throws IOException indicating that the transform could not be applied
-     */
-    public void applyTransportModeTransform(@NonNull DatagramSocket socket,
-            @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
-        applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform);
-    }
-
-    /**
-     * Apply an IPsec transform to a socket.
-     *
-     * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
-     * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
-     * the transform is removed from the socket by calling {@link #removeTransportModeTransforms},
-     * unprotected traffic can resume on that socket.
-     *
-     * <p>For security reasons, the destination address of any traffic on the socket must match the
-     * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
-     * other IP address will result in an IOException. In addition, reads and writes on the socket
-     * will throw IOException if the user deactivates the transform (by calling {@link
-     * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}.
-     *
-     * <p>Note that when applied to TCP sockets, calling {@link IpSecTransform#close()} on an
-     * applied transform before completion of graceful shutdown may result in the shutdown sequence
-     * failing to complete. As such, applications requiring graceful shutdown MUST close the socket
-     * prior to deactivating the applied transform. Socket closure may be performed asynchronously
-     * (in batches), so the returning of a close function does not guarantee shutdown of a socket.
-     * Setting an SO_LINGER timeout results in socket closure being performed synchronously, and is
-     * sufficient to ensure shutdown.
-     *
-     * Specifically, if the transform is deactivated (by calling {@link IpSecTransform#close()}),
-     * prior to the socket being closed, the standard [FIN - FIN/ACK - ACK], or the reset [RST]
-     * packets are dropped due to the lack of a valid Transform. Similarly, if a socket without the
-     * SO_LINGER option set is closed, the delayed/batched FIN packets may be dropped.
-     *
-     * <h4>Rekey Procedure</h4>
-     *
-     * <p>When applying a new tranform to a socket in the outbound direction, the previous transform
-     * will be removed and the new transform will take effect immediately, sending all traffic on
-     * the new transform; however, when applying a transform in the inbound direction, traffic
-     * on the old transform will continue to be decrypted and delivered until that transform is
-     * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey
-     * procedures where both transforms are valid until both endpoints are using the new transform
-     * and all in-flight packets have been received.
-     *
-     * @param socket a socket file descriptor
-     * @param direction the direction in which the transform should be applied
-     * @param transform a transport mode {@code IpSecTransform}
-     * @throws IOException indicating that the transform could not be applied
-     */
-    public void applyTransportModeTransform(@NonNull FileDescriptor socket,
-            @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
-        // We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor()
-        // constructor takes control and closes the user's FD when we exit the method.
-        try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) {
-            mService.applyTransportModeTransform(pfd, direction, transform.getResourceId());
-        } catch (ServiceSpecificException e) {
-            throw rethrowCheckedExceptionFromServiceSpecificException(e);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Remove an IPsec transform from a stream socket.
-     *
-     * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a
-     * socket allows the socket to be reused for communication in the clear.
-     *
-     * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
-     * {@link IpSecTransform#close()}, then communication on the socket will fail until this method
-     * is called.
-     *
-     * @param socket a socket that previously had a transform applied to it
-     * @throws IOException indicating that the transform could not be removed from the socket
-     */
-    public void removeTransportModeTransforms(@NonNull Socket socket) throws IOException {
-        // Ensure creation of FD. See b/77548890 for more details.
-        socket.getSoLinger();
-
-        removeTransportModeTransforms(socket.getFileDescriptor$());
-    }
-
-    /**
-     * Remove an IPsec transform from a datagram socket.
-     *
-     * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a
-     * socket allows the socket to be reused for communication in the clear.
-     *
-     * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
-     * {@link IpSecTransform#close()}, then communication on the socket will fail until this method
-     * is called.
-     *
-     * @param socket a socket that previously had a transform applied to it
-     * @throws IOException indicating that the transform could not be removed from the socket
-     */
-    public void removeTransportModeTransforms(@NonNull DatagramSocket socket) throws IOException {
-        removeTransportModeTransforms(socket.getFileDescriptor$());
-    }
-
-    /**
-     * Remove an IPsec transform from a socket.
-     *
-     * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a
-     * socket allows the socket to be reused for communication in the clear.
-     *
-     * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
-     * {@link IpSecTransform#close()}, then communication on the socket will fail until this method
-     * is called.
-     *
-     * @param socket a socket that previously had a transform applied to it
-     * @throws IOException indicating that the transform could not be removed from the socket
-     */
-    public void removeTransportModeTransforms(@NonNull FileDescriptor socket) throws IOException {
-        try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) {
-            mService.removeTransportModeTransforms(pfd);
-        } catch (ServiceSpecificException e) {
-            throw rethrowCheckedExceptionFromServiceSpecificException(e);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Remove a Tunnel Mode IPsec Transform from a {@link Network}. This must be used as part of
-     * cleanup if a tunneled Network experiences a change in default route. The Network will drop
-     * all traffic that cannot be routed to the Tunnel's outbound interface. If that interface is
-     * lost, all traffic will drop.
-     *
-     * <p>TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked.
-     *
-     * @param net a network that currently has transform applied to it.
-     * @param transform a Tunnel Mode IPsec Transform that has been previously applied to the given
-     *     network
-     * @hide
-     */
-    public void removeTunnelModeTransform(Network net, IpSecTransform transform) {}
-
-    /**
-     * This class provides access to a UDP encapsulation Socket.
-     *
-     * <p>{@code UdpEncapsulationSocket} wraps a system-provided datagram socket intended for IKEv2
-     * signalling and UDP encapsulated IPsec traffic. Instances can be obtained by calling {@link
-     * IpSecManager#openUdpEncapsulationSocket}. The provided socket cannot be re-bound by the
-     * caller. The caller should not close the {@code FileDescriptor} returned by {@link
-     * #getFileDescriptor}, but should use {@link #close} instead.
-     *
-     * <p>Allowing the user to close or unbind a UDP encapsulation socket could impact the traffic
-     * of the next user who binds to that port. To prevent this scenario, these sockets are held
-     * open by the system so that they may only be closed by calling {@link #close} or when the user
-     * process exits.
-     */
-    public static final class UdpEncapsulationSocket implements AutoCloseable {
-        private final ParcelFileDescriptor mPfd;
-        private final IIpSecService mService;
-        private int mResourceId = INVALID_RESOURCE_ID;
-        private final int mPort;
-        private final CloseGuard mCloseGuard = CloseGuard.get();
-
-        private UdpEncapsulationSocket(@NonNull IIpSecService service, int port)
-                throws ResourceUnavailableException, IOException {
-            mService = service;
-            try {
-                IpSecUdpEncapResponse result =
-                        mService.openUdpEncapsulationSocket(port, new Binder());
-                switch (result.status) {
-                    case Status.OK:
-                        break;
-                    case Status.RESOURCE_UNAVAILABLE:
-                        throw new ResourceUnavailableException(
-                                "No more Sockets may be allocated by this requester.");
-                    default:
-                        throw new RuntimeException(
-                                "Unknown status returned by IpSecService: " + result.status);
-                }
-                mResourceId = result.resourceId;
-                mPort = result.port;
-                mPfd = result.fileDescriptor;
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-            mCloseGuard.open("constructor");
-        }
-
-        /** Get the encapsulation socket's file descriptor. */
-        public FileDescriptor getFileDescriptor() {
-            if (mPfd == null) {
-                return null;
-            }
-            return mPfd.getFileDescriptor();
-        }
-
-        /** Get the bound port of the wrapped socket. */
-        public int getPort() {
-            return mPort;
-        }
-
-        /**
-         * Close this socket.
-         *
-         * <p>This closes the wrapped socket. Open encapsulation sockets count against a user's
-         * resource limits, and forgetting to close them eventually will result in {@link
-         * ResourceUnavailableException} being thrown.
-         */
-        @Override
-        public void close() throws IOException {
-            try {
-                mService.closeUdpEncapsulationSocket(mResourceId);
-                mResourceId = INVALID_RESOURCE_ID;
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            } catch (Exception e) {
-                // On close we swallow all random exceptions since failure to close is not
-                // actionable by the user.
-                Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
-            } finally {
-                mResourceId = INVALID_RESOURCE_ID;
-                mCloseGuard.close();
-            }
-
-            try {
-                mPfd.close();
-            } catch (IOException e) {
-                Log.e(TAG, "Failed to close UDP Encapsulation Socket with Port= " + mPort);
-                throw e;
-            }
-        }
-
-        /** Check that the socket was closed properly. */
-        @Override
-        protected void finalize() throws Throwable {
-            if (mCloseGuard != null) {
-                mCloseGuard.warnIfOpen();
-            }
-            close();
-        }
-
-        /** @hide */
-        @SystemApi(client = MODULE_LIBRARIES)
-        public int getResourceId() {
-            return mResourceId;
-        }
-
-        @Override
-        public String toString() {
-            return new StringBuilder()
-                .append("UdpEncapsulationSocket{port=")
-                .append(mPort)
-                .append(",resourceId=")
-                .append(mResourceId)
-                .append("}")
-                .toString();
-        }
-    };
-
-    /**
-     * Open a socket for UDP encapsulation and bind to the given port.
-     *
-     * <p>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket.
-     *
-     * @param port a local UDP port
-     * @return a socket that is bound to the given port
-     * @throws IOException indicating that the socket could not be opened or bound
-     * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
-     */
-    // Returning a socket in this fashion that has been created and bound by the system
-    // is the only safe way to ensure that a socket is both accessible to the user and
-    // safely usable for Encapsulation without allowing a user to possibly unbind from/close
-    // the port, which could potentially impact the traffic of the next user who binds to that
-    // socket.
-    @NonNull
-    public UdpEncapsulationSocket openUdpEncapsulationSocket(int port)
-            throws IOException, ResourceUnavailableException {
-        /*
-         * Most range checking is done in the service, but this version of the constructor expects
-         * a valid port number, and zero cannot be checked after being passed to the service.
-         */
-        if (port == 0) {
-            throw new IllegalArgumentException("Specified port must be a valid port number!");
-        }
-        try {
-            return new UdpEncapsulationSocket(mService, port);
-        } catch (ServiceSpecificException e) {
-            throw rethrowCheckedExceptionFromServiceSpecificException(e);
-        }
-    }
-
-    /**
-     * Open a socket for UDP encapsulation.
-     *
-     * <p>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket.
-     *
-     * <p>The local port of the returned socket can be obtained by calling {@link
-     * UdpEncapsulationSocket#getPort()}.
-     *
-     * @return a socket that is bound to a local port
-     * @throws IOException indicating that the socket could not be opened or bound
-     * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
-     */
-    // Returning a socket in this fashion that has been created and bound by the system
-    // is the only safe way to ensure that a socket is both accessible to the user and
-    // safely usable for Encapsulation without allowing a user to possibly unbind from/close
-    // the port, which could potentially impact the traffic of the next user who binds to that
-    // socket.
-    @NonNull
-    public UdpEncapsulationSocket openUdpEncapsulationSocket()
-            throws IOException, ResourceUnavailableException {
-        try {
-            return new UdpEncapsulationSocket(mService, 0);
-        } catch (ServiceSpecificException e) {
-            throw rethrowCheckedExceptionFromServiceSpecificException(e);
-        }
-    }
-
-    /**
-     * This class represents an IpSecTunnelInterface
-     *
-     * <p>IpSecTunnelInterface objects track tunnel interfaces that serve as
-     * local endpoints for IPsec tunnels.
-     *
-     * <p>Creating an IpSecTunnelInterface creates a device to which IpSecTransforms may be
-     * applied to provide IPsec security to packets sent through the tunnel. While a tunnel
-     * cannot be used in standalone mode within Android, the higher layers may use the tunnel
-     * to create Network objects which are accessible to the Android system.
-     * @hide
-     */
-    @SystemApi
-    public static final class IpSecTunnelInterface implements AutoCloseable {
-        private final String mOpPackageName;
-        private final IIpSecService mService;
-        private final InetAddress mRemoteAddress;
-        private final InetAddress mLocalAddress;
-        private final Network mUnderlyingNetwork;
-        private final CloseGuard mCloseGuard = CloseGuard.get();
-        private String mInterfaceName;
-        private int mResourceId = INVALID_RESOURCE_ID;
-
-        /** Get the underlying SPI held by this object. */
-        @NonNull
-        public String getInterfaceName() {
-            return mInterfaceName;
-        }
-
-        /**
-         * Add an address to the IpSecTunnelInterface
-         *
-         * <p>Add an address which may be used as the local inner address for
-         * tunneled traffic.
-         *
-         * @param address the local address for traffic inside the tunnel
-         * @param prefixLen length of the InetAddress prefix
-         * @hide
-         */
-        @SystemApi
-        @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
-        @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
-        public void addAddress(@NonNull InetAddress address, int prefixLen) throws IOException {
-            try {
-                mService.addAddressToTunnelInterface(
-                        mResourceId, new LinkAddress(address, prefixLen), mOpPackageName);
-            } catch (ServiceSpecificException e) {
-                throw rethrowCheckedExceptionFromServiceSpecificException(e);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-        }
-
-        /**
-         * Remove an address from the IpSecTunnelInterface
-         *
-         * <p>Remove an address which was previously added to the IpSecTunnelInterface
-         *
-         * @param address to be removed
-         * @param prefixLen length of the InetAddress prefix
-         * @hide
-         */
-        @SystemApi
-        @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
-        @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
-        public void removeAddress(@NonNull InetAddress address, int prefixLen) throws IOException {
-            try {
-                mService.removeAddressFromTunnelInterface(
-                        mResourceId, new LinkAddress(address, prefixLen), mOpPackageName);
-            } catch (ServiceSpecificException e) {
-                throw rethrowCheckedExceptionFromServiceSpecificException(e);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-        }
-
-        /**
-         * Update the underlying network for this IpSecTunnelInterface.
-         *
-         * <p>This new underlying network will be used for all transforms applied AFTER this call is
-         * complete. Before new {@link IpSecTransform}(s) with matching addresses are applied to
-         * this tunnel interface, traffic will still use the old SA, and be routed on the old
-         * underlying network.
-         *
-         * <p>To migrate IPsec tunnel mode traffic, a caller should:
-         *
-         * <ol>
-         *   <li>Update the IpSecTunnelInterface’s underlying network.
-         *   <li>Apply {@link IpSecTransform}(s) with matching addresses to this
-         *       IpSecTunnelInterface.
-         * </ol>
-         *
-         * @param underlyingNetwork the new {@link Network} that will carry traffic for this tunnel.
-         *     This network MUST never be the network exposing this IpSecTunnelInterface, otherwise
-         *     this method will throw an {@link IllegalArgumentException}. If the
-         *     IpSecTunnelInterface is later added to this network, all outbound traffic will be
-         *     blackholed.
-         */
-        // TODO: b/169171001 Update the documentation when transform migration is supported.
-        // The purpose of making updating network and applying transforms separate is to leave open
-        // the possibility to support lossless migration procedures. To do that, Android platform
-        // will need to support multiple inbound tunnel mode transforms, just like it can support
-        // multiple transport mode transforms.
-        @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
-        @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
-        public void setUnderlyingNetwork(@NonNull Network underlyingNetwork) throws IOException {
-            try {
-                mService.setNetworkForTunnelInterface(
-                        mResourceId, underlyingNetwork, mOpPackageName);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-        }
-
-        private IpSecTunnelInterface(@NonNull Context ctx, @NonNull IIpSecService service,
-                @NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress,
-                @NonNull Network underlyingNetwork)
-                throws ResourceUnavailableException, IOException {
-            mOpPackageName = ctx.getOpPackageName();
-            mService = service;
-            mLocalAddress = localAddress;
-            mRemoteAddress = remoteAddress;
-            mUnderlyingNetwork = underlyingNetwork;
-
-            try {
-                IpSecTunnelInterfaceResponse result =
-                        mService.createTunnelInterface(
-                                localAddress.getHostAddress(),
-                                remoteAddress.getHostAddress(),
-                                underlyingNetwork,
-                                new Binder(),
-                                mOpPackageName);
-                switch (result.status) {
-                    case Status.OK:
-                        break;
-                    case Status.RESOURCE_UNAVAILABLE:
-                        throw new ResourceUnavailableException(
-                                "No more tunnel interfaces may be allocated by this requester.");
-                    default:
-                        throw new RuntimeException(
-                                "Unknown status returned by IpSecService: " + result.status);
-                }
-                mResourceId = result.resourceId;
-                mInterfaceName = result.interfaceName;
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-            mCloseGuard.open("constructor");
-        }
-
-        /**
-         * Delete an IpSecTunnelInterface
-         *
-         * <p>Calling close will deallocate the IpSecTunnelInterface and all of its system
-         * resources. Any packets bound for this interface either inbound or outbound will
-         * all be lost.
-         */
-        @Override
-        public void close() {
-            try {
-                mService.deleteTunnelInterface(mResourceId, mOpPackageName);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            } catch (Exception e) {
-                // On close we swallow all random exceptions since failure to close is not
-                // actionable by the user.
-                Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
-            } finally {
-                mResourceId = INVALID_RESOURCE_ID;
-                mCloseGuard.close();
-            }
-        }
-
-        /** Check that the Interface was closed properly. */
-        @Override
-        protected void finalize() throws Throwable {
-            if (mCloseGuard != null) {
-                mCloseGuard.warnIfOpen();
-            }
-            close();
-        }
-
-        /** @hide */
-        @VisibleForTesting
-        public int getResourceId() {
-            return mResourceId;
-        }
-
-        @NonNull
-        @Override
-        public String toString() {
-            return new StringBuilder()
-                .append("IpSecTunnelInterface{ifname=")
-                .append(mInterfaceName)
-                .append(",resourceId=")
-                .append(mResourceId)
-                .append("}")
-                .toString();
-        }
-    }
-
-    /**
-     * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic.
-     *
-     * <p>An application that creates tunnels is responsible for cleaning up the tunnel when the
-     * underlying network goes away, and the onLost() callback is received.
-     *
-     * @param localAddress The local addres of the tunnel
-     * @param remoteAddress The local addres of the tunnel
-     * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel.
-     *        This network should almost certainly be a network such as WiFi with an L2 address.
-     * @return a new {@link IpSecManager#IpSecTunnelInterface} with the specified properties
-     * @throws IOException indicating that the socket could not be opened or bound
-     * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
-     * @hide
-     */
-    @SystemApi
-    @NonNull
-    @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
-    @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
-    public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress,
-            @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork)
-            throws ResourceUnavailableException, IOException {
-        try {
-            return new IpSecTunnelInterface(
-                    mContext, mService, localAddress, remoteAddress, underlyingNetwork);
-        } catch (ServiceSpecificException e) {
-            throw rethrowCheckedExceptionFromServiceSpecificException(e);
-        }
-    }
-
-    /**
-     * Apply an active Tunnel Mode IPsec Transform to a {@link IpSecTunnelInterface}, which will
-     * tunnel all traffic for the given direction through the underlying network's interface with
-     * IPsec (applies an outer IP header and IPsec Header to all traffic, and expects an additional
-     * IP header and IPsec Header on all inbound traffic).
-     * <p>Applications should probably not use this API directly.
-     *
-     *
-     * @param tunnel The {@link IpSecManager#IpSecTunnelInterface} that will use the supplied
-     *        transform.
-     * @param direction the direction, {@link DIRECTION_OUT} or {@link #DIRECTION_IN} in which
-     *        the transform will be used.
-     * @param transform an {@link IpSecTransform} created in tunnel mode
-     * @throws IOException indicating that the transform could not be applied due to a lower
-     *         layer failure.
-     * @hide
-     */
-    @SystemApi
-    @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
-    @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
-    public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel,
-            @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
-        try {
-            mService.applyTunnelModeTransform(
-                    tunnel.getResourceId(), direction,
-                    transform.getResourceId(), mContext.getOpPackageName());
-        } catch (ServiceSpecificException e) {
-            throw rethrowCheckedExceptionFromServiceSpecificException(e);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * @hide
-     */
-    public IpSecTransformResponse createTransform(IpSecConfig config, IBinder binder,
-            String callingPackage) {
-        try {
-            return mService.createTransform(config, binder, callingPackage);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * @hide
-     */
-    public void deleteTransform(int resourceId) {
-        try {
-            mService.deleteTransform(resourceId);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Construct an instance of IpSecManager within an application context.
-     *
-     * @param context the application context for this manager
-     * @hide
-     */
-    public IpSecManager(Context ctx, IIpSecService service) {
-        mContext = ctx;
-        mService = Objects.requireNonNull(service, "missing service");
-    }
-
-    private static void maybeHandleServiceSpecificException(ServiceSpecificException sse) {
-        // OsConstants are late binding, so switch statements can't be used.
-        if (sse.errorCode == OsConstants.EINVAL) {
-            throw new IllegalArgumentException(sse);
-        } else if (sse.errorCode == OsConstants.EAGAIN) {
-            throw new IllegalStateException(sse);
-        } else if (sse.errorCode == OsConstants.EOPNOTSUPP
-                || sse.errorCode == OsConstants.EPROTONOSUPPORT) {
-            throw new UnsupportedOperationException(sse);
-        }
-    }
-
-    /**
-     * Convert an Errno SSE to the correct Unchecked exception type.
-     *
-     * This method never actually returns.
-     */
-    // package
-    static RuntimeException
-            rethrowUncheckedExceptionFromServiceSpecificException(ServiceSpecificException sse) {
-        maybeHandleServiceSpecificException(sse);
-        throw new RuntimeException(sse);
-    }
-
-    /**
-     * Convert an Errno SSE to the correct Checked or Unchecked exception type.
-     *
-     * This method may throw IOException, or it may throw an unchecked exception; it will never
-     * actually return.
-     */
-    // package
-    static IOException rethrowCheckedExceptionFromServiceSpecificException(
-            ServiceSpecificException sse) throws IOException {
-        // First see if this is an unchecked exception of a type we know.
-        // If so, then we prefer the unchecked (specific) type of exception.
-        maybeHandleServiceSpecificException(sse);
-        // If not, then all we can do is provide the SSE in the form of an IOException.
-        throw new ErrnoException(
-                "IpSec encountered errno=" + sse.errorCode, sse.errorCode).rethrowAsIOException();
-    }
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecSpiResponse.aidl b/packages/ConnectivityT/framework-t/src/android/net/IpSecSpiResponse.aidl
deleted file mode 100644
index 6484a00..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/IpSecSpiResponse.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-/** @hide */
-parcelable IpSecSpiResponse;
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecSpiResponse.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecSpiResponse.java
deleted file mode 100644
index f99e570..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/IpSecSpiResponse.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * This class is used to return an SPI and corresponding status from the IpSecService to an
- * IpSecManager.SecurityParameterIndex.
- *
- * @hide
- */
-public final class IpSecSpiResponse implements Parcelable {
-    private static final String TAG = "IpSecSpiResponse";
-
-    public final int resourceId;
-    public final int status;
-    public final int spi;
-    // Parcelable Methods
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeInt(status);
-        out.writeInt(resourceId);
-        out.writeInt(spi);
-    }
-
-    public IpSecSpiResponse(int inStatus, int inResourceId, int inSpi) {
-        status = inStatus;
-        resourceId = inResourceId;
-        spi = inSpi;
-    }
-
-    public IpSecSpiResponse(int inStatus) {
-        if (inStatus == IpSecManager.Status.OK) {
-            throw new IllegalArgumentException("Valid status implies other args must be provided");
-        }
-        status = inStatus;
-        resourceId = IpSecManager.INVALID_RESOURCE_ID;
-        spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
-    }
-
-    private IpSecSpiResponse(Parcel in) {
-        status = in.readInt();
-        resourceId = in.readInt();
-        spi = in.readInt();
-    }
-
-    public static final @android.annotation.NonNull Parcelable.Creator<IpSecSpiResponse> CREATOR =
-            new Parcelable.Creator<IpSecSpiResponse>() {
-                public IpSecSpiResponse createFromParcel(Parcel in) {
-                    return new IpSecSpiResponse(in);
-                }
-
-                public IpSecSpiResponse[] newArray(int size) {
-                    return new IpSecSpiResponse[size];
-                }
-            };
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java
deleted file mode 100644
index 68ae5de..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net;
-
-import static android.net.IpSecManager.INVALID_RESOURCE_ID;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresFeature;
-import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Binder;
-import android.os.ServiceSpecificException;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import dalvik.system.CloseGuard;
-
-import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.net.InetAddress;
-import java.util.Objects;
-
-/**
- * This class represents a transform, which roughly corresponds to an IPsec Security Association.
- *
- * <p>Transforms are created using {@link IpSecTransform.Builder}. Each {@code IpSecTransform}
- * object encapsulates the properties and state of an IPsec security association. That includes,
- * but is not limited to, algorithm choice, key material, and allocated system resources.
- *
- * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the
- *     Internet Protocol</a>
- */
-public final class IpSecTransform implements AutoCloseable {
-    private static final String TAG = "IpSecTransform";
-
-    /** @hide */
-    public static final int MODE_TRANSPORT = 0;
-
-    /** @hide */
-    public static final int MODE_TUNNEL = 1;
-
-    /** @hide */
-    public static final int ENCAP_NONE = 0;
-
-    /**
-     * IPsec traffic will be encapsulated within UDP, but with 8 zero-value bytes between the UDP
-     * header and payload. This prevents traffic from being interpreted as ESP or IKEv2.
-     *
-     * @hide
-     */
-    public static final int ENCAP_ESPINUDP_NON_IKE = 1;
-
-    /**
-     * IPsec traffic will be encapsulated within UDP as per
-     * <a href="https://tools.ietf.org/html/rfc3948">RFC 3498</a>.
-     *
-     * @hide
-     */
-    public static final int ENCAP_ESPINUDP = 2;
-
-    /** @hide */
-    @IntDef(value = {ENCAP_NONE, ENCAP_ESPINUDP, ENCAP_ESPINUDP_NON_IKE})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface EncapType {}
-
-    /** @hide */
-    @VisibleForTesting
-    public IpSecTransform(Context context, IpSecConfig config) {
-        mContext = context;
-        mConfig = new IpSecConfig(config);
-        mResourceId = INVALID_RESOURCE_ID;
-    }
-
-    private IpSecManager getIpSecManager(Context context) {
-        return context.getSystemService(IpSecManager.class);
-    }
-    /**
-     * Checks the result status and throws an appropriate exception if the status is not Status.OK.
-     */
-    private void checkResultStatus(int status)
-            throws IOException, IpSecManager.ResourceUnavailableException,
-                    IpSecManager.SpiUnavailableException {
-        switch (status) {
-            case IpSecManager.Status.OK:
-                return;
-                // TODO: Pass Error string back from bundle so that errors can be more specific
-            case IpSecManager.Status.RESOURCE_UNAVAILABLE:
-                throw new IpSecManager.ResourceUnavailableException(
-                        "Failed to allocate a new IpSecTransform");
-            case IpSecManager.Status.SPI_UNAVAILABLE:
-                Log.wtf(TAG, "Attempting to use an SPI that was somehow not reserved");
-                // Fall through
-            default:
-                throw new IllegalStateException(
-                        "Failed to Create a Transform with status code " + status);
-        }
-    }
-
-    private IpSecTransform activate()
-            throws IOException, IpSecManager.ResourceUnavailableException,
-                    IpSecManager.SpiUnavailableException {
-        synchronized (this) {
-            try {
-                IpSecTransformResponse result = getIpSecManager(mContext).createTransform(
-                        mConfig, new Binder(), mContext.getOpPackageName());
-                int status = result.status;
-                checkResultStatus(status);
-                mResourceId = result.resourceId;
-                Log.d(TAG, "Added Transform with Id " + mResourceId);
-                mCloseGuard.open("build");
-            } catch (ServiceSpecificException e) {
-                throw IpSecManager.rethrowUncheckedExceptionFromServiceSpecificException(e);
-            }
-        }
-
-        return this;
-    }
-
-    /**
-     * Standard equals.
-     */
-    public boolean equals(@Nullable Object other) {
-        if (this == other) return true;
-        if (!(other instanceof IpSecTransform)) return false;
-        final IpSecTransform rhs = (IpSecTransform) other;
-        return getConfig().equals(rhs.getConfig()) && mResourceId == rhs.mResourceId;
-    }
-
-    /**
-     * Deactivate this {@code IpSecTransform} and free allocated resources.
-     *
-     * <p>Deactivating a transform while it is still applied to a socket will result in errors on
-     * that socket. Make sure to remove transforms by calling {@link
-     * IpSecManager#removeTransportModeTransforms}. Note, removing an {@code IpSecTransform} from a
-     * socket will not deactivate it (because one transform may be applied to multiple sockets).
-     *
-     * <p>It is safe to call this method on a transform that has already been deactivated.
-     */
-    public void close() {
-        Log.d(TAG, "Removing Transform with Id " + mResourceId);
-
-        // Always safe to attempt cleanup
-        if (mResourceId == INVALID_RESOURCE_ID) {
-            mCloseGuard.close();
-            return;
-        }
-        try {
-            getIpSecManager(mContext).deleteTransform(mResourceId);
-        } catch (Exception e) {
-            // On close we swallow all random exceptions since failure to close is not
-            // actionable by the user.
-            Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
-        } finally {
-            mResourceId = INVALID_RESOURCE_ID;
-            mCloseGuard.close();
-        }
-    }
-
-    /** Check that the transform was closed properly. */
-    @Override
-    protected void finalize() throws Throwable {
-        if (mCloseGuard != null) {
-            mCloseGuard.warnIfOpen();
-        }
-        close();
-    }
-
-    /* Package */
-    IpSecConfig getConfig() {
-        return mConfig;
-    }
-
-    private final IpSecConfig mConfig;
-    private int mResourceId;
-    private final Context mContext;
-    private final CloseGuard mCloseGuard = CloseGuard.get();
-
-    /** @hide */
-    @VisibleForTesting
-    public int getResourceId() {
-        return mResourceId;
-    }
-
-    /**
-     * A callback class to provide status information regarding a NAT-T keepalive session
-     *
-     * <p>Use this callback to receive status information regarding a NAT-T keepalive session
-     * by registering it when calling {@link #startNattKeepalive}.
-     *
-     * @hide
-     */
-    public static class NattKeepaliveCallback {
-        /** The specified {@code Network} is not connected. */
-        public static final int ERROR_INVALID_NETWORK = 1;
-        /** The hardware does not support this request. */
-        public static final int ERROR_HARDWARE_UNSUPPORTED = 2;
-        /** The hardware returned an error. */
-        public static final int ERROR_HARDWARE_ERROR = 3;
-
-        /** The requested keepalive was successfully started. */
-        public void onStarted() {}
-        /** The keepalive was successfully stopped. */
-        public void onStopped() {}
-        /** An error occurred. */
-        public void onError(int error) {}
-    }
-
-    /** This class is used to build {@link IpSecTransform} objects. */
-    public static class Builder {
-        private Context mContext;
-        private IpSecConfig mConfig;
-
-        /**
-         * Set the encryption algorithm.
-         *
-         * <p>Encryption is mutually exclusive with authenticated encryption.
-         *
-         * @param algo {@link IpSecAlgorithm} specifying the encryption to be applied.
-         */
-        @NonNull
-        public IpSecTransform.Builder setEncryption(@NonNull IpSecAlgorithm algo) {
-            // TODO: throw IllegalArgumentException if algo is not an encryption algorithm.
-            Objects.requireNonNull(algo);
-            mConfig.setEncryption(algo);
-            return this;
-        }
-
-        /**
-         * Set the authentication (integrity) algorithm.
-         *
-         * <p>Authentication is mutually exclusive with authenticated encryption.
-         *
-         * @param algo {@link IpSecAlgorithm} specifying the authentication to be applied.
-         */
-        @NonNull
-        public IpSecTransform.Builder setAuthentication(@NonNull IpSecAlgorithm algo) {
-            // TODO: throw IllegalArgumentException if algo is not an authentication algorithm.
-            Objects.requireNonNull(algo);
-            mConfig.setAuthentication(algo);
-            return this;
-        }
-
-        /**
-         * Set the authenticated encryption algorithm.
-         *
-         * <p>The Authenticated Encryption (AE) class of algorithms are also known as
-         * Authenticated Encryption with Associated Data (AEAD) algorithms, or Combined mode
-         * algorithms (as referred to in
-         * <a href="https://tools.ietf.org/html/rfc4301">RFC 4301</a>).
-         *
-         * <p>Authenticated encryption is mutually exclusive with encryption and authentication.
-         *
-         * @param algo {@link IpSecAlgorithm} specifying the authenticated encryption algorithm to
-         *     be applied.
-         */
-        @NonNull
-        public IpSecTransform.Builder setAuthenticatedEncryption(@NonNull IpSecAlgorithm algo) {
-            Objects.requireNonNull(algo);
-            mConfig.setAuthenticatedEncryption(algo);
-            return this;
-        }
-
-        /**
-         * Add UDP encapsulation to an IPv4 transform.
-         *
-         * <p>This allows IPsec traffic to pass through a NAT.
-         *
-         * @see <a href="https://tools.ietf.org/html/rfc3948">RFC 3948, UDP Encapsulation of IPsec
-         *     ESP Packets</a>
-         * @see <a href="https://tools.ietf.org/html/rfc7296#section-2.23">RFC 7296 section 2.23,
-         *     NAT Traversal of IKEv2</a>
-         * @param localSocket a socket for sending and receiving encapsulated traffic
-         * @param remotePort the UDP port number of the remote host that will send and receive
-         *     encapsulated traffic. In the case of IKEv2, this should be port 4500.
-         */
-        @NonNull
-        public IpSecTransform.Builder setIpv4Encapsulation(
-                @NonNull IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) {
-            Objects.requireNonNull(localSocket);
-            mConfig.setEncapType(ENCAP_ESPINUDP);
-            if (localSocket.getResourceId() == INVALID_RESOURCE_ID) {
-                throw new IllegalArgumentException("Invalid UdpEncapsulationSocket");
-            }
-            mConfig.setEncapSocketResourceId(localSocket.getResourceId());
-            mConfig.setEncapRemotePort(remotePort);
-            return this;
-        }
-
-        /**
-         * Build a transport mode {@link IpSecTransform}.
-         *
-         * <p>This builds and activates a transport mode transform. Note that an active transform
-         * will not affect any network traffic until it has been applied to one or more sockets.
-         *
-         * @see IpSecManager#applyTransportModeTransform
-         * @param sourceAddress the source {@code InetAddress} of traffic on sockets that will use
-         *     this transform; this address must belong to the Network used by all sockets that
-         *     utilize this transform; if provided, then only traffic originating from the
-         *     specified source address will be processed.
-         * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed
-         *     traffic
-         * @throws IllegalArgumentException indicating that a particular combination of transform
-         *     properties is invalid
-         * @throws IpSecManager.ResourceUnavailableException indicating that too many transforms
-         *     are active
-         * @throws IpSecManager.SpiUnavailableException indicating the rare case where an SPI
-         *     collides with an existing transform
-         * @throws IOException indicating other errors
-         */
-        @NonNull
-        public IpSecTransform buildTransportModeTransform(
-                @NonNull InetAddress sourceAddress,
-                @NonNull IpSecManager.SecurityParameterIndex spi)
-                throws IpSecManager.ResourceUnavailableException,
-                        IpSecManager.SpiUnavailableException, IOException {
-            Objects.requireNonNull(sourceAddress);
-            Objects.requireNonNull(spi);
-            if (spi.getResourceId() == INVALID_RESOURCE_ID) {
-                throw new IllegalArgumentException("Invalid SecurityParameterIndex");
-            }
-            mConfig.setMode(MODE_TRANSPORT);
-            mConfig.setSourceAddress(sourceAddress.getHostAddress());
-            mConfig.setSpiResourceId(spi.getResourceId());
-            // FIXME: modifying a builder after calling build can change the built transform.
-            return new IpSecTransform(mContext, mConfig).activate();
-        }
-
-        /**
-         * Build and return an {@link IpSecTransform} object as a Tunnel Mode Transform. Some
-         * parameters have interdependencies that are checked at build time.
-         *
-         * @param sourceAddress the {@link InetAddress} that provides the source address for this
-         *     IPsec tunnel. This is almost certainly an address belonging to the {@link Network}
-         *     that will originate the traffic, which is set as the {@link #setUnderlyingNetwork}.
-         * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed
-         *     traffic
-         * @throws IllegalArgumentException indicating that a particular combination of transform
-         *     properties is invalid.
-         * @throws IpSecManager.ResourceUnavailableException indicating that too many transforms
-         *     are active
-         * @throws IpSecManager.SpiUnavailableException indicating the rare case where an SPI
-         *     collides with an existing transform
-         * @throws IOException indicating other errors
-         * @hide
-         */
-        @SystemApi
-        @NonNull
-        @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
-        @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
-        public IpSecTransform buildTunnelModeTransform(
-                @NonNull InetAddress sourceAddress,
-                @NonNull IpSecManager.SecurityParameterIndex spi)
-                throws IpSecManager.ResourceUnavailableException,
-                        IpSecManager.SpiUnavailableException, IOException {
-            Objects.requireNonNull(sourceAddress);
-            Objects.requireNonNull(spi);
-            if (spi.getResourceId() == INVALID_RESOURCE_ID) {
-                throw new IllegalArgumentException("Invalid SecurityParameterIndex");
-            }
-            mConfig.setMode(MODE_TUNNEL);
-            mConfig.setSourceAddress(sourceAddress.getHostAddress());
-            mConfig.setSpiResourceId(spi.getResourceId());
-            return new IpSecTransform(mContext, mConfig).activate();
-        }
-
-        /**
-         * Create a new IpSecTransform.Builder.
-         *
-         * @param context current context
-         */
-        public Builder(@NonNull Context context) {
-            Objects.requireNonNull(context);
-            mContext = context;
-            mConfig = new IpSecConfig();
-        }
-    }
-
-    @Override
-    public String toString() {
-        return new StringBuilder()
-            .append("IpSecTransform{resourceId=")
-            .append(mResourceId)
-            .append("}")
-            .toString();
-    }
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransformResponse.aidl b/packages/ConnectivityT/framework-t/src/android/net/IpSecTransformResponse.aidl
deleted file mode 100644
index 546230d..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransformResponse.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-/** @hide */
-parcelable IpSecTransformResponse;
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransformResponse.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecTransformResponse.java
deleted file mode 100644
index 363f316..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransformResponse.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * This class is used to return an IpSecTransform resource Id and and corresponding status from the
- * IpSecService to an IpSecTransform object.
- *
- * @hide
- */
-public final class IpSecTransformResponse implements Parcelable {
-    private static final String TAG = "IpSecTransformResponse";
-
-    public final int resourceId;
-    public final int status;
-    // Parcelable Methods
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeInt(status);
-        out.writeInt(resourceId);
-    }
-
-    public IpSecTransformResponse(int inStatus) {
-        if (inStatus == IpSecManager.Status.OK) {
-            throw new IllegalArgumentException("Valid status implies other args must be provided");
-        }
-        status = inStatus;
-        resourceId = IpSecManager.INVALID_RESOURCE_ID;
-    }
-
-    public IpSecTransformResponse(int inStatus, int inResourceId) {
-        status = inStatus;
-        resourceId = inResourceId;
-    }
-
-    private IpSecTransformResponse(Parcel in) {
-        status = in.readInt();
-        resourceId = in.readInt();
-    }
-
-    @android.annotation.NonNull
-    public static final Parcelable.Creator<IpSecTransformResponse> CREATOR =
-            new Parcelable.Creator<IpSecTransformResponse>() {
-                public IpSecTransformResponse createFromParcel(Parcel in) {
-                    return new IpSecTransformResponse(in);
-                }
-
-                public IpSecTransformResponse[] newArray(int size) {
-                    return new IpSecTransformResponse[size];
-                }
-            };
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecTunnelInterfaceResponse.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecTunnelInterfaceResponse.java
deleted file mode 100644
index 127e30a..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/IpSecTunnelInterfaceResponse.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * This class is used to return an IpSecTunnelInterface resource Id and and corresponding status
- * from the IpSecService to an IpSecTunnelInterface object.
- *
- * @hide
- */
-public final class IpSecTunnelInterfaceResponse implements Parcelable {
-    private static final String TAG = "IpSecTunnelInterfaceResponse";
-
-    public final int resourceId;
-    public final String interfaceName;
-    public final int status;
-    // Parcelable Methods
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeInt(status);
-        out.writeInt(resourceId);
-        out.writeString(interfaceName);
-    }
-
-    public IpSecTunnelInterfaceResponse(int inStatus) {
-        if (inStatus == IpSecManager.Status.OK) {
-            throw new IllegalArgumentException("Valid status implies other args must be provided");
-        }
-        status = inStatus;
-        resourceId = IpSecManager.INVALID_RESOURCE_ID;
-        interfaceName = "";
-    }
-
-    public IpSecTunnelInterfaceResponse(int inStatus, int inResourceId, String inInterfaceName) {
-        status = inStatus;
-        resourceId = inResourceId;
-        interfaceName = inInterfaceName;
-    }
-
-    private IpSecTunnelInterfaceResponse(Parcel in) {
-        status = in.readInt();
-        resourceId = in.readInt();
-        interfaceName = in.readString();
-    }
-
-    @android.annotation.NonNull
-    public static final Parcelable.Creator<IpSecTunnelInterfaceResponse> CREATOR =
-            new Parcelable.Creator<IpSecTunnelInterfaceResponse>() {
-                public IpSecTunnelInterfaceResponse createFromParcel(Parcel in) {
-                    return new IpSecTunnelInterfaceResponse(in);
-                }
-
-                public IpSecTunnelInterfaceResponse[] newArray(int size) {
-                    return new IpSecTunnelInterfaceResponse[size];
-                }
-            };
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecUdpEncapResponse.aidl b/packages/ConnectivityT/framework-t/src/android/net/IpSecUdpEncapResponse.aidl
deleted file mode 100644
index 5e451f3..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/IpSecUdpEncapResponse.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-/** @hide */
-parcelable IpSecUdpEncapResponse;
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecUdpEncapResponse.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecUdpEncapResponse.java
deleted file mode 100644
index 390af82..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/IpSecUdpEncapResponse.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net;
-
-import android.os.Parcel;
-import android.os.ParcelFileDescriptor;
-import android.os.Parcelable;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-
-/**
- * This class is used to return a UDP Socket and corresponding status from the IpSecService to an
- * IpSecManager.UdpEncapsulationSocket.
- *
- * @hide
- */
-public final class IpSecUdpEncapResponse implements Parcelable {
-    private static final String TAG = "IpSecUdpEncapResponse";
-
-    public final int resourceId;
-    public final int port;
-    public final int status;
-    // There is a weird asymmetry with FileDescriptor: you can write a FileDescriptor
-    // but you read a ParcelFileDescriptor. To circumvent this, when we receive a FD
-    // from the user, we immediately create a ParcelFileDescriptor DUP, which we invalidate
-    // on writeParcel() by setting the flag to do close-on-write.
-    // TODO: tests to ensure this doesn't leak
-    public final ParcelFileDescriptor fileDescriptor;
-
-    // Parcelable Methods
-
-    @Override
-    public int describeContents() {
-        return (fileDescriptor != null) ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeInt(status);
-        out.writeInt(resourceId);
-        out.writeInt(port);
-        out.writeParcelable(fileDescriptor, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-    }
-
-    public IpSecUdpEncapResponse(int inStatus) {
-        if (inStatus == IpSecManager.Status.OK) {
-            throw new IllegalArgumentException("Valid status implies other args must be provided");
-        }
-        status = inStatus;
-        resourceId = IpSecManager.INVALID_RESOURCE_ID;
-        port = -1;
-        fileDescriptor = null; // yes I know it's redundant, but readability
-    }
-
-    public IpSecUdpEncapResponse(int inStatus, int inResourceId, int inPort, FileDescriptor inFd)
-            throws IOException {
-        if (inStatus == IpSecManager.Status.OK && inFd == null) {
-            throw new IllegalArgumentException("Valid status implies FD must be non-null");
-        }
-        status = inStatus;
-        resourceId = inResourceId;
-        port = inPort;
-        fileDescriptor = (status == IpSecManager.Status.OK) ? ParcelFileDescriptor.dup(inFd) : null;
-    }
-
-    private IpSecUdpEncapResponse(Parcel in) {
-        status = in.readInt();
-        resourceId = in.readInt();
-        port = in.readInt();
-        fileDescriptor = in.readParcelable(ParcelFileDescriptor.class.getClassLoader(), android.os.ParcelFileDescriptor.class);
-    }
-
-    @android.annotation.NonNull
-    public static final Parcelable.Creator<IpSecUdpEncapResponse> CREATOR =
-            new Parcelable.Creator<IpSecUdpEncapResponse>() {
-                public IpSecUdpEncapResponse createFromParcel(Parcel in) {
-                    return new IpSecUdpEncapResponse(in);
-                }
-
-                public IpSecUdpEncapResponse[] newArray(int size) {
-                    return new IpSecUdpEncapResponse[size];
-                }
-            };
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java
deleted file mode 100644
index da5f88d..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java
+++ /dev/null
@@ -1,594 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.NetworkTemplate.NETWORK_TYPE_ALL;
-import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.app.usage.NetworkStatsManager;
-import android.content.Context;
-import android.net.wifi.WifiInfo;
-import android.service.NetworkIdentityProto;
-import android.telephony.TelephonyManager;
-import android.util.proto.ProtoOutputStream;
-
-import com.android.net.module.util.CollectionUtils;
-import com.android.net.module.util.NetworkCapabilitiesUtils;
-import com.android.net.module.util.NetworkIdentityUtils;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.Objects;
-
-/**
- * Network definition that includes strong identity. Analogous to combining
- * {@link NetworkCapabilities} and an IMSI.
- *
- * @hide
- */
-@SystemApi(client = MODULE_LIBRARIES)
-public class NetworkIdentity {
-    private static final String TAG = "NetworkIdentity";
-
-    /** @hide */
-    // TODO: Remove this after migrating all callers to use
-    //  {@link NetworkTemplate#NETWORK_TYPE_ALL} instead.
-    public static final int SUBTYPE_COMBINED = -1;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = { "OEM_MANAGED_" }, flag = true, value = {
-            NetworkTemplate.OEM_MANAGED_NO,
-            NetworkTemplate.OEM_MANAGED_PAID,
-            NetworkTemplate.OEM_MANAGED_PRIVATE
-    })
-    public @interface OemManaged{}
-
-    /**
-     * Network has no {@code NetworkCapabilities#NET_CAPABILITY_OEM_*}.
-     * @hide
-     */
-    public static final int OEM_NONE = 0x0;
-    /**
-     * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID}.
-     * @hide
-     */
-    public static final int OEM_PAID = 1 << 0;
-    /**
-     * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PRIVATE}.
-     * @hide
-     */
-    public static final int OEM_PRIVATE = 1 << 1;
-
-    private static final long SUPPORTED_OEM_MANAGED_TYPES = OEM_PAID | OEM_PRIVATE;
-
-    final int mType;
-    final int mRatType;
-    final int mSubId;
-    final String mSubscriberId;
-    final String mWifiNetworkKey;
-    final boolean mRoaming;
-    final boolean mMetered;
-    final boolean mDefaultNetwork;
-    final int mOemManaged;
-
-    /** @hide */
-    public NetworkIdentity(
-            int type, int ratType, @Nullable String subscriberId, @Nullable String wifiNetworkKey,
-            boolean roaming, boolean metered, boolean defaultNetwork, int oemManaged, int subId) {
-        mType = type;
-        mRatType = ratType;
-        mSubscriberId = subscriberId;
-        mWifiNetworkKey = wifiNetworkKey;
-        mRoaming = roaming;
-        mMetered = metered;
-        mDefaultNetwork = defaultNetwork;
-        mOemManaged = oemManaged;
-        mSubId = subId;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mType, mRatType, mSubscriberId, mWifiNetworkKey, mRoaming, mMetered,
-                mDefaultNetwork, mOemManaged, mSubId);
-    }
-
-    @Override
-    public boolean equals(@Nullable Object obj) {
-        if (obj instanceof NetworkIdentity) {
-            final NetworkIdentity ident = (NetworkIdentity) obj;
-            return mType == ident.mType && mRatType == ident.mRatType && mRoaming == ident.mRoaming
-                    && Objects.equals(mSubscriberId, ident.mSubscriberId)
-                    && Objects.equals(mWifiNetworkKey, ident.mWifiNetworkKey)
-                    && mMetered == ident.mMetered
-                    && mDefaultNetwork == ident.mDefaultNetwork
-                    && mOemManaged == ident.mOemManaged
-                    && mSubId == ident.mSubId;
-        }
-        return false;
-    }
-
-    @Override
-    public String toString() {
-        final StringBuilder builder = new StringBuilder("{");
-        builder.append("type=").append(mType);
-        builder.append(", ratType=");
-        if (mRatType == NETWORK_TYPE_ALL) {
-            builder.append("COMBINED");
-        } else {
-            builder.append(mRatType);
-        }
-        if (mSubscriberId != null) {
-            builder.append(", subscriberId=")
-                    .append(NetworkIdentityUtils.scrubSubscriberId(mSubscriberId));
-        }
-        if (mWifiNetworkKey != null) {
-            builder.append(", wifiNetworkKey=").append(mWifiNetworkKey);
-        }
-        if (mRoaming) {
-            builder.append(", ROAMING");
-        }
-        builder.append(", metered=").append(mMetered);
-        builder.append(", defaultNetwork=").append(mDefaultNetwork);
-        builder.append(", oemManaged=").append(getOemManagedNames(mOemManaged));
-        builder.append(", subId=").append(mSubId);
-        return builder.append("}").toString();
-    }
-
-    /**
-     * Get the human readable representation of a bitfield representing the OEM managed state of a
-     * network.
-     */
-    static String getOemManagedNames(int oemManaged) {
-        if (oemManaged == OEM_NONE) {
-            return "OEM_NONE";
-        }
-        final int[] bitPositions = NetworkCapabilitiesUtils.unpackBits(oemManaged);
-        final ArrayList<String> oemManagedNames = new ArrayList<String>();
-        for (int position : bitPositions) {
-            oemManagedNames.add(nameOfOemManaged(1 << position));
-        }
-        return String.join(",", oemManagedNames);
-    }
-
-    private static String nameOfOemManaged(int oemManagedBit) {
-        switch (oemManagedBit) {
-            case OEM_PAID:
-                return "OEM_PAID";
-            case OEM_PRIVATE:
-                return "OEM_PRIVATE";
-            default:
-                return "Invalid(" + oemManagedBit + ")";
-        }
-    }
-
-    /** @hide */
-    public void dumpDebug(ProtoOutputStream proto, long tag) {
-        final long start = proto.start(tag);
-
-        proto.write(NetworkIdentityProto.TYPE, mType);
-
-        // TODO: dump mRatType as well.
-
-        proto.write(NetworkIdentityProto.ROAMING, mRoaming);
-        proto.write(NetworkIdentityProto.METERED, mMetered);
-        proto.write(NetworkIdentityProto.DEFAULT_NETWORK, mDefaultNetwork);
-        proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK, mOemManaged);
-
-        proto.end(start);
-    }
-
-    /** Get the network type of this instance. */
-    public int getType() {
-        return mType;
-    }
-
-    /** Get the Radio Access Technology(RAT) type of this instance. */
-    public int getRatType() {
-        return mRatType;
-    }
-
-    /** Get the Subscriber Id of this instance. */
-    @Nullable
-    public String getSubscriberId() {
-        return mSubscriberId;
-    }
-
-    /** Get the Wifi Network Key of this instance. See {@link WifiInfo#getNetworkKey()}. */
-    @Nullable
-    public String getWifiNetworkKey() {
-        return mWifiNetworkKey;
-    }
-
-    /** @hide */
-    // TODO: Remove this function after all callers are removed.
-    public boolean getRoaming() {
-        return mRoaming;
-    }
-
-    /** Return whether this network is roaming. */
-    public boolean isRoaming() {
-        return mRoaming;
-    }
-
-    /** @hide */
-    // TODO: Remove this function after all callers are removed.
-    public boolean getMetered() {
-        return mMetered;
-    }
-
-    /** Return whether this network is metered. */
-    public boolean isMetered() {
-        return mMetered;
-    }
-
-    /** @hide */
-    // TODO: Remove this function after all callers are removed.
-    public boolean getDefaultNetwork() {
-        return mDefaultNetwork;
-    }
-
-    /** Return whether this network is the default network. */
-    public boolean isDefaultNetwork() {
-        return mDefaultNetwork;
-    }
-
-    /** Get the OEM managed type of this instance. */
-    public int getOemManaged() {
-        return mOemManaged;
-    }
-
-    /** Get the SubId of this instance. */
-    public int getSubId() {
-        return mSubId;
-    }
-
-    /**
-     * Assemble a {@link NetworkIdentity} from the passed arguments.
-     *
-     * This methods builds an identity based on the capabilities of the network in the
-     * snapshot and other passed arguments. The identity is used as a key to record data usage.
-     *
-     * @param snapshot the snapshot of network state. See {@link NetworkStateSnapshot}.
-     * @param defaultNetwork whether the network is a default network.
-     * @param ratType the Radio Access Technology(RAT) type of the network. Or
-     *                {@link TelephonyManager#NETWORK_TYPE_UNKNOWN} if not applicable.
-     *                See {@code TelephonyManager.NETWORK_TYPE_*}.
-     * @hide
-     * @deprecated See {@link NetworkIdentity.Builder}.
-     */
-    // TODO: Remove this after all callers are migrated to use new Api.
-    @Deprecated
-    @NonNull
-    public static NetworkIdentity buildNetworkIdentity(Context context,
-            @NonNull NetworkStateSnapshot snapshot, boolean defaultNetwork, int ratType) {
-        final NetworkIdentity.Builder builder = new NetworkIdentity.Builder()
-                .setNetworkStateSnapshot(snapshot).setDefaultNetwork(defaultNetwork)
-                .setSubId(snapshot.getSubId());
-        if (snapshot.getLegacyType() == TYPE_MOBILE && ratType != NETWORK_TYPE_ALL) {
-            builder.setRatType(ratType);
-        }
-        return builder.build();
-    }
-
-    /**
-     * Builds a bitfield of {@code NetworkIdentity.OEM_*} based on {@link NetworkCapabilities}.
-     * @hide
-     */
-    public static int getOemBitfield(@NonNull NetworkCapabilities nc) {
-        int oemManaged = OEM_NONE;
-
-        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID)) {
-            oemManaged |= OEM_PAID;
-        }
-        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE)) {
-            oemManaged |= OEM_PRIVATE;
-        }
-
-        return oemManaged;
-    }
-
-    /** @hide */
-    public static int compare(@NonNull NetworkIdentity left, @NonNull NetworkIdentity right) {
-        Objects.requireNonNull(right);
-        int res = Integer.compare(left.mType, right.mType);
-        if (res == 0) {
-            res = Integer.compare(left.mRatType, right.mRatType);
-        }
-        if (res == 0 && left.mSubscriberId != null && right.mSubscriberId != null) {
-            res = left.mSubscriberId.compareTo(right.mSubscriberId);
-        }
-        if (res == 0 && left.mWifiNetworkKey != null && right.mWifiNetworkKey != null) {
-            res = left.mWifiNetworkKey.compareTo(right.mWifiNetworkKey);
-        }
-        if (res == 0) {
-            res = Boolean.compare(left.mRoaming, right.mRoaming);
-        }
-        if (res == 0) {
-            res = Boolean.compare(left.mMetered, right.mMetered);
-        }
-        if (res == 0) {
-            res = Boolean.compare(left.mDefaultNetwork, right.mDefaultNetwork);
-        }
-        if (res == 0) {
-            res = Integer.compare(left.mOemManaged, right.mOemManaged);
-        }
-        if (res == 0) {
-            res = Integer.compare(left.mSubId, right.mSubId);
-        }
-        return res;
-    }
-
-    /**
-     * Builder class for {@link NetworkIdentity}.
-     */
-    public static final class Builder {
-        // Need to be synchronized with ConnectivityManager.
-        // TODO: Use {@link ConnectivityManager#MAX_NETWORK_TYPE} when this file is in the module.
-        private static final int MAX_NETWORK_TYPE = 18; // TYPE_TEST
-        private static final int MIN_NETWORK_TYPE = TYPE_MOBILE;
-
-        private int mType;
-        private int mRatType;
-        private String mSubscriberId;
-        private String mWifiNetworkKey;
-        private boolean mRoaming;
-        private boolean mMetered;
-        private boolean mDefaultNetwork;
-        private int mOemManaged;
-        private int mSubId;
-
-        /**
-         * Creates a new Builder.
-         */
-        public Builder() {
-            // Initialize with default values. Will be overwritten by setters.
-            mType = ConnectivityManager.TYPE_NONE;
-            mRatType = NetworkTemplate.NETWORK_TYPE_ALL;
-            mSubscriberId = null;
-            mWifiNetworkKey = null;
-            mRoaming = false;
-            mMetered = false;
-            mDefaultNetwork = false;
-            mOemManaged = NetworkTemplate.OEM_MANAGED_NO;
-            mSubId = INVALID_SUBSCRIPTION_ID;
-        }
-
-        /**
-         * Add an {@link NetworkStateSnapshot} into the {@link NetworkIdentity} instance.
-         * This is a useful shorthand that will read from the snapshot and set the
-         * following fields, if they are set in the snapshot :
-         *  - type
-         *  - subscriberId
-         *  - roaming
-         *  - metered
-         *  - oemManaged
-         *  - wifiNetworkKey
-         *
-         * @param snapshot The target {@link NetworkStateSnapshot} object.
-         * @return The builder object.
-         */
-        @SuppressLint("MissingGetterMatchingBuilder")
-        @NonNull
-        public Builder setNetworkStateSnapshot(@NonNull NetworkStateSnapshot snapshot) {
-            setType(snapshot.getLegacyType());
-
-            setSubscriberId(snapshot.getSubscriberId());
-            setRoaming(!snapshot.getNetworkCapabilities().hasCapability(
-                    NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING));
-            setMetered(!(snapshot.getNetworkCapabilities().hasCapability(
-                    NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
-                    || snapshot.getNetworkCapabilities().hasCapability(
-                    NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)));
-
-            setOemManaged(getOemBitfield(snapshot.getNetworkCapabilities()));
-
-            if (mType == TYPE_WIFI) {
-                final TransportInfo transportInfo = snapshot.getNetworkCapabilities()
-                        .getTransportInfo();
-                if (transportInfo instanceof WifiInfo) {
-                    final WifiInfo info = (WifiInfo) transportInfo;
-                    setWifiNetworkKey(info.getNetworkKey());
-                }
-            }
-            return this;
-        }
-
-        /**
-         * Set the network type of the network.
-         *
-         * @param type the network type. See {@link ConnectivityManager#TYPE_*}.
-         *
-         * @return this builder.
-         */
-        @NonNull
-        public Builder setType(int type) {
-            // Include TYPE_NONE for compatibility, type field might not be filled by some
-            // networks such as test networks.
-            if ((type < MIN_NETWORK_TYPE || MAX_NETWORK_TYPE < type)
-                    && type != ConnectivityManager.TYPE_NONE) {
-                throw new IllegalArgumentException("Invalid network type: " + type);
-            }
-            mType = type;
-            return this;
-        }
-
-        /**
-         * Set the Radio Access Technology(RAT) type of the network.
-         *
-         * No RAT type is specified by default. Call clearRatType to reset.
-         *
-         * @param ratType the Radio Access Technology(RAT) type if applicable. See
-         *                {@code TelephonyManager.NETWORK_TYPE_*}.
-         *
-         * @return this builder.
-         */
-        @NonNull
-        public Builder setRatType(int ratType) {
-            if (!CollectionUtils.contains(TelephonyManager.getAllNetworkTypes(), ratType)
-                    && ratType != TelephonyManager.NETWORK_TYPE_UNKNOWN
-                    && ratType != NetworkStatsManager.NETWORK_TYPE_5G_NSA) {
-                throw new IllegalArgumentException("Invalid ratType " + ratType);
-            }
-            mRatType = ratType;
-            return this;
-        }
-
-        /**
-         * Clear the Radio Access Technology(RAT) type of the network.
-         *
-         * @return this builder.
-         */
-        @NonNull
-        public Builder clearRatType() {
-            mRatType = NetworkTemplate.NETWORK_TYPE_ALL;
-            return this;
-        }
-
-        /**
-         * Set the Subscriber Id.
-         *
-         * @param subscriberId the Subscriber Id of the network. Or null if not applicable.
-         * @return this builder.
-         */
-        @NonNull
-        public Builder setSubscriberId(@Nullable String subscriberId) {
-            mSubscriberId = subscriberId;
-            return this;
-        }
-
-        /**
-         * Set the Wifi Network Key.
-         *
-         * @param wifiNetworkKey Wifi Network Key of the network,
-         *                        see {@link WifiInfo#getNetworkKey()}.
-         *                        Or null if not applicable.
-         * @return this builder.
-         */
-        @NonNull
-        public Builder setWifiNetworkKey(@Nullable String wifiNetworkKey) {
-            mWifiNetworkKey = wifiNetworkKey;
-            return this;
-        }
-
-        /**
-         * Set whether this network is roaming.
-         *
-         * This field is false by default. Call with false to reset.
-         *
-         * @param roaming the roaming status of the network.
-         * @return this builder.
-         */
-        @NonNull
-        public Builder setRoaming(boolean roaming) {
-            mRoaming = roaming;
-            return this;
-        }
-
-        /**
-         * Set whether this network is metered.
-         *
-         * This field is false by default. Call with false to reset.
-         *
-         * @param metered the meteredness of the network.
-         * @return this builder.
-         */
-        @NonNull
-        public Builder setMetered(boolean metered) {
-            mMetered = metered;
-            return this;
-        }
-
-        /**
-         * Set whether this network is the default network.
-         *
-         * This field is false by default. Call with false to reset.
-         *
-         * @param defaultNetwork the default network status of the network.
-         * @return this builder.
-         */
-        @NonNull
-        public Builder setDefaultNetwork(boolean defaultNetwork) {
-            mDefaultNetwork = defaultNetwork;
-            return this;
-        }
-
-        /**
-         * Set the OEM managed type.
-         *
-         * @param oemManaged Type of OEM managed network or unmanaged networks.
-         *                   See {@code NetworkTemplate#OEM_MANAGED_*}.
-         * @return this builder.
-         */
-        @NonNull
-        public Builder setOemManaged(@OemManaged int oemManaged) {
-            // Assert input does not contain illegal oemManage bits.
-            if ((~SUPPORTED_OEM_MANAGED_TYPES & oemManaged) != 0) {
-                throw new IllegalArgumentException("Invalid value for OemManaged : " + oemManaged);
-            }
-            mOemManaged = oemManaged;
-            return this;
-        }
-
-        /**
-         * Set the Subscription Id.
-         *
-         * @param subId the Subscription Id of the network. Or INVALID_SUBSCRIPTION_ID if not
-         *              applicable.
-         * @return this builder.
-         */
-        @NonNull
-        public Builder setSubId(int subId) {
-            mSubId = subId;
-            return this;
-        }
-
-        private void ensureValidParameters() {
-            // Assert non-mobile network cannot have a ratType.
-            if (mType != TYPE_MOBILE && mRatType != NetworkTemplate.NETWORK_TYPE_ALL) {
-                throw new IllegalArgumentException(
-                        "Invalid ratType " + mRatType + " for type " + mType);
-            }
-
-            // Assert non-wifi network cannot have a wifi network key.
-            if (mType != TYPE_WIFI && mWifiNetworkKey != null) {
-                throw new IllegalArgumentException("Invalid wifi network key for type " + mType);
-            }
-        }
-
-        /**
-         * Builds the instance of the {@link NetworkIdentity}.
-         *
-         * @return the built instance of {@link NetworkIdentity}.
-         */
-        @NonNull
-        public NetworkIdentity build() {
-            ensureValidParameters();
-            return new NetworkIdentity(mType, mRatType, mSubscriberId, mWifiNetworkKey,
-                    mRoaming, mMetered, mDefaultNetwork, mOemManaged, mSubId);
-        }
-    }
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java
deleted file mode 100644
index ad3a958..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-
-import android.annotation.NonNull;
-import android.service.NetworkIdentitySetProto;
-import android.util.proto.ProtoOutputStream;
-
-import java.io.DataInput;
-import java.io.DataOutput;
-import java.io.IOException;
-import java.util.HashSet;
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * Identity of a {@code iface}, defined by the set of {@link NetworkIdentity}
- * active on that interface.
- *
- * @hide
- */
-public class NetworkIdentitySet extends HashSet<NetworkIdentity> {
-    private static final int VERSION_INIT = 1;
-    private static final int VERSION_ADD_ROAMING = 2;
-    private static final int VERSION_ADD_NETWORK_ID = 3;
-    private static final int VERSION_ADD_METERED = 4;
-    private static final int VERSION_ADD_DEFAULT_NETWORK = 5;
-    private static final int VERSION_ADD_OEM_MANAGED_NETWORK = 6;
-    private static final int VERSION_ADD_SUB_ID = 7;
-
-    /**
-     * Construct a {@link NetworkIdentitySet} object.
-     */
-    public NetworkIdentitySet() {
-        super();
-    }
-
-    /** @hide */
-    public NetworkIdentitySet(@NonNull Set<NetworkIdentity> ident) {
-        super(ident);
-    }
-
-    /** @hide */
-    public NetworkIdentitySet(DataInput in) throws IOException {
-        final int version = in.readInt();
-        final int size = in.readInt();
-        for (int i = 0; i < size; i++) {
-            if (version <= VERSION_INIT) {
-                final int ignored = in.readInt();
-            }
-            final int type = in.readInt();
-            final int ratType = in.readInt();
-            final String subscriberId = readOptionalString(in);
-            final String networkId;
-            if (version >= VERSION_ADD_NETWORK_ID) {
-                networkId = readOptionalString(in);
-            } else {
-                networkId = null;
-            }
-            final boolean roaming;
-            if (version >= VERSION_ADD_ROAMING) {
-                roaming = in.readBoolean();
-            } else {
-                roaming = false;
-            }
-
-            final boolean metered;
-            if (version >= VERSION_ADD_METERED) {
-                metered = in.readBoolean();
-            } else {
-                // If this is the old data and the type is mobile, treat it as metered. (Note that
-                // if this is a mobile network, TYPE_MOBILE is the only possible type that could be
-                // used.)
-                metered = (type == TYPE_MOBILE);
-            }
-
-            final boolean defaultNetwork;
-            if (version >= VERSION_ADD_DEFAULT_NETWORK) {
-                defaultNetwork = in.readBoolean();
-            } else {
-                defaultNetwork = true;
-            }
-
-            final int oemNetCapabilities;
-            if (version >= VERSION_ADD_OEM_MANAGED_NETWORK) {
-                oemNetCapabilities = in.readInt();
-            } else {
-                oemNetCapabilities = NetworkIdentity.OEM_NONE;
-            }
-
-            final int subId;
-            if (version >= VERSION_ADD_SUB_ID) {
-                subId = in.readInt();
-            } else {
-                subId = INVALID_SUBSCRIPTION_ID;
-            }
-
-            add(new NetworkIdentity(type, ratType, subscriberId, networkId, roaming, metered,
-                    defaultNetwork, oemNetCapabilities, subId));
-        }
-    }
-
-    /**
-     * Method to serialize this object into a {@code DataOutput}.
-     * @hide
-     */
-    public void writeToStream(DataOutput out) throws IOException {
-        out.writeInt(VERSION_ADD_SUB_ID);
-        out.writeInt(size());
-        for (NetworkIdentity ident : this) {
-            out.writeInt(ident.getType());
-            out.writeInt(ident.getRatType());
-            writeOptionalString(out, ident.getSubscriberId());
-            writeOptionalString(out, ident.getWifiNetworkKey());
-            out.writeBoolean(ident.isRoaming());
-            out.writeBoolean(ident.isMetered());
-            out.writeBoolean(ident.isDefaultNetwork());
-            out.writeInt(ident.getOemManaged());
-            out.writeInt(ident.getSubId());
-        }
-    }
-
-    /**
-     * @return whether any {@link NetworkIdentity} in this set is considered metered.
-     * @hide
-     */
-    public boolean isAnyMemberMetered() {
-        if (isEmpty()) {
-            return false;
-        }
-        for (NetworkIdentity ident : this) {
-            if (ident.isMetered()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * @return whether any {@link NetworkIdentity} in this set is considered roaming.
-     * @hide
-     */
-    public boolean isAnyMemberRoaming() {
-        if (isEmpty()) {
-            return false;
-        }
-        for (NetworkIdentity ident : this) {
-            if (ident.isRoaming()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * @return whether any {@link NetworkIdentity} in this set is considered on the default
-     *         network.
-     * @hide
-     */
-    public boolean areAllMembersOnDefaultNetwork() {
-        if (isEmpty()) {
-            return true;
-        }
-        for (NetworkIdentity ident : this) {
-            if (!ident.isDefaultNetwork()) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    private static void writeOptionalString(DataOutput out, String value) throws IOException {
-        if (value != null) {
-            out.writeByte(1);
-            out.writeUTF(value);
-        } else {
-            out.writeByte(0);
-        }
-    }
-
-    private static String readOptionalString(DataInput in) throws IOException {
-        if (in.readByte() != 0) {
-            return in.readUTF();
-        } else {
-            return null;
-        }
-    }
-
-    public static int compare(@NonNull NetworkIdentitySet left, @NonNull NetworkIdentitySet right) {
-        Objects.requireNonNull(left);
-        Objects.requireNonNull(right);
-        if (left.isEmpty()) return -1;
-        if (right.isEmpty()) return 1;
-
-        final NetworkIdentity leftIdent = left.iterator().next();
-        final NetworkIdentity rightIdent = right.iterator().next();
-        return NetworkIdentity.compare(leftIdent, rightIdent);
-    }
-
-    /**
-     * Method to dump this object into proto debug file.
-     * @hide
-     */
-    public void dumpDebug(ProtoOutputStream proto, long tag) {
-        final long start = proto.start(tag);
-
-        for (NetworkIdentity ident : this) {
-            ident.dumpDebug(proto, NetworkIdentitySetProto.IDENTITIES);
-        }
-
-        proto.end(start);
-    }
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.java
deleted file mode 100644
index c018e91..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.net.module.util.NetworkIdentityUtils;
-
-import java.util.Objects;
-
-/**
- * Snapshot of network state.
- *
- * @hide
- */
-@SystemApi(client = MODULE_LIBRARIES)
-public final class NetworkStateSnapshot implements Parcelable {
-    /** The network associated with this snapshot. */
-    @NonNull
-    private final Network mNetwork;
-
-    /** The {@link NetworkCapabilities} of the network associated with this snapshot. */
-    @NonNull
-    private final NetworkCapabilities mNetworkCapabilities;
-
-    /** The {@link LinkProperties} of the network associated with this snapshot. */
-    @NonNull
-    private final LinkProperties mLinkProperties;
-
-    /**
-     * The Subscriber Id of the network associated with this snapshot. See
-     * {@link android.telephony.TelephonyManager#getSubscriberId()}.
-     */
-    @Nullable
-    private final String mSubscriberId;
-
-    /**
-     * The legacy type of the network associated with this snapshot. See
-     * {@code ConnectivityManager#TYPE_*}.
-     */
-    private final int mLegacyType;
-
-    public NetworkStateSnapshot(@NonNull Network network,
-            @NonNull NetworkCapabilities networkCapabilities,
-            @NonNull LinkProperties linkProperties,
-            @Nullable String subscriberId, int legacyType) {
-        mNetwork = Objects.requireNonNull(network);
-        mNetworkCapabilities = Objects.requireNonNull(networkCapabilities);
-        mLinkProperties = Objects.requireNonNull(linkProperties);
-        mSubscriberId = subscriberId;
-        mLegacyType = legacyType;
-    }
-
-    /** @hide */
-    public NetworkStateSnapshot(@NonNull Parcel in) {
-        mNetwork = in.readParcelable(null, android.net.Network.class);
-        mNetworkCapabilities = in.readParcelable(null, android.net.NetworkCapabilities.class);
-        mLinkProperties = in.readParcelable(null, android.net.LinkProperties.class);
-        mSubscriberId = in.readString();
-        mLegacyType = in.readInt();
-    }
-
-    /** Get the network associated with this snapshot */
-    @NonNull
-    public Network getNetwork() {
-        return mNetwork;
-    }
-
-    /** Get {@link NetworkCapabilities} of the network associated with this snapshot. */
-    @NonNull
-    public NetworkCapabilities getNetworkCapabilities() {
-        return mNetworkCapabilities;
-    }
-
-    /** Get the {@link LinkProperties} of the network associated with this snapshot. */
-    @NonNull
-    public LinkProperties getLinkProperties() {
-        return mLinkProperties;
-    }
-
-    /**
-     * Get the Subscriber Id of the network associated with this snapshot.
-     * @deprecated Please use #getSubId, which doesn't return personally identifiable
-     * information.
-     */
-    @Deprecated
-    @Nullable
-    public String getSubscriberId() {
-        return mSubscriberId;
-    }
-
-    /** Get the subId of the network associated with this snapshot. */
-    public int getSubId() {
-        if (mNetworkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
-            final NetworkSpecifier spec = mNetworkCapabilities.getNetworkSpecifier();
-            if (spec instanceof TelephonyNetworkSpecifier) {
-                return ((TelephonyNetworkSpecifier) spec).getSubscriptionId();
-            }
-        }
-        return INVALID_SUBSCRIPTION_ID;
-    }
-
-
-    /**
-     * Get the legacy type of the network associated with this snapshot.
-     * @return the legacy network type. See {@code ConnectivityManager#TYPE_*}.
-     */
-    public int getLegacyType() {
-        return mLegacyType;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel out, int flags) {
-        out.writeParcelable(mNetwork, flags);
-        out.writeParcelable(mNetworkCapabilities, flags);
-        out.writeParcelable(mLinkProperties, flags);
-        out.writeString(mSubscriberId);
-        out.writeInt(mLegacyType);
-    }
-
-    @NonNull
-    public static final Creator<NetworkStateSnapshot> CREATOR =
-            new Creator<NetworkStateSnapshot>() {
-        @NonNull
-        @Override
-        public NetworkStateSnapshot createFromParcel(@NonNull Parcel in) {
-            return new NetworkStateSnapshot(in);
-        }
-
-        @NonNull
-        @Override
-        public NetworkStateSnapshot[] newArray(int size) {
-            return new NetworkStateSnapshot[size];
-        }
-    };
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (!(o instanceof NetworkStateSnapshot)) return false;
-        NetworkStateSnapshot that = (NetworkStateSnapshot) o;
-        return mLegacyType == that.mLegacyType
-                && Objects.equals(mNetwork, that.mNetwork)
-                && Objects.equals(mNetworkCapabilities, that.mNetworkCapabilities)
-                && Objects.equals(mLinkProperties, that.mLinkProperties)
-                && Objects.equals(mSubscriberId, that.mSubscriberId);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mNetwork,
-                mNetworkCapabilities, mLinkProperties, mSubscriberId, mLegacyType);
-    }
-
-    @Override
-    public String toString() {
-        return "NetworkStateSnapshot{"
-                + "network=" + mNetwork
-                + ", networkCapabilities=" + mNetworkCapabilities
-                + ", linkProperties=" + mLinkProperties
-                + ", subscriberId='" + NetworkIdentityUtils.scrubSubscriberId(mSubscriberId) + '\''
-                + ", legacyType=" + mLegacyType
-                + '}';
-    }
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
deleted file mode 100644
index f681ba1..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
+++ /dev/null
@@ -1,1843 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.Process;
-import android.os.SystemClock;
-import android.text.TextUtils;
-import android.util.SparseBooleanArray;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.net.module.util.CollectionUtils;
-
-import libcore.util.EmptyArray;
-
-import java.io.CharArrayWriter;
-import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.function.Predicate;
-
-/**
- * Collection of active network statistics. Can contain summary details across
- * all interfaces, or details with per-UID granularity. Internally stores data
- * as a large table, closely matching {@code /proc/} data format. This structure
- * optimizes for rapid in-memory comparison, but consider using
- * {@link NetworkStatsHistory} when persisting.
- *
- * @hide
- */
-// @NotThreadSafe
-@SystemApi
-public final class NetworkStats implements Parcelable, Iterable<NetworkStats.Entry> {
-    private static final String TAG = "NetworkStats";
-
-    /**
-     * {@link #iface} value when interface details unavailable.
-     * @hide
-     */
-    @Nullable public static final String IFACE_ALL = null;
-
-    /**
-     * Virtual network interface for video telephony. This is for VT data usage counting
-     * purpose.
-     */
-    public static final String IFACE_VT = "vt_data0";
-
-    /** {@link #uid} value when UID details unavailable. */
-    public static final int UID_ALL = -1;
-    /** Special UID value for data usage by tethering. */
-    public static final int UID_TETHERING = -5;
-
-    /**
-     * {@link #tag} value matching any tag.
-     * @hide
-     */
-    // TODO: Rename TAG_ALL to TAG_ANY.
-    public static final int TAG_ALL = -1;
-    /** {@link #set} value for all sets combined, not including debug sets. */
-    public static final int SET_ALL = -1;
-    /** {@link #set} value where background data is accounted. */
-    public static final int SET_DEFAULT = 0;
-    /** {@link #set} value where foreground data is accounted. */
-    public static final int SET_FOREGROUND = 1;
-    /**
-     * All {@link #set} value greater than SET_DEBUG_START are debug {@link #set} values.
-     * @hide
-     */
-    public static final int SET_DEBUG_START = 1000;
-    /**
-     * Debug {@link #set} value when the VPN stats are moved in.
-     * @hide
-     */
-    public static final int SET_DBG_VPN_IN = 1001;
-    /**
-     * Debug {@link #set} value when the VPN stats are moved out of a vpn UID.
-     * @hide
-     */
-    public static final int SET_DBG_VPN_OUT = 1002;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = { "SET_" }, value = {
-            SET_ALL,
-            SET_DEFAULT,
-            SET_FOREGROUND,
-    })
-    public @interface State {
-    }
-
-    /**
-     * Include all interfaces when filtering
-     * @hide
-     */
-    public @Nullable static final String[] INTERFACES_ALL = null;
-
-    /** {@link #tag} value for total data across all tags. */
-    // TODO: Rename TAG_NONE to TAG_ALL.
-    public static final int TAG_NONE = 0;
-
-    /** {@link #metered} value to account for all metered states. */
-    public static final int METERED_ALL = -1;
-    /** {@link #metered} value where native, unmetered data is accounted. */
-    public static final int METERED_NO = 0;
-    /** {@link #metered} value where metered data is accounted. */
-    public static final int METERED_YES = 1;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = { "METERED_" }, value = {
-            METERED_ALL,
-            METERED_NO,
-            METERED_YES
-    })
-    public @interface Meteredness {
-    }
-
-
-    /** {@link #roaming} value to account for all roaming states. */
-    public static final int ROAMING_ALL = -1;
-    /** {@link #roaming} value where native, non-roaming data is accounted. */
-    public static final int ROAMING_NO = 0;
-    /** {@link #roaming} value where roaming data is accounted. */
-    public static final int ROAMING_YES = 1;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = { "ROAMING_" }, value = {
-            ROAMING_ALL,
-            ROAMING_NO,
-            ROAMING_YES
-    })
-    public @interface Roaming {
-    }
-
-    /** {@link #onDefaultNetwork} value to account for all default network states. */
-    public static final int DEFAULT_NETWORK_ALL = -1;
-    /** {@link #onDefaultNetwork} value to account for usage while not the default network. */
-    public static final int DEFAULT_NETWORK_NO = 0;
-    /** {@link #onDefaultNetwork} value to account for usage while the default network. */
-    public static final int DEFAULT_NETWORK_YES = 1;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = { "DEFAULT_NETWORK_" }, value = {
-            DEFAULT_NETWORK_ALL,
-            DEFAULT_NETWORK_NO,
-            DEFAULT_NETWORK_YES
-    })
-    public @interface DefaultNetwork {
-    }
-
-    /**
-     * Denotes a request for stats at the interface level.
-     * @hide
-     */
-    public static final int STATS_PER_IFACE = 0;
-    /**
-     * Denotes a request for stats at the interface and UID level.
-     * @hide
-     */
-    public static final int STATS_PER_UID = 1;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = { "STATS_PER_" }, value = {
-            STATS_PER_IFACE,
-            STATS_PER_UID
-    })
-    public @interface StatsType {
-    }
-
-    private static final String CLATD_INTERFACE_PREFIX = "v4-";
-    // Delta between IPv4 header (20b) and IPv6 header (40b).
-    // Used for correct stats accounting on clatd interfaces.
-    private static final int IPV4V6_HEADER_DELTA = 20;
-
-    // TODO: move fields to "mVariable" notation
-
-    /**
-     * {@link SystemClock#elapsedRealtime()} timestamp in milliseconds when this data was
-     * generated.
-     * It's a timestamps delta when {@link #subtract()},
-     * {@code INetworkStatsSession#getSummaryForAllUid()} methods are used.
-     */
-    private long elapsedRealtime;
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    private int size;
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    private int capacity;
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    private String[] iface;
-    @UnsupportedAppUsage
-    private int[] uid;
-    @UnsupportedAppUsage
-    private int[] set;
-    @UnsupportedAppUsage
-    private int[] tag;
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    private int[] metered;
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    private int[] roaming;
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    private int[] defaultNetwork;
-    @UnsupportedAppUsage
-    private long[] rxBytes;
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    private long[] rxPackets;
-    @UnsupportedAppUsage
-    private long[] txBytes;
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    private long[] txPackets;
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    private long[] operations;
-
-    /**
-     * Basic element of network statistics. Contains the number of packets and number of bytes
-     * transferred on both directions in a given set of conditions. See
-     * {@link Entry#Entry(String, int, int, int, int, int, int, long, long, long, long, long)}.
-     *
-     * @hide
-     */
-    @SystemApi
-    public static class Entry {
-        /** @hide */
-        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-        public String iface;
-        /** @hide */
-        @UnsupportedAppUsage
-        public int uid;
-        /** @hide */
-        @UnsupportedAppUsage
-        public int set;
-        /** @hide */
-        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-        public int tag;
-        /**
-         * Note that this is only populated w/ the default value when read from /proc or written
-         * to disk. We merge in the correct value when reporting this value to clients of
-         * getSummary().
-         * @hide
-         */
-        public int metered;
-        /**
-         * Note that this is only populated w/ the default value when read from /proc or written
-         * to disk. We merge in the correct value when reporting this value to clients of
-         * getSummary().
-         * @hide
-         */
-        public int roaming;
-        /**
-         * Note that this is only populated w/ the default value when read from /proc or written
-         * to disk. We merge in the correct value when reporting this value to clients of
-         * getSummary().
-         * @hide
-         */
-        public int defaultNetwork;
-        /** @hide */
-        @UnsupportedAppUsage
-        public long rxBytes;
-        /** @hide */
-        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-        public long rxPackets;
-        /** @hide */
-        @UnsupportedAppUsage
-        public long txBytes;
-        /** @hide */
-        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-        public long txPackets;
-        /** @hide */
-        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-        public long operations;
-
-        /** @hide */
-        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-        public Entry() {
-            this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
-        }
-
-        /** @hide */
-        public Entry(long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
-            this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets,
-                    operations);
-        }
-
-        /** @hide */
-        public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets,
-                long txBytes, long txPackets, long operations) {
-            this(iface, uid, set, tag, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO,
-                    rxBytes, rxPackets, txBytes, txPackets, operations);
-        }
-
-        /**
-         * Construct a {@link Entry} object by giving statistics of packet and byte transferred on
-         * both direction, and associated with a set of given conditions.
-         *
-         * @param iface interface name of this {@link Entry}. Or null if not specified.
-         * @param uid uid of this {@link Entry}. {@link #UID_TETHERING} if this {@link Entry} is
-         *            for tethering. Or {@link #UID_ALL} if this {@link NetworkStats} is only
-         *            counting iface stats.
-         * @param set usage state of this {@link Entry}. Should be one of the following
-         *            values: {@link #SET_DEFAULT}, {@link #SET_FOREGROUND}.
-         * @param tag tag of this {@link Entry}.
-         * @param metered metered state of this {@link Entry}. Should be one of the following
-         *                values: {link #METERED_YES}, {link #METERED_NO}.
-         * @param roaming roaming state of this {@link Entry}. Should be one of the following
-         *                values: {link #ROAMING_YES}, {link #ROAMING_NO}.
-         * @param defaultNetwork default network status of this {@link Entry}. Should be one
-         *                       of the following values: {link #DEFAULT_NETWORK_YES},
-         *                       {link #DEFAULT_NETWORK_NO}.
-         * @param rxBytes Number of bytes received for this {@link Entry}. Statistics should
-         *                represent the contents of IP packets, including IP headers.
-         * @param rxPackets Number of packets received for this {@link Entry}. Statistics should
-         *                  represent the contents of IP packets, including IP headers.
-         * @param txBytes Number of bytes transmitted for this {@link Entry}. Statistics should
-         *                represent the contents of IP packets, including IP headers.
-         * @param txPackets Number of bytes transmitted for this {@link Entry}. Statistics should
-         *                  represent the contents of IP packets, including IP headers.
-         * @param operations count of network operations performed for this {@link Entry}. This can
-         *                   be used to derive bytes-per-operation.
-         */
-        public Entry(@Nullable String iface, int uid, @State int set, int tag,
-                @Meteredness int metered, @Roaming int roaming, @DefaultNetwork int defaultNetwork,
-                long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
-            this.iface = iface;
-            this.uid = uid;
-            this.set = set;
-            this.tag = tag;
-            this.metered = metered;
-            this.roaming = roaming;
-            this.defaultNetwork = defaultNetwork;
-            this.rxBytes = rxBytes;
-            this.rxPackets = rxPackets;
-            this.txBytes = txBytes;
-            this.txPackets = txPackets;
-            this.operations = operations;
-        }
-
-        /** @hide */
-        public boolean isNegative() {
-            return rxBytes < 0 || rxPackets < 0 || txBytes < 0 || txPackets < 0 || operations < 0;
-        }
-
-        /** @hide */
-        public boolean isEmpty() {
-            return rxBytes == 0 && rxPackets == 0 && txBytes == 0 && txPackets == 0
-                    && operations == 0;
-        }
-
-        /** @hide */
-        public void add(Entry another) {
-            this.rxBytes += another.rxBytes;
-            this.rxPackets += another.rxPackets;
-            this.txBytes += another.txBytes;
-            this.txPackets += another.txPackets;
-            this.operations += another.operations;
-        }
-
-        /**
-         * @return interface name of this entry.
-         * @hide
-         */
-        @Nullable public String getIface() {
-            return iface;
-        }
-
-        /**
-         * @return the uid of this entry.
-         */
-        public int getUid() {
-            return uid;
-        }
-
-        /**
-         * @return the set state of this entry. Should be one of the following
-         * values: {@link #SET_DEFAULT}, {@link #SET_FOREGROUND}.
-         */
-        @State public int getSet() {
-            return set;
-        }
-
-        /**
-         * @return the tag value of this entry.
-         */
-        public int getTag() {
-            return tag;
-        }
-
-        /**
-         * @return the metered state. Should be one of the following
-         * values: {link #METERED_YES}, {link #METERED_NO}.
-         */
-        @Meteredness public int getMetered() {
-            return metered;
-        }
-
-        /**
-         * @return the roaming state. Should be one of the following
-         * values: {link #ROAMING_YES}, {link #ROAMING_NO}.
-         */
-        @Roaming public int getRoaming() {
-            return roaming;
-        }
-
-        /**
-         * @return the default network state. Should be one of the following
-         * values: {link #DEFAULT_NETWORK_YES}, {link #DEFAULT_NETWORK_NO}.
-         */
-        @DefaultNetwork public int getDefaultNetwork() {
-            return defaultNetwork;
-        }
-
-        /**
-         * @return the number of received bytes.
-         */
-        public long getRxBytes() {
-            return rxBytes;
-        }
-
-        /**
-         * @return the number of received packets.
-         */
-        public long getRxPackets() {
-            return rxPackets;
-        }
-
-        /**
-         * @return the number of transmitted bytes.
-         */
-        public long getTxBytes() {
-            return txBytes;
-        }
-
-        /**
-         * @return the number of transmitted packets.
-         */
-        public long getTxPackets() {
-            return txPackets;
-        }
-
-        /**
-         * @return the count of network operations performed for this entry.
-         */
-        public long getOperations() {
-            return operations;
-        }
-
-        @Override
-        public String toString() {
-            final StringBuilder builder = new StringBuilder();
-            builder.append("iface=").append(iface);
-            builder.append(" uid=").append(uid);
-            builder.append(" set=").append(setToString(set));
-            builder.append(" tag=").append(tagToString(tag));
-            builder.append(" metered=").append(meteredToString(metered));
-            builder.append(" roaming=").append(roamingToString(roaming));
-            builder.append(" defaultNetwork=").append(defaultNetworkToString(defaultNetwork));
-            builder.append(" rxBytes=").append(rxBytes);
-            builder.append(" rxPackets=").append(rxPackets);
-            builder.append(" txBytes=").append(txBytes);
-            builder.append(" txPackets=").append(txPackets);
-            builder.append(" operations=").append(operations);
-            return builder.toString();
-        }
-
-        /** @hide */
-        @Override
-        public boolean equals(@Nullable Object o) {
-            if (o instanceof Entry) {
-                final Entry e = (Entry) o;
-                return uid == e.uid && set == e.set && tag == e.tag && metered == e.metered
-                        && roaming == e.roaming && defaultNetwork == e.defaultNetwork
-                        && rxBytes == e.rxBytes && rxPackets == e.rxPackets
-                        && txBytes == e.txBytes && txPackets == e.txPackets
-                        && operations == e.operations && TextUtils.equals(iface, e.iface);
-            }
-            return false;
-        }
-
-        /** @hide */
-        @Override
-        public int hashCode() {
-            return Objects.hash(uid, set, tag, metered, roaming, defaultNetwork, iface);
-        }
-    }
-
-    public NetworkStats(long elapsedRealtime, int initialSize) {
-        this.elapsedRealtime = elapsedRealtime;
-        this.size = 0;
-        if (initialSize > 0) {
-            this.capacity = initialSize;
-            this.iface = new String[initialSize];
-            this.uid = new int[initialSize];
-            this.set = new int[initialSize];
-            this.tag = new int[initialSize];
-            this.metered = new int[initialSize];
-            this.roaming = new int[initialSize];
-            this.defaultNetwork = new int[initialSize];
-            this.rxBytes = new long[initialSize];
-            this.rxPackets = new long[initialSize];
-            this.txBytes = new long[initialSize];
-            this.txPackets = new long[initialSize];
-            this.operations = new long[initialSize];
-        } else {
-            // Special case for use by NetworkStatsFactory to start out *really* empty.
-            clear();
-        }
-    }
-
-    /** @hide */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public NetworkStats(Parcel parcel) {
-        elapsedRealtime = parcel.readLong();
-        size = parcel.readInt();
-        capacity = parcel.readInt();
-        iface = parcel.createStringArray();
-        uid = parcel.createIntArray();
-        set = parcel.createIntArray();
-        tag = parcel.createIntArray();
-        metered = parcel.createIntArray();
-        roaming = parcel.createIntArray();
-        defaultNetwork = parcel.createIntArray();
-        rxBytes = parcel.createLongArray();
-        rxPackets = parcel.createLongArray();
-        txBytes = parcel.createLongArray();
-        txPackets = parcel.createLongArray();
-        operations = parcel.createLongArray();
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeLong(elapsedRealtime);
-        dest.writeInt(size);
-        dest.writeInt(capacity);
-        dest.writeStringArray(iface);
-        dest.writeIntArray(uid);
-        dest.writeIntArray(set);
-        dest.writeIntArray(tag);
-        dest.writeIntArray(metered);
-        dest.writeIntArray(roaming);
-        dest.writeIntArray(defaultNetwork);
-        dest.writeLongArray(rxBytes);
-        dest.writeLongArray(rxPackets);
-        dest.writeLongArray(txBytes);
-        dest.writeLongArray(txPackets);
-        dest.writeLongArray(operations);
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public NetworkStats clone() {
-        final NetworkStats clone = new NetworkStats(elapsedRealtime, size);
-        NetworkStats.Entry entry = null;
-        for (int i = 0; i < size; i++) {
-            entry = getValues(i, entry);
-            clone.insertEntry(entry);
-        }
-        return clone;
-    }
-
-    /**
-     * Clear all data stored in this object.
-     * @hide
-     */
-    public void clear() {
-        this.capacity = 0;
-        this.iface = EmptyArray.STRING;
-        this.uid = EmptyArray.INT;
-        this.set = EmptyArray.INT;
-        this.tag = EmptyArray.INT;
-        this.metered = EmptyArray.INT;
-        this.roaming = EmptyArray.INT;
-        this.defaultNetwork = EmptyArray.INT;
-        this.rxBytes = EmptyArray.LONG;
-        this.rxPackets = EmptyArray.LONG;
-        this.txBytes = EmptyArray.LONG;
-        this.txPackets = EmptyArray.LONG;
-        this.operations = EmptyArray.LONG;
-    }
-
-    /** @hide */
-    @VisibleForTesting
-    public NetworkStats insertEntry(
-            String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) {
-        return insertEntry(
-                iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L);
-    }
-
-    /** @hide */
-    @VisibleForTesting
-    public NetworkStats insertEntry(String iface, int uid, int set, int tag, long rxBytes,
-            long rxPackets, long txBytes, long txPackets, long operations) {
-        return insertEntry(new Entry(
-                iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
-    }
-
-    /** @hide */
-    @VisibleForTesting
-    public NetworkStats insertEntry(String iface, int uid, int set, int tag, int metered,
-            int roaming, int defaultNetwork, long rxBytes, long rxPackets, long txBytes,
-            long txPackets, long operations) {
-        return insertEntry(new Entry(
-                iface, uid, set, tag, metered, roaming, defaultNetwork, rxBytes, rxPackets,
-                txBytes, txPackets, operations));
-    }
-
-    /**
-     * Add new stats entry, copying from given {@link Entry}. The {@link Entry}
-     * object can be recycled across multiple calls.
-     * @hide
-     */
-    public NetworkStats insertEntry(Entry entry) {
-        if (size >= capacity) {
-            final int newLength = Math.max(size, 10) * 3 / 2;
-            iface = Arrays.copyOf(iface, newLength);
-            uid = Arrays.copyOf(uid, newLength);
-            set = Arrays.copyOf(set, newLength);
-            tag = Arrays.copyOf(tag, newLength);
-            metered = Arrays.copyOf(metered, newLength);
-            roaming = Arrays.copyOf(roaming, newLength);
-            defaultNetwork = Arrays.copyOf(defaultNetwork, newLength);
-            rxBytes = Arrays.copyOf(rxBytes, newLength);
-            rxPackets = Arrays.copyOf(rxPackets, newLength);
-            txBytes = Arrays.copyOf(txBytes, newLength);
-            txPackets = Arrays.copyOf(txPackets, newLength);
-            operations = Arrays.copyOf(operations, newLength);
-            capacity = newLength;
-        }
-
-        setValues(size, entry);
-        size++;
-
-        return this;
-    }
-
-    private void setValues(int i, Entry entry) {
-        iface[i] = entry.iface;
-        uid[i] = entry.uid;
-        set[i] = entry.set;
-        tag[i] = entry.tag;
-        metered[i] = entry.metered;
-        roaming[i] = entry.roaming;
-        defaultNetwork[i] = entry.defaultNetwork;
-        rxBytes[i] = entry.rxBytes;
-        rxPackets[i] = entry.rxPackets;
-        txBytes[i] = entry.txBytes;
-        txPackets[i] = entry.txPackets;
-        operations[i] = entry.operations;
-    }
-
-    /**
-     * Iterate over Entry objects.
-     *
-     * Return an iterator of this object that will iterate through all contained Entry objects.
-     *
-     * This iterator does not support concurrent modification and makes no guarantee of fail-fast
-     * behavior. If any method that can mutate the contents of this object is called while
-     * iteration is in progress, either inside the loop or in another thread, then behavior is
-     * undefined.
-     * The remove() method is not implemented and will throw UnsupportedOperationException.
-     * @hide
-     */
-    @SystemApi
-    @NonNull public Iterator<Entry> iterator() {
-        return new Iterator<Entry>() {
-            int mIndex = 0;
-
-            @Override
-            public boolean hasNext() {
-                return mIndex < size;
-            }
-
-            @Override
-            public Entry next() {
-                return getValues(mIndex++, null);
-            }
-        };
-    }
-
-    /**
-     * Return specific stats entry.
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public Entry getValues(int i, @Nullable Entry recycle) {
-        final Entry entry = recycle != null ? recycle : new Entry();
-        entry.iface = iface[i];
-        entry.uid = uid[i];
-        entry.set = set[i];
-        entry.tag = tag[i];
-        entry.metered = metered[i];
-        entry.roaming = roaming[i];
-        entry.defaultNetwork = defaultNetwork[i];
-        entry.rxBytes = rxBytes[i];
-        entry.rxPackets = rxPackets[i];
-        entry.txBytes = txBytes[i];
-        entry.txPackets = txPackets[i];
-        entry.operations = operations[i];
-        return entry;
-    }
-
-    /**
-     * If @{code dest} is not equal to @{code src}, copy entry from index @{code src} to index
-     * @{code dest}.
-     */
-    private void maybeCopyEntry(int dest, int src) {
-        if (dest == src) return;
-        iface[dest] = iface[src];
-        uid[dest] = uid[src];
-        set[dest] = set[src];
-        tag[dest] = tag[src];
-        metered[dest] = metered[src];
-        roaming[dest] = roaming[src];
-        defaultNetwork[dest] = defaultNetwork[src];
-        rxBytes[dest] = rxBytes[src];
-        rxPackets[dest] = rxPackets[src];
-        txBytes[dest] = txBytes[src];
-        txPackets[dest] = txPackets[src];
-        operations[dest] = operations[src];
-    }
-
-    /** @hide */
-    public long getElapsedRealtime() {
-        return elapsedRealtime;
-    }
-
-    /** @hide */
-    public void setElapsedRealtime(long time) {
-        elapsedRealtime = time;
-    }
-
-    /**
-     * Return age of this {@link NetworkStats} object with respect to
-     * {@link SystemClock#elapsedRealtime()}.
-     * @hide
-     */
-    public long getElapsedRealtimeAge() {
-        return SystemClock.elapsedRealtime() - elapsedRealtime;
-    }
-
-    /** @hide */
-    @UnsupportedAppUsage
-    public int size() {
-        return size;
-    }
-
-    /** @hide */
-    @VisibleForTesting
-    public int internalSize() {
-        return capacity;
-    }
-
-    /** @hide */
-    @Deprecated
-    public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
-            long txBytes, long txPackets, long operations) {
-        return combineValues(
-                iface, uid, SET_DEFAULT, tag, rxBytes, rxPackets, txBytes,
-                txPackets, operations);
-    }
-
-    /** @hide */
-    public NetworkStats combineValues(String iface, int uid, int set, int tag,
-            long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
-        return combineValues(new Entry(
-                iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
-    }
-
-    /**
-     * Combine given values with an existing row, or create a new row if
-     * {@link #findIndex(String, int, int, int, int, int, int)} is unable to find match. Can
-     * also be used to subtract values from existing rows. This method mutates the referencing
-     * {@link NetworkStats} object.
-     *
-     * @param entry the {@link Entry} to combine.
-     * @return a reference to this mutated {@link NetworkStats} object.
-     * @hide
-     */
-    public @NonNull NetworkStats combineValues(@NonNull Entry entry) {
-        final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.metered,
-                entry.roaming, entry.defaultNetwork);
-        if (i == -1) {
-            // only create new entry when positive contribution
-            insertEntry(entry);
-        } else {
-            rxBytes[i] += entry.rxBytes;
-            rxPackets[i] += entry.rxPackets;
-            txBytes[i] += entry.txBytes;
-            txPackets[i] += entry.txPackets;
-            operations[i] += entry.operations;
-        }
-        return this;
-    }
-
-    /**
-     * Add given values with an existing row, or create a new row if
-     * {@link #findIndex(String, int, int, int, int, int, int)} is unable to find match. Can
-     * also be used to subtract values from existing rows.
-     *
-     * @param entry the {@link Entry} to add.
-     * @return a new constructed {@link NetworkStats} object that contains the result.
-     */
-    public @NonNull NetworkStats addEntry(@NonNull Entry entry) {
-        return this.clone().combineValues(entry);
-    }
-
-    /**
-     * Add the given {@link NetworkStats} objects.
-     *
-     * @return the sum of two objects.
-     */
-    public @NonNull NetworkStats add(@NonNull NetworkStats another) {
-        final NetworkStats ret = this.clone();
-        ret.combineAllValues(another);
-        return ret;
-    }
-
-    /**
-     * Combine all values from another {@link NetworkStats} into this object.
-     * @hide
-     */
-    public void combineAllValues(@NonNull NetworkStats another) {
-        NetworkStats.Entry entry = null;
-        for (int i = 0; i < another.size; i++) {
-            entry = another.getValues(i, entry);
-            combineValues(entry);
-        }
-    }
-
-    /**
-     * Find first stats index that matches the requested parameters.
-     * @hide
-     */
-    public int findIndex(String iface, int uid, int set, int tag, int metered, int roaming,
-            int defaultNetwork) {
-        for (int i = 0; i < size; i++) {
-            if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i]
-                    && metered == this.metered[i] && roaming == this.roaming[i]
-                    && defaultNetwork == this.defaultNetwork[i]
-                    && Objects.equals(iface, this.iface[i])) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    /**
-     * Find first stats index that matches the requested parameters, starting
-     * search around the hinted index as an optimization.
-     * @hide
-     */
-    @VisibleForTesting
-    public int findIndexHinted(String iface, int uid, int set, int tag, int metered, int roaming,
-            int defaultNetwork, int hintIndex) {
-        for (int offset = 0; offset < size; offset++) {
-            final int halfOffset = offset / 2;
-
-            // search outwards from hint index, alternating forward and backward
-            final int i;
-            if (offset % 2 == 0) {
-                i = (hintIndex + halfOffset) % size;
-            } else {
-                i = (size + hintIndex - halfOffset - 1) % size;
-            }
-
-            if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i]
-                    && metered == this.metered[i] && roaming == this.roaming[i]
-                    && defaultNetwork == this.defaultNetwork[i]
-                    && Objects.equals(iface, this.iface[i])) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    /**
-     * Splice in {@link #operations} from the given {@link NetworkStats} based
-     * on matching {@link #uid} and {@link #tag} rows. Ignores {@link #iface},
-     * since operation counts are at data layer.
-     * @hide
-     */
-    public void spliceOperationsFrom(NetworkStats stats) {
-        for (int i = 0; i < size; i++) {
-            final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], metered[i], roaming[i],
-                    defaultNetwork[i]);
-            if (j == -1) {
-                operations[i] = 0;
-            } else {
-                operations[i] = stats.operations[j];
-            }
-        }
-    }
-
-    /**
-     * Return list of unique interfaces known by this data structure.
-     * @hide
-     */
-    public String[] getUniqueIfaces() {
-        final HashSet<String> ifaces = new HashSet<String>();
-        for (String iface : this.iface) {
-            if (iface != IFACE_ALL) {
-                ifaces.add(iface);
-            }
-        }
-        return ifaces.toArray(new String[ifaces.size()]);
-    }
-
-    /**
-     * Return list of unique UIDs known by this data structure.
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public int[] getUniqueUids() {
-        final SparseBooleanArray uids = new SparseBooleanArray();
-        for (int uid : this.uid) {
-            uids.put(uid, true);
-        }
-
-        final int size = uids.size();
-        final int[] result = new int[size];
-        for (int i = 0; i < size; i++) {
-            result[i] = uids.keyAt(i);
-        }
-        return result;
-    }
-
-    /**
-     * Return total bytes represented by this snapshot object, usually used when
-     * checking if a {@link #subtract(NetworkStats)} delta passes a threshold.
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public long getTotalBytes() {
-        final Entry entry = getTotal(null);
-        return entry.rxBytes + entry.txBytes;
-    }
-
-    /**
-     * Return total of all fields represented by this snapshot object.
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public Entry getTotal(Entry recycle) {
-        return getTotal(recycle, null, UID_ALL, false);
-    }
-
-    /**
-     * Return total of all fields represented by this snapshot object matching
-     * the requested {@link #uid}.
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public Entry getTotal(Entry recycle, int limitUid) {
-        return getTotal(recycle, null, limitUid, false);
-    }
-
-    /**
-     * Return total of all fields represented by this snapshot object matching
-     * the requested {@link #iface}.
-     * @hide
-     */
-    public Entry getTotal(Entry recycle, HashSet<String> limitIface) {
-        return getTotal(recycle, limitIface, UID_ALL, false);
-    }
-
-    /** @hide */
-    @UnsupportedAppUsage
-    public Entry getTotalIncludingTags(Entry recycle) {
-        return getTotal(recycle, null, UID_ALL, true);
-    }
-
-    /**
-     * Return total of all fields represented by this snapshot object matching
-     * the requested {@link #iface} and {@link #uid}.
-     *
-     * @param limitIface Set of {@link #iface} to include in total; or {@code
-     *            null} to include all ifaces.
-     */
-    private Entry getTotal(
-            Entry recycle, HashSet<String> limitIface, int limitUid, boolean includeTags) {
-        final Entry entry = recycle != null ? recycle : new Entry();
-
-        entry.iface = IFACE_ALL;
-        entry.uid = limitUid;
-        entry.set = SET_ALL;
-        entry.tag = TAG_NONE;
-        entry.metered = METERED_ALL;
-        entry.roaming = ROAMING_ALL;
-        entry.defaultNetwork = DEFAULT_NETWORK_ALL;
-        entry.rxBytes = 0;
-        entry.rxPackets = 0;
-        entry.txBytes = 0;
-        entry.txPackets = 0;
-        entry.operations = 0;
-
-        for (int i = 0; i < size; i++) {
-            final boolean matchesUid = (limitUid == UID_ALL) || (limitUid == uid[i]);
-            final boolean matchesIface = (limitIface == null) || (limitIface.contains(iface[i]));
-
-            if (matchesUid && matchesIface) {
-                // skip specific tags, since already counted in TAG_NONE
-                if (tag[i] != TAG_NONE && !includeTags) continue;
-
-                entry.rxBytes += rxBytes[i];
-                entry.rxPackets += rxPackets[i];
-                entry.txBytes += txBytes[i];
-                entry.txPackets += txPackets[i];
-                entry.operations += operations[i];
-            }
-        }
-        return entry;
-    }
-
-    /**
-     * Fast path for battery stats.
-     * @hide
-     */
-    public long getTotalPackets() {
-        long total = 0;
-        for (int i = size-1; i >= 0; i--) {
-            total += rxPackets[i] + txPackets[i];
-        }
-        return total;
-    }
-
-    /**
-     * Subtract the given {@link NetworkStats}, effectively leaving the delta
-     * between two snapshots in time. Assumes that statistics rows collect over
-     * time, and that none of them have disappeared. This method does not mutate
-     * the referencing object.
-     *
-     * @return the delta between two objects.
-     */
-    public @NonNull NetworkStats subtract(@NonNull NetworkStats right) {
-        return subtract(this, right, null, null);
-    }
-
-    /**
-     * Subtract the two given {@link NetworkStats} objects, returning the delta
-     * between two snapshots in time. Assumes that statistics rows collect over
-     * time, and that none of them have disappeared.
-     * <p>
-     * If counters have rolled backwards, they are clamped to {@code 0} and
-     * reported to the given {@link NonMonotonicObserver}.
-     * @hide
-     */
-    public static <C> NetworkStats subtract(NetworkStats left, NetworkStats right,
-            NonMonotonicObserver<C> observer, C cookie) {
-        return subtract(left, right, observer, cookie, null);
-    }
-
-    /**
-     * Subtract the two given {@link NetworkStats} objects, returning the delta
-     * between two snapshots in time. Assumes that statistics rows collect over
-     * time, and that none of them have disappeared.
-     * <p>
-     * If counters have rolled backwards, they are clamped to {@code 0} and
-     * reported to the given {@link NonMonotonicObserver}.
-     * <p>
-     * If <var>recycle</var> is supplied, this NetworkStats object will be
-     * reused (and returned) as the result if it is large enough to contain
-     * the data.
-     * @hide
-     */
-    public static <C> NetworkStats subtract(NetworkStats left, NetworkStats right,
-            NonMonotonicObserver<C> observer, C cookie, NetworkStats recycle) {
-        long deltaRealtime = left.elapsedRealtime - right.elapsedRealtime;
-        if (deltaRealtime < 0) {
-            if (observer != null) {
-                observer.foundNonMonotonic(left, -1, right, -1, cookie);
-            }
-            deltaRealtime = 0;
-        }
-
-        // result will have our rows, and elapsed time between snapshots
-        final Entry entry = new Entry();
-        final NetworkStats result;
-        if (recycle != null && recycle.capacity >= left.size) {
-            result = recycle;
-            result.size = 0;
-            result.elapsedRealtime = deltaRealtime;
-        } else {
-            result = new NetworkStats(deltaRealtime, left.size);
-        }
-        for (int i = 0; i < left.size; i++) {
-            entry.iface = left.iface[i];
-            entry.uid = left.uid[i];
-            entry.set = left.set[i];
-            entry.tag = left.tag[i];
-            entry.metered = left.metered[i];
-            entry.roaming = left.roaming[i];
-            entry.defaultNetwork = left.defaultNetwork[i];
-            entry.rxBytes = left.rxBytes[i];
-            entry.rxPackets = left.rxPackets[i];
-            entry.txBytes = left.txBytes[i];
-            entry.txPackets = left.txPackets[i];
-            entry.operations = left.operations[i];
-
-            // find remote row that matches, and subtract
-            final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag,
-                    entry.metered, entry.roaming, entry.defaultNetwork, i);
-            if (j != -1) {
-                // Found matching row, subtract remote value.
-                entry.rxBytes -= right.rxBytes[j];
-                entry.rxPackets -= right.rxPackets[j];
-                entry.txBytes -= right.txBytes[j];
-                entry.txPackets -= right.txPackets[j];
-                entry.operations -= right.operations[j];
-            }
-
-            if (entry.isNegative()) {
-                if (observer != null) {
-                    observer.foundNonMonotonic(left, i, right, j, cookie);
-                }
-                entry.rxBytes = Math.max(entry.rxBytes, 0);
-                entry.rxPackets = Math.max(entry.rxPackets, 0);
-                entry.txBytes = Math.max(entry.txBytes, 0);
-                entry.txPackets = Math.max(entry.txPackets, 0);
-                entry.operations = Math.max(entry.operations, 0);
-            }
-
-            result.insertEntry(entry);
-        }
-
-        return result;
-    }
-
-    /**
-     * Calculate and apply adjustments to captured statistics for 464xlat traffic.
-     *
-     * <p>This mutates stacked traffic stats, to account for IPv4/IPv6 header size difference.
-     *
-     * <p>UID stats, which are only accounted on the stacked interface, need to be increased
-     * by 20 bytes/packet to account for translation overhead.
-     *
-     * <p>The potential additional overhead of 8 bytes/packet for ip fragments is ignored.
-     *
-     * <p>Interface stats need to sum traffic on both stacked and base interface because:
-     *   - eBPF offloaded packets appear only on the stacked interface
-     *   - Non-offloaded ingress packets appear only on the stacked interface
-     *     (due to iptables raw PREROUTING drop rules)
-     *   - Non-offloaded egress packets appear only on the stacked interface
-     *     (due to ignoring traffic from clat daemon by uid match)
-     * (and of course the 20 bytes/packet overhead needs to be applied to stacked interface stats)
-     *
-     * <p>This method will behave fine if {@code stackedIfaces} is an non-synchronized but add-only
-     * {@code ConcurrentHashMap}
-     * @param baseTraffic Traffic on the base interfaces. Will be mutated.
-     * @param stackedTraffic Stats with traffic stacked on top of our ifaces. Will also be mutated.
-     * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both.
-     * @hide
-     */
-    public static void apply464xlatAdjustments(NetworkStats baseTraffic,
-            NetworkStats stackedTraffic, Map<String, String> stackedIfaces) {
-        // For recycling
-        Entry entry = null;
-        for (int i = 0; i < stackedTraffic.size; i++) {
-            entry = stackedTraffic.getValues(i, entry);
-            if (entry == null) continue;
-            if (entry.iface == null) continue;
-            if (!entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) continue;
-
-            // For 464xlat traffic, per uid stats only counts the bytes of the native IPv4 packet
-            // sent on the stacked interface with prefix "v4-" and drops the IPv6 header size after
-            // unwrapping. To account correctly for on-the-wire traffic, add the 20 additional bytes
-            // difference for all packets (http://b/12249687, http:/b/33681750).
-            //
-            // Note: this doesn't account for LRO/GRO/GSO/TSO (ie. >mtu) traffic correctly, nor
-            // does it correctly account for the 8 extra bytes in the IPv6 fragmentation header.
-            //
-            // While the ebpf code path does try to simulate proper post segmentation packet
-            // counts, we have nothing of the sort of xt_qtaguid stats.
-            entry.rxBytes += entry.rxPackets * IPV4V6_HEADER_DELTA;
-            entry.txBytes += entry.txPackets * IPV4V6_HEADER_DELTA;
-            stackedTraffic.setValues(i, entry);
-        }
-    }
-
-    /**
-     * Calculate and apply adjustments to captured statistics for 464xlat traffic counted twice.
-     *
-     * <p>This mutates the object this method is called on. Equivalent to calling
-     * {@link #apply464xlatAdjustments(NetworkStats, NetworkStats, Map)} with {@code this} as
-     * base and stacked traffic.
-     * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both.
-     * @hide
-     */
-    public void apply464xlatAdjustments(Map<String, String> stackedIfaces) {
-        apply464xlatAdjustments(this, this, stackedIfaces);
-    }
-
-    /**
-     * Return total statistics grouped by {@link #iface}; doesn't mutate the
-     * original structure.
-     * @hide
-     */
-    public NetworkStats groupedByIface() {
-        final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
-
-        final Entry entry = new Entry();
-        entry.uid = UID_ALL;
-        entry.set = SET_ALL;
-        entry.tag = TAG_NONE;
-        entry.metered = METERED_ALL;
-        entry.roaming = ROAMING_ALL;
-        entry.defaultNetwork = DEFAULT_NETWORK_ALL;
-        entry.operations = 0L;
-
-        for (int i = 0; i < size; i++) {
-            // skip specific tags, since already counted in TAG_NONE
-            if (tag[i] != TAG_NONE) continue;
-
-            entry.iface = iface[i];
-            entry.rxBytes = rxBytes[i];
-            entry.rxPackets = rxPackets[i];
-            entry.txBytes = txBytes[i];
-            entry.txPackets = txPackets[i];
-            stats.combineValues(entry);
-        }
-
-        return stats;
-    }
-
-    /**
-     * Return total statistics grouped by {@link #uid}; doesn't mutate the
-     * original structure.
-     * @hide
-     */
-    public NetworkStats groupedByUid() {
-        final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
-
-        final Entry entry = new Entry();
-        entry.iface = IFACE_ALL;
-        entry.set = SET_ALL;
-        entry.tag = TAG_NONE;
-        entry.metered = METERED_ALL;
-        entry.roaming = ROAMING_ALL;
-        entry.defaultNetwork = DEFAULT_NETWORK_ALL;
-
-        for (int i = 0; i < size; i++) {
-            // skip specific tags, since already counted in TAG_NONE
-            if (tag[i] != TAG_NONE) continue;
-
-            entry.uid = uid[i];
-            entry.rxBytes = rxBytes[i];
-            entry.rxPackets = rxPackets[i];
-            entry.txBytes = txBytes[i];
-            entry.txPackets = txPackets[i];
-            entry.operations = operations[i];
-            stats.combineValues(entry);
-        }
-
-        return stats;
-    }
-
-    /**
-     * Remove all rows that match one of specified UIDs.
-     * This mutates the original structure in place.
-     * @hide
-     */
-    public void removeUids(int[] uids) {
-        filter(e -> !CollectionUtils.contains(uids, e.uid));
-    }
-
-    /**
-     * Remove all rows that match one of specified UIDs.
-     * @return the result object.
-     * @hide
-     */
-    @NonNull
-    public NetworkStats removeEmptyEntries() {
-        final NetworkStats ret = this.clone();
-        ret.filter(e -> e.rxBytes != 0 || e.rxPackets != 0 || e.txBytes != 0 || e.txPackets != 0
-                || e.operations != 0);
-        return ret;
-    }
-
-    /**
-     * Only keep entries that match all specified filters.
-     *
-     * <p>This mutates the original structure in place. After this method is called,
-     * size is the number of matching entries, and capacity is the previous capacity.
-     * @param limitUid UID to filter for, or {@link #UID_ALL}.
-     * @param limitIfaces Interfaces to filter for, or {@link #INTERFACES_ALL}.
-     * @param limitTag Tag to filter for, or {@link #TAG_ALL}.
-     * @hide
-     */
-    public void filter(int limitUid, String[] limitIfaces, int limitTag) {
-        if (limitUid == UID_ALL && limitTag == TAG_ALL && limitIfaces == INTERFACES_ALL) {
-            return;
-        }
-        filter(e -> (limitUid == UID_ALL || limitUid == e.uid)
-                && (limitTag == TAG_ALL || limitTag == e.tag)
-                && (limitIfaces == INTERFACES_ALL
-                    || CollectionUtils.contains(limitIfaces, e.iface)));
-    }
-
-    /**
-     * Only keep entries with {@link #set} value less than {@link #SET_DEBUG_START}.
-     *
-     * <p>This mutates the original structure in place.
-     * @hide
-     */
-    public void filterDebugEntries() {
-        filter(e -> e.set < SET_DEBUG_START);
-    }
-
-    private void filter(Predicate<Entry> predicate) {
-        Entry entry = new Entry();
-        int nextOutputEntry = 0;
-        for (int i = 0; i < size; i++) {
-            entry = getValues(i, entry);
-            if (predicate.test(entry)) {
-                if (nextOutputEntry != i) {
-                    setValues(nextOutputEntry, entry);
-                }
-                nextOutputEntry++;
-            }
-        }
-        size = nextOutputEntry;
-    }
-
-    /** @hide */
-    public void dump(String prefix, PrintWriter pw) {
-        pw.print(prefix);
-        pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
-        for (int i = 0; i < size; i++) {
-            pw.print(prefix);
-            pw.print("  ["); pw.print(i); pw.print("]");
-            pw.print(" iface="); pw.print(iface[i]);
-            pw.print(" uid="); pw.print(uid[i]);
-            pw.print(" set="); pw.print(setToString(set[i]));
-            pw.print(" tag="); pw.print(tagToString(tag[i]));
-            pw.print(" metered="); pw.print(meteredToString(metered[i]));
-            pw.print(" roaming="); pw.print(roamingToString(roaming[i]));
-            pw.print(" defaultNetwork="); pw.print(defaultNetworkToString(defaultNetwork[i]));
-            pw.print(" rxBytes="); pw.print(rxBytes[i]);
-            pw.print(" rxPackets="); pw.print(rxPackets[i]);
-            pw.print(" txBytes="); pw.print(txBytes[i]);
-            pw.print(" txPackets="); pw.print(txPackets[i]);
-            pw.print(" operations="); pw.println(operations[i]);
-        }
-    }
-
-    /**
-     * Return text description of {@link #set} value.
-     * @hide
-     */
-    public static String setToString(int set) {
-        switch (set) {
-            case SET_ALL:
-                return "ALL";
-            case SET_DEFAULT:
-                return "DEFAULT";
-            case SET_FOREGROUND:
-                return "FOREGROUND";
-            case SET_DBG_VPN_IN:
-                return "DBG_VPN_IN";
-            case SET_DBG_VPN_OUT:
-                return "DBG_VPN_OUT";
-            default:
-                return "UNKNOWN";
-        }
-    }
-
-    /**
-     * Return text description of {@link #set} value.
-     * @hide
-     */
-    public static String setToCheckinString(int set) {
-        switch (set) {
-            case SET_ALL:
-                return "all";
-            case SET_DEFAULT:
-                return "def";
-            case SET_FOREGROUND:
-                return "fg";
-            case SET_DBG_VPN_IN:
-                return "vpnin";
-            case SET_DBG_VPN_OUT:
-                return "vpnout";
-            default:
-                return "unk";
-        }
-    }
-
-    /**
-     * @return true if the querySet matches the dataSet.
-     * @hide
-     */
-    public static boolean setMatches(int querySet, int dataSet) {
-        if (querySet == dataSet) {
-            return true;
-        }
-        // SET_ALL matches all non-debugging sets.
-        return querySet == SET_ALL && dataSet < SET_DEBUG_START;
-    }
-
-    /**
-     * Return text description of {@link #tag} value.
-     * @hide
-     */
-    public static String tagToString(int tag) {
-        return "0x" + Integer.toHexString(tag);
-    }
-
-    /**
-     * Return text description of {@link #metered} value.
-     * @hide
-     */
-    public static String meteredToString(int metered) {
-        switch (metered) {
-            case METERED_ALL:
-                return "ALL";
-            case METERED_NO:
-                return "NO";
-            case METERED_YES:
-                return "YES";
-            default:
-                return "UNKNOWN";
-        }
-    }
-
-    /**
-     * Return text description of {@link #roaming} value.
-     * @hide
-     */
-    public static String roamingToString(int roaming) {
-        switch (roaming) {
-            case ROAMING_ALL:
-                return "ALL";
-            case ROAMING_NO:
-                return "NO";
-            case ROAMING_YES:
-                return "YES";
-            default:
-                return "UNKNOWN";
-        }
-    }
-
-    /**
-     * Return text description of {@link #defaultNetwork} value.
-     * @hide
-     */
-    public static String defaultNetworkToString(int defaultNetwork) {
-        switch (defaultNetwork) {
-            case DEFAULT_NETWORK_ALL:
-                return "ALL";
-            case DEFAULT_NETWORK_NO:
-                return "NO";
-            case DEFAULT_NETWORK_YES:
-                return "YES";
-            default:
-                return "UNKNOWN";
-        }
-    }
-
-    /** @hide */
-    @Override
-    public String toString() {
-        final CharArrayWriter writer = new CharArrayWriter();
-        dump("", new PrintWriter(writer));
-        return writer.toString();
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    public static final @NonNull Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() {
-        @Override
-        public NetworkStats createFromParcel(Parcel in) {
-            return new NetworkStats(in);
-        }
-
-        @Override
-        public NetworkStats[] newArray(int size) {
-            return new NetworkStats[size];
-        }
-    };
-
-    /** @hide */
-    public interface NonMonotonicObserver<C> {
-        public void foundNonMonotonic(
-                NetworkStats left, int leftIndex, NetworkStats right, int rightIndex, C cookie);
-        public void foundNonMonotonic(
-                NetworkStats stats, int statsIndex, C cookie);
-    }
-
-    /**
-     * VPN accounting. Move some VPN's underlying traffic to other UIDs that use tun0 iface.
-     *
-     * <p>This method should only be called on delta NetworkStats. Do not call this method on a
-     * snapshot {@link NetworkStats} object because the tunUid and/or the underlyingIface may change
-     * over time.
-     *
-     * <p>This method performs adjustments for one active VPN package and one VPN iface at a time.
-     *
-     * @param tunUid uid of the VPN application
-     * @param tunIface iface of the vpn tunnel
-     * @param underlyingIfaces underlying network ifaces used by the VPN application
-     * @hide
-     */
-    public void migrateTun(int tunUid, @NonNull String tunIface,
-            @NonNull List<String> underlyingIfaces) {
-        // Combined usage by all apps using VPN.
-        final Entry tunIfaceTotal = new Entry();
-        // Usage by VPN, grouped by its {@code underlyingIfaces}.
-        final Entry[] perInterfaceTotal = new Entry[underlyingIfaces.size()];
-        // Usage by VPN, summed across all its {@code underlyingIfaces}.
-        final Entry underlyingIfacesTotal = new Entry();
-
-        for (int i = 0; i < perInterfaceTotal.length; i++) {
-            perInterfaceTotal[i] = new Entry();
-        }
-
-        tunAdjustmentInit(tunUid, tunIface, underlyingIfaces, tunIfaceTotal, perInterfaceTotal,
-                underlyingIfacesTotal);
-
-        // If tunIface < underlyingIfacesTotal, it leaves the overhead traffic in the VPN app.
-        // If tunIface > underlyingIfacesTotal, the VPN app doesn't get credit for data compression.
-        // Negative stats should be avoided.
-        final Entry[] moved =
-                addTrafficToApplications(tunUid, tunIface, underlyingIfaces, tunIfaceTotal,
-                        perInterfaceTotal, underlyingIfacesTotal);
-        deductTrafficFromVpnApp(tunUid, underlyingIfaces, moved);
-    }
-
-    /**
-     * Initializes the data used by the migrateTun() method.
-     *
-     * <p>This is the first pass iteration which does the following work:
-     *
-     * <ul>
-     *   <li>Adds up all the traffic through the tunUid's underlyingIfaces (both foreground and
-     *       background).
-     *   <li>Adds up all the traffic through tun0 excluding traffic from the vpn app itself.
-     * </ul>
-     *
-     * @param tunUid uid of the VPN application
-     * @param tunIface iface of the vpn tunnel
-     * @param underlyingIfaces underlying network ifaces used by the VPN application
-     * @param tunIfaceTotal output parameter; combined data usage by all apps using VPN
-     * @param perInterfaceTotal output parameter; data usage by VPN app, grouped by its {@code
-     *     underlyingIfaces}
-     * @param underlyingIfacesTotal output parameter; data usage by VPN, summed across all of its
-     *     {@code underlyingIfaces}
-     */
-    private void tunAdjustmentInit(int tunUid, @NonNull String tunIface,
-            @NonNull List<String> underlyingIfaces, @NonNull Entry tunIfaceTotal,
-            @NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) {
-        final Entry recycle = new Entry();
-        for (int i = 0; i < size; i++) {
-            getValues(i, recycle);
-            if (recycle.uid == UID_ALL) {
-                throw new IllegalStateException(
-                        "Cannot adjust VPN accounting on an iface aggregated NetworkStats.");
-            }
-            if (recycle.set == SET_DBG_VPN_IN || recycle.set == SET_DBG_VPN_OUT) {
-                throw new IllegalStateException(
-                        "Cannot adjust VPN accounting on a NetworkStats containing SET_DBG_VPN_*");
-            }
-            if (recycle.tag != TAG_NONE) {
-                // TODO(b/123666283): Take all tags for tunUid into account.
-                continue;
-            }
-
-            if (tunUid == Process.SYSTEM_UID) {
-                // Kernel-based VPN or VCN, traffic sent by apps on the VPN/VCN network
-                //
-                // Since the data is not UID-accounted on underlying networks, just use VPN/VCN
-                // network usage as ground truth. Encrypted traffic on the underlying networks will
-                // never be processed here because encrypted traffic on the underlying interfaces
-                // is not present in UID stats, and this method is only called on UID stats.
-                if (tunIface.equals(recycle.iface)) {
-                    tunIfaceTotal.add(recycle);
-                    underlyingIfacesTotal.add(recycle);
-
-                    // In steady state, there should always be one network, but edge cases may
-                    // result in the network being null (network lost), and thus no underlying
-                    // ifaces is possible.
-                    if (perInterfaceTotal.length > 0) {
-                        // While platform VPNs and VCNs have exactly one underlying network, that
-                        // network may have multiple interfaces (eg for 464xlat). This layer does
-                        // not have the required information to identify which of the interfaces
-                        // were used. Select "any" of the interfaces. Since overhead is already
-                        // lost, this number is an approximation anyways.
-                        perInterfaceTotal[0].add(recycle);
-                    }
-                }
-            } else if (recycle.uid == tunUid) {
-                // VpnService VPN, traffic sent by the VPN app over underlying networks
-                for (int j = 0; j < underlyingIfaces.size(); j++) {
-                    if (Objects.equals(underlyingIfaces.get(j), recycle.iface)) {
-                        perInterfaceTotal[j].add(recycle);
-                        underlyingIfacesTotal.add(recycle);
-                        break;
-                    }
-                }
-            } else if (tunIface.equals(recycle.iface)) {
-                // VpnService VPN; traffic sent by apps on the VPN network
-                tunIfaceTotal.add(recycle);
-            }
-        }
-    }
-
-    /**
-     * Distributes traffic across apps that are using given {@code tunIface}, and returns the total
-     * traffic that should be moved off of {@code tunUid} grouped by {@code underlyingIfaces}.
-     *
-     * @param tunUid uid of the VPN application
-     * @param tunIface iface of the vpn tunnel
-     * @param underlyingIfaces underlying network ifaces used by the VPN application
-     * @param tunIfaceTotal combined data usage across all apps using {@code tunIface}
-     * @param perInterfaceTotal data usage by VPN app, grouped by its {@code underlyingIfaces}
-     * @param underlyingIfacesTotal data usage by VPN, summed across all of its {@code
-     *     underlyingIfaces}
-     */
-    private Entry[] addTrafficToApplications(int tunUid, @NonNull String tunIface,
-            @NonNull List<String> underlyingIfaces, @NonNull Entry tunIfaceTotal,
-            @NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) {
-        // Traffic that should be moved off of each underlying interface for tunUid (see
-        // deductTrafficFromVpnApp below).
-        final Entry[] moved = new Entry[underlyingIfaces.size()];
-        for (int i = 0; i < underlyingIfaces.size(); i++) {
-            moved[i] = new Entry();
-        }
-
-        final Entry tmpEntry = new Entry();
-        final int origSize = size;
-        for (int i = 0; i < origSize; i++) {
-            if (!Objects.equals(iface[i], tunIface)) {
-                // Consider only entries that go onto the VPN interface.
-                continue;
-            }
-
-            if (uid[i] == tunUid && tunUid != Process.SYSTEM_UID) {
-                // Exclude VPN app from the redistribution, as it can choose to create packet
-                // streams by writing to itself.
-                //
-                // However, for platform VPNs, do not exclude the system's usage of the VPN network,
-                // since it is never local-only, and never double counted
-                continue;
-            }
-            tmpEntry.uid = uid[i];
-            tmpEntry.tag = tag[i];
-            tmpEntry.metered = metered[i];
-            tmpEntry.roaming = roaming[i];
-            tmpEntry.defaultNetwork = defaultNetwork[i];
-
-            // In a first pass, compute this entry's total share of data across all
-            // underlyingIfaces. This is computed on the basis of the share of this entry's usage
-            // over tunIface.
-            // TODO: Consider refactoring first pass into a separate helper method.
-            long totalRxBytes = 0;
-            if (tunIfaceTotal.rxBytes > 0) {
-                // Note - The multiplication below should not overflow since NetworkStatsService
-                // processes this every time device has transmitted/received amount equivalent to
-                // global threshold alert (~ 2MB) across all interfaces.
-                final long rxBytesAcrossUnderlyingIfaces =
-                        multiplySafeByRational(underlyingIfacesTotal.rxBytes,
-                                rxBytes[i], tunIfaceTotal.rxBytes);
-                // app must not be blamed for more than it consumed on tunIface
-                totalRxBytes = Math.min(rxBytes[i], rxBytesAcrossUnderlyingIfaces);
-            }
-            long totalRxPackets = 0;
-            if (tunIfaceTotal.rxPackets > 0) {
-                final long rxPacketsAcrossUnderlyingIfaces =
-                        multiplySafeByRational(underlyingIfacesTotal.rxPackets,
-                                rxPackets[i], tunIfaceTotal.rxPackets);
-                totalRxPackets = Math.min(rxPackets[i], rxPacketsAcrossUnderlyingIfaces);
-            }
-            long totalTxBytes = 0;
-            if (tunIfaceTotal.txBytes > 0) {
-                final long txBytesAcrossUnderlyingIfaces =
-                        multiplySafeByRational(underlyingIfacesTotal.txBytes,
-                                txBytes[i], tunIfaceTotal.txBytes);
-                totalTxBytes = Math.min(txBytes[i], txBytesAcrossUnderlyingIfaces);
-            }
-            long totalTxPackets = 0;
-            if (tunIfaceTotal.txPackets > 0) {
-                final long txPacketsAcrossUnderlyingIfaces =
-                        multiplySafeByRational(underlyingIfacesTotal.txPackets,
-                                txPackets[i], tunIfaceTotal.txPackets);
-                totalTxPackets = Math.min(txPackets[i], txPacketsAcrossUnderlyingIfaces);
-            }
-            long totalOperations = 0;
-            if (tunIfaceTotal.operations > 0) {
-                final long operationsAcrossUnderlyingIfaces =
-                        multiplySafeByRational(underlyingIfacesTotal.operations,
-                                operations[i], tunIfaceTotal.operations);
-                totalOperations = Math.min(operations[i], operationsAcrossUnderlyingIfaces);
-            }
-            // In a second pass, distribute these values across interfaces in the proportion that
-            // each interface represents of the total traffic of the underlying interfaces.
-            for (int j = 0; j < underlyingIfaces.size(); j++) {
-                tmpEntry.iface = underlyingIfaces.get(j);
-                tmpEntry.rxBytes = 0;
-                // Reset 'set' to correct value since it gets updated when adding debug info below.
-                tmpEntry.set = set[i];
-                if (underlyingIfacesTotal.rxBytes > 0) {
-                    tmpEntry.rxBytes =
-                            multiplySafeByRational(totalRxBytes,
-                                    perInterfaceTotal[j].rxBytes,
-                                    underlyingIfacesTotal.rxBytes);
-                }
-                tmpEntry.rxPackets = 0;
-                if (underlyingIfacesTotal.rxPackets > 0) {
-                    tmpEntry.rxPackets =
-                            multiplySafeByRational(totalRxPackets,
-                                    perInterfaceTotal[j].rxPackets,
-                                    underlyingIfacesTotal.rxPackets);
-                }
-                tmpEntry.txBytes = 0;
-                if (underlyingIfacesTotal.txBytes > 0) {
-                    tmpEntry.txBytes =
-                            multiplySafeByRational(totalTxBytes,
-                                    perInterfaceTotal[j].txBytes,
-                                    underlyingIfacesTotal.txBytes);
-                }
-                tmpEntry.txPackets = 0;
-                if (underlyingIfacesTotal.txPackets > 0) {
-                    tmpEntry.txPackets =
-                            multiplySafeByRational(totalTxPackets,
-                                    perInterfaceTotal[j].txPackets,
-                                    underlyingIfacesTotal.txPackets);
-                }
-                tmpEntry.operations = 0;
-                if (underlyingIfacesTotal.operations > 0) {
-                    tmpEntry.operations =
-                            multiplySafeByRational(totalOperations,
-                                    perInterfaceTotal[j].operations,
-                                    underlyingIfacesTotal.operations);
-                }
-                // tmpEntry now contains the migrated data of the i-th entry for the j-th underlying
-                // interface. Add that data usage to this object.
-                combineValues(tmpEntry);
-                if (tag[i] == TAG_NONE) {
-                    // Add the migrated data to moved so it is deducted from the VPN app later.
-                    moved[j].add(tmpEntry);
-                    // Add debug info
-                    tmpEntry.set = SET_DBG_VPN_IN;
-                    combineValues(tmpEntry);
-                }
-            }
-        }
-        return moved;
-    }
-
-    private void deductTrafficFromVpnApp(
-            int tunUid,
-            @NonNull List<String> underlyingIfaces,
-            @NonNull Entry[] moved) {
-        if (tunUid == Process.SYSTEM_UID) {
-            // No traffic recorded on a per-UID basis for in-kernel VPN/VCNs over underlying
-            // networks; thus no traffic to deduct.
-            return;
-        }
-
-        for (int i = 0; i < underlyingIfaces.size(); i++) {
-            moved[i].uid = tunUid;
-            // Add debug info
-            moved[i].set = SET_DBG_VPN_OUT;
-            moved[i].tag = TAG_NONE;
-            moved[i].iface = underlyingIfaces.get(i);
-            moved[i].metered = METERED_ALL;
-            moved[i].roaming = ROAMING_ALL;
-            moved[i].defaultNetwork = DEFAULT_NETWORK_ALL;
-            combineValues(moved[i]);
-
-            // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than
-            // the TAG_NONE traffic.
-            //
-            // Relies on the fact that the underlying traffic only has state ROAMING_NO and
-            // METERED_NO, which should be the case as it comes directly from the /proc file.
-            // We only blend in the roaming data after applying these adjustments, by checking the
-            // NetworkIdentity of the underlying iface.
-            final int idxVpnBackground = findIndex(underlyingIfaces.get(i), tunUid, SET_DEFAULT,
-                            TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO);
-            if (idxVpnBackground != -1) {
-                // Note - tunSubtract also updates moved[i]; whatever traffic that's left is removed
-                // from foreground usage.
-                tunSubtract(idxVpnBackground, this, moved[i]);
-            }
-
-            final int idxVpnForeground = findIndex(underlyingIfaces.get(i), tunUid, SET_FOREGROUND,
-                            TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO);
-            if (idxVpnForeground != -1) {
-                tunSubtract(idxVpnForeground, this, moved[i]);
-            }
-        }
-    }
-
-    private static void tunSubtract(int i, @NonNull NetworkStats left, @NonNull Entry right) {
-        long rxBytes = Math.min(left.rxBytes[i], right.rxBytes);
-        left.rxBytes[i] -= rxBytes;
-        right.rxBytes -= rxBytes;
-
-        long rxPackets = Math.min(left.rxPackets[i], right.rxPackets);
-        left.rxPackets[i] -= rxPackets;
-        right.rxPackets -= rxPackets;
-
-        long txBytes = Math.min(left.txBytes[i], right.txBytes);
-        left.txBytes[i] -= txBytes;
-        right.txBytes -= txBytes;
-
-        long txPackets = Math.min(left.txPackets[i], right.txPackets);
-        left.txPackets[i] -= txPackets;
-        right.txPackets -= txPackets;
-    }
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java
deleted file mode 100644
index b64fbdb..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.net.NetworkStats.UID_ALL;
-import static android.net.TrafficStats.UID_REMOVED;
-import static android.net.TrafficStats.UID_TETHERING;
-
-import android.Manifest;
-import android.annotation.IntDef;
-import android.app.AppOpsManager;
-import android.app.admin.DevicePolicyManager;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Binder;
-import android.os.Process;
-import android.os.UserHandle;
-import android.telephony.TelephonyManager;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Utility methods for controlling access to network stats APIs.
- *
- * @hide
- */
-public final class NetworkStatsAccess {
-    private NetworkStatsAccess() {}
-
-    /**
-     * Represents an access level for the network usage history and statistics APIs.
-     *
-     * <p>Access levels are in increasing order; that is, it is reasonable to check access by
-     * verifying that the caller's access level is at least the minimum required level.
-     */
-    @IntDef({
-            Level.DEFAULT,
-            Level.USER,
-            Level.DEVICESUMMARY,
-            Level.DEVICE,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Level {
-        /**
-         * Default, unprivileged access level.
-         *
-         * <p>Can only access usage for one's own UID.
-         *
-         * <p>Every app will have at least this access level.
-         */
-        int DEFAULT = 0;
-
-        /**
-         * Access level for apps which can access usage for any app running in the same user.
-         *
-         * <p>Granted to:
-         * <ul>
-         * <li>Profile owners.
-         * </ul>
-         */
-        int USER = 1;
-
-        /**
-         * Access level for apps which can access usage summary of device. Device summary includes
-         * usage by apps running in any profiles/users, however this access level does not
-         * allow querying usage of individual apps running in other profiles/users.
-         *
-         * <p>Granted to:
-         * <ul>
-         * <li>Apps with the PACKAGE_USAGE_STATS permission granted. Note that this is an AppOps bit
-         * so it is not necessarily sufficient to declare this in the manifest.
-         * <li>Apps with the (signature/privileged) READ_NETWORK_USAGE_HISTORY permission.
-         * </ul>
-         */
-        int DEVICESUMMARY = 2;
-
-        /**
-         * Access level for apps which can access usage for any app on the device, including apps
-         * running on other users/profiles.
-         *
-         * <p>Granted to:
-         * <ul>
-         * <li>Device owners.
-         * <li>Carrier-privileged applications.
-         * <li>The system UID.
-         * </ul>
-         */
-        int DEVICE = 3;
-    }
-
-    /** Returns the {@link NetworkStatsAccess.Level} for the given caller. */
-    public static @NetworkStatsAccess.Level int checkAccessLevel(
-            Context context, int callingPid, int callingUid, String callingPackage) {
-        final DevicePolicyManager mDpm = context.getSystemService(DevicePolicyManager.class);
-        final TelephonyManager tm = (TelephonyManager)
-                context.getSystemService(Context.TELEPHONY_SERVICE);
-        boolean hasCarrierPrivileges;
-        final long token = Binder.clearCallingIdentity();
-        try {
-            hasCarrierPrivileges = tm != null
-                    && tm.checkCarrierPrivilegesForPackageAnyPhone(callingPackage)
-                            == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-
-        final boolean isDeviceOwner = mDpm != null && mDpm.isDeviceOwnerApp(callingPackage);
-        final int appId = UserHandle.getAppId(callingUid);
-
-        final boolean isNetworkStack = context.checkPermission(
-                android.Manifest.permission.NETWORK_STACK, callingPid, callingUid)
-                == PERMISSION_GRANTED;
-
-        if (hasCarrierPrivileges || isDeviceOwner
-                || appId == Process.SYSTEM_UID || isNetworkStack) {
-            // Carrier-privileged apps and device owners, and the system (including the
-            // network stack) can access data usage for all apps on the device.
-            return NetworkStatsAccess.Level.DEVICE;
-        }
-
-        boolean hasAppOpsPermission = hasAppOpsPermission(context, callingUid, callingPackage);
-        if (hasAppOpsPermission || context.checkCallingOrSelfPermission(
-                READ_NETWORK_USAGE_HISTORY) == PackageManager.PERMISSION_GRANTED) {
-            return NetworkStatsAccess.Level.DEVICESUMMARY;
-        }
-
-        //TODO(b/169395065) Figure out if this flow makes sense in Device Owner mode.
-        boolean isProfileOwner = mDpm != null && (mDpm.isProfileOwnerApp(callingPackage)
-                || mDpm.isDeviceOwnerApp(callingPackage));
-        if (isProfileOwner) {
-            // Apps with the AppOps permission, profile owners, and apps with the privileged
-            // permission can access data usage for all apps in this user/profile.
-            return NetworkStatsAccess.Level.USER;
-        }
-
-        // Everyone else gets default access (only to their own UID).
-        return NetworkStatsAccess.Level.DEFAULT;
-    }
-
-    /**
-     * Returns whether the given caller should be able to access the given UID when the caller has
-     * the given {@link NetworkStatsAccess.Level}.
-     */
-    public static boolean isAccessibleToUser(int uid, int callerUid,
-            @NetworkStatsAccess.Level int accessLevel) {
-        final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
-        final int callerUserId = UserHandle.getUserHandleForUid(callerUid).getIdentifier();
-        switch (accessLevel) {
-            case NetworkStatsAccess.Level.DEVICE:
-                // Device-level access - can access usage for any uid.
-                return true;
-            case NetworkStatsAccess.Level.DEVICESUMMARY:
-                // Can access usage for any app running in the same user, along
-                // with some special uids (system, removed, or tethering) and
-                // anonymized uids
-                return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED
-                        || uid == UID_TETHERING || uid == UID_ALL
-                        || userId == callerUserId;
-            case NetworkStatsAccess.Level.USER:
-                // User-level access - can access usage for any app running in the same user, along
-                // with some special uids (system, removed, or tethering).
-                return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED
-                        || uid == UID_TETHERING
-                        || userId == callerUserId;
-            case NetworkStatsAccess.Level.DEFAULT:
-            default:
-                // Default access level - can only access one's own usage.
-                return uid == callerUid;
-        }
-    }
-
-    private static boolean hasAppOpsPermission(
-            Context context, int callingUid, String callingPackage) {
-        if (callingPackage != null) {
-            AppOpsManager appOps = (AppOpsManager) context.getSystemService(
-                    Context.APP_OPS_SERVICE);
-
-            final int mode = appOps.noteOp(AppOpsManager.OPSTR_GET_USAGE_STATS,
-                    callingUid, callingPackage, null /* attributionTag */, null /* message */);
-            if (mode == AppOpsManager.MODE_DEFAULT) {
-                // The default behavior here is to check if PackageManager has given the app
-                // permission.
-                final int permissionCheck = context.checkCallingPermission(
-                        Manifest.permission.PACKAGE_USAGE_STATS);
-                return permissionCheck == PackageManager.PERMISSION_GRANTED;
-            }
-            return (mode == AppOpsManager.MODE_ALLOWED);
-        }
-        return false;
-    }
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java
deleted file mode 100644
index 735c44d..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java
+++ /dev/null
@@ -1,954 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
-import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
-import static android.net.NetworkStats.IFACE_ALL;
-import static android.net.NetworkStats.METERED_NO;
-import static android.net.NetworkStats.METERED_YES;
-import static android.net.NetworkStats.ROAMING_NO;
-import static android.net.NetworkStats.ROAMING_YES;
-import static android.net.NetworkStats.SET_ALL;
-import static android.net.NetworkStats.SET_DEFAULT;
-import static android.net.NetworkStats.TAG_NONE;
-import static android.net.NetworkStats.UID_ALL;
-import static android.net.TrafficStats.UID_REMOVED;
-import static android.text.format.DateUtils.WEEK_IN_MILLIS;
-
-import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.net.NetworkStatsHistory.Entry;
-import android.os.Binder;
-import android.service.NetworkStatsCollectionKeyProto;
-import android.service.NetworkStatsCollectionProto;
-import android.service.NetworkStatsCollectionStatsProto;
-import android.telephony.SubscriptionPlan;
-import android.text.format.DateUtils;
-import android.util.ArrayMap;
-import android.util.AtomicFile;
-import android.util.IndentingPrintWriter;
-import android.util.Log;
-import android.util.Range;
-import android.util.proto.ProtoOutputStream;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FileRotator;
-import com.android.net.module.util.CollectionUtils;
-import com.android.net.module.util.NetworkStatsUtils;
-
-import libcore.io.IoUtils;
-
-import java.io.BufferedInputStream;
-import java.io.DataInput;
-import java.io.DataInputStream;
-import java.io.DataOutput;
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.net.ProtocolException;
-import java.time.ZonedDateTime;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * Collection of {@link NetworkStatsHistory}, stored based on combined key of
- * {@link NetworkIdentitySet}, UID, set, and tag. Knows how to persist itself.
- *
- * @hide
- */
-@SystemApi(client = MODULE_LIBRARIES)
-public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.Writer {
-    private static final String TAG = NetworkStatsCollection.class.getSimpleName();
-    /** File header magic number: "ANET" */
-    private static final int FILE_MAGIC = 0x414E4554;
-
-    private static final int VERSION_NETWORK_INIT = 1;
-
-    private static final int VERSION_UID_INIT = 1;
-    private static final int VERSION_UID_WITH_IDENT = 2;
-    private static final int VERSION_UID_WITH_TAG = 3;
-    private static final int VERSION_UID_WITH_SET = 4;
-
-    private static final int VERSION_UNIFIED_INIT = 16;
-
-    private ArrayMap<Key, NetworkStatsHistory> mStats = new ArrayMap<>();
-
-    private final long mBucketDuration;
-
-    private long mStartMillis;
-    private long mEndMillis;
-    private long mTotalBytes;
-    private boolean mDirty;
-
-    /**
-     * Construct a {@link NetworkStatsCollection} object.
-     *
-     * @param bucketDuration duration of the buckets in this object, in milliseconds.
-     * @hide
-     */
-    public NetworkStatsCollection(long bucketDuration) {
-        mBucketDuration = bucketDuration;
-        reset();
-    }
-
-    /** @hide */
-    public void clear() {
-        reset();
-    }
-
-    /** @hide */
-    public void reset() {
-        mStats.clear();
-        mStartMillis = Long.MAX_VALUE;
-        mEndMillis = Long.MIN_VALUE;
-        mTotalBytes = 0;
-        mDirty = false;
-    }
-
-    /** @hide */
-    public long getStartMillis() {
-        return mStartMillis;
-    }
-
-    /**
-     * Return first atomic bucket in this collection, which is more conservative
-     * than {@link #mStartMillis}.
-     * @hide
-     */
-    public long getFirstAtomicBucketMillis() {
-        if (mStartMillis == Long.MAX_VALUE) {
-            return Long.MAX_VALUE;
-        } else {
-            return mStartMillis + mBucketDuration;
-        }
-    }
-
-    /** @hide */
-    public long getEndMillis() {
-        return mEndMillis;
-    }
-
-    /** @hide */
-    public long getTotalBytes() {
-        return mTotalBytes;
-    }
-
-    /** @hide */
-    public boolean isDirty() {
-        return mDirty;
-    }
-
-    /** @hide */
-    public void clearDirty() {
-        mDirty = false;
-    }
-
-    /** @hide */
-    public boolean isEmpty() {
-        return mStartMillis == Long.MAX_VALUE && mEndMillis == Long.MIN_VALUE;
-    }
-
-    /** @hide */
-    @VisibleForTesting
-    public long roundUp(long time) {
-        if (time == Long.MIN_VALUE || time == Long.MAX_VALUE
-                || time == SubscriptionPlan.TIME_UNKNOWN) {
-            return time;
-        } else {
-            final long mod = time % mBucketDuration;
-            if (mod > 0) {
-                time -= mod;
-                time += mBucketDuration;
-            }
-            return time;
-        }
-    }
-
-    /** @hide */
-    @VisibleForTesting
-    public long roundDown(long time) {
-        if (time == Long.MIN_VALUE || time == Long.MAX_VALUE
-                || time == SubscriptionPlan.TIME_UNKNOWN) {
-            return time;
-        } else {
-            final long mod = time % mBucketDuration;
-            if (mod > 0) {
-                time -= mod;
-            }
-            return time;
-        }
-    }
-
-    /** @hide */
-    public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel) {
-        return getRelevantUids(accessLevel, Binder.getCallingUid());
-    }
-
-    /** @hide */
-    public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel,
-                final int callerUid) {
-        final ArrayList<Integer> uids = new ArrayList<>();
-        for (int i = 0; i < mStats.size(); i++) {
-            final Key key = mStats.keyAt(i);
-            if (NetworkStatsAccess.isAccessibleToUser(key.uid, callerUid, accessLevel)) {
-                int j = Collections.binarySearch(uids, new Integer(key.uid));
-
-                if (j < 0) {
-                    j = ~j;
-                    uids.add(j, key.uid);
-                }
-            }
-        }
-        return CollectionUtils.toIntArray(uids);
-    }
-
-    /**
-     * Combine all {@link NetworkStatsHistory} in this collection which match
-     * the requested parameters.
-     * @hide
-     */
-    public NetworkStatsHistory getHistory(NetworkTemplate template, SubscriptionPlan augmentPlan,
-            int uid, int set, int tag, int fields, long start, long end,
-            @NetworkStatsAccess.Level int accessLevel, int callerUid) {
-        if (!NetworkStatsAccess.isAccessibleToUser(uid, callerUid, accessLevel)) {
-            throw new SecurityException("Network stats history of uid " + uid
-                    + " is forbidden for caller " + callerUid);
-        }
-
-        // 180 days of history should be enough for anyone; if we end up needing
-        // more, we'll dynamically grow the history object.
-        final int bucketEstimate = (int) NetworkStatsUtils.constrain(
-                ((end - start) / mBucketDuration), 0,
-                (180 * DateUtils.DAY_IN_MILLIS) / mBucketDuration);
-        final NetworkStatsHistory combined = new NetworkStatsHistory(
-                mBucketDuration, bucketEstimate, fields);
-
-        // shortcut when we know stats will be empty
-        if (start == end) return combined;
-
-        // Figure out the window of time that we should be augmenting (if any)
-        long augmentStart = SubscriptionPlan.TIME_UNKNOWN;
-        long augmentEnd = (augmentPlan != null) ? augmentPlan.getDataUsageTime()
-                : SubscriptionPlan.TIME_UNKNOWN;
-        // And if augmenting, we might need to collect more data to adjust with
-        long collectStart = start;
-        long collectEnd = end;
-
-        if (augmentEnd != SubscriptionPlan.TIME_UNKNOWN) {
-            final Iterator<Range<ZonedDateTime>> it = augmentPlan.cycleIterator();
-            while (it.hasNext()) {
-                final Range<ZonedDateTime> cycle = it.next();
-                final long cycleStart = cycle.getLower().toInstant().toEpochMilli();
-                final long cycleEnd = cycle.getUpper().toInstant().toEpochMilli();
-                if (cycleStart <= augmentEnd && augmentEnd < cycleEnd) {
-                    augmentStart = cycleStart;
-                    collectStart = Long.min(collectStart, augmentStart);
-                    collectEnd = Long.max(collectEnd, augmentEnd);
-                    break;
-                }
-            }
-        }
-
-        if (augmentStart != SubscriptionPlan.TIME_UNKNOWN) {
-            // Shrink augmentation window so we don't risk undercounting.
-            augmentStart = roundUp(augmentStart);
-            augmentEnd = roundDown(augmentEnd);
-            // Grow collection window so we get all the stats needed.
-            collectStart = roundDown(collectStart);
-            collectEnd = roundUp(collectEnd);
-        }
-
-        for (int i = 0; i < mStats.size(); i++) {
-            final Key key = mStats.keyAt(i);
-            if (key.uid == uid && NetworkStats.setMatches(set, key.set) && key.tag == tag
-                    && templateMatches(template, key.ident)) {
-                final NetworkStatsHistory value = mStats.valueAt(i);
-                combined.recordHistory(value, collectStart, collectEnd);
-            }
-        }
-
-        if (augmentStart != SubscriptionPlan.TIME_UNKNOWN) {
-            final NetworkStatsHistory.Entry entry = combined.getValues(
-                    augmentStart, augmentEnd, null);
-
-            // If we don't have any recorded data for this time period, give
-            // ourselves something to scale with.
-            if (entry.rxBytes == 0 || entry.txBytes == 0) {
-                combined.recordData(augmentStart, augmentEnd,
-                        new NetworkStats.Entry(1, 0, 1, 0, 0));
-                combined.getValues(augmentStart, augmentEnd, entry);
-            }
-
-            final long rawBytes = (entry.rxBytes + entry.txBytes) == 0 ? 1 :
-                    (entry.rxBytes + entry.txBytes);
-            final long rawRxBytes = entry.rxBytes == 0 ? 1 : entry.rxBytes;
-            final long rawTxBytes = entry.txBytes == 0 ? 1 : entry.txBytes;
-            final long targetBytes = augmentPlan.getDataUsageBytes();
-
-            final long targetRxBytes = multiplySafeByRational(targetBytes, rawRxBytes, rawBytes);
-            final long targetTxBytes = multiplySafeByRational(targetBytes, rawTxBytes, rawBytes);
-
-
-            // Scale all matching buckets to reach anchor target
-            final long beforeTotal = combined.getTotalBytes();
-            for (int i = 0; i < combined.size(); i++) {
-                combined.getValues(i, entry);
-                if (entry.bucketStart >= augmentStart
-                        && entry.bucketStart + entry.bucketDuration <= augmentEnd) {
-                    entry.rxBytes = multiplySafeByRational(
-                            targetRxBytes, entry.rxBytes, rawRxBytes);
-                    entry.txBytes = multiplySafeByRational(
-                            targetTxBytes, entry.txBytes, rawTxBytes);
-                    // We purposefully clear out packet counters to indicate
-                    // that this data has been augmented.
-                    entry.rxPackets = 0;
-                    entry.txPackets = 0;
-                    combined.setValues(i, entry);
-                }
-            }
-
-            final long deltaTotal = combined.getTotalBytes() - beforeTotal;
-            if (deltaTotal != 0) {
-                Log.d(TAG, "Augmented network usage by " + deltaTotal + " bytes");
-            }
-
-            // Finally we can slice data as originally requested
-            final NetworkStatsHistory sliced = new NetworkStatsHistory(
-                    mBucketDuration, bucketEstimate, fields);
-            sliced.recordHistory(combined, start, end);
-            return sliced;
-        } else {
-            return combined;
-        }
-    }
-
-    /**
-     * Summarize all {@link NetworkStatsHistory} in this collection which match
-     * the requested parameters across the requested range.
-     *
-     * @param template - a predicate for filtering netstats.
-     * @param start - start of the range, timestamp in milliseconds since the epoch.
-     * @param end - end of the range, timestamp in milliseconds since the epoch.
-     * @param accessLevel - caller access level.
-     * @param callerUid - caller UID.
-     * @hide
-     */
-    public NetworkStats getSummary(NetworkTemplate template, long start, long end,
-            @NetworkStatsAccess.Level int accessLevel, int callerUid) {
-        final long now = System.currentTimeMillis();
-
-        final NetworkStats stats = new NetworkStats(end - start, 24);
-
-        // shortcut when we know stats will be empty
-        if (start == end) return stats;
-
-        final NetworkStats.Entry entry = new NetworkStats.Entry();
-        NetworkStatsHistory.Entry historyEntry = null;
-
-        for (int i = 0; i < mStats.size(); i++) {
-            final Key key = mStats.keyAt(i);
-            if (templateMatches(template, key.ident)
-                    && NetworkStatsAccess.isAccessibleToUser(key.uid, callerUid, accessLevel)
-                    && key.set < NetworkStats.SET_DEBUG_START) {
-                final NetworkStatsHistory value = mStats.valueAt(i);
-                historyEntry = value.getValues(start, end, now, historyEntry);
-
-                entry.iface = IFACE_ALL;
-                entry.uid = key.uid;
-                entry.set = key.set;
-                entry.tag = key.tag;
-                entry.defaultNetwork = key.ident.areAllMembersOnDefaultNetwork()
-                        ? DEFAULT_NETWORK_YES : DEFAULT_NETWORK_NO;
-                entry.metered = key.ident.isAnyMemberMetered() ? METERED_YES : METERED_NO;
-                entry.roaming = key.ident.isAnyMemberRoaming() ? ROAMING_YES : ROAMING_NO;
-                entry.rxBytes = historyEntry.rxBytes;
-                entry.rxPackets = historyEntry.rxPackets;
-                entry.txBytes = historyEntry.txBytes;
-                entry.txPackets = historyEntry.txPackets;
-                entry.operations = historyEntry.operations;
-
-                if (!entry.isEmpty()) {
-                    stats.combineValues(entry);
-                }
-            }
-        }
-
-        return stats;
-    }
-
-    /**
-     * Record given {@link android.net.NetworkStats.Entry} into this collection.
-     * @hide
-     */
-    public void recordData(NetworkIdentitySet ident, int uid, int set, int tag, long start,
-            long end, NetworkStats.Entry entry) {
-        final NetworkStatsHistory history = findOrCreateHistory(ident, uid, set, tag);
-        history.recordData(start, end, entry);
-        noteRecordedHistory(history.getStart(), history.getEnd(), entry.rxBytes + entry.txBytes);
-    }
-
-    /**
-     * Record given {@link NetworkStatsHistory} into this collection.
-     *
-     * @hide
-     */
-    public void recordHistory(@NonNull Key key, @NonNull NetworkStatsHistory history) {
-        Objects.requireNonNull(key);
-        Objects.requireNonNull(history);
-        if (history.size() == 0) return;
-        noteRecordedHistory(history.getStart(), history.getEnd(), history.getTotalBytes());
-
-        NetworkStatsHistory target = mStats.get(key);
-        if (target == null) {
-            target = new NetworkStatsHistory(history.getBucketDuration());
-            mStats.put(key, target);
-        }
-        target.recordEntireHistory(history);
-    }
-
-    /**
-     * Record all {@link NetworkStatsHistory} contained in the given collection
-     * into this collection.
-     *
-     * @hide
-     */
-    public void recordCollection(@NonNull NetworkStatsCollection another) {
-        Objects.requireNonNull(another);
-        for (int i = 0; i < another.mStats.size(); i++) {
-            final Key key = another.mStats.keyAt(i);
-            final NetworkStatsHistory value = another.mStats.valueAt(i);
-            recordHistory(key, value);
-        }
-    }
-
-    private NetworkStatsHistory findOrCreateHistory(
-            NetworkIdentitySet ident, int uid, int set, int tag) {
-        final Key key = new Key(ident, uid, set, tag);
-        final NetworkStatsHistory existing = mStats.get(key);
-
-        // update when no existing, or when bucket duration changed
-        NetworkStatsHistory updated = null;
-        if (existing == null) {
-            updated = new NetworkStatsHistory(mBucketDuration, 10);
-        } else if (existing.getBucketDuration() != mBucketDuration) {
-            updated = new NetworkStatsHistory(existing, mBucketDuration);
-        }
-
-        if (updated != null) {
-            mStats.put(key, updated);
-            return updated;
-        } else {
-            return existing;
-        }
-    }
-
-    /** @hide */
-    @Override
-    public void read(InputStream in) throws IOException {
-        read((DataInput) new DataInputStream(in));
-    }
-
-    private void read(DataInput in) throws IOException {
-        // verify file magic header intact
-        final int magic = in.readInt();
-        if (magic != FILE_MAGIC) {
-            throw new ProtocolException("unexpected magic: " + magic);
-        }
-
-        final int version = in.readInt();
-        switch (version) {
-            case VERSION_UNIFIED_INIT: {
-                // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory))
-                final int identSize = in.readInt();
-                for (int i = 0; i < identSize; i++) {
-                    final NetworkIdentitySet ident = new NetworkIdentitySet(in);
-
-                    final int size = in.readInt();
-                    for (int j = 0; j < size; j++) {
-                        final int uid = in.readInt();
-                        final int set = in.readInt();
-                        final int tag = in.readInt();
-
-                        final Key key = new Key(ident, uid, set, tag);
-                        final NetworkStatsHistory history = new NetworkStatsHistory(in);
-                        recordHistory(key, history);
-                    }
-                }
-                break;
-            }
-            default: {
-                throw new ProtocolException("unexpected version: " + version);
-            }
-        }
-    }
-
-    /** @hide */
-    @Override
-    public void write(OutputStream out) throws IOException {
-        write((DataOutput) new DataOutputStream(out));
-        out.flush();
-    }
-
-    private void write(DataOutput out) throws IOException {
-        // cluster key lists grouped by ident
-        final HashMap<NetworkIdentitySet, ArrayList<Key>> keysByIdent = new HashMap<>();
-        for (Key key : mStats.keySet()) {
-            ArrayList<Key> keys = keysByIdent.get(key.ident);
-            if (keys == null) {
-                keys = new ArrayList<>();
-                keysByIdent.put(key.ident, keys);
-            }
-            keys.add(key);
-        }
-
-        out.writeInt(FILE_MAGIC);
-        out.writeInt(VERSION_UNIFIED_INIT);
-
-        out.writeInt(keysByIdent.size());
-        for (NetworkIdentitySet ident : keysByIdent.keySet()) {
-            final ArrayList<Key> keys = keysByIdent.get(ident);
-            ident.writeToStream(out);
-
-            out.writeInt(keys.size());
-            for (Key key : keys) {
-                final NetworkStatsHistory history = mStats.get(key);
-                out.writeInt(key.uid);
-                out.writeInt(key.set);
-                out.writeInt(key.tag);
-                history.writeToStream(out);
-            }
-        }
-    }
-
-    /**
-     * Read legacy network summary statistics file format into the collection,
-     * See {@code NetworkStatsService#maybeUpgradeLegacyStatsLocked}.
-     *
-     * @deprecated
-     * @hide
-     */
-    @Deprecated
-    public void readLegacyNetwork(File file) throws IOException {
-        final AtomicFile inputFile = new AtomicFile(file);
-
-        DataInputStream in = null;
-        try {
-            in = new DataInputStream(new BufferedInputStream(inputFile.openRead()));
-
-            // verify file magic header intact
-            final int magic = in.readInt();
-            if (magic != FILE_MAGIC) {
-                throw new ProtocolException("unexpected magic: " + magic);
-            }
-
-            final int version = in.readInt();
-            switch (version) {
-                case VERSION_NETWORK_INIT: {
-                    // network := size *(NetworkIdentitySet NetworkStatsHistory)
-                    final int size = in.readInt();
-                    for (int i = 0; i < size; i++) {
-                        final NetworkIdentitySet ident = new NetworkIdentitySet(in);
-                        final NetworkStatsHistory history = new NetworkStatsHistory(in);
-
-                        final Key key = new Key(ident, UID_ALL, SET_ALL, TAG_NONE);
-                        recordHistory(key, history);
-                    }
-                    break;
-                }
-                default: {
-                    throw new ProtocolException("unexpected version: " + version);
-                }
-            }
-        } catch (FileNotFoundException e) {
-            // missing stats is okay, probably first boot
-        } finally {
-            IoUtils.closeQuietly(in);
-        }
-    }
-
-    /**
-     * Read legacy Uid statistics file format into the collection,
-     * See {@code NetworkStatsService#maybeUpgradeLegacyStatsLocked}.
-     *
-     * @deprecated
-     * @hide
-     */
-    @Deprecated
-    public void readLegacyUid(File file, boolean onlyTags) throws IOException {
-        final AtomicFile inputFile = new AtomicFile(file);
-
-        DataInputStream in = null;
-        try {
-            in = new DataInputStream(new BufferedInputStream(inputFile.openRead()));
-
-            // verify file magic header intact
-            final int magic = in.readInt();
-            if (magic != FILE_MAGIC) {
-                throw new ProtocolException("unexpected magic: " + magic);
-            }
-
-            final int version = in.readInt();
-            switch (version) {
-                case VERSION_UID_INIT: {
-                    // uid := size *(UID NetworkStatsHistory)
-
-                    // drop this data version, since we don't have a good
-                    // mapping into NetworkIdentitySet.
-                    break;
-                }
-                case VERSION_UID_WITH_IDENT: {
-                    // uid := size *(NetworkIdentitySet size *(UID NetworkStatsHistory))
-
-                    // drop this data version, since this version only existed
-                    // for a short time.
-                    break;
-                }
-                case VERSION_UID_WITH_TAG:
-                case VERSION_UID_WITH_SET: {
-                    // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory))
-                    final int identSize = in.readInt();
-                    for (int i = 0; i < identSize; i++) {
-                        final NetworkIdentitySet ident = new NetworkIdentitySet(in);
-
-                        final int size = in.readInt();
-                        for (int j = 0; j < size; j++) {
-                            final int uid = in.readInt();
-                            final int set = (version >= VERSION_UID_WITH_SET) ? in.readInt()
-                                    : SET_DEFAULT;
-                            final int tag = in.readInt();
-
-                            final Key key = new Key(ident, uid, set, tag);
-                            final NetworkStatsHistory history = new NetworkStatsHistory(in);
-
-                            if ((tag == TAG_NONE) != onlyTags) {
-                                recordHistory(key, history);
-                            }
-                        }
-                    }
-                    break;
-                }
-                default: {
-                    throw new ProtocolException("unexpected version: " + version);
-                }
-            }
-        } catch (FileNotFoundException e) {
-            // missing stats is okay, probably first boot
-        } finally {
-            IoUtils.closeQuietly(in);
-        }
-    }
-
-    /**
-     * Remove any {@link NetworkStatsHistory} attributed to the requested UID,
-     * moving any {@link NetworkStats#TAG_NONE} series to
-     * {@link TrafficStats#UID_REMOVED}.
-     * @hide
-     */
-    public void removeUids(int[] uids) {
-        final ArrayList<Key> knownKeys = new ArrayList<>();
-        knownKeys.addAll(mStats.keySet());
-
-        // migrate all UID stats into special "removed" bucket
-        for (Key key : knownKeys) {
-            if (CollectionUtils.contains(uids, key.uid)) {
-                // only migrate combined TAG_NONE history
-                if (key.tag == TAG_NONE) {
-                    final NetworkStatsHistory uidHistory = mStats.get(key);
-                    final NetworkStatsHistory removedHistory = findOrCreateHistory(
-                            key.ident, UID_REMOVED, SET_DEFAULT, TAG_NONE);
-                    removedHistory.recordEntireHistory(uidHistory);
-                }
-                mStats.remove(key);
-                mDirty = true;
-            }
-        }
-    }
-
-    private void noteRecordedHistory(long startMillis, long endMillis, long totalBytes) {
-        if (startMillis < mStartMillis) mStartMillis = startMillis;
-        if (endMillis > mEndMillis) mEndMillis = endMillis;
-        mTotalBytes += totalBytes;
-        mDirty = true;
-    }
-
-    private int estimateBuckets() {
-        return (int) (Math.min(mEndMillis - mStartMillis, WEEK_IN_MILLIS * 5)
-                / mBucketDuration);
-    }
-
-    private ArrayList<Key> getSortedKeys() {
-        final ArrayList<Key> keys = new ArrayList<>();
-        keys.addAll(mStats.keySet());
-        Collections.sort(keys, (left, right) -> Key.compare(left, right));
-        return keys;
-    }
-
-    /** @hide */
-    public void dump(IndentingPrintWriter pw) {
-        for (Key key : getSortedKeys()) {
-            pw.print("ident="); pw.print(key.ident.toString());
-            pw.print(" uid="); pw.print(key.uid);
-            pw.print(" set="); pw.print(NetworkStats.setToString(key.set));
-            pw.print(" tag="); pw.println(NetworkStats.tagToString(key.tag));
-
-            final NetworkStatsHistory history = mStats.get(key);
-            pw.increaseIndent();
-            history.dump(pw, true);
-            pw.decreaseIndent();
-        }
-    }
-
-    /** @hide */
-    public void dumpDebug(ProtoOutputStream proto, long tag) {
-        final long start = proto.start(tag);
-
-        for (Key key : getSortedKeys()) {
-            final long startStats = proto.start(NetworkStatsCollectionProto.STATS);
-
-            // Key
-            final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY);
-            key.ident.dumpDebug(proto, NetworkStatsCollectionKeyProto.IDENTITY);
-            proto.write(NetworkStatsCollectionKeyProto.UID, key.uid);
-            proto.write(NetworkStatsCollectionKeyProto.SET, key.set);
-            proto.write(NetworkStatsCollectionKeyProto.TAG, key.tag);
-            proto.end(startKey);
-
-            // Value
-            final NetworkStatsHistory history = mStats.get(key);
-            history.dumpDebug(proto, NetworkStatsCollectionStatsProto.HISTORY);
-            proto.end(startStats);
-        }
-
-        proto.end(start);
-    }
-
-    /** @hide */
-    public void dumpCheckin(PrintWriter pw, long start, long end) {
-        dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateMobileWildcard(), "cell");
-        dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateWifiWildcard(), "wifi");
-        dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateEthernet(), "eth");
-        dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateBluetooth(), "bt");
-    }
-
-    /**
-     * Dump all contained stats that match requested parameters, but group
-     * together all matching {@link NetworkTemplate} under a single prefix.
-     */
-    private void dumpCheckin(PrintWriter pw, long start, long end, NetworkTemplate groupTemplate,
-            String groupPrefix) {
-        final ArrayMap<Key, NetworkStatsHistory> grouped = new ArrayMap<>();
-
-        // Walk through all history, grouping by matching network templates
-        for (int i = 0; i < mStats.size(); i++) {
-            final Key key = mStats.keyAt(i);
-            final NetworkStatsHistory value = mStats.valueAt(i);
-
-            if (!templateMatches(groupTemplate, key.ident)) continue;
-            if (key.set >= NetworkStats.SET_DEBUG_START) continue;
-
-            final Key groupKey = new Key(null, key.uid, key.set, key.tag);
-            NetworkStatsHistory groupHistory = grouped.get(groupKey);
-            if (groupHistory == null) {
-                groupHistory = new NetworkStatsHistory(value.getBucketDuration());
-                grouped.put(groupKey, groupHistory);
-            }
-            groupHistory.recordHistory(value, start, end);
-        }
-
-        for (int i = 0; i < grouped.size(); i++) {
-            final Key key = grouped.keyAt(i);
-            final NetworkStatsHistory value = grouped.valueAt(i);
-
-            if (value.size() == 0) continue;
-
-            pw.print("c,");
-            pw.print(groupPrefix); pw.print(',');
-            pw.print(key.uid); pw.print(',');
-            pw.print(NetworkStats.setToCheckinString(key.set)); pw.print(',');
-            pw.print(key.tag);
-            pw.println();
-
-            value.dumpCheckin(pw);
-        }
-    }
-
-    /**
-     * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity}
-     * in the given {@link NetworkIdentitySet}.
-     */
-    private static boolean templateMatches(NetworkTemplate template, NetworkIdentitySet identSet) {
-        for (NetworkIdentity ident : identSet) {
-            if (template.matches(ident)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Get the all historical stats of the collection {@link NetworkStatsCollection}.
-     *
-     * @return All {@link NetworkStatsHistory} in this collection.
-     */
-    @NonNull
-    public Map<Key, NetworkStatsHistory> getEntries() {
-        return new ArrayMap(mStats);
-    }
-
-    /**
-     * Builder class for {@link NetworkStatsCollection}.
-     */
-    public static final class Builder {
-        private final long mBucketDuration;
-        private final ArrayMap<Key, NetworkStatsHistory> mEntries = new ArrayMap<>();
-
-        /**
-         * Creates a new Builder with given bucket duration.
-         *
-         * @param bucketDuration Duration of the buckets of the object, in milliseconds.
-         */
-        public Builder(long bucketDuration) {
-            mBucketDuration = bucketDuration;
-        }
-
-        /**
-         * Add association of the history with the specified key in this map.
-         *
-         * @param key The object used to identify a network, see {@link Key}.
-         * @param history {@link NetworkStatsHistory} instance associated to the given {@link Key}.
-         * @return The builder object.
-         */
-        @NonNull
-        public NetworkStatsCollection.Builder addEntry(@NonNull Key key,
-                @NonNull NetworkStatsHistory history) {
-            Objects.requireNonNull(key);
-            Objects.requireNonNull(history);
-            final List<Entry> historyEntries = history.getEntries();
-
-            final NetworkStatsHistory.Builder historyBuilder =
-                    new NetworkStatsHistory.Builder(mBucketDuration, historyEntries.size());
-            for (Entry entry : historyEntries) {
-                historyBuilder.addEntry(entry);
-            }
-
-            mEntries.put(key, historyBuilder.build());
-            return this;
-        }
-
-        /**
-         * Builds the instance of the {@link NetworkStatsCollection}.
-         *
-         * @return the built instance of {@link NetworkStatsCollection}.
-         */
-        @NonNull
-        public NetworkStatsCollection build() {
-            final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration);
-            for (int i = 0; i < mEntries.size(); i++) {
-                collection.recordHistory(mEntries.keyAt(i), mEntries.valueAt(i));
-            }
-            return collection;
-        }
-    }
-
-    /**
-     * the identifier that associate with the {@link NetworkStatsHistory} object to identify
-     * a certain record in the {@link NetworkStatsCollection} object.
-     */
-    public static class Key {
-        /** @hide */
-        public final NetworkIdentitySet ident;
-        /** @hide */
-        public final int uid;
-        /** @hide */
-        public final int set;
-        /** @hide */
-        public final int tag;
-
-        private final int mHashCode;
-
-        /**
-         * Construct a {@link Key} object.
-         *
-         * @param ident a Set of {@link NetworkIdentity} that associated with the record.
-         * @param uid Uid of the record.
-         * @param set Set of the record, see {@code NetworkStats#SET_*}.
-         * @param tag Tag of the record, see {@link TrafficStats#setThreadStatsTag(int)}.
-         */
-        public Key(@NonNull Set<NetworkIdentity> ident, int uid, int set, int tag) {
-            this(new NetworkIdentitySet(Objects.requireNonNull(ident)), uid, set, tag);
-        }
-
-        /** @hide */
-        public Key(@NonNull NetworkIdentitySet ident, int uid, int set, int tag) {
-            this.ident = Objects.requireNonNull(ident);
-            this.uid = uid;
-            this.set = set;
-            this.tag = tag;
-            mHashCode = Objects.hash(ident, uid, set, tag);
-        }
-
-        @Override
-        public int hashCode() {
-            return mHashCode;
-        }
-
-        @Override
-        public boolean equals(@Nullable Object obj) {
-            if (obj instanceof Key) {
-                final Key key = (Key) obj;
-                return uid == key.uid && set == key.set && tag == key.tag
-                        && Objects.equals(ident, key.ident);
-            }
-            return false;
-        }
-
-        /** @hide */
-        public static int compare(@NonNull Key left, @NonNull Key right) {
-            Objects.requireNonNull(left);
-            Objects.requireNonNull(right);
-            int res = 0;
-            if (left.ident != null && right.ident != null) {
-                res = NetworkIdentitySet.compare(left.ident, right.ident);
-            }
-            if (res == 0) {
-                res = Integer.compare(left.uid, right.uid);
-            }
-            if (res == 0) {
-                res = Integer.compare(left.set, right.set);
-            }
-            if (res == 0) {
-                res = Integer.compare(left.tag, right.tag);
-            }
-            return res;
-        }
-    }
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.aidl b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.aidl
deleted file mode 100644
index 8b9069f..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2011, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-parcelable NetworkStatsHistory;
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java
deleted file mode 100644
index 301fef9..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java
+++ /dev/null
@@ -1,1162 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-import static android.net.NetworkStats.IFACE_ALL;
-import static android.net.NetworkStats.SET_DEFAULT;
-import static android.net.NetworkStats.TAG_NONE;
-import static android.net.NetworkStats.UID_ALL;
-import static android.net.NetworkStatsHistory.DataStreamUtils.readFullLongArray;
-import static android.net.NetworkStatsHistory.DataStreamUtils.readVarLongArray;
-import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLongArray;
-import static android.net.NetworkStatsHistory.Entry.UNKNOWN;
-import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray;
-import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray;
-import static android.text.format.DateUtils.SECOND_IN_MILLIS;
-
-import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational;
-
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.service.NetworkStatsHistoryBucketProto;
-import android.service.NetworkStatsHistoryProto;
-import android.util.IndentingPrintWriter;
-import android.util.proto.ProtoOutputStream;
-
-import com.android.net.module.util.CollectionUtils;
-import com.android.net.module.util.NetworkStatsUtils;
-
-import libcore.util.EmptyArray;
-
-import java.io.CharArrayWriter;
-import java.io.DataInput;
-import java.io.DataOutput;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.net.ProtocolException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Random;
-
-/**
- * Collection of historical network statistics, recorded into equally-sized
- * "buckets" in time. Internally it stores data in {@code long} series for more
- * efficient persistence.
- * <p>
- * Each bucket is defined by a {@link #bucketStart} timestamp, and lasts for
- * {@link #bucketDuration}. Internally assumes that {@link #bucketStart} is
- * sorted at all times.
- *
- * @hide
- */
-@SystemApi(client = MODULE_LIBRARIES)
-public final class NetworkStatsHistory implements Parcelable {
-    private static final int VERSION_INIT = 1;
-    private static final int VERSION_ADD_PACKETS = 2;
-    private static final int VERSION_ADD_ACTIVE = 3;
-
-    /** @hide */
-    public static final int FIELD_ACTIVE_TIME = 0x01;
-    /** @hide */
-    public static final int FIELD_RX_BYTES = 0x02;
-    /** @hide */
-    public static final int FIELD_RX_PACKETS = 0x04;
-    /** @hide */
-    public static final int FIELD_TX_BYTES = 0x08;
-    /** @hide */
-    public static final int FIELD_TX_PACKETS = 0x10;
-    /** @hide */
-    public static final int FIELD_OPERATIONS = 0x20;
-    /** @hide */
-    public static final int FIELD_ALL = 0xFFFFFFFF;
-
-    private long bucketDuration;
-    private int bucketCount;
-    private long[] bucketStart;
-    private long[] activeTime;
-    private long[] rxBytes;
-    private long[] rxPackets;
-    private long[] txBytes;
-    private long[] txPackets;
-    private long[] operations;
-    private long totalBytes;
-
-    /** @hide */
-    public NetworkStatsHistory(long bucketDuration, long[] bucketStart, long[] activeTime,
-            long[] rxBytes, long[] rxPackets, long[] txBytes, long[] txPackets,
-            long[] operations, int bucketCount, long totalBytes) {
-        this.bucketDuration = bucketDuration;
-        this.bucketStart = bucketStart;
-        this.activeTime = activeTime;
-        this.rxBytes = rxBytes;
-        this.rxPackets = rxPackets;
-        this.txBytes = txBytes;
-        this.txPackets = txPackets;
-        this.operations = operations;
-        this.bucketCount = bucketCount;
-        this.totalBytes = totalBytes;
-    }
-
-    /**
-     * An instance to represent a single record in a {@link NetworkStatsHistory} object.
-     */
-    public static final class Entry {
-        /** @hide */
-        public static final long UNKNOWN = -1;
-
-        /** @hide */
-        // TODO: Migrate all callers to get duration from the history object and remove this field.
-        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-        public long bucketDuration;
-        /** @hide */
-        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-        public long bucketStart;
-        /** @hide */
-        public long activeTime;
-        /** @hide */
-        @UnsupportedAppUsage
-        public long rxBytes;
-        /** @hide */
-        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-        public long rxPackets;
-        /** @hide */
-        @UnsupportedAppUsage
-        public long txBytes;
-        /** @hide */
-        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-        public long txPackets;
-        /** @hide */
-        public long operations;
-        /** @hide */
-        Entry() {}
-
-        /**
-         * Construct a {@link Entry} instance to represent a single record in a
-         * {@link NetworkStatsHistory} object.
-         *
-         * @param bucketStart Start of period for this {@link Entry}, in milliseconds since the
-         *                    Unix epoch, see {@link java.lang.System#currentTimeMillis}.
-         * @param activeTime Active time for this {@link Entry}, in milliseconds.
-         * @param rxBytes Number of bytes received for this {@link Entry}. Statistics should
-         *                represent the contents of IP packets, including IP headers.
-         * @param rxPackets Number of packets received for this {@link Entry}. Statistics should
-         *                  represent the contents of IP packets, including IP headers.
-         * @param txBytes Number of bytes transmitted for this {@link Entry}. Statistics should
-         *                represent the contents of IP packets, including IP headers.
-         * @param txPackets Number of bytes transmitted for this {@link Entry}. Statistics should
-         *                  represent the contents of IP packets, including IP headers.
-         * @param operations count of network operations performed for this {@link Entry}. This can
-         *                   be used to derive bytes-per-operation.
-         */
-        public Entry(long bucketStart, long activeTime, long rxBytes,
-                long rxPackets, long txBytes, long txPackets, long operations) {
-            this.bucketStart = bucketStart;
-            this.activeTime = activeTime;
-            this.rxBytes = rxBytes;
-            this.rxPackets = rxPackets;
-            this.txBytes = txBytes;
-            this.txPackets = txPackets;
-            this.operations = operations;
-        }
-
-        /**
-         * Get start timestamp of the bucket's time interval, in milliseconds since the Unix epoch.
-         */
-        public long getBucketStart() {
-            return bucketStart;
-        }
-
-        /**
-         * Get active time of the bucket's time interval, in milliseconds.
-         */
-        public long getActiveTime() {
-            return activeTime;
-        }
-
-        /** Get number of bytes received for this {@link Entry}. */
-        public long getRxBytes() {
-            return rxBytes;
-        }
-
-        /** Get number of packets received for this {@link Entry}. */
-        public long getRxPackets() {
-            return rxPackets;
-        }
-
-        /** Get number of bytes transmitted for this {@link Entry}. */
-        public long getTxBytes() {
-            return txBytes;
-        }
-
-        /** Get number of packets transmitted for this {@link Entry}. */
-        public long getTxPackets() {
-            return txPackets;
-        }
-
-        /** Get count of network operations performed for this {@link Entry}. */
-        public long getOperations() {
-            return operations;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o.getClass() != getClass()) return false;
-            Entry entry = (Entry) o;
-            return bucketStart == entry.bucketStart
-                    && activeTime == entry.activeTime && rxBytes == entry.rxBytes
-                    && rxPackets == entry.rxPackets && txBytes == entry.txBytes
-                    && txPackets == entry.txPackets && operations == entry.operations;
-        }
-
-        @Override
-        public int hashCode() {
-            return (int) (bucketStart * 2
-                    + activeTime * 3
-                    + rxBytes * 5
-                    + rxPackets * 7
-                    + txBytes * 11
-                    + txPackets * 13
-                    + operations * 17);
-        }
-
-        @Override
-        public String toString() {
-            return "Entry{"
-                    + "bucketStart=" + bucketStart
-                    + ", activeTime=" + activeTime
-                    + ", rxBytes=" + rxBytes
-                    + ", rxPackets=" + rxPackets
-                    + ", txBytes=" + txBytes
-                    + ", txPackets=" + txPackets
-                    + ", operations=" + operations
-                    + "}";
-        }
-    }
-
-    /** @hide */
-    @UnsupportedAppUsage
-    public NetworkStatsHistory(long bucketDuration) {
-        this(bucketDuration, 10, FIELD_ALL);
-    }
-
-    /** @hide */
-    public NetworkStatsHistory(long bucketDuration, int initialSize) {
-        this(bucketDuration, initialSize, FIELD_ALL);
-    }
-
-    /** @hide */
-    public NetworkStatsHistory(long bucketDuration, int initialSize, int fields) {
-        this.bucketDuration = bucketDuration;
-        bucketStart = new long[initialSize];
-        if ((fields & FIELD_ACTIVE_TIME) != 0) activeTime = new long[initialSize];
-        if ((fields & FIELD_RX_BYTES) != 0) rxBytes = new long[initialSize];
-        if ((fields & FIELD_RX_PACKETS) != 0) rxPackets = new long[initialSize];
-        if ((fields & FIELD_TX_BYTES) != 0) txBytes = new long[initialSize];
-        if ((fields & FIELD_TX_PACKETS) != 0) txPackets = new long[initialSize];
-        if ((fields & FIELD_OPERATIONS) != 0) operations = new long[initialSize];
-        bucketCount = 0;
-        totalBytes = 0;
-    }
-
-    /** @hide */
-    public NetworkStatsHistory(NetworkStatsHistory existing, long bucketDuration) {
-        this(bucketDuration, existing.estimateResizeBuckets(bucketDuration));
-        recordEntireHistory(existing);
-    }
-
-    /** @hide */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public NetworkStatsHistory(Parcel in) {
-        bucketDuration = in.readLong();
-        bucketStart = readLongArray(in);
-        activeTime = readLongArray(in);
-        rxBytes = readLongArray(in);
-        rxPackets = readLongArray(in);
-        txBytes = readLongArray(in);
-        txPackets = readLongArray(in);
-        operations = readLongArray(in);
-        bucketCount = bucketStart.length;
-        totalBytes = in.readLong();
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel out, int flags) {
-        out.writeLong(bucketDuration);
-        writeLongArray(out, bucketStart, bucketCount);
-        writeLongArray(out, activeTime, bucketCount);
-        writeLongArray(out, rxBytes, bucketCount);
-        writeLongArray(out, rxPackets, bucketCount);
-        writeLongArray(out, txBytes, bucketCount);
-        writeLongArray(out, txPackets, bucketCount);
-        writeLongArray(out, operations, bucketCount);
-        out.writeLong(totalBytes);
-    }
-
-    /** @hide */
-    public NetworkStatsHistory(DataInput in) throws IOException {
-        final int version = in.readInt();
-        switch (version) {
-            case VERSION_INIT: {
-                bucketDuration = in.readLong();
-                bucketStart = readFullLongArray(in);
-                rxBytes = readFullLongArray(in);
-                rxPackets = new long[bucketStart.length];
-                txBytes = readFullLongArray(in);
-                txPackets = new long[bucketStart.length];
-                operations = new long[bucketStart.length];
-                bucketCount = bucketStart.length;
-                totalBytes = CollectionUtils.total(rxBytes) + CollectionUtils.total(txBytes);
-                break;
-            }
-            case VERSION_ADD_PACKETS:
-            case VERSION_ADD_ACTIVE: {
-                bucketDuration = in.readLong();
-                bucketStart = readVarLongArray(in);
-                activeTime = (version >= VERSION_ADD_ACTIVE) ? readVarLongArray(in)
-                        : new long[bucketStart.length];
-                rxBytes = readVarLongArray(in);
-                rxPackets = readVarLongArray(in);
-                txBytes = readVarLongArray(in);
-                txPackets = readVarLongArray(in);
-                operations = readVarLongArray(in);
-                bucketCount = bucketStart.length;
-                totalBytes = CollectionUtils.total(rxBytes) + CollectionUtils.total(txBytes);
-                break;
-            }
-            default: {
-                throw new ProtocolException("unexpected version: " + version);
-            }
-        }
-
-        if (bucketStart.length != bucketCount || rxBytes.length != bucketCount
-                || rxPackets.length != bucketCount || txBytes.length != bucketCount
-                || txPackets.length != bucketCount || operations.length != bucketCount) {
-            throw new ProtocolException("Mismatched history lengths");
-        }
-    }
-
-    /** @hide */
-    public void writeToStream(DataOutput out) throws IOException {
-        out.writeInt(VERSION_ADD_ACTIVE);
-        out.writeLong(bucketDuration);
-        writeVarLongArray(out, bucketStart, bucketCount);
-        writeVarLongArray(out, activeTime, bucketCount);
-        writeVarLongArray(out, rxBytes, bucketCount);
-        writeVarLongArray(out, rxPackets, bucketCount);
-        writeVarLongArray(out, txBytes, bucketCount);
-        writeVarLongArray(out, txPackets, bucketCount);
-        writeVarLongArray(out, operations, bucketCount);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    /** @hide */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public int size() {
-        return bucketCount;
-    }
-
-    /** @hide */
-    public long getBucketDuration() {
-        return bucketDuration;
-    }
-
-    /** @hide */
-    @UnsupportedAppUsage
-    public long getStart() {
-        if (bucketCount > 0) {
-            return bucketStart[0];
-        } else {
-            return Long.MAX_VALUE;
-        }
-    }
-
-    /** @hide */
-    @UnsupportedAppUsage
-    public long getEnd() {
-        if (bucketCount > 0) {
-            return bucketStart[bucketCount - 1] + bucketDuration;
-        } else {
-            return Long.MIN_VALUE;
-        }
-    }
-
-    /**
-     * Return total bytes represented by this history.
-     * @hide
-     */
-    public long getTotalBytes() {
-        return totalBytes;
-    }
-
-    /**
-     * Return index of bucket that contains or is immediately before the
-     * requested time.
-     * @hide
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public int getIndexBefore(long time) {
-        int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time);
-        if (index < 0) {
-            index = (~index) - 1;
-        } else {
-            index -= 1;
-        }
-        return NetworkStatsUtils.constrain(index, 0, bucketCount - 1);
-    }
-
-    /**
-     * Return index of bucket that contains or is immediately after the
-     * requested time.
-     * @hide
-     */
-    public int getIndexAfter(long time) {
-        int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time);
-        if (index < 0) {
-            index = ~index;
-        } else {
-            index += 1;
-        }
-        return NetworkStatsUtils.constrain(index, 0, bucketCount - 1);
-    }
-
-    /**
-     * Return specific stats entry.
-     * @hide
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public Entry getValues(int i, Entry recycle) {
-        final Entry entry = recycle != null ? recycle : new Entry();
-        entry.bucketStart = bucketStart[i];
-        entry.bucketDuration = bucketDuration;
-        entry.activeTime = getLong(activeTime, i, UNKNOWN);
-        entry.rxBytes = getLong(rxBytes, i, UNKNOWN);
-        entry.rxPackets = getLong(rxPackets, i, UNKNOWN);
-        entry.txBytes = getLong(txBytes, i, UNKNOWN);
-        entry.txPackets = getLong(txPackets, i, UNKNOWN);
-        entry.operations = getLong(operations, i, UNKNOWN);
-        return entry;
-    }
-
-    /**
-     * Get List of {@link Entry} of the {@link NetworkStatsHistory} instance.
-     *
-     * @return
-     */
-    @NonNull
-    public List<Entry> getEntries() {
-        // TODO: Return a wrapper that uses this list instead, to prevent the returned result
-        //  from being changed.
-        final ArrayList<Entry> ret = new ArrayList<>(size());
-        for (int i = 0; i < size(); i++) {
-            ret.add(getValues(i, null /* recycle */));
-        }
-        return ret;
-    }
-
-    /** @hide */
-    public void setValues(int i, Entry entry) {
-        // Unwind old values
-        if (rxBytes != null) totalBytes -= rxBytes[i];
-        if (txBytes != null) totalBytes -= txBytes[i];
-
-        bucketStart[i] = entry.bucketStart;
-        setLong(activeTime, i, entry.activeTime);
-        setLong(rxBytes, i, entry.rxBytes);
-        setLong(rxPackets, i, entry.rxPackets);
-        setLong(txBytes, i, entry.txBytes);
-        setLong(txPackets, i, entry.txPackets);
-        setLong(operations, i, entry.operations);
-
-        // Apply new values
-        if (rxBytes != null) totalBytes += rxBytes[i];
-        if (txBytes != null) totalBytes += txBytes[i];
-    }
-
-    /**
-     * Record that data traffic occurred in the given time range. Will
-     * distribute across internal buckets, creating new buckets as needed.
-     * @hide
-     */
-    @Deprecated
-    public void recordData(long start, long end, long rxBytes, long txBytes) {
-        recordData(start, end, new NetworkStats.Entry(
-                IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, 0L, txBytes, 0L, 0L));
-    }
-
-    /**
-     * Record that data traffic occurred in the given time range. Will
-     * distribute across internal buckets, creating new buckets as needed.
-     * @hide
-     */
-    public void recordData(long start, long end, NetworkStats.Entry entry) {
-        long rxBytes = entry.rxBytes;
-        long rxPackets = entry.rxPackets;
-        long txBytes = entry.txBytes;
-        long txPackets = entry.txPackets;
-        long operations = entry.operations;
-
-        if (entry.isNegative()) {
-            throw new IllegalArgumentException("tried recording negative data");
-        }
-        if (entry.isEmpty()) {
-            return;
-        }
-
-        // create any buckets needed by this range
-        ensureBuckets(start, end);
-        // Return fast if there is still no entry. This would typically happen when the start,
-        // end or duration are not valid values, e.g. start > end, negative duration value, etc.
-        if (bucketCount == 0) return;
-
-        // distribute data usage into buckets
-        long duration = end - start;
-        final int startIndex = getIndexAfter(end);
-        for (int i = startIndex; i >= 0; i--) {
-            final long curStart = bucketStart[i];
-            final long curEnd = curStart + bucketDuration;
-
-            // bucket is older than record; we're finished
-            if (curEnd < start) break;
-            // bucket is newer than record; keep looking
-            if (curStart > end) continue;
-
-            final long overlap = Math.min(curEnd, end) - Math.max(curStart, start);
-            if (overlap <= 0) continue;
-
-            // integer math each time is faster than floating point
-            final long fracRxBytes = multiplySafeByRational(rxBytes, overlap, duration);
-            final long fracRxPackets = multiplySafeByRational(rxPackets, overlap, duration);
-            final long fracTxBytes = multiplySafeByRational(txBytes, overlap, duration);
-            final long fracTxPackets = multiplySafeByRational(txPackets, overlap, duration);
-            final long fracOperations = multiplySafeByRational(operations, overlap, duration);
-
-
-            addLong(activeTime, i, overlap);
-            addLong(this.rxBytes, i, fracRxBytes); rxBytes -= fracRxBytes;
-            addLong(this.rxPackets, i, fracRxPackets); rxPackets -= fracRxPackets;
-            addLong(this.txBytes, i, fracTxBytes); txBytes -= fracTxBytes;
-            addLong(this.txPackets, i, fracTxPackets); txPackets -= fracTxPackets;
-            addLong(this.operations, i, fracOperations); operations -= fracOperations;
-
-            duration -= overlap;
-        }
-
-        totalBytes += entry.rxBytes + entry.txBytes;
-    }
-
-    /**
-     * Record an entire {@link NetworkStatsHistory} into this history. Usually
-     * for combining together stats for external reporting.
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public void recordEntireHistory(NetworkStatsHistory input) {
-        recordHistory(input, Long.MIN_VALUE, Long.MAX_VALUE);
-    }
-
-    /**
-     * Record given {@link NetworkStatsHistory} into this history, copying only
-     * buckets that atomically occur in the inclusive time range. Doesn't
-     * interpolate across partial buckets.
-     * @hide
-     */
-    public void recordHistory(NetworkStatsHistory input, long start, long end) {
-        final NetworkStats.Entry entry = new NetworkStats.Entry(
-                IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
-        for (int i = 0; i < input.bucketCount; i++) {
-            final long bucketStart = input.bucketStart[i];
-            final long bucketEnd = bucketStart + input.bucketDuration;
-
-            // skip when bucket is outside requested range
-            if (bucketStart < start || bucketEnd > end) continue;
-
-            entry.rxBytes = getLong(input.rxBytes, i, 0L);
-            entry.rxPackets = getLong(input.rxPackets, i, 0L);
-            entry.txBytes = getLong(input.txBytes, i, 0L);
-            entry.txPackets = getLong(input.txPackets, i, 0L);
-            entry.operations = getLong(input.operations, i, 0L);
-
-            recordData(bucketStart, bucketEnd, entry);
-        }
-    }
-
-    /**
-     * Ensure that buckets exist for given time range, creating as needed.
-     */
-    private void ensureBuckets(long start, long end) {
-        // normalize incoming range to bucket boundaries
-        start -= start % bucketDuration;
-        end += (bucketDuration - (end % bucketDuration)) % bucketDuration;
-
-        for (long now = start; now < end; now += bucketDuration) {
-            // try finding existing bucket
-            final int index = Arrays.binarySearch(bucketStart, 0, bucketCount, now);
-            if (index < 0) {
-                // bucket missing, create and insert
-                insertBucket(~index, now);
-            }
-        }
-    }
-
-    /**
-     * Insert new bucket at requested index and starting time.
-     */
-    private void insertBucket(int index, long start) {
-        // create more buckets when needed
-        if (bucketCount >= bucketStart.length) {
-            final int newLength = Math.max(bucketStart.length, 10) * 3 / 2;
-            bucketStart = Arrays.copyOf(bucketStart, newLength);
-            if (activeTime != null) activeTime = Arrays.copyOf(activeTime, newLength);
-            if (rxBytes != null) rxBytes = Arrays.copyOf(rxBytes, newLength);
-            if (rxPackets != null) rxPackets = Arrays.copyOf(rxPackets, newLength);
-            if (txBytes != null) txBytes = Arrays.copyOf(txBytes, newLength);
-            if (txPackets != null) txPackets = Arrays.copyOf(txPackets, newLength);
-            if (operations != null) operations = Arrays.copyOf(operations, newLength);
-        }
-
-        // create gap when inserting bucket in middle
-        if (index < bucketCount) {
-            final int dstPos = index + 1;
-            final int length = bucketCount - index;
-
-            System.arraycopy(bucketStart, index, bucketStart, dstPos, length);
-            if (activeTime != null) System.arraycopy(activeTime, index, activeTime, dstPos, length);
-            if (rxBytes != null) System.arraycopy(rxBytes, index, rxBytes, dstPos, length);
-            if (rxPackets != null) System.arraycopy(rxPackets, index, rxPackets, dstPos, length);
-            if (txBytes != null) System.arraycopy(txBytes, index, txBytes, dstPos, length);
-            if (txPackets != null) System.arraycopy(txPackets, index, txPackets, dstPos, length);
-            if (operations != null) System.arraycopy(operations, index, operations, dstPos, length);
-        }
-
-        bucketStart[index] = start;
-        setLong(activeTime, index, 0L);
-        setLong(rxBytes, index, 0L);
-        setLong(rxPackets, index, 0L);
-        setLong(txBytes, index, 0L);
-        setLong(txPackets, index, 0L);
-        setLong(operations, index, 0L);
-        bucketCount++;
-    }
-
-    /**
-     * Clear all data stored in this object.
-     * @hide
-     */
-    public void clear() {
-        bucketStart = EmptyArray.LONG;
-        if (activeTime != null) activeTime = EmptyArray.LONG;
-        if (rxBytes != null) rxBytes = EmptyArray.LONG;
-        if (rxPackets != null) rxPackets = EmptyArray.LONG;
-        if (txBytes != null) txBytes = EmptyArray.LONG;
-        if (txPackets != null) txPackets = EmptyArray.LONG;
-        if (operations != null) operations = EmptyArray.LONG;
-        bucketCount = 0;
-        totalBytes = 0;
-    }
-
-    /**
-     * Remove buckets older than requested cutoff.
-     * @hide
-     */
-    public void removeBucketsBefore(long cutoff) {
-        // TODO: Consider use getIndexBefore.
-        int i;
-        for (i = 0; i < bucketCount; i++) {
-            final long curStart = bucketStart[i];
-            final long curEnd = curStart + bucketDuration;
-
-            // cutoff happens before or during this bucket; everything before
-            // this bucket should be removed.
-            if (curEnd > cutoff) break;
-        }
-
-        if (i > 0) {
-            final int length = bucketStart.length;
-            bucketStart = Arrays.copyOfRange(bucketStart, i, length);
-            if (activeTime != null) activeTime = Arrays.copyOfRange(activeTime, i, length);
-            if (rxBytes != null) rxBytes = Arrays.copyOfRange(rxBytes, i, length);
-            if (rxPackets != null) rxPackets = Arrays.copyOfRange(rxPackets, i, length);
-            if (txBytes != null) txBytes = Arrays.copyOfRange(txBytes, i, length);
-            if (txPackets != null) txPackets = Arrays.copyOfRange(txPackets, i, length);
-            if (operations != null) operations = Arrays.copyOfRange(operations, i, length);
-            bucketCount -= i;
-
-            totalBytes = 0;
-            if (rxBytes != null) totalBytes += CollectionUtils.total(rxBytes);
-            if (txBytes != null) totalBytes += CollectionUtils.total(txBytes);
-        }
-    }
-
-    /**
-     * Return interpolated data usage across the requested range. Interpolates
-     * across buckets, so values may be rounded slightly.
-     *
-     * <p>If the active bucket is not completed yet, it returns the proportional value of it
-     * based on its duration and the {@code end} param.
-     *
-     * @param start - start of the range, timestamp in milliseconds since the epoch.
-     * @param end - end of the range, timestamp in milliseconds since the epoch.
-     * @param recycle - entry instance for performance, could be null.
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public Entry getValues(long start, long end, Entry recycle) {
-        return getValues(start, end, Long.MAX_VALUE, recycle);
-    }
-
-    /**
-     * Return interpolated data usage across the requested range. Interpolates
-     * across buckets, so values may be rounded slightly.
-     *
-     * @param start - start of the range, timestamp in milliseconds since the epoch.
-     * @param end - end of the range, timestamp in milliseconds since the epoch.
-     * @param now - current timestamp in milliseconds since the epoch (wall clock).
-     * @param recycle - entry instance for performance, could be null.
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public Entry getValues(long start, long end, long now, Entry recycle) {
-        final Entry entry = recycle != null ? recycle : new Entry();
-        entry.bucketDuration = end - start;
-        entry.bucketStart = start;
-        entry.activeTime = activeTime != null ? 0 : UNKNOWN;
-        entry.rxBytes = rxBytes != null ? 0 : UNKNOWN;
-        entry.rxPackets = rxPackets != null ? 0 : UNKNOWN;
-        entry.txBytes = txBytes != null ? 0 : UNKNOWN;
-        entry.txPackets = txPackets != null ? 0 : UNKNOWN;
-        entry.operations = operations != null ? 0 : UNKNOWN;
-
-        // Return fast if there is no entry.
-        if (bucketCount == 0) return entry;
-
-        final int startIndex = getIndexAfter(end);
-        for (int i = startIndex; i >= 0; i--) {
-            final long curStart = bucketStart[i];
-            long curEnd = curStart + bucketDuration;
-
-            // bucket is older than request; we're finished
-            if (curEnd <= start) break;
-            // bucket is newer than request; keep looking
-            if (curStart >= end) continue;
-
-            // the active bucket is shorter then a normal completed bucket
-            if (curEnd > now) curEnd = now;
-            // usually this is simply bucketDuration
-            final long bucketSpan = curEnd - curStart;
-            // prevent division by zero
-            if (bucketSpan <= 0) continue;
-
-            final long overlapEnd = curEnd < end ? curEnd : end;
-            final long overlapStart = curStart > start ? curStart : start;
-            final long overlap = overlapEnd - overlapStart;
-            if (overlap <= 0) continue;
-
-            // integer math each time is faster than floating point
-            if (activeTime != null) {
-                entry.activeTime += multiplySafeByRational(activeTime[i], overlap, bucketSpan);
-            }
-            if (rxBytes != null) {
-                entry.rxBytes += multiplySafeByRational(rxBytes[i], overlap, bucketSpan);
-            }
-            if (rxPackets != null) {
-                entry.rxPackets += multiplySafeByRational(rxPackets[i], overlap, bucketSpan);
-            }
-            if (txBytes != null) {
-                entry.txBytes += multiplySafeByRational(txBytes[i], overlap, bucketSpan);
-            }
-            if (txPackets != null) {
-                entry.txPackets += multiplySafeByRational(txPackets[i], overlap, bucketSpan);
-            }
-            if (operations != null) {
-                entry.operations += multiplySafeByRational(operations[i], overlap, bucketSpan);
-            }
-        }
-        return entry;
-    }
-
-    /**
-     * @deprecated only for temporary testing
-     * @hide
-     */
-    @Deprecated
-    public void generateRandom(long start, long end, long bytes) {
-        final Random r = new Random();
-
-        final float fractionRx = r.nextFloat();
-        final long rxBytes = (long) (bytes * fractionRx);
-        final long txBytes = (long) (bytes * (1 - fractionRx));
-
-        final long rxPackets = rxBytes / 1024;
-        final long txPackets = txBytes / 1024;
-        final long operations = rxBytes / 2048;
-
-        generateRandom(start, end, rxBytes, rxPackets, txBytes, txPackets, operations, r);
-    }
-
-    /**
-     * @deprecated only for temporary testing
-     * @hide
-     */
-    @Deprecated
-    public void generateRandom(long start, long end, long rxBytes, long rxPackets, long txBytes,
-            long txPackets, long operations, Random r) {
-        ensureBuckets(start, end);
-
-        final NetworkStats.Entry entry = new NetworkStats.Entry(
-                IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
-        while (rxBytes > 1024 || rxPackets > 128 || txBytes > 1024 || txPackets > 128
-                || operations > 32) {
-            final long curStart = randomLong(r, start, end);
-            final long curEnd = curStart + randomLong(r, 0, (end - curStart) / 2);
-
-            entry.rxBytes = randomLong(r, 0, rxBytes);
-            entry.rxPackets = randomLong(r, 0, rxPackets);
-            entry.txBytes = randomLong(r, 0, txBytes);
-            entry.txPackets = randomLong(r, 0, txPackets);
-            entry.operations = randomLong(r, 0, operations);
-
-            rxBytes -= entry.rxBytes;
-            rxPackets -= entry.rxPackets;
-            txBytes -= entry.txBytes;
-            txPackets -= entry.txPackets;
-            operations -= entry.operations;
-
-            recordData(curStart, curEnd, entry);
-        }
-    }
-
-    /** @hide */
-    public static long randomLong(Random r, long start, long end) {
-        return (long) (start + (r.nextFloat() * (end - start)));
-    }
-
-    /**
-     * Quickly determine if this history intersects with given window.
-     * @hide
-     */
-    public boolean intersects(long start, long end) {
-        final long dataStart = getStart();
-        final long dataEnd = getEnd();
-        if (start >= dataStart && start <= dataEnd) return true;
-        if (end >= dataStart && end <= dataEnd) return true;
-        if (dataStart >= start && dataStart <= end) return true;
-        if (dataEnd >= start && dataEnd <= end) return true;
-        return false;
-    }
-
-    /** @hide */
-    public void dump(IndentingPrintWriter pw, boolean fullHistory) {
-        pw.print("NetworkStatsHistory: bucketDuration=");
-        pw.println(bucketDuration / SECOND_IN_MILLIS);
-        pw.increaseIndent();
-
-        final int start = fullHistory ? 0 : Math.max(0, bucketCount - 32);
-        if (start > 0) {
-            pw.print("(omitting "); pw.print(start); pw.println(" buckets)");
-        }
-
-        for (int i = start; i < bucketCount; i++) {
-            pw.print("st="); pw.print(bucketStart[i] / SECOND_IN_MILLIS);
-            if (rxBytes != null) { pw.print(" rb="); pw.print(rxBytes[i]); }
-            if (rxPackets != null) { pw.print(" rp="); pw.print(rxPackets[i]); }
-            if (txBytes != null) { pw.print(" tb="); pw.print(txBytes[i]); }
-            if (txPackets != null) { pw.print(" tp="); pw.print(txPackets[i]); }
-            if (operations != null) { pw.print(" op="); pw.print(operations[i]); }
-            pw.println();
-        }
-
-        pw.decreaseIndent();
-    }
-
-    /** @hide */
-    public void dumpCheckin(PrintWriter pw) {
-        pw.print("d,");
-        pw.print(bucketDuration / SECOND_IN_MILLIS);
-        pw.println();
-
-        for (int i = 0; i < bucketCount; i++) {
-            pw.print("b,");
-            pw.print(bucketStart[i] / SECOND_IN_MILLIS); pw.print(',');
-            if (rxBytes != null) { pw.print(rxBytes[i]); } else { pw.print("*"); } pw.print(',');
-            if (rxPackets != null) { pw.print(rxPackets[i]); } else { pw.print("*"); } pw.print(',');
-            if (txBytes != null) { pw.print(txBytes[i]); } else { pw.print("*"); } pw.print(',');
-            if (txPackets != null) { pw.print(txPackets[i]); } else { pw.print("*"); } pw.print(',');
-            if (operations != null) { pw.print(operations[i]); } else { pw.print("*"); }
-            pw.println();
-        }
-    }
-
-    /** @hide */
-    public void dumpDebug(ProtoOutputStream proto, long tag) {
-        final long start = proto.start(tag);
-
-        proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS, bucketDuration);
-
-        for (int i = 0; i < bucketCount; i++) {
-            final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS);
-
-            proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS,
-                    bucketStart[i]);
-            dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_BYTES, rxBytes, i);
-            dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_PACKETS, rxPackets, i);
-            dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_BYTES, txBytes, i);
-            dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_PACKETS, txPackets, i);
-            dumpDebug(proto, NetworkStatsHistoryBucketProto.OPERATIONS, operations, i);
-
-            proto.end(startBucket);
-        }
-
-        proto.end(start);
-    }
-
-    private static void dumpDebug(ProtoOutputStream proto, long tag, long[] array, int index) {
-        if (array != null) {
-            proto.write(tag, array[index]);
-        }
-    }
-
-    @Override
-    public String toString() {
-        final CharArrayWriter writer = new CharArrayWriter();
-        dump(new IndentingPrintWriter(writer, "  "), false);
-        return writer.toString();
-    }
-
-    @UnsupportedAppUsage
-    public static final @android.annotation.NonNull Creator<NetworkStatsHistory> CREATOR = new Creator<NetworkStatsHistory>() {
-        @Override
-        public NetworkStatsHistory createFromParcel(Parcel in) {
-            return new NetworkStatsHistory(in);
-        }
-
-        @Override
-        public NetworkStatsHistory[] newArray(int size) {
-            return new NetworkStatsHistory[size];
-        }
-    };
-
-    private static long getLong(long[] array, int i, long value) {
-        return array != null ? array[i] : value;
-    }
-
-    private static void setLong(long[] array, int i, long value) {
-        if (array != null) array[i] = value;
-    }
-
-    private static void addLong(long[] array, int i, long value) {
-        if (array != null) array[i] += value;
-    }
-
-    /** @hide */
-    public int estimateResizeBuckets(long newBucketDuration) {
-        return (int) (size() * getBucketDuration() / newBucketDuration);
-    }
-
-    /**
-     * Utility methods for interacting with {@link DataInputStream} and
-     * {@link DataOutputStream}, mostly dealing with writing partial arrays.
-     * @hide
-     */
-    public static class DataStreamUtils {
-        @Deprecated
-        public static long[] readFullLongArray(DataInput in) throws IOException {
-            final int size = in.readInt();
-            if (size < 0) throw new ProtocolException("negative array size");
-            final long[] values = new long[size];
-            for (int i = 0; i < values.length; i++) {
-                values[i] = in.readLong();
-            }
-            return values;
-        }
-
-        /**
-         * Read variable-length {@link Long} using protobuf-style approach.
-         */
-        public static long readVarLong(DataInput in) throws IOException {
-            int shift = 0;
-            long result = 0;
-            while (shift < 64) {
-                byte b = in.readByte();
-                result |= (long) (b & 0x7F) << shift;
-                if ((b & 0x80) == 0)
-                    return result;
-                shift += 7;
-            }
-            throw new ProtocolException("malformed long");
-        }
-
-        /**
-         * Write variable-length {@link Long} using protobuf-style approach.
-         */
-        public static void writeVarLong(DataOutput out, long value) throws IOException {
-            while (true) {
-                if ((value & ~0x7FL) == 0) {
-                    out.writeByte((int) value);
-                    return;
-                } else {
-                    out.writeByte(((int) value & 0x7F) | 0x80);
-                    value >>>= 7;
-                }
-            }
-        }
-
-        public static long[] readVarLongArray(DataInput in) throws IOException {
-            final int size = in.readInt();
-            if (size == -1) return null;
-            if (size < 0) throw new ProtocolException("negative array size");
-            final long[] values = new long[size];
-            for (int i = 0; i < values.length; i++) {
-                values[i] = readVarLong(in);
-            }
-            return values;
-        }
-
-        public static void writeVarLongArray(DataOutput out, long[] values, int size)
-                throws IOException {
-            if (values == null) {
-                out.writeInt(-1);
-                return;
-            }
-            if (size > values.length) {
-                throw new IllegalArgumentException("size larger than length");
-            }
-            out.writeInt(size);
-            for (int i = 0; i < size; i++) {
-                writeVarLong(out, values[i]);
-            }
-        }
-    }
-
-    /**
-     * Utility methods for interacting with {@link Parcel} structures, mostly
-     * dealing with writing partial arrays.
-     * @hide
-     */
-    public static class ParcelUtils {
-        public static long[] readLongArray(Parcel in) {
-            final int size = in.readInt();
-            if (size == -1) return null;
-            final long[] values = new long[size];
-            for (int i = 0; i < values.length; i++) {
-                values[i] = in.readLong();
-            }
-            return values;
-        }
-
-        public static void writeLongArray(Parcel out, long[] values, int size) {
-            if (values == null) {
-                out.writeInt(-1);
-                return;
-            }
-            if (size > values.length) {
-                throw new IllegalArgumentException("size larger than length");
-            }
-            out.writeInt(size);
-            for (int i = 0; i < size; i++) {
-                out.writeLong(values[i]);
-            }
-        }
-    }
-
-    /**
-     * Builder class for {@link NetworkStatsHistory}.
-     */
-    public static final class Builder {
-        private final long mBucketDuration;
-        private final List<Long> mBucketStart;
-        private final List<Long> mActiveTime;
-        private final List<Long> mRxBytes;
-        private final List<Long> mRxPackets;
-        private final List<Long> mTxBytes;
-        private final List<Long> mTxPackets;
-        private final List<Long> mOperations;
-
-        /**
-         * Creates a new Builder with given bucket duration and initial capacity to construct
-         * {@link NetworkStatsHistory} objects.
-         *
-         * @param bucketDuration Duration of the buckets of the object, in milliseconds.
-         * @param initialCapacity Estimated number of records.
-         */
-        public Builder(long bucketDuration, int initialCapacity) {
-            mBucketDuration = bucketDuration;
-            mBucketStart = new ArrayList<>(initialCapacity);
-            mActiveTime = new ArrayList<>(initialCapacity);
-            mRxBytes = new ArrayList<>(initialCapacity);
-            mRxPackets = new ArrayList<>(initialCapacity);
-            mTxBytes = new ArrayList<>(initialCapacity);
-            mTxPackets = new ArrayList<>(initialCapacity);
-            mOperations = new ArrayList<>(initialCapacity);
-        }
-
-        /**
-         * Add an {@link Entry} into the {@link NetworkStatsHistory} instance.
-         *
-         * @param entry The target {@link Entry} object.
-         * @return The builder object.
-         */
-        @NonNull
-        public Builder addEntry(@NonNull Entry entry) {
-            mBucketStart.add(entry.bucketStart);
-            mActiveTime.add(entry.activeTime);
-            mRxBytes.add(entry.rxBytes);
-            mRxPackets.add(entry.rxPackets);
-            mTxBytes.add(entry.txBytes);
-            mTxPackets.add(entry.txPackets);
-            mOperations.add(entry.operations);
-            return this;
-        }
-
-        private static long sum(@NonNull List<Long> list) {
-            long sum = 0;
-            for (long entry : list) {
-                sum += entry;
-            }
-            return sum;
-        }
-
-        /**
-         * Builds the instance of the {@link NetworkStatsHistory}.
-         *
-         * @return the built instance of {@link NetworkStatsHistory}.
-         */
-        @NonNull
-        public NetworkStatsHistory build() {
-            return new NetworkStatsHistory(mBucketDuration,
-                    CollectionUtils.toLongArray(mBucketStart),
-                    CollectionUtils.toLongArray(mActiveTime),
-                    CollectionUtils.toLongArray(mRxBytes),
-                    CollectionUtils.toLongArray(mRxPackets),
-                    CollectionUtils.toLongArray(mTxBytes),
-                    CollectionUtils.toLongArray(mTxPackets),
-                    CollectionUtils.toLongArray(mOperations),
-                    mBucketStart.size(),
-                    sum(mRxBytes) + sum(mTxBytes));
-        }
-    }
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java
deleted file mode 100644
index 7b5afd7..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java
+++ /dev/null
@@ -1,1119 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
-import static android.net.ConnectivityManager.TYPE_ETHERNET;
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_PROXY;
-import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
-import static android.net.ConnectivityManager.TYPE_WIMAX;
-import static android.net.NetworkIdentity.OEM_NONE;
-import static android.net.NetworkIdentity.OEM_PAID;
-import static android.net.NetworkIdentity.OEM_PRIVATE;
-import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
-import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
-import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
-import static android.net.NetworkStats.METERED_ALL;
-import static android.net.NetworkStats.METERED_NO;
-import static android.net.NetworkStats.METERED_YES;
-import static android.net.NetworkStats.ROAMING_ALL;
-import static android.net.NetworkStats.ROAMING_NO;
-import static android.net.NetworkStats.ROAMING_YES;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.app.usage.NetworkStatsManager;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.net.wifi.WifiInfo;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-import android.util.ArraySet;
-
-import com.android.net.module.util.CollectionUtils;
-import com.android.net.module.util.NetworkIdentityUtils;
-import com.android.net.module.util.NetworkStatsUtils;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-/**
- * Predicate used to match {@link NetworkIdentity}, usually when collecting
- * statistics. (It should probably have been named {@code NetworkPredicate}.)
- *
- * @hide
- */
-@SystemApi(client = MODULE_LIBRARIES)
-public final class NetworkTemplate implements Parcelable {
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = { "MATCH_" }, value = {
-            MATCH_MOBILE,
-            MATCH_WIFI,
-            MATCH_ETHERNET,
-            MATCH_BLUETOOTH,
-            MATCH_PROXY,
-            MATCH_CARRIER,
-    })
-    public @interface TemplateMatchRule{}
-
-    /** Match rule to match cellular networks with given Subscriber Ids. */
-    public static final int MATCH_MOBILE = 1;
-    /** Match rule to match wifi networks. */
-    public static final int MATCH_WIFI = 4;
-    /** Match rule to match ethernet networks. */
-    public static final int MATCH_ETHERNET = 5;
-    /**
-     * Match rule to match all cellular networks.
-     *
-     * @hide
-     */
-    public static final int MATCH_MOBILE_WILDCARD = 6;
-    /**
-     * Match rule to match all wifi networks.
-     *
-     * @hide
-     */
-    public static final int MATCH_WIFI_WILDCARD = 7;
-    /** Match rule to match bluetooth networks. */
-    public static final int MATCH_BLUETOOTH = 8;
-    /**
-     * Match rule to match networks with {@link ConnectivityManager#TYPE_PROXY} as the legacy
-     * network type.
-     */
-    public static final int MATCH_PROXY = 9;
-    /**
-     * Match rule to match all networks with subscriberId inside the template. Some carriers
-     * may offer non-cellular networks like WiFi, which will be matched by this rule.
-     */
-    public static final int MATCH_CARRIER = 10;
-
-    // TODO: Remove this and replace all callers with WIFI_NETWORK_KEY_ALL.
-    /** @hide */
-    public static final String WIFI_NETWORKID_ALL = null;
-
-    /**
-     * Wi-Fi Network Key is never supposed to be null (if it is, it is a bug that
-     * should be fixed), so it's not possible to want to match null vs
-     * non-null. Therefore it's fine to use null as a sentinel for Wifi Network Key.
-     *
-     * @hide
-     */
-    public static final String WIFI_NETWORK_KEY_ALL = WIFI_NETWORKID_ALL;
-
-    /**
-     * Include all network types when filtering. This is meant to merge in with the
-     * {@code TelephonyManager.NETWORK_TYPE_*} constants, and thus needs to stay in sync.
-     */
-    public static final int NETWORK_TYPE_ALL = -1;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = { "OEM_MANAGED_" }, value = {
-            OEM_MANAGED_ALL,
-            OEM_MANAGED_NO,
-            OEM_MANAGED_YES,
-            OEM_MANAGED_PAID,
-            OEM_MANAGED_PRIVATE
-    })
-    public @interface OemManaged{}
-
-    /**
-     * Value to match both OEM managed and unmanaged networks (all networks).
-     */
-    public static final int OEM_MANAGED_ALL = -1;
-    /**
-     * Value to match networks which are not OEM managed.
-     */
-    public static final int OEM_MANAGED_NO = OEM_NONE;
-    /**
-     * Value to match any OEM managed network.
-     */
-    public static final int OEM_MANAGED_YES = -2;
-    /**
-     * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID}.
-     */
-    public static final int OEM_MANAGED_PAID = OEM_PAID;
-    /**
-     * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PRIVATE}.
-     */
-    public static final int OEM_MANAGED_PRIVATE = OEM_PRIVATE;
-
-    private static boolean isKnownMatchRule(final int rule) {
-        switch (rule) {
-            case MATCH_MOBILE:
-            case MATCH_WIFI:
-            case MATCH_ETHERNET:
-            case MATCH_MOBILE_WILDCARD:
-            case MATCH_WIFI_WILDCARD:
-            case MATCH_BLUETOOTH:
-            case MATCH_PROXY:
-            case MATCH_CARRIER:
-                return true;
-
-            default:
-                return false;
-        }
-    }
-
-    /**
-     * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
-     * the given IMSI.
-     *
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public static NetworkTemplate buildTemplateMobileAll(String subscriberId) {
-        return new NetworkTemplate(MATCH_MOBILE, subscriberId, null);
-    }
-
-    /**
-     * Template to match cellular networks with the given IMSI, {@code ratType} and
-     * {@code metered}. Use {@link #NETWORK_TYPE_ALL} to include all network types when
-     * filtering. See {@code TelephonyManager.NETWORK_TYPE_*}.
-     *
-     * @hide
-     */
-    public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId,
-            int ratType, int metered) {
-        if (TextUtils.isEmpty(subscriberId)) {
-            return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null /* subscriberId */,
-                    null /* matchSubscriberIds */,
-                    new String[0] /* matchWifiNetworkKeys */, metered, ROAMING_ALL,
-                    DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
-                    NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
-        }
-        return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[] { subscriberId },
-                new String[0] /* matchWifiNetworkKeys */,
-                metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
-                NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
-    }
-
-    /**
-     * Template to match metered {@link ConnectivityManager#TYPE_MOBILE} networks,
-     * regardless of IMSI.
-     *
-     * @hide
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public static NetworkTemplate buildTemplateMobileWildcard() {
-        return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null);
-    }
-
-    /**
-     * Template to match all metered {@link ConnectivityManager#TYPE_WIFI} networks,
-     * regardless of key of the wifi network.
-     *
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public static NetworkTemplate buildTemplateWifiWildcard() {
-        // TODO: Consider replace this with MATCH_WIFI with NETWORK_ID_ALL
-        // and SUBSCRIBER_ID_MATCH_RULE_ALL.
-        return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null);
-    }
-
-    /** @hide */
-    @Deprecated
-    @UnsupportedAppUsage
-    public static NetworkTemplate buildTemplateWifi() {
-        return buildTemplateWifiWildcard();
-    }
-
-    /**
-     * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the
-     * given key of the wifi network.
-     *
-     * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getNetworkKey()}
-     *                  to know details about the key.
-     * @hide
-     */
-    public static NetworkTemplate buildTemplateWifi(@NonNull String wifiNetworkKey) {
-        Objects.requireNonNull(wifiNetworkKey);
-        return new NetworkTemplate(MATCH_WIFI, null /* subscriberId */,
-                new String[] { null } /* matchSubscriberIds */,
-                new String[] { wifiNetworkKey }, METERED_ALL, ROAMING_ALL,
-                DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
-                NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL);
-    }
-
-    /**
-     * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given
-     * key of the wifi network and IMSI.
-     *
-     * Call with {@link #WIFI_NETWORK_KEY_ALL} for {@code wifiNetworkKey} to get result regardless
-     * of key of the wifi network.
-     *
-     * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getNetworkKey()}
-     *                  to know details about the key.
-     * @param subscriberId the IMSI associated to this wifi network.
-     *
-     * @hide
-     */
-    public static NetworkTemplate buildTemplateWifi(@Nullable String wifiNetworkKey,
-            @Nullable String subscriberId) {
-        return new NetworkTemplate(MATCH_WIFI, subscriberId, new String[] { subscriberId },
-                wifiNetworkKey != null
-                        ? new String[] { wifiNetworkKey } : new String[0],
-                METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
-                NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
-    }
-
-    /**
-     * Template to combine all {@link ConnectivityManager#TYPE_ETHERNET} style
-     * networks together.
-     *
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public static NetworkTemplate buildTemplateEthernet() {
-        return new NetworkTemplate(MATCH_ETHERNET, null, null);
-    }
-
-    /**
-     * Template to combine all {@link ConnectivityManager#TYPE_BLUETOOTH} style
-     * networks together.
-     *
-     * @hide
-     */
-    public static NetworkTemplate buildTemplateBluetooth() {
-        return new NetworkTemplate(MATCH_BLUETOOTH, null, null);
-    }
-
-    /**
-     * Template to combine all {@link ConnectivityManager#TYPE_PROXY} style
-     * networks together.
-     *
-     * @hide
-     */
-    public static NetworkTemplate buildTemplateProxy() {
-        return new NetworkTemplate(MATCH_PROXY, null, null);
-    }
-
-    /**
-     * Template to match all metered carrier networks with the given IMSI.
-     *
-     * @hide
-     */
-    public static NetworkTemplate buildTemplateCarrierMetered(@NonNull String subscriberId) {
-        Objects.requireNonNull(subscriberId);
-        return new NetworkTemplate(MATCH_CARRIER, subscriberId,
-                new String[] { subscriberId },
-                new String[0] /* matchWifiNetworkKeys */,
-                METERED_YES, ROAMING_ALL,
-                DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
-                NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
-    }
-
-    private final int mMatchRule;
-    private final String mSubscriberId;
-
-    /**
-     * Ugh, templates are designed to target a single subscriber, but we might
-     * need to match several "merged" subscribers. These are the subscribers
-     * that should be considered to match this template.
-     * <p>
-     * Since the merge set is dynamic, it should <em>not</em> be persisted or
-     * used for determining equality.
-     */
-    private final String[] mMatchSubscriberIds;
-
-    @NonNull
-    private final String[] mMatchWifiNetworkKeys;
-
-    // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*.
-    private final int mMetered;
-    private final int mRoaming;
-    private final int mDefaultNetwork;
-    private final int mRatType;
-    /**
-     * The subscriber Id match rule defines how the template should match networks with
-     * specific subscriberId(s). See NetworkTemplate#SUBSCRIBER_ID_MATCH_RULE_* for more detail.
-     */
-    private final int mSubscriberIdMatchRule;
-
-    // Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}.
-    private final int mOemManaged;
-
-    private static void checkValidSubscriberIdMatchRule(int matchRule, int subscriberIdMatchRule) {
-        switch (matchRule) {
-            case MATCH_MOBILE:
-            case MATCH_CARRIER:
-                // MOBILE and CARRIER templates must always specify a subscriber ID.
-                if (subscriberIdMatchRule == NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL) {
-                    throw new IllegalArgumentException("Invalid SubscriberIdMatchRule "
-                            + "on match rule: " + getMatchRuleName(matchRule));
-                }
-                return;
-            default:
-                return;
-        }
-    }
-
-    /** @hide */
-    // TODO: Deprecate this constructor, mark it @UnsupportedAppUsage(maxTargetSdk = S)
-    @UnsupportedAppUsage
-    public NetworkTemplate(int matchRule, String subscriberId, String wifiNetworkKey) {
-        this(matchRule, subscriberId, new String[] { subscriberId }, wifiNetworkKey);
-    }
-
-    /** @hide */
-    public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
-            String wifiNetworkKey) {
-        // Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates
-        // to metered networks. It is now possible to match mobile with any meteredness, but
-        // in order to preserve backward compatibility of @UnsupportedAppUsage methods, this
-        //constructor passes METERED_YES for these types.
-        this(matchRule, subscriberId, matchSubscriberIds,
-                wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0],
-                (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD) ? METERED_YES
-                : METERED_ALL , ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
-                OEM_MANAGED_ALL, NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
-    }
-
-    /** @hide */
-    // TODO: Remove it after updating all of the caller.
-    public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
-            String wifiNetworkKey, int metered, int roaming, int defaultNetwork, int ratType,
-            int oemManaged) {
-        this(matchRule, subscriberId, matchSubscriberIds,
-                wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0],
-                metered, roaming, defaultNetwork, ratType, oemManaged,
-                NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
-    }
-
-    /** @hide */
-    public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
-            String[] matchWifiNetworkKeys, int metered, int roaming,
-            int defaultNetwork, int ratType, int oemManaged, int subscriberIdMatchRule) {
-        Objects.requireNonNull(matchWifiNetworkKeys);
-        mMatchRule = matchRule;
-        mSubscriberId = subscriberId;
-        // TODO: Check whether mMatchSubscriberIds = null or mMatchSubscriberIds = {null} when
-        // mSubscriberId is null
-        mMatchSubscriberIds = matchSubscriberIds;
-        mMatchWifiNetworkKeys = matchWifiNetworkKeys;
-        mMetered = metered;
-        mRoaming = roaming;
-        mDefaultNetwork = defaultNetwork;
-        mRatType = ratType;
-        mOemManaged = oemManaged;
-        mSubscriberIdMatchRule = subscriberIdMatchRule;
-        checkValidSubscriberIdMatchRule(matchRule, subscriberIdMatchRule);
-        if (!isKnownMatchRule(matchRule)) {
-            throw new IllegalArgumentException("Unknown network template rule " + matchRule
-                    + " will not match any identity.");
-        }
-    }
-
-    private NetworkTemplate(Parcel in) {
-        mMatchRule = in.readInt();
-        mSubscriberId = in.readString();
-        mMatchSubscriberIds = in.createStringArray();
-        mMatchWifiNetworkKeys = in.createStringArray();
-        mMetered = in.readInt();
-        mRoaming = in.readInt();
-        mDefaultNetwork = in.readInt();
-        mRatType = in.readInt();
-        mOemManaged = in.readInt();
-        mSubscriberIdMatchRule = in.readInt();
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeInt(mMatchRule);
-        dest.writeString(mSubscriberId);
-        dest.writeStringArray(mMatchSubscriberIds);
-        dest.writeStringArray(mMatchWifiNetworkKeys);
-        dest.writeInt(mMetered);
-        dest.writeInt(mRoaming);
-        dest.writeInt(mDefaultNetwork);
-        dest.writeInt(mRatType);
-        dest.writeInt(mOemManaged);
-        dest.writeInt(mSubscriberIdMatchRule);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public String toString() {
-        final StringBuilder builder = new StringBuilder("NetworkTemplate: ");
-        builder.append("matchRule=").append(getMatchRuleName(mMatchRule));
-        if (mSubscriberId != null) {
-            builder.append(", subscriberId=").append(
-                    NetworkIdentityUtils.scrubSubscriberId(mSubscriberId));
-        }
-        if (mMatchSubscriberIds != null) {
-            builder.append(", matchSubscriberIds=").append(
-                    Arrays.toString(NetworkIdentityUtils.scrubSubscriberIds(mMatchSubscriberIds)));
-        }
-        builder.append(", matchWifiNetworkKeys=").append(Arrays.toString(mMatchWifiNetworkKeys));
-        if (mMetered != METERED_ALL) {
-            builder.append(", metered=").append(NetworkStats.meteredToString(mMetered));
-        }
-        if (mRoaming != ROAMING_ALL) {
-            builder.append(", roaming=").append(NetworkStats.roamingToString(mRoaming));
-        }
-        if (mDefaultNetwork != DEFAULT_NETWORK_ALL) {
-            builder.append(", defaultNetwork=").append(NetworkStats.defaultNetworkToString(
-                    mDefaultNetwork));
-        }
-        if (mRatType != NETWORK_TYPE_ALL) {
-            builder.append(", ratType=").append(mRatType);
-        }
-        if (mOemManaged != OEM_MANAGED_ALL) {
-            builder.append(", oemManaged=").append(getOemManagedNames(mOemManaged));
-        }
-        builder.append(", subscriberIdMatchRule=")
-                .append(subscriberIdMatchRuleToString(mSubscriberIdMatchRule));
-        return builder.toString();
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mMatchRule, mSubscriberId, Arrays.hashCode(mMatchWifiNetworkKeys),
-                mMetered, mRoaming, mDefaultNetwork, mRatType, mOemManaged, mSubscriberIdMatchRule);
-    }
-
-    @Override
-    public boolean equals(@Nullable Object obj) {
-        if (obj instanceof NetworkTemplate) {
-            final NetworkTemplate other = (NetworkTemplate) obj;
-            return mMatchRule == other.mMatchRule
-                    && Objects.equals(mSubscriberId, other.mSubscriberId)
-                    && mMetered == other.mMetered
-                    && mRoaming == other.mRoaming
-                    && mDefaultNetwork == other.mDefaultNetwork
-                    && mRatType == other.mRatType
-                    && mOemManaged == other.mOemManaged
-                    && mSubscriberIdMatchRule == other.mSubscriberIdMatchRule
-                    && Arrays.equals(mMatchWifiNetworkKeys, other.mMatchWifiNetworkKeys);
-        }
-        return false;
-    }
-
-    private static String subscriberIdMatchRuleToString(int rule) {
-        switch (rule) {
-            case NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT:
-                return "EXACT_MATCH";
-            case NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL:
-                return "ALL";
-            default:
-                return "Unknown rule " + rule;
-        }
-    }
-
-    /** @hide */
-    public boolean isMatchRuleMobile() {
-        switch (mMatchRule) {
-            case MATCH_MOBILE:
-            case MATCH_MOBILE_WILDCARD:
-                return true;
-            default:
-                return false;
-        }
-    }
-
-    /**
-     * Get match rule of the template. See {@code MATCH_*}.
-     */
-    @UnsupportedAppUsage
-    public int getMatchRule() {
-        // Wildcard rules are not exposed. For external callers, convert wildcard rules to
-        // exposed rules before returning.
-        switch (mMatchRule) {
-            case MATCH_MOBILE_WILDCARD:
-                return MATCH_MOBILE;
-            case MATCH_WIFI_WILDCARD:
-                return MATCH_WIFI;
-            default:
-                return mMatchRule;
-        }
-    }
-
-    /**
-     * Get subscriber Id of the template.
-     * @hide
-     */
-    @Nullable
-    @UnsupportedAppUsage
-    public String getSubscriberId() {
-        return mSubscriberId;
-    }
-
-    /**
-     * Get set of subscriber Ids of the template.
-     */
-    @NonNull
-    public Set<String> getSubscriberIds() {
-        return new ArraySet<>(Arrays.asList(mMatchSubscriberIds));
-    }
-
-    /**
-     * Get the set of Wifi Network Keys of the template.
-     * See {@link WifiInfo#getNetworkKey()}.
-     */
-    @NonNull
-    public Set<String> getWifiNetworkKeys() {
-        return new ArraySet<>(Arrays.asList(mMatchWifiNetworkKeys));
-    }
-
-    /** @hide */
-    // TODO: Remove this and replace all callers with {@link #getWifiNetworkKeys()}.
-    @Nullable
-    public String getNetworkId() {
-        return getWifiNetworkKeys().isEmpty() ? null : getWifiNetworkKeys().iterator().next();
-    }
-
-    /**
-     * Get meteredness filter of the template.
-     */
-    @NetworkStats.Meteredness
-    public int getMeteredness() {
-        return mMetered;
-    }
-
-    /**
-     * Get roaming filter of the template.
-     */
-    @NetworkStats.Roaming
-    public int getRoaming() {
-        return mRoaming;
-    }
-
-    /**
-     * Get the default network status filter of the template.
-     */
-    @NetworkStats.DefaultNetwork
-    public int getDefaultNetworkStatus() {
-        return mDefaultNetwork;
-    }
-
-    /**
-     * Get the Radio Access Technology(RAT) type filter of the template.
-     */
-    public int getRatType() {
-        return mRatType;
-    }
-
-    /**
-     * Get the OEM managed filter of the template. See {@code OEM_MANAGED_*} or
-     * {@code android.net.NetworkIdentity#OEM_*}.
-     */
-    @OemManaged
-    public int getOemManaged() {
-        return mOemManaged;
-    }
-
-    /**
-     * Test if given {@link NetworkIdentity} matches this template.
-     *
-     * @hide
-     */
-    @SystemApi(client = MODULE_LIBRARIES)
-    public boolean matches(@NonNull NetworkIdentity ident) {
-        Objects.requireNonNull(ident);
-        if (!matchesMetered(ident)) return false;
-        if (!matchesRoaming(ident)) return false;
-        if (!matchesDefaultNetwork(ident)) return false;
-        if (!matchesOemNetwork(ident)) return false;
-
-        switch (mMatchRule) {
-            case MATCH_MOBILE:
-                return matchesMobile(ident);
-            case MATCH_WIFI:
-                return matchesWifi(ident);
-            case MATCH_ETHERNET:
-                return matchesEthernet(ident);
-            case MATCH_MOBILE_WILDCARD:
-                return matchesMobileWildcard(ident);
-            case MATCH_WIFI_WILDCARD:
-                return matchesWifiWildcard(ident);
-            case MATCH_BLUETOOTH:
-                return matchesBluetooth(ident);
-            case MATCH_PROXY:
-                return matchesProxy(ident);
-            case MATCH_CARRIER:
-                return matchesCarrier(ident);
-            default:
-                // We have no idea what kind of network template we are, so we
-                // just claim not to match anything.
-                return false;
-        }
-    }
-
-    private boolean matchesMetered(NetworkIdentity ident) {
-        return (mMetered == METERED_ALL)
-            || (mMetered == METERED_YES && ident.mMetered)
-            || (mMetered == METERED_NO && !ident.mMetered);
-    }
-
-    private boolean matchesRoaming(NetworkIdentity ident) {
-        return (mRoaming == ROAMING_ALL)
-            || (mRoaming == ROAMING_YES && ident.mRoaming)
-            || (mRoaming == ROAMING_NO && !ident.mRoaming);
-    }
-
-    private boolean matchesDefaultNetwork(NetworkIdentity ident) {
-        return (mDefaultNetwork == DEFAULT_NETWORK_ALL)
-            || (mDefaultNetwork == DEFAULT_NETWORK_YES && ident.mDefaultNetwork)
-            || (mDefaultNetwork == DEFAULT_NETWORK_NO && !ident.mDefaultNetwork);
-    }
-
-    private boolean matchesOemNetwork(NetworkIdentity ident) {
-        return (mOemManaged == OEM_MANAGED_ALL)
-            || (mOemManaged == OEM_MANAGED_YES
-                    && ident.mOemManaged != OEM_NONE)
-            || (mOemManaged == ident.mOemManaged);
-    }
-
-    private boolean matchesCollapsedRatType(NetworkIdentity ident) {
-        return mRatType == NETWORK_TYPE_ALL
-                || NetworkStatsManager.getCollapsedRatType(mRatType)
-                == NetworkStatsManager.getCollapsedRatType(ident.mRatType);
-    }
-
-    /**
-     * Check if this template matches {@code subscriberId}. Returns true if this
-     * template was created with {@code SUBSCRIBER_ID_MATCH_RULE_ALL}, or with a
-     * {@code mMatchSubscriberIds} array that contains {@code subscriberId}.
-     *
-     * @hide
-     */
-    public boolean matchesSubscriberId(@Nullable String subscriberId) {
-        return mSubscriberIdMatchRule == NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL
-                || CollectionUtils.contains(mMatchSubscriberIds, subscriberId);
-    }
-
-    /**
-     * Check if network matches key of the wifi network.
-     * Returns true when the key matches, or when {@code mMatchWifiNetworkKeys} is
-     * empty.
-     *
-     * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getNetworkKey()}
-     *                  to know details about the key.
-     */
-    private boolean matchesWifiNetworkKey(@NonNull String wifiNetworkKey) {
-        Objects.requireNonNull(wifiNetworkKey);
-        return CollectionUtils.isEmpty(mMatchWifiNetworkKeys)
-                || CollectionUtils.contains(mMatchWifiNetworkKeys, wifiNetworkKey);
-    }
-
-    /**
-     * Check if mobile network matches IMSI.
-     */
-    private boolean matchesMobile(NetworkIdentity ident) {
-        if (ident.mType == TYPE_WIMAX) {
-            // TODO: consider matching against WiMAX subscriber identity
-            return true;
-        } else {
-            return ident.mType == TYPE_MOBILE && !CollectionUtils.isEmpty(mMatchSubscriberIds)
-                    && CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId)
-                    && matchesCollapsedRatType(ident);
-        }
-    }
-
-    /**
-     * Check if matches Wi-Fi network template.
-     */
-    private boolean matchesWifi(NetworkIdentity ident) {
-        switch (ident.mType) {
-            case TYPE_WIFI:
-                return matchesSubscriberId(ident.mSubscriberId)
-                        && matchesWifiNetworkKey(ident.mWifiNetworkKey);
-            default:
-                return false;
-        }
-    }
-
-    /**
-     * Check if matches Ethernet network template.
-     */
-    private boolean matchesEthernet(NetworkIdentity ident) {
-        if (ident.mType == TYPE_ETHERNET) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Check if matches carrier network. The carrier networks means it includes the subscriberId.
-     */
-    private boolean matchesCarrier(NetworkIdentity ident) {
-        return ident.mSubscriberId != null
-                && !CollectionUtils.isEmpty(mMatchSubscriberIds)
-                && CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId);
-    }
-
-    private boolean matchesMobileWildcard(NetworkIdentity ident) {
-        if (ident.mType == TYPE_WIMAX) {
-            return true;
-        } else {
-            return ident.mType == TYPE_MOBILE && matchesCollapsedRatType(ident);
-        }
-    }
-
-    private boolean matchesWifiWildcard(NetworkIdentity ident) {
-        switch (ident.mType) {
-            case TYPE_WIFI:
-            case TYPE_WIFI_P2P:
-                return true;
-            default:
-                return false;
-        }
-    }
-
-    /**
-     * Check if matches Bluetooth network template.
-     */
-    private boolean matchesBluetooth(NetworkIdentity ident) {
-        if (ident.mType == TYPE_BLUETOOTH) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Check if matches Proxy network template.
-     */
-    private boolean matchesProxy(NetworkIdentity ident) {
-        return ident.mType == TYPE_PROXY;
-    }
-
-    private static String getMatchRuleName(int matchRule) {
-        switch (matchRule) {
-            case MATCH_MOBILE:
-                return "MOBILE";
-            case MATCH_WIFI:
-                return "WIFI";
-            case MATCH_ETHERNET:
-                return "ETHERNET";
-            case MATCH_MOBILE_WILDCARD:
-                return "MOBILE_WILDCARD";
-            case MATCH_WIFI_WILDCARD:
-                return "WIFI_WILDCARD";
-            case MATCH_BLUETOOTH:
-                return "BLUETOOTH";
-            case MATCH_PROXY:
-                return "PROXY";
-            case MATCH_CARRIER:
-                return "CARRIER";
-            default:
-                return "UNKNOWN(" + matchRule + ")";
-        }
-    }
-
-    private static String getOemManagedNames(int oemManaged) {
-        switch (oemManaged) {
-            case OEM_MANAGED_ALL:
-                return "OEM_MANAGED_ALL";
-            case OEM_MANAGED_NO:
-                return "OEM_MANAGED_NO";
-            case OEM_MANAGED_YES:
-                return "OEM_MANAGED_YES";
-            default:
-                return NetworkIdentity.getOemManagedNames(oemManaged);
-        }
-    }
-
-    /**
-     * Examine the given template and normalize it.
-     * We pick the "lowest" merged subscriber as the primary
-     * for key purposes, and expand the template to match all other merged
-     * subscribers.
-     * <p>
-     * For example, given an incoming template matching B, and the currently
-     * active merge set [A,B], we'd return a new template that primarily matches
-     * A, but also matches B.
-     * TODO: remove and use {@link #normalize(NetworkTemplate, List)}.
-     *
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public static NetworkTemplate normalize(NetworkTemplate template, String[] merged) {
-        return normalize(template, Arrays.<String[]>asList(merged));
-    }
-
-    /**
-     * Examine the given template and normalize it.
-     * We pick the "lowest" merged subscriber as the primary
-     * for key purposes, and expand the template to match all other merged
-     * subscribers.
-     *
-     * There can be multiple merged subscriberIds for multi-SIM devices.
-     *
-     * <p>
-     * For example, given an incoming template matching B, and the currently
-     * active merge set [A,B], we'd return a new template that primarily matches
-     * A, but also matches B.
-     *
-     * @hide
-     */
-    // TODO: @SystemApi when ready.
-    public static NetworkTemplate normalize(NetworkTemplate template, List<String[]> mergedList) {
-        // Now there are several types of network which uses SubscriberId to store network
-        // information. For instances:
-        // The TYPE_WIFI with subscriberId means that it is a merged carrier wifi network.
-        // The TYPE_CARRIER means that the network associate to specific carrier network.
-
-        if (template.mSubscriberId == null) return template;
-
-        for (String[] merged : mergedList) {
-            if (CollectionUtils.contains(merged, template.mSubscriberId)) {
-                // Requested template subscriber is part of the merge group; return
-                // a template that matches all merged subscribers.
-                final String[] matchWifiNetworkKeys = template.mMatchWifiNetworkKeys;
-                return new NetworkTemplate(template.mMatchRule, merged[0], merged,
-                        CollectionUtils.isEmpty(matchWifiNetworkKeys)
-                                ? null : matchWifiNetworkKeys[0]);
-            }
-        }
-
-        return template;
-    }
-
-    @UnsupportedAppUsage
-    public static final @android.annotation.NonNull Creator<NetworkTemplate> CREATOR = new Creator<NetworkTemplate>() {
-        @Override
-        public NetworkTemplate createFromParcel(Parcel in) {
-            return new NetworkTemplate(in);
-        }
-
-        @Override
-        public NetworkTemplate[] newArray(int size) {
-            return new NetworkTemplate[size];
-        }
-    };
-
-    /**
-     * Builder class for NetworkTemplate.
-     */
-    public static final class Builder {
-        private final int mMatchRule;
-        // Use a SortedSet to provide a deterministic order when fetching the first one.
-        @NonNull
-        private final SortedSet<String> mMatchSubscriberIds =
-                new TreeSet<>(Comparator.nullsFirst(Comparator.naturalOrder()));
-        @NonNull
-        private final SortedSet<String> mMatchWifiNetworkKeys = new TreeSet<>();
-
-        // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*.
-        private int mMetered;
-        private int mRoaming;
-        private int mDefaultNetwork;
-        private int mRatType;
-
-        // Bitfield containing OEM network properties {@code NetworkIdentity#OEM_*}.
-        private int mOemManaged;
-
-        /**
-         * Creates a new Builder with given match rule to construct NetworkTemplate objects.
-         *
-         * @param matchRule the match rule of the template, see {@code MATCH_*}.
-         */
-        public Builder(@TemplateMatchRule final int matchRule) {
-            assertRequestableMatchRule(matchRule);
-            // Initialize members with default values.
-            mMatchRule = matchRule;
-            mMetered = METERED_ALL;
-            mRoaming = ROAMING_ALL;
-            mDefaultNetwork = DEFAULT_NETWORK_ALL;
-            mRatType = NETWORK_TYPE_ALL;
-            mOemManaged = OEM_MANAGED_ALL;
-        }
-
-        /**
-         * Set the Subscriber Ids. Calling this function with an empty set represents
-         * the intention of matching any Subscriber Ids.
-         *
-         * @param subscriberIds the list of Subscriber Ids.
-         * @return this builder.
-         */
-        @NonNull
-        public Builder setSubscriberIds(@NonNull Set<String> subscriberIds) {
-            Objects.requireNonNull(subscriberIds);
-            mMatchSubscriberIds.clear();
-            mMatchSubscriberIds.addAll(subscriberIds);
-            return this;
-        }
-
-        /**
-         * Set the Wifi Network Keys. Calling this function with an empty set represents
-         * the intention of matching any Wifi Network Key.
-         *
-         * @param wifiNetworkKeys the list of Wifi Network Key,
-         *                        see {@link WifiInfo#getNetworkKey()}.
-         *                        Or an empty list to match all networks.
-         *                        Note that {@code getNetworkKey()} might get null key
-         *                        when wifi disconnects. However, the caller should never invoke
-         *                        this function with a null Wifi Network Key since such statistics
-         *                        never exists.
-         * @return this builder.
-         */
-        @NonNull
-        public Builder setWifiNetworkKeys(@NonNull Set<String> wifiNetworkKeys) {
-            Objects.requireNonNull(wifiNetworkKeys);
-            for (String key : wifiNetworkKeys) {
-                if (key == null) {
-                    throw new IllegalArgumentException("Null is not a valid key");
-                }
-            }
-            mMatchWifiNetworkKeys.clear();
-            mMatchWifiNetworkKeys.addAll(wifiNetworkKeys);
-            return this;
-        }
-
-        /**
-         * Set the meteredness filter.
-         *
-         * @param metered the meteredness filter.
-         * @return this builder.
-         */
-        @NonNull
-        public Builder setMeteredness(@NetworkStats.Meteredness int metered) {
-            mMetered = metered;
-            return this;
-        }
-
-        /**
-         * Set the roaming filter.
-         *
-         * @param roaming the roaming filter.
-         * @return this builder.
-         */
-        @NonNull
-        public Builder setRoaming(@NetworkStats.Roaming int roaming) {
-            mRoaming = roaming;
-            return this;
-        }
-
-        /**
-         * Set the default network status filter.
-         *
-         * @param defaultNetwork the default network status filter.
-         * @return this builder.
-         */
-        @NonNull
-        public Builder setDefaultNetworkStatus(@NetworkStats.DefaultNetwork int defaultNetwork) {
-            mDefaultNetwork = defaultNetwork;
-            return this;
-        }
-
-        /**
-         * Set the Radio Access Technology(RAT) type filter.
-         *
-         * @param ratType the Radio Access Technology(RAT) type filter. Use
-         *                {@link #NETWORK_TYPE_ALL} to include all network types when filtering.
-         *                See {@code TelephonyManager.NETWORK_TYPE_*}.
-         * @return this builder.
-         */
-        @NonNull
-        public Builder setRatType(int ratType) {
-            // Input will be validated with the match rule when building the template.
-            mRatType = ratType;
-            return this;
-        }
-
-        /**
-         * Set the OEM managed filter.
-         *
-         * @param oemManaged the match rule to match different type of OEM managed network or
-         *                   unmanaged networks. See {@code OEM_MANAGED_*}.
-         * @return this builder.
-         */
-        @NonNull
-        public Builder setOemManaged(@OemManaged int oemManaged) {
-            mOemManaged = oemManaged;
-            return this;
-        }
-
-        /**
-         * Check whether the match rule is requestable.
-         *
-         * @param matchRule the target match rule to be checked.
-         */
-        private static void assertRequestableMatchRule(final int matchRule) {
-            if (!isKnownMatchRule(matchRule)
-                    || matchRule == MATCH_PROXY
-                    || matchRule == MATCH_MOBILE_WILDCARD
-                    || matchRule == MATCH_WIFI_WILDCARD) {
-                throw new IllegalArgumentException("Invalid match rule: "
-                        + getMatchRuleName(matchRule));
-            }
-        }
-
-        private void assertRequestableParameters() {
-            validateWifiNetworkKeys();
-            // TODO: Check all the input are legitimate.
-        }
-
-        private void validateWifiNetworkKeys() {
-            if (mMatchRule != MATCH_WIFI && !mMatchWifiNetworkKeys.isEmpty()) {
-                throw new IllegalArgumentException("Trying to build non wifi match rule: "
-                        + mMatchRule + " with wifi network keys");
-            }
-        }
-
-        /**
-         * For backward compatibility, deduce match rule to a wildcard match rule
-         * if the Subscriber Ids are empty.
-         */
-        private int getWildcardDeducedMatchRule() {
-            if (mMatchRule == MATCH_MOBILE && mMatchSubscriberIds.isEmpty()) {
-                return MATCH_MOBILE_WILDCARD;
-            } else if (mMatchRule == MATCH_WIFI && mMatchSubscriberIds.isEmpty()
-                    && mMatchWifiNetworkKeys.isEmpty()) {
-                return MATCH_WIFI_WILDCARD;
-            }
-            return mMatchRule;
-        }
-
-        /**
-         * Builds the instance of the NetworkTemplate.
-         *
-         * @return the built instance of NetworkTemplate.
-         */
-        @NonNull
-        public NetworkTemplate build() {
-            assertRequestableParameters();
-            final int subscriberIdMatchRule = mMatchSubscriberIds.isEmpty()
-                    ? NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL
-                    : NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT;
-            return new NetworkTemplate(getWildcardDeducedMatchRule(),
-                    mMatchSubscriberIds.isEmpty() ? null : mMatchSubscriberIds.iterator().next(),
-                    mMatchSubscriberIds.toArray(new String[0]),
-                    mMatchWifiNetworkKeys.toArray(new String[0]), mMetered, mRoaming,
-                    mDefaultNetwork, mRatType, mOemManaged, subscriberIdMatchRule);
-        }
-    }
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
deleted file mode 100644
index bc836d8..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
+++ /dev/null
@@ -1,1148 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-
-import android.annotation.NonNull;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.annotation.TestApi;
-import android.app.DownloadManager;
-import android.app.backup.BackupManager;
-import android.app.usage.NetworkStatsManager;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.Context;
-import android.media.MediaPlayer;
-import android.os.Binder;
-import android.os.Build;
-import android.os.RemoteException;
-import android.os.StrictMode;
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.net.DatagramSocket;
-import java.net.Socket;
-import java.net.SocketException;
-
-/**
- * Class that provides network traffic statistics. These statistics include
- * bytes transmitted and received and network packets transmitted and received,
- * over all interfaces, over the mobile interface, and on a per-UID basis.
- * <p>
- * These statistics may not be available on all platforms. If the statistics are
- * not supported by this device, {@link #UNSUPPORTED} will be returned.
- * <p>
- * Note that the statistics returned by this class reset and start from zero
- * after every reboot. To access more robust historical network statistics data,
- * use {@link NetworkStatsManager} instead.
- */
-public class TrafficStats {
-    static {
-        System.loadLibrary("framework-connectivity-tiramisu-jni");
-    }
-
-    private static final String TAG = TrafficStats.class.getSimpleName();
-    /**
-     * The return value to indicate that the device does not support the statistic.
-     */
-    public final static int UNSUPPORTED = -1;
-
-    /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */
-    @Deprecated
-    public static final long KB_IN_BYTES = 1024;
-    /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */
-    @Deprecated
-    public static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
-    /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */
-    @Deprecated
-    public static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
-    /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */
-    @Deprecated
-    public static final long TB_IN_BYTES = GB_IN_BYTES * 1024;
-    /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */
-    @Deprecated
-    public static final long PB_IN_BYTES = TB_IN_BYTES * 1024;
-
-    /**
-     * Special UID value used when collecting {@link NetworkStatsHistory} for
-     * removed applications.
-     *
-     * @hide
-     */
-    public static final int UID_REMOVED = -4;
-
-    /**
-     * Special UID value used when collecting {@link NetworkStatsHistory} for
-     * tethering traffic.
-     *
-     * @hide
-     */
-    public static final int UID_TETHERING = NetworkStats.UID_TETHERING;
-
-    /**
-     * Tag values in this range are reserved for the network stack. The network stack is
-     * running as UID {@link android.os.Process.NETWORK_STACK_UID} when in the mainline
-     * module separate process, and as the system UID otherwise.
-     */
-    /** @hide */
-    @SystemApi
-    public static final int TAG_NETWORK_STACK_RANGE_START = 0xFFFFFD00;
-    /** @hide */
-    @SystemApi
-    public static final int TAG_NETWORK_STACK_RANGE_END = 0xFFFFFEFF;
-
-    /**
-     * Tags between 0xFFFFFF00 and 0xFFFFFFFF are reserved and used internally by system services
-     * like DownloadManager when performing traffic on behalf of an application.
-     */
-    // Please note there is no enforcement of these constants, so do not rely on them to
-    // determine that the caller is a system caller.
-    /** @hide */
-    @SystemApi
-    public static final int TAG_SYSTEM_IMPERSONATION_RANGE_START = 0xFFFFFF00;
-    /** @hide */
-    @SystemApi
-    public static final int TAG_SYSTEM_IMPERSONATION_RANGE_END = 0xFFFFFF0F;
-
-    /**
-     * Tag values between these ranges are reserved for the network stack to do traffic
-     * on behalf of applications. It is a subrange of the range above.
-     */
-    /** @hide */
-    @SystemApi
-    public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_START = 0xFFFFFF80;
-    /** @hide */
-    @SystemApi
-    public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_END = 0xFFFFFF8F;
-
-    /**
-     * Default tag value for {@link DownloadManager} traffic.
-     *
-     * @hide
-     */
-    public static final int TAG_SYSTEM_DOWNLOAD = 0xFFFFFF01;
-
-    /**
-     * Default tag value for {@link MediaPlayer} traffic.
-     *
-     * @hide
-     */
-    public static final int TAG_SYSTEM_MEDIA = 0xFFFFFF02;
-
-    /**
-     * Default tag value for {@link BackupManager} backup traffic; that is,
-     * traffic from the device to the storage backend.
-     *
-     * @hide
-     */
-    public static final int TAG_SYSTEM_BACKUP = 0xFFFFFF03;
-
-    /**
-     * Default tag value for {@link BackupManager} restore traffic; that is,
-     * app data retrieved from the storage backend at install time.
-     *
-     * @hide
-     */
-    public static final int TAG_SYSTEM_RESTORE = 0xFFFFFF04;
-
-    /**
-     * Default tag value for code (typically APKs) downloaded by an app store on
-     * behalf of the app, such as updates.
-     *
-     * @hide
-     */
-    public static final int TAG_SYSTEM_APP = 0xFFFFFF05;
-
-    // TODO : remove this constant when Wifi code is updated
-    /** @hide */
-    public static final int TAG_SYSTEM_PROBE = 0xFFFFFF42;
-
-    private static INetworkStatsService sStatsService;
-
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
-    private synchronized static INetworkStatsService getStatsService() {
-        if (sStatsService == null) {
-            throw new IllegalStateException("TrafficStats not initialized, uid="
-                    + Binder.getCallingUid());
-        }
-        return sStatsService;
-    }
-
-    /**
-     * Snapshot of {@link NetworkStats} when the currently active profiling
-     * session started, or {@code null} if no session active.
-     *
-     * @see #startDataProfiling(Context)
-     * @see #stopDataProfiling(Context)
-     */
-    private static NetworkStats sActiveProfilingStart;
-
-    private static Object sProfilingLock = new Object();
-
-    private static final String LOOPBACK_IFACE = "lo";
-
-    /**
-     * Initialization {@link TrafficStats} with the context, to
-     * allow {@link TrafficStats} to fetch the needed binder.
-     *
-     * @param context a long-lived context, such as the application context or system
-     *                server context.
-     * @hide
-     */
-    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-    @SuppressLint("VisiblySynchronized")
-    public static synchronized void init(@NonNull final Context context) {
-        if (sStatsService != null) {
-            throw new IllegalStateException("TrafficStats is already initialized, uid="
-                    + Binder.getCallingUid());
-        }
-        final NetworkStatsManager statsManager =
-                context.getSystemService(NetworkStatsManager.class);
-        if (statsManager == null) {
-            // TODO: Currently Process.isSupplemental is not working yet, because it depends on
-            //  process to run in a certain UID range, which is not true for now. Change this
-            //  to Log.wtf once Process.isSupplemental is ready.
-            Log.e(TAG, "TrafficStats not initialized, uid=" + Binder.getCallingUid());
-            return;
-        }
-        sStatsService = statsManager.getBinder();
-    }
-
-    /**
-     * Attach the socket tagger implementation to the current process, to
-     * get notified when a socket's {@link FileDescriptor} is assigned to
-     * a thread. See {@link SocketTagger#set(SocketTagger)}.
-     *
-     * @hide
-     */
-    @SystemApi(client = MODULE_LIBRARIES)
-    public static void attachSocketTagger() {
-        dalvik.system.SocketTagger.set(new SocketTagger());
-    }
-
-    private static class SocketTagger extends dalvik.system.SocketTagger {
-
-        // TODO: set to false
-        private static final boolean LOGD = true;
-
-        SocketTagger() {
-        }
-
-        @Override
-        public void tag(FileDescriptor fd) throws SocketException {
-            final UidTag tagInfo = sThreadUidTag.get();
-            if (LOGD) {
-                Log.d(TAG, "tagSocket(" + fd.getInt$() + ") with statsTag=0x"
-                        + Integer.toHexString(tagInfo.tag) + ", statsUid=" + tagInfo.uid);
-            }
-            if (tagInfo.tag == -1) {
-                StrictMode.noteUntaggedSocket();
-            }
-
-            if (tagInfo.tag == -1 && tagInfo.uid == -1) return;
-            final int errno = native_tagSocketFd(fd, tagInfo.tag, tagInfo.uid);
-            if (errno < 0) {
-                Log.i(TAG, "tagSocketFd(" + fd.getInt$() + ", "
-                        + tagInfo.tag + ", "
-                        + tagInfo.uid + ") failed with errno" + errno);
-            }
-        }
-
-        @Override
-        public void untag(FileDescriptor fd) throws SocketException {
-            if (LOGD) {
-                Log.i(TAG, "untagSocket(" + fd.getInt$() + ")");
-            }
-
-            final UidTag tagInfo = sThreadUidTag.get();
-            if (tagInfo.tag == -1 && tagInfo.uid == -1) return;
-
-            final int errno = native_untagSocketFd(fd);
-            if (errno < 0) {
-                Log.w(TAG, "untagSocket(" + fd.getInt$() + ") failed with errno " + errno);
-            }
-        }
-    }
-
-    private static native int native_tagSocketFd(FileDescriptor fd, int tag, int uid);
-    private static native int native_untagSocketFd(FileDescriptor fd);
-
-    private static class UidTag {
-        public int tag = -1;
-        public int uid = -1;
-    }
-
-    private static ThreadLocal<UidTag> sThreadUidTag = new ThreadLocal<UidTag>() {
-        @Override
-        protected UidTag initialValue() {
-            return new UidTag();
-        }
-    };
-
-    /**
-     * Set active tag to use when accounting {@link Socket} traffic originating
-     * from the current thread. Only one active tag per thread is supported.
-     * <p>
-     * Changes only take effect during subsequent calls to
-     * {@link #tagSocket(Socket)}.
-     * <p>
-     * Tags between {@code 0xFFFFFF00} and {@code 0xFFFFFFFF} are reserved and
-     * used internally by system services like {@link DownloadManager} when
-     * performing traffic on behalf of an application.
-     *
-     * @see #clearThreadStatsTag()
-     */
-    public static void setThreadStatsTag(int tag) {
-        getAndSetThreadStatsTag(tag);
-    }
-
-    /**
-     * Set active tag to use when accounting {@link Socket} traffic originating
-     * from the current thread. Only one active tag per thread is supported.
-     * <p>
-     * Changes only take effect during subsequent calls to
-     * {@link #tagSocket(Socket)}.
-     * <p>
-     * Tags between {@code 0xFFFFFF00} and {@code 0xFFFFFFFF} are reserved and
-     * used internally by system services like {@link DownloadManager} when
-     * performing traffic on behalf of an application.
-     *
-     * @return the current tag for the calling thread, which can be used to
-     *         restore any existing values after a nested operation is finished
-     */
-    public static int getAndSetThreadStatsTag(int tag) {
-        final int old = sThreadUidTag.get().tag;
-        sThreadUidTag.get().tag = tag;
-        return old;
-    }
-
-    /**
-     * Set active tag to use when accounting {@link Socket} traffic originating
-     * from the current thread. The tag used internally is well-defined to
-     * distinguish all backup-related traffic.
-     *
-     * @hide
-     */
-    @SystemApi
-    public static void setThreadStatsTagBackup() {
-        setThreadStatsTag(TAG_SYSTEM_BACKUP);
-    }
-
-    /**
-     * Set active tag to use when accounting {@link Socket} traffic originating
-     * from the current thread. The tag used internally is well-defined to
-     * distinguish all restore-related traffic.
-     *
-     * @hide
-     */
-    @SystemApi
-    public static void setThreadStatsTagRestore() {
-        setThreadStatsTag(TAG_SYSTEM_RESTORE);
-    }
-
-    /**
-     * Set active tag to use when accounting {@link Socket} traffic originating
-     * from the current thread. The tag used internally is well-defined to
-     * distinguish all code (typically APKs) downloaded by an app store on
-     * behalf of the app, such as updates.
-     *
-     * @hide
-     */
-    @SystemApi
-    public static void setThreadStatsTagApp() {
-        setThreadStatsTag(TAG_SYSTEM_APP);
-    }
-
-    /**
-     * Set active tag to use when accounting {@link Socket} traffic originating
-     * from the current thread. The tag used internally is well-defined to
-     * distinguish all download provider traffic.
-     *
-     * @hide
-     */
-    @SystemApi
-    public static void setThreadStatsTagDownload() {
-        setThreadStatsTag(TAG_SYSTEM_DOWNLOAD);
-    }
-
-    /**
-     * Get the active tag used when accounting {@link Socket} traffic originating
-     * from the current thread. Only one active tag per thread is supported.
-     * {@link #tagSocket(Socket)}.
-     *
-     * @see #setThreadStatsTag(int)
-     */
-    public static int getThreadStatsTag() {
-        return sThreadUidTag.get().tag;
-    }
-
-    /**
-     * Clear any active tag set to account {@link Socket} traffic originating
-     * from the current thread.
-     *
-     * @see #setThreadStatsTag(int)
-     */
-    public static void clearThreadStatsTag() {
-        sThreadUidTag.get().tag = -1;
-    }
-
-    /**
-     * Set specific UID to use when accounting {@link Socket} traffic
-     * originating from the current thread. Designed for use when performing an
-     * operation on behalf of another application, or when another application
-     * is performing operations on your behalf.
-     * <p>
-     * Any app can <em>accept</em> blame for traffic performed on a socket
-     * originally created by another app by calling this method with the
-     * {@link android.system.Os#getuid()} value. However, only apps holding the
-     * {@code android.Manifest.permission#UPDATE_DEVICE_STATS} permission may
-     * <em>assign</em> blame to another UIDs.
-     * <p>
-     * Changes only take effect during subsequent calls to
-     * {@link #tagSocket(Socket)}.
-     */
-    @SuppressLint("RequiresPermission")
-    public static void setThreadStatsUid(int uid) {
-        sThreadUidTag.get().uid = uid;
-    }
-
-    /**
-     * Get the active UID used when accounting {@link Socket} traffic originating
-     * from the current thread. Only one active tag per thread is supported.
-     * {@link #tagSocket(Socket)}.
-     *
-     * @see #setThreadStatsUid(int)
-     */
-    public static int getThreadStatsUid() {
-        return sThreadUidTag.get().uid;
-    }
-
-    /**
-     * Set specific UID to use when accounting {@link Socket} traffic
-     * originating from the current thread as the calling UID. Designed for use
-     * when another application is performing operations on your behalf.
-     * <p>
-     * Changes only take effect during subsequent calls to
-     * {@link #tagSocket(Socket)}.
-     *
-     * @removed
-     * @deprecated use {@link #setThreadStatsUid(int)} instead.
-     */
-    @Deprecated
-    public static void setThreadStatsUidSelf() {
-        setThreadStatsUid(android.os.Process.myUid());
-    }
-
-    /**
-     * Clear any active UID set to account {@link Socket} traffic originating
-     * from the current thread.
-     *
-     * @see #setThreadStatsUid(int)
-     */
-    @SuppressLint("RequiresPermission")
-    public static void clearThreadStatsUid() {
-        setThreadStatsUid(-1);
-    }
-
-    /**
-     * Tag the given {@link Socket} with any statistics parameters active for
-     * the current thread. Subsequent calls always replace any existing
-     * parameters. When finished, call {@link #untagSocket(Socket)} to remove
-     * statistics parameters.
-     *
-     * @see #setThreadStatsTag(int)
-     */
-    public static void tagSocket(Socket socket) throws SocketException {
-        SocketTagger.get().tag(socket);
-    }
-
-    /**
-     * Remove any statistics parameters from the given {@link Socket}.
-     * <p>
-     * In Android 8.1 (API level 27) and lower, a socket is automatically
-     * untagged when it's sent to another process using binder IPC with a
-     * {@code ParcelFileDescriptor} container. In Android 9.0 (API level 28)
-     * and higher, the socket tag is kept when the socket is sent to another
-     * process using binder IPC. You can mimic the previous behavior by
-     * calling {@code untagSocket()} before sending the socket to another
-     * process.
-     */
-    public static void untagSocket(Socket socket) throws SocketException {
-        SocketTagger.get().untag(socket);
-    }
-
-    /**
-     * Tag the given {@link DatagramSocket} with any statistics parameters
-     * active for the current thread. Subsequent calls always replace any
-     * existing parameters. When finished, call
-     * {@link #untagDatagramSocket(DatagramSocket)} to remove statistics
-     * parameters.
-     *
-     * @see #setThreadStatsTag(int)
-     */
-    public static void tagDatagramSocket(DatagramSocket socket) throws SocketException {
-        SocketTagger.get().tag(socket);
-    }
-
-    /**
-     * Remove any statistics parameters from the given {@link DatagramSocket}.
-     */
-    public static void untagDatagramSocket(DatagramSocket socket) throws SocketException {
-        SocketTagger.get().untag(socket);
-    }
-
-    /**
-     * Tag the given {@link FileDescriptor} socket with any statistics
-     * parameters active for the current thread. Subsequent calls always replace
-     * any existing parameters. When finished, call
-     * {@link #untagFileDescriptor(FileDescriptor)} to remove statistics
-     * parameters.
-     *
-     * @see #setThreadStatsTag(int)
-     */
-    public static void tagFileDescriptor(FileDescriptor fd) throws IOException {
-        SocketTagger.get().tag(fd);
-    }
-
-    /**
-     * Remove any statistics parameters from the given {@link FileDescriptor}
-     * socket.
-     */
-    public static void untagFileDescriptor(FileDescriptor fd) throws IOException {
-        SocketTagger.get().untag(fd);
-    }
-
-    /**
-     * Start profiling data usage for current UID. Only one profiling session
-     * can be active at a time.
-     *
-     * @hide
-     */
-    public static void startDataProfiling(Context context) {
-        synchronized (sProfilingLock) {
-            if (sActiveProfilingStart != null) {
-                throw new IllegalStateException("already profiling data");
-            }
-
-            // take snapshot in time; we calculate delta later
-            sActiveProfilingStart = getDataLayerSnapshotForUid(context);
-        }
-    }
-
-    /**
-     * Stop profiling data usage for current UID.
-     *
-     * @return Detailed {@link NetworkStats} of data that occurred since last
-     *         {@link #startDataProfiling(Context)} call.
-     * @hide
-     */
-    public static NetworkStats stopDataProfiling(Context context) {
-        synchronized (sProfilingLock) {
-            if (sActiveProfilingStart == null) {
-                throw new IllegalStateException("not profiling data");
-            }
-
-            // subtract starting values and return delta
-            final NetworkStats profilingStop = getDataLayerSnapshotForUid(context);
-            final NetworkStats profilingDelta = NetworkStats.subtract(
-                    profilingStop, sActiveProfilingStart, null, null);
-            sActiveProfilingStart = null;
-            return profilingDelta;
-        }
-    }
-
-    /**
-     * Increment count of network operations performed under the accounting tag
-     * currently active on the calling thread. This can be used to derive
-     * bytes-per-operation.
-     *
-     * @param operationCount Number of operations to increment count by.
-     */
-    public static void incrementOperationCount(int operationCount) {
-        final int tag = getThreadStatsTag();
-        incrementOperationCount(tag, operationCount);
-    }
-
-    /**
-     * Increment count of network operations performed under the given
-     * accounting tag. This can be used to derive bytes-per-operation.
-     *
-     * @param tag Accounting tag used in {@link #setThreadStatsTag(int)}.
-     * @param operationCount Number of operations to increment count by.
-     */
-    public static void incrementOperationCount(int tag, int operationCount) {
-        final int uid = android.os.Process.myUid();
-        try {
-            getStatsService().incrementOperationCount(uid, tag, operationCount);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /** {@hide} */
-    public static void closeQuietly(INetworkStatsSession session) {
-        // TODO: move to NetworkStatsService once it exists
-        if (session != null) {
-            try {
-                session.close();
-            } catch (RuntimeException rethrown) {
-                throw rethrown;
-            } catch (Exception ignored) {
-            }
-        }
-    }
-
-    private static long addIfSupported(long stat) {
-        return (stat == UNSUPPORTED) ? 0 : stat;
-    }
-
-    /**
-     * Return number of packets transmitted across mobile networks since device
-     * boot. Counts packets across all mobile network interfaces, and always
-     * increases monotonically since device boot. Statistics are measured at the
-     * network layer, so they include both TCP and UDP usage.
-     * <p>
-     * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
-     * return {@link #UNSUPPORTED} on devices where statistics aren't available.
-     */
-    public static long getMobileTxPackets() {
-        long total = 0;
-        for (String iface : getMobileIfaces()) {
-            total += addIfSupported(getTxPackets(iface));
-        }
-        return total;
-    }
-
-    /**
-     * Return number of packets received across mobile networks since device
-     * boot. Counts packets across all mobile network interfaces, and always
-     * increases monotonically since device boot. Statistics are measured at the
-     * network layer, so they include both TCP and UDP usage.
-     * <p>
-     * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
-     * return {@link #UNSUPPORTED} on devices where statistics aren't available.
-     */
-    public static long getMobileRxPackets() {
-        long total = 0;
-        for (String iface : getMobileIfaces()) {
-            total += addIfSupported(getRxPackets(iface));
-        }
-        return total;
-    }
-
-    /**
-     * Return number of bytes transmitted across mobile networks since device
-     * boot. Counts packets across all mobile network interfaces, and always
-     * increases monotonically since device boot. Statistics are measured at the
-     * network layer, so they include both TCP and UDP usage.
-     * <p>
-     * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
-     * return {@link #UNSUPPORTED} on devices where statistics aren't available.
-     */
-    public static long getMobileTxBytes() {
-        long total = 0;
-        for (String iface : getMobileIfaces()) {
-            total += addIfSupported(getTxBytes(iface));
-        }
-        return total;
-    }
-
-    /**
-     * Return number of bytes received across mobile networks since device boot.
-     * Counts packets across all mobile network interfaces, and always increases
-     * monotonically since device boot. Statistics are measured at the network
-     * layer, so they include both TCP and UDP usage.
-     * <p>
-     * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
-     * return {@link #UNSUPPORTED} on devices where statistics aren't available.
-     */
-    public static long getMobileRxBytes() {
-        long total = 0;
-        for (String iface : getMobileIfaces()) {
-            total += addIfSupported(getRxBytes(iface));
-        }
-        return total;
-    }
-
-    /** {@hide} */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public static long getMobileTcpRxPackets() {
-        long total = 0;
-        for (String iface : getMobileIfaces()) {
-            long stat = UNSUPPORTED;
-            try {
-                stat = getStatsService().getIfaceStats(iface, TYPE_TCP_RX_PACKETS);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-            total += addIfSupported(stat);
-        }
-        return total;
-    }
-
-    /** {@hide} */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public static long getMobileTcpTxPackets() {
-        long total = 0;
-        for (String iface : getMobileIfaces()) {
-            long stat = UNSUPPORTED;
-            try {
-                stat = getStatsService().getIfaceStats(iface, TYPE_TCP_TX_PACKETS);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-            total += addIfSupported(stat);
-        }
-        return total;
-    }
-
-    /**
-     * Return the number of packets transmitted on the specified interface since the interface
-     * was created. Statistics are measured at the network layer, so both TCP and
-     * UDP usage are included.
-     *
-     * Note that the returned values are partial statistics that do not count data from several
-     * sources and do not apply several adjustments that are necessary for correctness, such
-     * as adjusting for VPN apps, IPv6-in-IPv4 translation, etc. These values can be used to
-     * determine whether traffic is being transferred on the specific interface but are not a
-     * substitute for the more accurate statistics provided by the {@link NetworkStatsManager}
-     * APIs.
-     *
-     * @param iface The name of the interface.
-     * @return The number of transmitted packets.
-     */
-    public static long getTxPackets(@NonNull String iface) {
-        try {
-            return getStatsService().getIfaceStats(iface, TYPE_TX_PACKETS);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Return the number of packets received on the specified interface since the interface was
-     * created. Statistics are measured at the network layer, so both TCP
-     * and UDP usage are included.
-     *
-     * Note that the returned values are partial statistics that do not count data from several
-     * sources and do not apply several adjustments that are necessary for correctness, such
-     * as adjusting for VPN apps, IPv6-in-IPv4 translation, etc. These values can be used to
-     * determine whether traffic is being transferred on the specific interface but are not a
-     * substitute for the more accurate statistics provided by the {@link NetworkStatsManager}
-     * APIs.
-     *
-     * @param iface The name of the interface.
-     * @return The number of received packets.
-     */
-    public static long getRxPackets(@NonNull String iface) {
-        try {
-            return getStatsService().getIfaceStats(iface, TYPE_RX_PACKETS);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Return the number of bytes transmitted on the specified interface since the interface
-     * was created. Statistics are measured at the network layer, so both TCP and
-     * UDP usage are included.
-     *
-     * Note that the returned values are partial statistics that do not count data from several
-     * sources and do not apply several adjustments that are necessary for correctness, such
-     * as adjusting for VPN apps, IPv6-in-IPv4 translation, etc. These values can be used to
-     * determine whether traffic is being transferred on the specific interface but are not a
-     * substitute for the more accurate statistics provided by the {@link NetworkStatsManager}
-     * APIs.
-     *
-     * @param iface The name of the interface.
-     * @return The number of transmitted bytes.
-     */
-    public static long getTxBytes(@NonNull String iface) {
-        try {
-            return getStatsService().getIfaceStats(iface, TYPE_TX_BYTES);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Return the number of bytes received on the specified interface since the interface
-     * was created. Statistics are measured at the network layer, so both TCP
-     * and UDP usage are included.
-     *
-     * Note that the returned values are partial statistics that do not count data from several
-     * sources and do not apply several adjustments that are necessary for correctness, such
-     * as adjusting for VPN apps, IPv6-in-IPv4 translation, etc. These values can be used to
-     * determine whether traffic is being transferred on the specific interface but are not a
-     * substitute for the more accurate statistics provided by the {@link NetworkStatsManager}
-     * APIs.
-     *
-     * @param iface The name of the interface.
-     * @return The number of received bytes.
-     */
-    public static long getRxBytes(@NonNull String iface) {
-        try {
-            return getStatsService().getIfaceStats(iface, TYPE_RX_BYTES);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /** {@hide} */
-    @TestApi
-    public static long getLoopbackTxPackets() {
-        try {
-            return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_TX_PACKETS);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /** {@hide} */
-    @TestApi
-    public static long getLoopbackRxPackets() {
-        try {
-            return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_RX_PACKETS);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /** {@hide} */
-    @TestApi
-    public static long getLoopbackTxBytes() {
-        try {
-            return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_TX_BYTES);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /** {@hide} */
-    @TestApi
-    public static long getLoopbackRxBytes() {
-        try {
-            return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_RX_BYTES);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Return number of packets transmitted since device boot. Counts packets
-     * across all network interfaces, and always increases monotonically since
-     * device boot. Statistics are measured at the network layer, so they
-     * include both TCP and UDP usage.
-     * <p>
-     * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
-     * return {@link #UNSUPPORTED} on devices where statistics aren't available.
-     */
-    public static long getTotalTxPackets() {
-        try {
-            return getStatsService().getTotalStats(TYPE_TX_PACKETS);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Return number of packets received since device boot. Counts packets
-     * across all network interfaces, and always increases monotonically since
-     * device boot. Statistics are measured at the network layer, so they
-     * include both TCP and UDP usage.
-     * <p>
-     * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
-     * return {@link #UNSUPPORTED} on devices where statistics aren't available.
-     */
-    public static long getTotalRxPackets() {
-        try {
-            return getStatsService().getTotalStats(TYPE_RX_PACKETS);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Return number of bytes transmitted since device boot. Counts packets
-     * across all network interfaces, and always increases monotonically since
-     * device boot. Statistics are measured at the network layer, so they
-     * include both TCP and UDP usage.
-     * <p>
-     * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
-     * return {@link #UNSUPPORTED} on devices where statistics aren't available.
-     */
-    public static long getTotalTxBytes() {
-        try {
-            return getStatsService().getTotalStats(TYPE_TX_BYTES);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Return number of bytes received since device boot. Counts packets across
-     * all network interfaces, and always increases monotonically since device
-     * boot. Statistics are measured at the network layer, so they include both
-     * TCP and UDP usage.
-     * <p>
-     * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
-     * return {@link #UNSUPPORTED} on devices where statistics aren't available.
-     */
-    public static long getTotalRxBytes() {
-        try {
-            return getStatsService().getTotalStats(TYPE_RX_BYTES);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Return number of bytes transmitted by the given UID since device boot.
-     * Counts packets across all network interfaces, and always increases
-     * monotonically since device boot. Statistics are measured at the network
-     * layer, so they include both TCP and UDP usage.
-     * <p>
-     * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
-     * return {@link #UNSUPPORTED} on devices where statistics aren't available.
-     * <p>
-     * Starting in {@link android.os.Build.VERSION_CODES#N} this will only
-     * report traffic statistics for the calling UID. It will return
-     * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access
-     * historical network statistics belonging to other UIDs, use
-     * {@link NetworkStatsManager}.
-     *
-     * @see android.os.Process#myUid()
-     * @see android.content.pm.ApplicationInfo#uid
-     */
-    public static long getUidTxBytes(int uid) {
-        try {
-            return getStatsService().getUidStats(uid, TYPE_TX_BYTES);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Return number of bytes received by the given UID since device boot.
-     * Counts packets across all network interfaces, and always increases
-     * monotonically since device boot. Statistics are measured at the network
-     * layer, so they include both TCP and UDP usage.
-     * <p>
-     * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return
-     * {@link #UNSUPPORTED} on devices where statistics aren't available.
-     * <p>
-     * Starting in {@link android.os.Build.VERSION_CODES#N} this will only
-     * report traffic statistics for the calling UID. It will return
-     * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access
-     * historical network statistics belonging to other UIDs, use
-     * {@link NetworkStatsManager}.
-     *
-     * @see android.os.Process#myUid()
-     * @see android.content.pm.ApplicationInfo#uid
-     */
-    public static long getUidRxBytes(int uid) {
-        try {
-            return getStatsService().getUidStats(uid, TYPE_RX_BYTES);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Return number of packets transmitted by the given UID since device boot.
-     * Counts packets across all network interfaces, and always increases
-     * monotonically since device boot. Statistics are measured at the network
-     * layer, so they include both TCP and UDP usage.
-     * <p>
-     * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return
-     * {@link #UNSUPPORTED} on devices where statistics aren't available.
-     * <p>
-     * Starting in {@link android.os.Build.VERSION_CODES#N} this will only
-     * report traffic statistics for the calling UID. It will return
-     * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access
-     * historical network statistics belonging to other UIDs, use
-     * {@link NetworkStatsManager}.
-     *
-     * @see android.os.Process#myUid()
-     * @see android.content.pm.ApplicationInfo#uid
-     */
-    public static long getUidTxPackets(int uid) {
-        try {
-            return getStatsService().getUidStats(uid, TYPE_TX_PACKETS);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Return number of packets received by the given UID since device boot.
-     * Counts packets across all network interfaces, and always increases
-     * monotonically since device boot. Statistics are measured at the network
-     * layer, so they include both TCP and UDP usage.
-     * <p>
-     * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return
-     * {@link #UNSUPPORTED} on devices where statistics aren't available.
-     * <p>
-     * Starting in {@link android.os.Build.VERSION_CODES#N} this will only
-     * report traffic statistics for the calling UID. It will return
-     * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access
-     * historical network statistics belonging to other UIDs, use
-     * {@link NetworkStatsManager}.
-     *
-     * @see android.os.Process#myUid()
-     * @see android.content.pm.ApplicationInfo#uid
-     */
-    public static long getUidRxPackets(int uid) {
-        try {
-            return getStatsService().getUidStats(uid, TYPE_RX_PACKETS);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
-     *             transport layer statistics are no longer available, and will
-     *             always return {@link #UNSUPPORTED}.
-     * @see #getUidTxBytes(int)
-     */
-    @Deprecated
-    public static long getUidTcpTxBytes(int uid) {
-        return UNSUPPORTED;
-    }
-
-    /**
-     * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
-     *             transport layer statistics are no longer available, and will
-     *             always return {@link #UNSUPPORTED}.
-     * @see #getUidRxBytes(int)
-     */
-    @Deprecated
-    public static long getUidTcpRxBytes(int uid) {
-        return UNSUPPORTED;
-    }
-
-    /**
-     * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
-     *             transport layer statistics are no longer available, and will
-     *             always return {@link #UNSUPPORTED}.
-     * @see #getUidTxBytes(int)
-     */
-    @Deprecated
-    public static long getUidUdpTxBytes(int uid) {
-        return UNSUPPORTED;
-    }
-
-    /**
-     * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
-     *             transport layer statistics are no longer available, and will
-     *             always return {@link #UNSUPPORTED}.
-     * @see #getUidRxBytes(int)
-     */
-    @Deprecated
-    public static long getUidUdpRxBytes(int uid) {
-        return UNSUPPORTED;
-    }
-
-    /**
-     * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
-     *             transport layer statistics are no longer available, and will
-     *             always return {@link #UNSUPPORTED}.
-     * @see #getUidTxPackets(int)
-     */
-    @Deprecated
-    public static long getUidTcpTxSegments(int uid) {
-        return UNSUPPORTED;
-    }
-
-    /**
-     * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
-     *             transport layer statistics are no longer available, and will
-     *             always return {@link #UNSUPPORTED}.
-     * @see #getUidRxPackets(int)
-     */
-    @Deprecated
-    public static long getUidTcpRxSegments(int uid) {
-        return UNSUPPORTED;
-    }
-
-    /**
-     * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
-     *             transport layer statistics are no longer available, and will
-     *             always return {@link #UNSUPPORTED}.
-     * @see #getUidTxPackets(int)
-     */
-    @Deprecated
-    public static long getUidUdpTxPackets(int uid) {
-        return UNSUPPORTED;
-    }
-
-    /**
-     * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
-     *             transport layer statistics are no longer available, and will
-     *             always return {@link #UNSUPPORTED}.
-     * @see #getUidRxPackets(int)
-     */
-    @Deprecated
-    public static long getUidUdpRxPackets(int uid) {
-        return UNSUPPORTED;
-    }
-
-    /**
-     * Return detailed {@link NetworkStats} for the current UID. Requires no
-     * special permission.
-     */
-    private static NetworkStats getDataLayerSnapshotForUid(Context context) {
-        // TODO: take snapshot locally, since proc file is now visible
-        final int uid = android.os.Process.myUid();
-        try {
-            return getStatsService().getDataLayerSnapshotForUid(uid);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Return set of any ifaces associated with mobile networks since boot.
-     * Interfaces are never removed from this list, so counters should always be
-     * monotonic.
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
-    private static String[] getMobileIfaces() {
-        try {
-            return getStatsService().getMobileIfaces();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    // NOTE: keep these in sync with {@code com_android_server_net_NetworkStatsService.cpp}.
-    /** {@hide} */
-    public static final int TYPE_RX_BYTES = 0;
-    /** {@hide} */
-    public static final int TYPE_RX_PACKETS = 1;
-    /** {@hide} */
-    public static final int TYPE_TX_BYTES = 2;
-    /** {@hide} */
-    public static final int TYPE_TX_PACKETS = 3;
-    /** {@hide} */
-    public static final int TYPE_TCP_RX_PACKETS = 4;
-    /** {@hide} */
-    public static final int TYPE_TCP_TX_PACKETS = 5;
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.java b/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.java
deleted file mode 100644
index 7ab53b1..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * A lightweight container used to carry information on the networks that underly a given
- * virtual network.
- *
- * @hide
- */
-@SystemApi(client = MODULE_LIBRARIES)
-public final class UnderlyingNetworkInfo implements Parcelable {
-    /** The owner of this network. */
-    private final int mOwnerUid;
-
-    /** The interface name of this network. */
-    @NonNull
-    private final String mIface;
-
-    /** The names of the interfaces underlying this network. */
-    @NonNull
-    private final List<String> mUnderlyingIfaces;
-
-    public UnderlyingNetworkInfo(int ownerUid, @NonNull String iface,
-            @NonNull List<String> underlyingIfaces) {
-        Objects.requireNonNull(iface);
-        Objects.requireNonNull(underlyingIfaces);
-        mOwnerUid = ownerUid;
-        mIface = iface;
-        mUnderlyingIfaces = Collections.unmodifiableList(new ArrayList<>(underlyingIfaces));
-    }
-
-    private UnderlyingNetworkInfo(@NonNull Parcel in) {
-        mOwnerUid = in.readInt();
-        mIface = in.readString();
-        List<String> underlyingIfaces = new ArrayList<>();
-        in.readList(underlyingIfaces, null /*classLoader*/, java.lang.String.class);
-        mUnderlyingIfaces = Collections.unmodifiableList(underlyingIfaces);
-    }
-
-    /** Get the owner of this network. */
-    public int getOwnerUid() {
-        return mOwnerUid;
-    }
-
-    /** Get the interface name of this network. */
-    @NonNull
-    public String getInterface() {
-        return mIface;
-    }
-
-    /** Get the names of the interfaces underlying this network. */
-    @NonNull
-    public List<String> getUnderlyingInterfaces() {
-        return mUnderlyingIfaces;
-    }
-
-    @Override
-    public String toString() {
-        return "UnderlyingNetworkInfo{"
-                + "ownerUid=" + mOwnerUid
-                + ", iface='" + mIface + '\''
-                + ", underlyingIfaces='" + mUnderlyingIfaces.toString() + '\''
-                + '}';
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeInt(mOwnerUid);
-        dest.writeString(mIface);
-        dest.writeList(mUnderlyingIfaces);
-    }
-
-    @NonNull
-    public static final Parcelable.Creator<UnderlyingNetworkInfo> CREATOR =
-            new Parcelable.Creator<UnderlyingNetworkInfo>() {
-        @NonNull
-        @Override
-        public UnderlyingNetworkInfo createFromParcel(@NonNull Parcel in) {
-            return new UnderlyingNetworkInfo(in);
-        }
-
-        @NonNull
-        @Override
-        public UnderlyingNetworkInfo[] newArray(int size) {
-            return new UnderlyingNetworkInfo[size];
-        }
-    };
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (!(o instanceof UnderlyingNetworkInfo)) return false;
-        final UnderlyingNetworkInfo that = (UnderlyingNetworkInfo) o;
-        return mOwnerUid == that.getOwnerUid()
-                && Objects.equals(mIface, that.getInterface())
-                && Objects.equals(mUnderlyingIfaces, that.getUnderlyingInterfaces());
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mOwnerUid, mIface, mUnderlyingIfaces);
-    }
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProvider.aidl b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProvider.aidl
deleted file mode 100644
index 74c3ba4..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProvider.aidl
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netstats.provider;
-
-/**
- * Interface for NetworkStatsService to query network statistics and set data limits.
- *
- * @hide
- */
-oneway interface INetworkStatsProvider {
-    void onRequestStatsUpdate(int token);
-    void onSetAlert(long quotaBytes);
-    void onSetWarningAndLimit(String iface, long warningBytes, long limitBytes);
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl
deleted file mode 100644
index 7eaa01e..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netstats.provider;
-
-import android.net.NetworkStats;
-
-/**
- * Interface for implementor of {@link INetworkStatsProviderCallback} to push events
- * such as network statistics update or notify limit reached.
- * @hide
- */
-oneway interface INetworkStatsProviderCallback {
-    void notifyStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats);
-    void notifyAlertReached();
-    void notifyWarningOrLimitReached();
-    void unregister();
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java
deleted file mode 100644
index 23fc069..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netstats.provider;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.net.NetworkStats;
-import android.os.RemoteException;
-
-/**
- * A base class that allows external modules to implement a custom network statistics provider.
- * @hide
- */
-@SystemApi
-public abstract class NetworkStatsProvider {
-    /**
-     * A value used by {@link #onSetLimit}, {@link #onSetAlert} and {@link #onSetWarningAndLimit}
-     * indicates there is no limit.
-     */
-    public static final int QUOTA_UNLIMITED = -1;
-
-    @NonNull private final INetworkStatsProvider mProviderBinder =
-            new INetworkStatsProvider.Stub() {
-
-        @Override
-        public void onRequestStatsUpdate(int token) {
-            NetworkStatsProvider.this.onRequestStatsUpdate(token);
-        }
-
-        @Override
-        public void onSetAlert(long quotaBytes) {
-            NetworkStatsProvider.this.onSetAlert(quotaBytes);
-        }
-
-        @Override
-        public void onSetWarningAndLimit(String iface, long warningBytes, long limitBytes) {
-            NetworkStatsProvider.this.onSetWarningAndLimit(iface, warningBytes, limitBytes);
-        }
-    };
-
-    // The binder given by the service when successfully registering. Only null before registering,
-    // never null once non-null.
-    @Nullable
-    private INetworkStatsProviderCallback mProviderCbBinder;
-
-    /**
-     * Return the binder invoked by the service and redirect function calls to the overridden
-     * methods.
-     * @hide
-     */
-    @NonNull
-    public INetworkStatsProvider getProviderBinder() {
-        return mProviderBinder;
-    }
-
-    /**
-     * Store the binder that was returned by the service when successfully registering. Note that
-     * the provider cannot be re-registered. Hence this method can only be called once per provider.
-     *
-     * @hide
-     */
-    public void setProviderCallbackBinder(@NonNull INetworkStatsProviderCallback binder) {
-        if (mProviderCbBinder != null) {
-            throw new IllegalArgumentException("provider is already registered");
-        }
-        mProviderCbBinder = binder;
-    }
-
-    /**
-     * Get the binder that was returned by the service when successfully registering. Or null if the
-     * provider was never registered.
-     *
-     * @hide
-     */
-    @Nullable
-    public INetworkStatsProviderCallback getProviderCallbackBinder() {
-        return mProviderCbBinder;
-    }
-
-    /**
-     * Get the binder that was returned by the service when successfully registering. Throw an
-     * {@link IllegalStateException} if the provider is not registered.
-     *
-     * @hide
-     */
-    @NonNull
-    public INetworkStatsProviderCallback getProviderCallbackBinderOrThrow() {
-        if (mProviderCbBinder == null) {
-            throw new IllegalStateException("the provider is not registered");
-        }
-        return mProviderCbBinder;
-    }
-
-    /**
-     * Notify the system of new network statistics.
-     *
-     * Send the network statistics recorded since the last call to {@link #notifyStatsUpdated}. Must
-     * be called as soon as possible after {@link NetworkStatsProvider#onRequestStatsUpdate(int)}
-     * being called. Responding later increases the probability stats will be dropped. The
-     * provider can also call this whenever it wants to reports new stats for any reason.
-     * Note that the system will not necessarily immediately propagate the statistics to
-     * reflect the update.
-     *
-     * @param token the token under which these stats were gathered. Providers can call this method
-     *              with the current token as often as they want, until the token changes.
-     *              {@see NetworkStatsProvider#onRequestStatsUpdate()}
-     * @param ifaceStats the {@link NetworkStats} per interface to be reported.
-     *                   The provider should not include any traffic that is already counted by
-     *                   kernel interface counters.
-     * @param uidStats the same stats as above, but counts {@link NetworkStats}
-     *                 per uid.
-     */
-    public void notifyStatsUpdated(int token, @NonNull NetworkStats ifaceStats,
-            @NonNull NetworkStats uidStats) {
-        try {
-            getProviderCallbackBinderOrThrow().notifyStatsUpdated(token, ifaceStats, uidStats);
-        } catch (RemoteException e) {
-            e.rethrowAsRuntimeException();
-        }
-    }
-
-    /**
-     * Notify system that the quota set by {@code onSetAlert} has been reached.
-     */
-    public void notifyAlertReached() {
-        try {
-            getProviderCallbackBinderOrThrow().notifyAlertReached();
-        } catch (RemoteException e) {
-            e.rethrowAsRuntimeException();
-        }
-    }
-
-    /**
-     * Notify system that the warning set by {@link #onSetWarningAndLimit} has been reached.
-     */
-    public void notifyWarningReached() {
-        try {
-            // Reuse the code path to notify warning reached with limit reached
-            // since framework handles them in the same way.
-            getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached();
-        } catch (RemoteException e) {
-            e.rethrowAsRuntimeException();
-        }
-    }
-
-    /**
-     * Notify system that the quota set by {@link #onSetLimit} or limit set by
-     * {@link #onSetWarningAndLimit} has been reached.
-     */
-    public void notifyLimitReached() {
-        try {
-            getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached();
-        } catch (RemoteException e) {
-            e.rethrowAsRuntimeException();
-        }
-    }
-
-    /**
-     * Called by {@code NetworkStatsService} when it requires to know updated stats.
-     * The provider MUST respond by calling {@link #notifyStatsUpdated} as soon as possible.
-     * Responding later increases the probability stats will be dropped. Memory allowing, the
-     * system will try to take stats into account up to one minute after calling
-     * {@link #onRequestStatsUpdate}.
-     *
-     * @param token a positive number identifying the new state of the system under which
-     *              {@link NetworkStats} have to be gathered from now on. When this is called,
-     *              custom implementations of providers MUST tally and report the latest stats with
-     *              the previous token, under which stats were being gathered so far.
-     */
-    public abstract void onRequestStatsUpdate(int token);
-
-    /**
-     * Called by {@code NetworkStatsService} when setting the interface quota for the specified
-     * upstream interface. When this is called, the custom implementation should block all egress
-     * packets on the {@code iface} associated with the provider when {@code quotaBytes} bytes have
-     * been reached, and MUST respond to it by calling
-     * {@link NetworkStatsProvider#notifyLimitReached()}.
-     *
-     * @param iface the interface requiring the operation.
-     * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting
-     *                   from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit.
-     */
-    public abstract void onSetLimit(@NonNull String iface, long quotaBytes);
-
-    /**
-     * Called by {@code NetworkStatsService} when setting the interface quotas for the specified
-     * upstream interface. If a provider implements {@link #onSetWarningAndLimit}, the system
-     * will not call {@link #onSetLimit}. When this method is called, the implementation
-     * should behave as follows:
-     *   1. If {@code warningBytes} is reached on {@code iface}, block all further traffic on
-     *      {@code iface} and call {@link NetworkStatsProvider@notifyWarningReached()}.
-     *   2. If {@code limitBytes} is reached on {@code iface}, block all further traffic on
-     *   {@code iface} and call {@link NetworkStatsProvider#notifyLimitReached()}.
-     *
-     * @param iface the interface requiring the operation.
-     * @param warningBytes the warning defined as the number of bytes, starting from zero and
-     *                     counting from now. A value of {@link #QUOTA_UNLIMITED} indicates
-     *                     there is no warning.
-     * @param limitBytes the limit defined as the number of bytes, starting from zero and counting
-     *                   from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit.
-     */
-    public void onSetWarningAndLimit(@NonNull String iface, long warningBytes, long limitBytes) {
-        // Backward compatibility for those who didn't override this function.
-        onSetLimit(iface, limitBytes);
-    }
-
-    /**
-     * Called by {@code NetworkStatsService} when setting the alert bytes. Custom implementations
-     * MUST call {@link NetworkStatsProvider#notifyAlertReached()} when {@code quotaBytes} bytes
-     * have been reached. Unlike {@link #onSetLimit(String, long)}, the custom implementation should
-     * not block all egress packets.
-     *
-     * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting
-     *                   from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no alert.
-     */
-    public abstract void onSetAlert(long quotaBytes);
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdManager.aidl b/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdManager.aidl
deleted file mode 100644
index 89e9cdb..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdManager.aidl
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.nsd;
-
-import android.net.nsd.INsdManagerCallback;
-import android.net.nsd.INsdServiceConnector;
-import android.os.Messenger;
-
-/**
- * Interface that NsdService implements to connect NsdManager clients.
- *
- * {@hide}
- */
-interface INsdManager {
-    INsdServiceConnector connect(INsdManagerCallback cb);
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdManagerCallback.aidl b/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdManagerCallback.aidl
deleted file mode 100644
index 1a262ec..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdManagerCallback.aidl
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.nsd;
-
-import android.os.Messenger;
-import android.net.nsd.NsdServiceInfo;
-
-/**
- * Callbacks from NsdService to NsdManager
- * @hide
- */
-oneway interface INsdManagerCallback {
-    void onDiscoverServicesStarted(int listenerKey, in NsdServiceInfo info);
-    void onDiscoverServicesFailed(int listenerKey, int error);
-    void onServiceFound(int listenerKey, in NsdServiceInfo info);
-    void onServiceLost(int listenerKey, in NsdServiceInfo info);
-    void onStopDiscoveryFailed(int listenerKey, int error);
-    void onStopDiscoverySucceeded(int listenerKey);
-    void onRegisterServiceFailed(int listenerKey, int error);
-    void onRegisterServiceSucceeded(int listenerKey, in NsdServiceInfo info);
-    void onUnregisterServiceFailed(int listenerKey, int error);
-    void onUnregisterServiceSucceeded(int listenerKey);
-    void onResolveServiceFailed(int listenerKey, int error);
-    void onResolveServiceSucceeded(int listenerKey, in NsdServiceInfo info);
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdServiceConnector.aidl b/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdServiceConnector.aidl
deleted file mode 100644
index b06ae55..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdServiceConnector.aidl
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.nsd;
-
-import android.net.nsd.INsdManagerCallback;
-import android.net.nsd.NsdServiceInfo;
-import android.os.Messenger;
-
-/**
- * Interface that NsdService implements for each NsdManager client.
- *
- * {@hide}
- */
-interface INsdServiceConnector {
-    void registerService(int listenerKey, in NsdServiceInfo serviceInfo);
-    void unregisterService(int listenerKey);
-    void discoverServices(int listenerKey, in NsdServiceInfo serviceInfo);
-    void stopDiscovery(int listenerKey);
-    void resolveService(int listenerKey, in NsdServiceInfo serviceInfo);
-    void startDaemon();
-}
\ No newline at end of file
diff --git a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java b/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java
deleted file mode 100644
index 512fbce..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java
+++ /dev/null
@@ -1,1005 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.nsd;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SystemService;
-import android.app.compat.CompatChanges;
-import android.compat.annotation.ChangeId;
-import android.compat.annotation.EnabledSince;
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.NetworkCallback;
-import android.net.Network;
-import android.net.NetworkRequest;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.Objects;
-
-/**
- * The Network Service Discovery Manager class provides the API to discover services
- * on a network. As an example, if device A and device B are connected over a Wi-Fi
- * network, a game registered on device A can be discovered by a game on device
- * B. Another example use case is an application discovering printers on the network.
- *
- * <p> The API currently supports DNS based service discovery and discovery is currently
- * limited to a local network over Multicast DNS. DNS service discovery is described at
- * http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt
- *
- * <p> The API is asynchronous, and responses to requests from an application are on listener
- * callbacks on a separate internal thread.
- *
- * <p> There are three main operations the API supports - registration, discovery and resolution.
- * <pre>
- *                          Application start
- *                                 |
- *                                 |
- *                                 |                  onServiceRegistered()
- *                     Register any local services  /
- *                      to be advertised with       \
- *                       registerService()            onRegistrationFailed()
- *                                 |
- *                                 |
- *                          discoverServices()
- *                                 |
- *                      Maintain a list to track
- *                        discovered services
- *                                 |
- *                                 |--------->
- *                                 |          |
- *                                 |      onServiceFound()
- *                                 |          |
- *                                 |     add service to list
- *                                 |          |
- *                                 |<----------
- *                                 |
- *                                 |--------->
- *                                 |          |
- *                                 |      onServiceLost()
- *                                 |          |
- *                                 |   remove service from list
- *                                 |          |
- *                                 |<----------
- *                                 |
- *                                 |
- *                                 | Connect to a service
- *                                 | from list ?
- *                                 |
- *                          resolveService()
- *                                 |
- *                         onServiceResolved()
- *                                 |
- *                     Establish connection to service
- *                     with the host and port information
- *
- * </pre>
- * An application that needs to advertise itself over a network for other applications to
- * discover it can do so with a call to {@link #registerService}. If Example is a http based
- * application that can provide HTML data to peer services, it can register a name "Example"
- * with service type "_http._tcp". A successful registration is notified with a callback to
- * {@link RegistrationListener#onServiceRegistered} and a failure to register is notified
- * over {@link RegistrationListener#onRegistrationFailed}
- *
- * <p> A peer application looking for http services can initiate a discovery for "_http._tcp"
- * with a call to {@link #discoverServices}. A service found is notified with a callback
- * to {@link DiscoveryListener#onServiceFound} and a service lost is notified on
- * {@link DiscoveryListener#onServiceLost}.
- *
- * <p> Once the peer application discovers the "Example" http service, and either needs to read the
- * attributes of the service or wants to receive data from the "Example" application, it can
- * initiate a resolve with {@link #resolveService} to resolve the attributes, host, and port
- * details. A successful resolve is notified on {@link ResolveListener#onServiceResolved} and a
- * failure is notified on {@link ResolveListener#onResolveFailed}.
- *
- * Applications can reserve for a service type at
- * http://www.iana.org/form/ports-service. Existing services can be found at
- * http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml
- *
- * {@see NsdServiceInfo}
- */
-@SystemService(Context.NSD_SERVICE)
-public final class NsdManager {
-    private static final String TAG = NsdManager.class.getSimpleName();
-    private static final boolean DBG = false;
-
-    /**
-     * When enabled, apps targeting < Android 12 are considered legacy for
-     * the NSD native daemon.
-     * The platform will only keep the daemon running as long as there are
-     * any legacy apps connected.
-     *
-     * After Android 12, directly communicate with native daemon might not
-     * work since the native damon won't always stay alive.
-     * Use the NSD APIs from NsdManager as the replacement is recommended.
-     * An another alternative could be bundling your own mdns solutions instead of
-     * depending on the system mdns native daemon.
-     *
-     * @hide
-     */
-    @ChangeId
-    @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S)
-    public static final long RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS = 191844585L;
-
-    /**
-     * Broadcast intent action to indicate whether network service discovery is
-     * enabled or disabled. An extra {@link #EXTRA_NSD_STATE} provides the state
-     * information as int.
-     *
-     * @see #EXTRA_NSD_STATE
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_NSD_STATE_CHANGED = "android.net.nsd.STATE_CHANGED";
-
-    /**
-     * The lookup key for an int that indicates whether network service discovery is enabled
-     * or disabled. Retrieve it with {@link android.content.Intent#getIntExtra(String,int)}.
-     *
-     * @see #NSD_STATE_DISABLED
-     * @see #NSD_STATE_ENABLED
-     */
-    public static final String EXTRA_NSD_STATE = "nsd_state";
-
-    /**
-     * Network service discovery is disabled
-     *
-     * @see #ACTION_NSD_STATE_CHANGED
-     */
-    public static final int NSD_STATE_DISABLED = 1;
-
-    /**
-     * Network service discovery is enabled
-     *
-     * @see #ACTION_NSD_STATE_CHANGED
-     */
-    public static final int NSD_STATE_ENABLED = 2;
-
-    /** @hide */
-    public static final int DISCOVER_SERVICES                       = 1;
-    /** @hide */
-    public static final int DISCOVER_SERVICES_STARTED               = 2;
-    /** @hide */
-    public static final int DISCOVER_SERVICES_FAILED                = 3;
-    /** @hide */
-    public static final int SERVICE_FOUND                           = 4;
-    /** @hide */
-    public static final int SERVICE_LOST                            = 5;
-
-    /** @hide */
-    public static final int STOP_DISCOVERY                          = 6;
-    /** @hide */
-    public static final int STOP_DISCOVERY_FAILED                   = 7;
-    /** @hide */
-    public static final int STOP_DISCOVERY_SUCCEEDED                = 8;
-
-    /** @hide */
-    public static final int REGISTER_SERVICE                        = 9;
-    /** @hide */
-    public static final int REGISTER_SERVICE_FAILED                 = 10;
-    /** @hide */
-    public static final int REGISTER_SERVICE_SUCCEEDED              = 11;
-
-    /** @hide */
-    public static final int UNREGISTER_SERVICE                      = 12;
-    /** @hide */
-    public static final int UNREGISTER_SERVICE_FAILED               = 13;
-    /** @hide */
-    public static final int UNREGISTER_SERVICE_SUCCEEDED            = 14;
-
-    /** @hide */
-    public static final int RESOLVE_SERVICE                         = 15;
-    /** @hide */
-    public static final int RESOLVE_SERVICE_FAILED                  = 16;
-    /** @hide */
-    public static final int RESOLVE_SERVICE_SUCCEEDED               = 17;
-
-    /** @hide */
-    public static final int DAEMON_CLEANUP                          = 18;
-
-    /** @hide */
-    public static final int DAEMON_STARTUP                          = 19;
-
-    /** @hide */
-    public static final int ENABLE                                  = 20;
-    /** @hide */
-    public static final int DISABLE                                 = 21;
-
-    /** @hide */
-    public static final int NATIVE_DAEMON_EVENT                     = 22;
-
-    /** @hide */
-    public static final int REGISTER_CLIENT                         = 23;
-    /** @hide */
-    public static final int UNREGISTER_CLIENT                       = 24;
-
-    /** Dns based service discovery protocol */
-    public static final int PROTOCOL_DNS_SD = 0x0001;
-
-    private static final SparseArray<String> EVENT_NAMES = new SparseArray<>();
-    static {
-        EVENT_NAMES.put(DISCOVER_SERVICES, "DISCOVER_SERVICES");
-        EVENT_NAMES.put(DISCOVER_SERVICES_STARTED, "DISCOVER_SERVICES_STARTED");
-        EVENT_NAMES.put(DISCOVER_SERVICES_FAILED, "DISCOVER_SERVICES_FAILED");
-        EVENT_NAMES.put(SERVICE_FOUND, "SERVICE_FOUND");
-        EVENT_NAMES.put(SERVICE_LOST, "SERVICE_LOST");
-        EVENT_NAMES.put(STOP_DISCOVERY, "STOP_DISCOVERY");
-        EVENT_NAMES.put(STOP_DISCOVERY_FAILED, "STOP_DISCOVERY_FAILED");
-        EVENT_NAMES.put(STOP_DISCOVERY_SUCCEEDED, "STOP_DISCOVERY_SUCCEEDED");
-        EVENT_NAMES.put(REGISTER_SERVICE, "REGISTER_SERVICE");
-        EVENT_NAMES.put(REGISTER_SERVICE_FAILED, "REGISTER_SERVICE_FAILED");
-        EVENT_NAMES.put(REGISTER_SERVICE_SUCCEEDED, "REGISTER_SERVICE_SUCCEEDED");
-        EVENT_NAMES.put(UNREGISTER_SERVICE, "UNREGISTER_SERVICE");
-        EVENT_NAMES.put(UNREGISTER_SERVICE_FAILED, "UNREGISTER_SERVICE_FAILED");
-        EVENT_NAMES.put(UNREGISTER_SERVICE_SUCCEEDED, "UNREGISTER_SERVICE_SUCCEEDED");
-        EVENT_NAMES.put(RESOLVE_SERVICE, "RESOLVE_SERVICE");
-        EVENT_NAMES.put(RESOLVE_SERVICE_FAILED, "RESOLVE_SERVICE_FAILED");
-        EVENT_NAMES.put(RESOLVE_SERVICE_SUCCEEDED, "RESOLVE_SERVICE_SUCCEEDED");
-        EVENT_NAMES.put(DAEMON_CLEANUP, "DAEMON_CLEANUP");
-        EVENT_NAMES.put(DAEMON_STARTUP, "DAEMON_STARTUP");
-        EVENT_NAMES.put(ENABLE, "ENABLE");
-        EVENT_NAMES.put(DISABLE, "DISABLE");
-        EVENT_NAMES.put(NATIVE_DAEMON_EVENT, "NATIVE_DAEMON_EVENT");
-    }
-
-    /** @hide */
-    public static String nameOf(int event) {
-        String name = EVENT_NAMES.get(event);
-        if (name == null) {
-            return Integer.toString(event);
-        }
-        return name;
-    }
-
-    private static final int FIRST_LISTENER_KEY = 1;
-
-    private final INsdServiceConnector mService;
-    private final Context mContext;
-
-    private int mListenerKey = FIRST_LISTENER_KEY;
-    private final SparseArray mListenerMap = new SparseArray();
-    private final SparseArray<NsdServiceInfo> mServiceMap = new SparseArray<>();
-    private final Object mMapLock = new Object();
-    // Map of listener key sent by client -> per-network discovery tracker
-    @GuardedBy("mPerNetworkDiscoveryMap")
-    private final ArrayMap<Integer, PerNetworkDiscoveryTracker>
-            mPerNetworkDiscoveryMap = new ArrayMap<>();
-
-    private final ServiceHandler mHandler;
-
-    private class PerNetworkDiscoveryTracker {
-        final String mServiceType;
-        final int mProtocolType;
-        final DiscoveryListener mBaseListener;
-        final ArrayMap<Network, DelegatingDiscoveryListener> mPerNetworkListeners =
-                new ArrayMap<>();
-
-        final NetworkCallback mNetworkCb = new NetworkCallback() {
-            @Override
-            public void onAvailable(@NonNull Network network) {
-                final DelegatingDiscoveryListener wrappedListener = new DelegatingDiscoveryListener(
-                        network, mBaseListener);
-                mPerNetworkListeners.put(network, wrappedListener);
-                discoverServices(mServiceType, mProtocolType, network, wrappedListener);
-            }
-
-            @Override
-            public void onLost(@NonNull Network network) {
-                final DelegatingDiscoveryListener listener = mPerNetworkListeners.get(network);
-                if (listener == null) return;
-                listener.notifyAllServicesLost();
-                // Listener will be removed from map in discovery stopped callback
-                stopServiceDiscovery(listener);
-            }
-        };
-
-        // Accessed from mHandler
-        private boolean mStopRequested;
-
-        public void start(@NonNull NetworkRequest request) {
-            final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
-            cm.registerNetworkCallback(request, mNetworkCb, mHandler);
-            mHandler.post(() -> mBaseListener.onDiscoveryStarted(mServiceType));
-        }
-
-        /**
-         * Stop discovery on all networks tracked by this class.
-         *
-         * This will request all underlying listeners to stop, and the last one to stop will call
-         * onDiscoveryStopped or onStopDiscoveryFailed.
-         *
-         * Must be called on the handler thread.
-         */
-        public void requestStop() {
-            mHandler.post(() -> {
-                mStopRequested = true;
-                final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
-                cm.unregisterNetworkCallback(mNetworkCb);
-                if (mPerNetworkListeners.size() == 0) {
-                    mBaseListener.onDiscoveryStopped(mServiceType);
-                    return;
-                }
-                for (int i = 0; i < mPerNetworkListeners.size(); i++) {
-                    final DelegatingDiscoveryListener listener = mPerNetworkListeners.valueAt(i);
-                    stopServiceDiscovery(listener);
-                }
-            });
-        }
-
-        private PerNetworkDiscoveryTracker(String serviceType, int protocolType,
-                DiscoveryListener baseListener) {
-            mServiceType = serviceType;
-            mProtocolType = protocolType;
-            mBaseListener = baseListener;
-        }
-
-        /**
-         * Subset of NsdServiceInfo that is tracked to generate service lost notifications when a
-         * network is lost.
-         *
-         * Service lost notifications only contain service name, type and network, so only track
-         * that information (Network is known from the listener). This also implements
-         * equals/hashCode for usage in maps.
-         */
-        private class TrackedNsdInfo {
-            private final String mServiceName;
-            private final String mServiceType;
-            TrackedNsdInfo(NsdServiceInfo info) {
-                mServiceName = info.getServiceName();
-                mServiceType = info.getServiceType();
-            }
-
-            @Override
-            public int hashCode() {
-                return Objects.hash(mServiceName, mServiceType);
-            }
-
-            @Override
-            public boolean equals(Object obj) {
-                if (!(obj instanceof TrackedNsdInfo)) return false;
-                final TrackedNsdInfo other = (TrackedNsdInfo) obj;
-                return Objects.equals(mServiceName, other.mServiceName)
-                        && Objects.equals(mServiceType, other.mServiceType);
-            }
-        }
-
-        private class DelegatingDiscoveryListener implements DiscoveryListener {
-            private final Network mNetwork;
-            private final DiscoveryListener mWrapped;
-            private final ArraySet<TrackedNsdInfo> mFoundInfo = new ArraySet<>();
-
-            private DelegatingDiscoveryListener(Network network, DiscoveryListener listener) {
-                mNetwork = network;
-                mWrapped = listener;
-            }
-
-            void notifyAllServicesLost() {
-                for (int i = 0; i < mFoundInfo.size(); i++) {
-                    final TrackedNsdInfo trackedInfo = mFoundInfo.valueAt(i);
-                    final NsdServiceInfo serviceInfo = new NsdServiceInfo(
-                            trackedInfo.mServiceName, trackedInfo.mServiceType);
-                    serviceInfo.setNetwork(mNetwork);
-                    mWrapped.onServiceLost(serviceInfo);
-                }
-            }
-
-            @Override
-            public void onStartDiscoveryFailed(String serviceType, int errorCode) {
-                // The delegated listener is used when NsdManager takes care of starting/stopping
-                // discovery on multiple networks. Failure to start on one network is not a global
-                // failure to be reported up, as other networks may succeed: just log.
-                Log.e(TAG, "Failed to start discovery for " + serviceType + " on " + mNetwork
-                        + " with code " + errorCode);
-                mPerNetworkListeners.remove(mNetwork);
-            }
-
-            @Override
-            public void onDiscoveryStarted(String serviceType) {
-                // Wrapped listener was called upon registration, it is not called for discovery
-                // on each network
-            }
-
-            @Override
-            public void onStopDiscoveryFailed(String serviceType, int errorCode) {
-                Log.e(TAG, "Failed to stop discovery for " + serviceType + " on " + mNetwork
-                        + " with code " + errorCode);
-                mPerNetworkListeners.remove(mNetwork);
-                if (mStopRequested && mPerNetworkListeners.size() == 0) {
-                    // Do not report onStopDiscoveryFailed when some underlying listeners failed:
-                    // this does not mean that all listeners did, and onStopDiscoveryFailed is not
-                    // actionable anyway. Just report that discovery stopped.
-                    mWrapped.onDiscoveryStopped(serviceType);
-                }
-            }
-
-            @Override
-            public void onDiscoveryStopped(String serviceType) {
-                mPerNetworkListeners.remove(mNetwork);
-                if (mStopRequested && mPerNetworkListeners.size() == 0) {
-                    mWrapped.onDiscoveryStopped(serviceType);
-                }
-            }
-
-            @Override
-            public void onServiceFound(NsdServiceInfo serviceInfo) {
-                mFoundInfo.add(new TrackedNsdInfo(serviceInfo));
-                mWrapped.onServiceFound(serviceInfo);
-            }
-
-            @Override
-            public void onServiceLost(NsdServiceInfo serviceInfo) {
-                mFoundInfo.remove(new TrackedNsdInfo(serviceInfo));
-                mWrapped.onServiceLost(serviceInfo);
-            }
-        }
-    }
-
-    /**
-     * Create a new Nsd instance. Applications use
-     * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
-     * {@link android.content.Context#NSD_SERVICE Context.NSD_SERVICE}.
-     * @param service the Binder interface
-     * @hide - hide this because it takes in a parameter of type INsdManager, which
-     * is a system private class.
-     */
-    public NsdManager(Context context, INsdManager service) {
-        mContext = context;
-
-        HandlerThread t = new HandlerThread("NsdManager");
-        t.start();
-        mHandler = new ServiceHandler(t.getLooper());
-
-        try {
-            mService = service.connect(new NsdCallbackImpl(mHandler));
-        } catch (RemoteException e) {
-            throw new RuntimeException("Failed to connect to NsdService");
-        }
-
-        // Only proactively start the daemon if the target SDK < S, otherwise the internal service
-        // would automatically start/stop the native daemon as needed.
-        if (!CompatChanges.isChangeEnabled(RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)) {
-            try {
-                mService.startDaemon();
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to proactively start daemon");
-                // Continue: the daemon can still be started on-demand later
-            }
-        }
-    }
-
-    private static class NsdCallbackImpl extends INsdManagerCallback.Stub {
-        private final Handler mServHandler;
-
-        NsdCallbackImpl(Handler serviceHandler) {
-            mServHandler = serviceHandler;
-        }
-
-        private void sendInfo(int message, int listenerKey, NsdServiceInfo info) {
-            mServHandler.sendMessage(mServHandler.obtainMessage(message, 0, listenerKey, info));
-        }
-
-        private void sendError(int message, int listenerKey, int error) {
-            mServHandler.sendMessage(mServHandler.obtainMessage(message, error, listenerKey));
-        }
-
-        private void sendNoArg(int message, int listenerKey) {
-            mServHandler.sendMessage(mServHandler.obtainMessage(message, 0, listenerKey));
-        }
-
-        @Override
-        public void onDiscoverServicesStarted(int listenerKey, NsdServiceInfo info) {
-            sendInfo(DISCOVER_SERVICES_STARTED, listenerKey, info);
-        }
-
-        @Override
-        public void onDiscoverServicesFailed(int listenerKey, int error) {
-            sendError(DISCOVER_SERVICES_FAILED, listenerKey, error);
-        }
-
-        @Override
-        public void onServiceFound(int listenerKey, NsdServiceInfo info) {
-            sendInfo(SERVICE_FOUND, listenerKey, info);
-        }
-
-        @Override
-        public void onServiceLost(int listenerKey, NsdServiceInfo info) {
-            sendInfo(SERVICE_LOST, listenerKey, info);
-        }
-
-        @Override
-        public void onStopDiscoveryFailed(int listenerKey, int error) {
-            sendError(STOP_DISCOVERY_FAILED, listenerKey, error);
-        }
-
-        @Override
-        public void onStopDiscoverySucceeded(int listenerKey) {
-            sendNoArg(STOP_DISCOVERY_SUCCEEDED, listenerKey);
-        }
-
-        @Override
-        public void onRegisterServiceFailed(int listenerKey, int error) {
-            sendError(REGISTER_SERVICE_FAILED, listenerKey, error);
-        }
-
-        @Override
-        public void onRegisterServiceSucceeded(int listenerKey, NsdServiceInfo info) {
-            sendInfo(REGISTER_SERVICE_SUCCEEDED, listenerKey, info);
-        }
-
-        @Override
-        public void onUnregisterServiceFailed(int listenerKey, int error) {
-            sendError(UNREGISTER_SERVICE_FAILED, listenerKey, error);
-        }
-
-        @Override
-        public void onUnregisterServiceSucceeded(int listenerKey) {
-            sendNoArg(UNREGISTER_SERVICE_SUCCEEDED, listenerKey);
-        }
-
-        @Override
-        public void onResolveServiceFailed(int listenerKey, int error) {
-            sendError(RESOLVE_SERVICE_FAILED, listenerKey, error);
-        }
-
-        @Override
-        public void onResolveServiceSucceeded(int listenerKey, NsdServiceInfo info) {
-            sendInfo(RESOLVE_SERVICE_SUCCEEDED, listenerKey, info);
-        }
-    }
-
-    /**
-     * Failures are passed with {@link RegistrationListener#onRegistrationFailed},
-     * {@link RegistrationListener#onUnregistrationFailed},
-     * {@link DiscoveryListener#onStartDiscoveryFailed},
-     * {@link DiscoveryListener#onStopDiscoveryFailed} or {@link ResolveListener#onResolveFailed}.
-     *
-     * Indicates that the operation failed due to an internal error.
-     */
-    public static final int FAILURE_INTERNAL_ERROR               = 0;
-
-    /**
-     * Indicates that the operation failed because it is already active.
-     */
-    public static final int FAILURE_ALREADY_ACTIVE              = 3;
-
-    /**
-     * Indicates that the operation failed because the maximum outstanding
-     * requests from the applications have reached.
-     */
-    public static final int FAILURE_MAX_LIMIT                   = 4;
-
-    /** Interface for callback invocation for service discovery */
-    public interface DiscoveryListener {
-
-        public void onStartDiscoveryFailed(String serviceType, int errorCode);
-
-        public void onStopDiscoveryFailed(String serviceType, int errorCode);
-
-        public void onDiscoveryStarted(String serviceType);
-
-        public void onDiscoveryStopped(String serviceType);
-
-        public void onServiceFound(NsdServiceInfo serviceInfo);
-
-        public void onServiceLost(NsdServiceInfo serviceInfo);
-    }
-
-    /** Interface for callback invocation for service registration */
-    public interface RegistrationListener {
-
-        public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode);
-
-        public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode);
-
-        public void onServiceRegistered(NsdServiceInfo serviceInfo);
-
-        public void onServiceUnregistered(NsdServiceInfo serviceInfo);
-    }
-
-    /** Interface for callback invocation for service resolution */
-    public interface ResolveListener {
-
-        public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode);
-
-        public void onServiceResolved(NsdServiceInfo serviceInfo);
-    }
-
-    @VisibleForTesting
-    class ServiceHandler extends Handler {
-        ServiceHandler(Looper looper) {
-            super(looper);
-        }
-
-        @Override
-        public void handleMessage(Message message) {
-            final int what = message.what;
-            final int key = message.arg2;
-            final Object listener;
-            final NsdServiceInfo ns;
-            synchronized (mMapLock) {
-                listener = mListenerMap.get(key);
-                ns = mServiceMap.get(key);
-            }
-            if (listener == null) {
-                Log.d(TAG, "Stale key " + message.arg2);
-                return;
-            }
-            if (DBG) {
-                Log.d(TAG, "received " + nameOf(what) + " for key " + key + ", service " + ns);
-            }
-            switch (what) {
-                case DISCOVER_SERVICES_STARTED:
-                    String s = getNsdServiceInfoType((NsdServiceInfo) message.obj);
-                    ((DiscoveryListener) listener).onDiscoveryStarted(s);
-                    break;
-                case DISCOVER_SERVICES_FAILED:
-                    removeListener(key);
-                    ((DiscoveryListener) listener).onStartDiscoveryFailed(getNsdServiceInfoType(ns),
-                            message.arg1);
-                    break;
-                case SERVICE_FOUND:
-                    ((DiscoveryListener) listener).onServiceFound((NsdServiceInfo) message.obj);
-                    break;
-                case SERVICE_LOST:
-                    ((DiscoveryListener) listener).onServiceLost((NsdServiceInfo) message.obj);
-                    break;
-                case STOP_DISCOVERY_FAILED:
-                    // TODO: failure to stop discovery should be internal and retried internally, as
-                    // the effect for the client is indistinguishable from STOP_DISCOVERY_SUCCEEDED
-                    removeListener(key);
-                    ((DiscoveryListener) listener).onStopDiscoveryFailed(getNsdServiceInfoType(ns),
-                            message.arg1);
-                    break;
-                case STOP_DISCOVERY_SUCCEEDED:
-                    removeListener(key);
-                    ((DiscoveryListener) listener).onDiscoveryStopped(getNsdServiceInfoType(ns));
-                    break;
-                case REGISTER_SERVICE_FAILED:
-                    removeListener(key);
-                    ((RegistrationListener) listener).onRegistrationFailed(ns, message.arg1);
-                    break;
-                case REGISTER_SERVICE_SUCCEEDED:
-                    ((RegistrationListener) listener).onServiceRegistered(
-                            (NsdServiceInfo) message.obj);
-                    break;
-                case UNREGISTER_SERVICE_FAILED:
-                    removeListener(key);
-                    ((RegistrationListener) listener).onUnregistrationFailed(ns, message.arg1);
-                    break;
-                case UNREGISTER_SERVICE_SUCCEEDED:
-                    // TODO: do not unregister listener until service is unregistered, or provide
-                    // alternative way for unregistering ?
-                    removeListener(message.arg2);
-                    ((RegistrationListener) listener).onServiceUnregistered(ns);
-                    break;
-                case RESOLVE_SERVICE_FAILED:
-                    removeListener(key);
-                    ((ResolveListener) listener).onResolveFailed(ns, message.arg1);
-                    break;
-                case RESOLVE_SERVICE_SUCCEEDED:
-                    removeListener(key);
-                    ((ResolveListener) listener).onServiceResolved((NsdServiceInfo) message.obj);
-                    break;
-                default:
-                    Log.d(TAG, "Ignored " + message);
-                    break;
-            }
-        }
-    }
-
-    private int nextListenerKey() {
-        // Ensure mListenerKey >= FIRST_LISTENER_KEY;
-        mListenerKey = Math.max(FIRST_LISTENER_KEY, mListenerKey + 1);
-        return mListenerKey;
-    }
-
-    // Assert that the listener is not in the map, then add it and returns its key
-    private int putListener(Object listener, NsdServiceInfo s) {
-        checkListener(listener);
-        final int key;
-        synchronized (mMapLock) {
-            int valueIndex = mListenerMap.indexOfValue(listener);
-            if (valueIndex != -1) {
-                throw new IllegalArgumentException("listener already in use");
-            }
-            key = nextListenerKey();
-            mListenerMap.put(key, listener);
-            mServiceMap.put(key, s);
-        }
-        return key;
-    }
-
-    private void removeListener(int key) {
-        synchronized (mMapLock) {
-            mListenerMap.remove(key);
-            mServiceMap.remove(key);
-        }
-    }
-
-    private int getListenerKey(Object listener) {
-        checkListener(listener);
-        synchronized (mMapLock) {
-            int valueIndex = mListenerMap.indexOfValue(listener);
-            if (valueIndex == -1) {
-                throw new IllegalArgumentException("listener not registered");
-            }
-            return mListenerMap.keyAt(valueIndex);
-        }
-    }
-
-    private static String getNsdServiceInfoType(NsdServiceInfo s) {
-        if (s == null) return "?";
-        return s.getServiceType();
-    }
-
-    /**
-     * Register a service to be discovered by other services.
-     *
-     * <p> The function call immediately returns after sending a request to register service
-     * to the framework. The application is notified of a successful registration
-     * through the callback {@link RegistrationListener#onServiceRegistered} or a failure
-     * through {@link RegistrationListener#onRegistrationFailed}.
-     *
-     * <p> The application should call {@link #unregisterService} when the service
-     * registration is no longer required, and/or whenever the application is stopped.
-     *
-     * @param serviceInfo The service being registered
-     * @param protocolType The service discovery protocol
-     * @param listener The listener notifies of a successful registration and is used to
-     * unregister this service through a call on {@link #unregisterService}. Cannot be null.
-     * Cannot be in use for an active service registration.
-     */
-    public void registerService(NsdServiceInfo serviceInfo, int protocolType,
-            RegistrationListener listener) {
-        if (serviceInfo.getPort() <= 0) {
-            throw new IllegalArgumentException("Invalid port number");
-        }
-        checkServiceInfo(serviceInfo);
-        checkProtocol(protocolType);
-        int key = putListener(listener, serviceInfo);
-        try {
-            mService.registerService(key, serviceInfo);
-        } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Unregister a service registered through {@link #registerService}. A successful
-     * unregister is notified to the application with a call to
-     * {@link RegistrationListener#onServiceUnregistered}.
-     *
-     * @param listener This should be the listener object that was passed to
-     * {@link #registerService}. It identifies the service that should be unregistered
-     * and notifies of a successful or unsuccessful unregistration via the listener
-     * callbacks.  In API versions 20 and above, the listener object may be used for
-     * another service registration once the callback has been called.  In API versions <= 19,
-     * there is no entirely reliable way to know when a listener may be re-used, and a new
-     * listener should be created for each service registration request.
-     */
-    public void unregisterService(RegistrationListener listener) {
-        int id = getListenerKey(listener);
-        try {
-            mService.unregisterService(id);
-        } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Same as {@link #discoverServices(String, int, Network, DiscoveryListener)} with a null
-     * {@link Network}.
-     */
-    public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) {
-        discoverServices(serviceType, protocolType, (Network) null, listener);
-    }
-
-    /**
-     * Initiate service discovery to browse for instances of a service type. Service discovery
-     * consumes network bandwidth and will continue until the application calls
-     * {@link #stopServiceDiscovery}.
-     *
-     * <p> The function call immediately returns after sending a request to start service
-     * discovery to the framework. The application is notified of a success to initiate
-     * discovery through the callback {@link DiscoveryListener#onDiscoveryStarted} or a failure
-     * through {@link DiscoveryListener#onStartDiscoveryFailed}.
-     *
-     * <p> Upon successful start, application is notified when a service is found with
-     * {@link DiscoveryListener#onServiceFound} or when a service is lost with
-     * {@link DiscoveryListener#onServiceLost}.
-     *
-     * <p> Upon failure to start, service discovery is not active and application does
-     * not need to invoke {@link #stopServiceDiscovery}
-     *
-     * <p> The application should call {@link #stopServiceDiscovery} when discovery of this
-     * service type is no longer required, and/or whenever the application is paused or
-     * stopped.
-     *
-     * @param serviceType The service type being discovered. Examples include "_http._tcp" for
-     * http services or "_ipp._tcp" for printers
-     * @param protocolType The service discovery protocol
-     * @param network Network to discover services on, or null to discover on all available networks
-     * @param listener  The listener notifies of a successful discovery and is used
-     * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}.
-     * Cannot be null. Cannot be in use for an active service discovery.
-     */
-    public void discoverServices(@NonNull String serviceType, int protocolType,
-            @Nullable Network network, @NonNull DiscoveryListener listener) {
-        if (TextUtils.isEmpty(serviceType)) {
-            throw new IllegalArgumentException("Service type cannot be empty");
-        }
-        checkProtocol(protocolType);
-
-        NsdServiceInfo s = new NsdServiceInfo();
-        s.setServiceType(serviceType);
-        s.setNetwork(network);
-
-        int key = putListener(listener, s);
-        try {
-            mService.discoverServices(key, s);
-        } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Initiate service discovery to browse for instances of a service type. Service discovery
-     * consumes network bandwidth and will continue until the application calls
-     * {@link #stopServiceDiscovery}.
-     *
-     * <p> The function call immediately returns after sending a request to start service
-     * discovery to the framework. The application is notified of a success to initiate
-     * discovery through the callback {@link DiscoveryListener#onDiscoveryStarted} or a failure
-     * through {@link DiscoveryListener#onStartDiscoveryFailed}.
-     *
-     * <p> Upon successful start, application is notified when a service is found with
-     * {@link DiscoveryListener#onServiceFound} or when a service is lost with
-     * {@link DiscoveryListener#onServiceLost}.
-     *
-     * <p> Upon failure to start, service discovery is not active and application does
-     * not need to invoke {@link #stopServiceDiscovery}
-     *
-     * <p> The application should call {@link #stopServiceDiscovery} when discovery of this
-     * service type is no longer required, and/or whenever the application is paused or
-     * stopped.
-     *
-     * <p> During discovery, new networks may connect or existing networks may disconnect - for
-     * example if wifi is reconnected. When a service was found on a network that disconnects,
-     * {@link DiscoveryListener#onServiceLost} will be called. If a new network connects that
-     * matches the {@link NetworkRequest}, {@link DiscoveryListener#onServiceFound} will be called
-     * for services found on that network. Applications that do not want to track networks
-     * themselves are encouraged to use this method instead of other overloads of
-     * {@code discoverServices}, as they will receive proper notifications when a service becomes
-     * available or unavailable due to network changes.
-     *
-     * @param serviceType The service type being discovered. Examples include "_http._tcp" for
-     * http services or "_ipp._tcp" for printers
-     * @param protocolType The service discovery protocol
-     * @param networkRequest Request specifying networks that should be considered when discovering
-     * @param listener  The listener notifies of a successful discovery and is used
-     * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}.
-     * Cannot be null. Cannot be in use for an active service discovery.
-     */
-    @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
-    public void discoverServices(@NonNull String serviceType, int protocolType,
-            @NonNull NetworkRequest networkRequest, @NonNull DiscoveryListener listener) {
-        if (TextUtils.isEmpty(serviceType)) {
-            throw new IllegalArgumentException("Service type cannot be empty");
-        }
-        Objects.requireNonNull(networkRequest, "NetworkRequest cannot be null");
-        checkProtocol(protocolType);
-
-        NsdServiceInfo s = new NsdServiceInfo();
-        s.setServiceType(serviceType);
-
-        final int baseListenerKey = putListener(listener, s);
-
-        final PerNetworkDiscoveryTracker discoveryInfo = new PerNetworkDiscoveryTracker(
-                serviceType, protocolType, listener);
-
-        synchronized (mPerNetworkDiscoveryMap) {
-            mPerNetworkDiscoveryMap.put(baseListenerKey, discoveryInfo);
-            discoveryInfo.start(networkRequest);
-        }
-    }
-
-    /**
-     * Stop service discovery initiated with {@link #discoverServices}.  An active service
-     * discovery is notified to the application with {@link DiscoveryListener#onDiscoveryStarted}
-     * and it stays active until the application invokes a stop service discovery. A successful
-     * stop is notified to with a call to {@link DiscoveryListener#onDiscoveryStopped}.
-     *
-     * <p> Upon failure to stop service discovery, application is notified through
-     * {@link DiscoveryListener#onStopDiscoveryFailed}.
-     *
-     * @param listener This should be the listener object that was passed to {@link #discoverServices}.
-     * It identifies the discovery that should be stopped and notifies of a successful or
-     * unsuccessful stop.  In API versions 20 and above, the listener object may be used for
-     * another service discovery once the callback has been called.  In API versions <= 19,
-     * there is no entirely reliable way to know when a listener may be re-used, and a new
-     * listener should be created for each service discovery request.
-     */
-    public void stopServiceDiscovery(DiscoveryListener listener) {
-        int id = getListenerKey(listener);
-        // If this is a PerNetworkDiscovery request, handle it as such
-        synchronized (mPerNetworkDiscoveryMap) {
-            final PerNetworkDiscoveryTracker info = mPerNetworkDiscoveryMap.get(id);
-            if (info != null) {
-                info.requestStop();
-                return;
-            }
-        }
-        try {
-            mService.stopDiscovery(id);
-        } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Resolve a discovered service. An application can resolve a service right before
-     * establishing a connection to fetch the IP and port details on which to setup
-     * the connection.
-     *
-     * @param serviceInfo service to be resolved
-     * @param listener to receive callback upon success or failure. Cannot be null.
-     * Cannot be in use for an active service resolution.
-     */
-    public void resolveService(NsdServiceInfo serviceInfo, ResolveListener listener) {
-        checkServiceInfo(serviceInfo);
-        int key = putListener(listener, serviceInfo);
-        try {
-            mService.resolveService(key, serviceInfo);
-        } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-        }
-    }
-
-    private static void checkListener(Object listener) {
-        Objects.requireNonNull(listener, "listener cannot be null");
-    }
-
-    private static void checkProtocol(int protocolType) {
-        if (protocolType != PROTOCOL_DNS_SD) {
-            throw new IllegalArgumentException("Unsupported protocol");
-        }
-    }
-
-    private static void checkServiceInfo(NsdServiceInfo serviceInfo) {
-        Objects.requireNonNull(serviceInfo, "NsdServiceInfo cannot be null");
-        if (TextUtils.isEmpty(serviceInfo.getServiceName())) {
-            throw new IllegalArgumentException("Service name cannot be empty");
-        }
-        if (TextUtils.isEmpty(serviceInfo.getServiceType())) {
-            throw new IllegalArgumentException("Service type cannot be empty");
-        }
-    }
-}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java b/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java
deleted file mode 100644
index 8506db1..0000000
--- a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java
+++ /dev/null
@@ -1,418 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.nsd;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.net.Network;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.Base64;
-import android.util.Log;
-
-import java.io.UnsupportedEncodingException;
-import java.net.InetAddress;
-import java.nio.charset.StandardCharsets;
-import java.util.Collections;
-import java.util.Map;
-
-/**
- * A class representing service information for network service discovery
- * {@see NsdManager}
- */
-public final class NsdServiceInfo implements Parcelable {
-
-    private static final String TAG = "NsdServiceInfo";
-
-    private String mServiceName;
-
-    private String mServiceType;
-
-    private final ArrayMap<String, byte[]> mTxtRecord = new ArrayMap<>();
-
-    private InetAddress mHost;
-
-    private int mPort;
-
-    @Nullable
-    private Network mNetwork;
-
-    public NsdServiceInfo() {
-    }
-
-    /** @hide */
-    public NsdServiceInfo(String sn, String rt) {
-        mServiceName = sn;
-        mServiceType = rt;
-    }
-
-    /** Get the service name */
-    public String getServiceName() {
-        return mServiceName;
-    }
-
-    /** Set the service name */
-    public void setServiceName(String s) {
-        mServiceName = s;
-    }
-
-    /** Get the service type */
-    public String getServiceType() {
-        return mServiceType;
-    }
-
-    /** Set the service type */
-    public void setServiceType(String s) {
-        mServiceType = s;
-    }
-
-    /** Get the host address. The host address is valid for a resolved service. */
-    public InetAddress getHost() {
-        return mHost;
-    }
-
-    /** Set the host address */
-    public void setHost(InetAddress s) {
-        mHost = s;
-    }
-
-    /** Get port number. The port number is valid for a resolved service. */
-    public int getPort() {
-        return mPort;
-    }
-
-    /** Set port number */
-    public void setPort(int p) {
-        mPort = p;
-    }
-
-    /**
-     * Unpack txt information from a base-64 encoded byte array.
-     *
-     * @param rawRecords The raw base64 encoded records string read from netd.
-     *
-     * @hide
-     */
-    public void setTxtRecords(@NonNull String rawRecords) {
-        byte[] txtRecordsRawBytes = Base64.decode(rawRecords, Base64.DEFAULT);
-
-        // There can be multiple TXT records after each other. Each record has to following format:
-        //
-        // byte                  type                  required   meaning
-        // -------------------   -------------------   --------   ----------------------------------
-        // 0                     unsigned 8 bit        yes        size of record excluding this byte
-        // 1 - n                 ASCII but not '='     yes        key
-        // n + 1                 '='                   optional   separator of key and value
-        // n + 2 - record size   uninterpreted bytes   optional   value
-        //
-        // Example legal records:
-        // [11, 'm', 'y', 'k', 'e', 'y', '=', 0x0, 0x4, 0x65, 0x7, 0xff]
-        // [17, 'm', 'y', 'K', 'e', 'y', 'W', 'i', 't', 'h', 'N', 'o', 'V', 'a', 'l', 'u', 'e', '=']
-        // [12, 'm', 'y', 'B', 'o', 'o', 'l', 'e', 'a', 'n', 'K', 'e', 'y']
-        //
-        // Example corrupted records
-        // [3, =, 1, 2]    <- key is empty
-        // [3, 0, =, 2]    <- key contains non-ASCII character. We handle this by replacing the
-        //                    invalid characters instead of skipping the record.
-        // [30, 'a', =, 2] <- length exceeds total left over bytes in the TXT records array, we
-        //                    handle this by reducing the length of the record as needed.
-        int pos = 0;
-        while (pos < txtRecordsRawBytes.length) {
-            // recordLen is an unsigned 8 bit value
-            int recordLen = txtRecordsRawBytes[pos] & 0xff;
-            pos += 1;
-
-            try {
-                if (recordLen == 0) {
-                    throw new IllegalArgumentException("Zero sized txt record");
-                } else if (pos + recordLen > txtRecordsRawBytes.length) {
-                    Log.w(TAG, "Corrupt record length (pos = " + pos + "): " + recordLen);
-                    recordLen = txtRecordsRawBytes.length - pos;
-                }
-
-                // Decode key-value records
-                String key = null;
-                byte[] value = null;
-                int valueLen = 0;
-                for (int i = pos; i < pos + recordLen; i++) {
-                    if (key == null) {
-                        if (txtRecordsRawBytes[i] == '=') {
-                            key = new String(txtRecordsRawBytes, pos, i - pos,
-                                    StandardCharsets.US_ASCII);
-                        }
-                    } else {
-                        if (value == null) {
-                            value = new byte[recordLen - key.length() - 1];
-                        }
-                        value[valueLen] = txtRecordsRawBytes[i];
-                        valueLen++;
-                    }
-                }
-
-                // If '=' was not found we have a boolean record
-                if (key == null) {
-                    key = new String(txtRecordsRawBytes, pos, recordLen, StandardCharsets.US_ASCII);
-                }
-
-                if (TextUtils.isEmpty(key)) {
-                    // Empty keys are not allowed (RFC6763 6.4)
-                    throw new IllegalArgumentException("Invalid txt record (key is empty)");
-                }
-
-                if (getAttributes().containsKey(key)) {
-                    // When we have a duplicate record, the later ones are ignored (RFC6763 6.4)
-                    throw new IllegalArgumentException("Invalid txt record (duplicate key \"" + key + "\")");
-                }
-
-                setAttribute(key, value);
-            } catch (IllegalArgumentException e) {
-                Log.e(TAG, "While parsing txt records (pos = " + pos + "): " + e.getMessage());
-            }
-
-            pos += recordLen;
-        }
-    }
-
-    /** @hide */
-    @UnsupportedAppUsage
-    public void setAttribute(String key, byte[] value) {
-        if (TextUtils.isEmpty(key)) {
-            throw new IllegalArgumentException("Key cannot be empty");
-        }
-
-        // Key must be printable US-ASCII, excluding =.
-        for (int i = 0; i < key.length(); ++i) {
-            char character = key.charAt(i);
-            if (character < 0x20 || character > 0x7E) {
-                throw new IllegalArgumentException("Key strings must be printable US-ASCII");
-            } else if (character == 0x3D) {
-                throw new IllegalArgumentException("Key strings must not include '='");
-            }
-        }
-
-        // Key length + value length must be < 255.
-        if (key.length() + (value == null ? 0 : value.length) >= 255) {
-            throw new IllegalArgumentException("Key length + value length must be < 255 bytes");
-        }
-
-        // Warn if key is > 9 characters, as recommended by RFC 6763 section 6.4.
-        if (key.length() > 9) {
-            Log.w(TAG, "Key lengths > 9 are discouraged: " + key);
-        }
-
-        // Check against total TXT record size limits.
-        // Arbitrary 400 / 1300 byte limits taken from RFC 6763 section 6.2.
-        int txtRecordSize = getTxtRecordSize();
-        int futureSize = txtRecordSize + key.length() + (value == null ? 0 : value.length) + 2;
-        if (futureSize > 1300) {
-            throw new IllegalArgumentException("Total length of attributes must be < 1300 bytes");
-        } else if (futureSize > 400) {
-            Log.w(TAG, "Total length of all attributes exceeds 400 bytes; truncation may occur");
-        }
-
-        mTxtRecord.put(key, value);
-    }
-
-    /**
-     * Add a service attribute as a key/value pair.
-     *
-     * <p> Service attributes are included as DNS-SD TXT record pairs.
-     *
-     * <p> The key must be US-ASCII printable characters, excluding the '=' character.  Values may
-     * be UTF-8 strings or null.  The total length of key + value must be less than 255 bytes.
-     *
-     * <p> Keys should be short, ideally no more than 9 characters, and unique per instance of
-     * {@link NsdServiceInfo}.  Calling {@link #setAttribute} twice with the same key will overwrite
-     * first value.
-     */
-    public void setAttribute(String key, String value) {
-        try {
-            setAttribute(key, value == null ? (byte []) null : value.getBytes("UTF-8"));
-        } catch (UnsupportedEncodingException e) {
-            throw new IllegalArgumentException("Value must be UTF-8");
-        }
-    }
-
-    /** Remove an attribute by key */
-    public void removeAttribute(String key) {
-        mTxtRecord.remove(key);
-    }
-
-    /**
-     * Retrieve attributes as a map of String keys to byte[] values. The attributes map is only
-     * valid for a resolved service.
-     *
-     * <p> The returned map is unmodifiable; changes must be made through {@link #setAttribute} and
-     * {@link #removeAttribute}.
-     */
-    public Map<String, byte[]> getAttributes() {
-        return Collections.unmodifiableMap(mTxtRecord);
-    }
-
-    private int getTxtRecordSize() {
-        int txtRecordSize = 0;
-        for (Map.Entry<String, byte[]> entry : mTxtRecord.entrySet()) {
-            txtRecordSize += 2;  // One for the length byte, one for the = between key and value.
-            txtRecordSize += entry.getKey().length();
-            byte[] value = entry.getValue();
-            txtRecordSize += value == null ? 0 : value.length;
-        }
-        return txtRecordSize;
-    }
-
-    /** @hide */
-    public @NonNull byte[] getTxtRecord() {
-        int txtRecordSize = getTxtRecordSize();
-        if (txtRecordSize == 0) {
-            return new byte[]{};
-        }
-
-        byte[] txtRecord = new byte[txtRecordSize];
-        int ptr = 0;
-        for (Map.Entry<String, byte[]> entry : mTxtRecord.entrySet()) {
-            String key = entry.getKey();
-            byte[] value = entry.getValue();
-
-            // One byte to record the length of this key/value pair.
-            txtRecord[ptr++] = (byte) (key.length() + (value == null ? 0 : value.length) + 1);
-
-            // The key, in US-ASCII.
-            // Note: use the StandardCharsets const here because it doesn't raise exceptions and we
-            // already know the key is ASCII at this point.
-            System.arraycopy(key.getBytes(StandardCharsets.US_ASCII), 0, txtRecord, ptr,
-                    key.length());
-            ptr += key.length();
-
-            // US-ASCII '=' character.
-            txtRecord[ptr++] = (byte)'=';
-
-            // The value, as any raw bytes.
-            if (value != null) {
-                System.arraycopy(value, 0, txtRecord, ptr, value.length);
-                ptr += value.length;
-            }
-        }
-        return txtRecord;
-    }
-
-    /**
-     * Get the network where the service can be found.
-     *
-     * This is never null if this {@link NsdServiceInfo} was obtained from
-     * {@link NsdManager#discoverServices} or {@link NsdManager#resolveService}.
-     */
-    @Nullable
-    public Network getNetwork() {
-        return mNetwork;
-    }
-
-    /**
-     * Set the network where the service can be found.
-     * @param network The network, or null to search for, or to announce, the service on all
-     *                connected networks.
-     */
-    public void setNetwork(@Nullable Network network) {
-        mNetwork = network;
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("name: ").append(mServiceName)
-                .append(", type: ").append(mServiceType)
-                .append(", host: ").append(mHost)
-                .append(", port: ").append(mPort)
-                .append(", network: ").append(mNetwork);
-
-        byte[] txtRecord = getTxtRecord();
-        sb.append(", txtRecord: ").append(new String(txtRecord, StandardCharsets.UTF_8));
-        return sb.toString();
-    }
-
-    /** Implement the Parcelable interface */
-    public int describeContents() {
-        return 0;
-    }
-
-    /** Implement the Parcelable interface */
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(mServiceName);
-        dest.writeString(mServiceType);
-        if (mHost != null) {
-            dest.writeInt(1);
-            dest.writeByteArray(mHost.getAddress());
-        } else {
-            dest.writeInt(0);
-        }
-        dest.writeInt(mPort);
-
-        // TXT record key/value pairs.
-        dest.writeInt(mTxtRecord.size());
-        for (String key : mTxtRecord.keySet()) {
-            byte[] value = mTxtRecord.get(key);
-            if (value != null) {
-                dest.writeInt(1);
-                dest.writeInt(value.length);
-                dest.writeByteArray(value);
-            } else {
-                dest.writeInt(0);
-            }
-            dest.writeString(key);
-        }
-
-        dest.writeParcelable(mNetwork, 0);
-    }
-
-    /** Implement the Parcelable interface */
-    public static final @android.annotation.NonNull Creator<NsdServiceInfo> CREATOR =
-        new Creator<NsdServiceInfo>() {
-            public NsdServiceInfo createFromParcel(Parcel in) {
-                NsdServiceInfo info = new NsdServiceInfo();
-                info.mServiceName = in.readString();
-                info.mServiceType = in.readString();
-
-                if (in.readInt() == 1) {
-                    try {
-                        info.mHost = InetAddress.getByAddress(in.createByteArray());
-                    } catch (java.net.UnknownHostException e) {}
-                }
-
-                info.mPort = in.readInt();
-
-                // TXT record key/value pairs.
-                int recordCount = in.readInt();
-                for (int i = 0; i < recordCount; ++i) {
-                    byte[] valueArray = null;
-                    if (in.readInt() == 1) {
-                        int valueLength = in.readInt();
-                        valueArray = new byte[valueLength];
-                        in.readByteArray(valueArray);
-                    }
-                    info.mTxtRecord.put(in.readString(), valueArray);
-                }
-                info.mNetwork = in.readParcelable(null, Network.class);
-                return info;
-            }
-
-            public NsdServiceInfo[] newArray(int size) {
-                return new NsdServiceInfo[size];
-            }
-        };
-}
diff --git a/packages/ConnectivityT/service/Android.bp b/packages/ConnectivityT/service/Android.bp
deleted file mode 100644
index 5100e7c..0000000
--- a/packages/ConnectivityT/service/Android.bp
+++ /dev/null
@@ -1,156 +0,0 @@
-//
-// Copyright (C) 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-package {
-    // See: http://go/android-license-faq
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-// NetworkStats related libraries.
-
-filegroup {
-    name: "services.connectivity-netstats-sources",
-    srcs: [
-        "src/com/android/server/net/NetworkIdentity*.java",
-        "src/com/android/server/net/NetworkStats*.java",
-        "src/com/android/server/net/BpfInterfaceMapUpdater.java",
-        "src/com/android/server/net/InterfaceMapValue.java",
-        "src/com/android/server/net/CookieTagMapKey.java",
-        "src/com/android/server/net/CookieTagMapValue.java",
-        "src/com/android/server/net/StatsMapKey.java",
-        "src/com/android/server/net/StatsMapValue.java",
-        "src/com/android/server/net/UidStatsMapKey.java",
-    ],
-    path: "src",
-    visibility: [
-        "//visibility:private",
-    ],
-}
-
-// For test code only.
-filegroup {
-    name: "lib_networkStatsFactory_native",
-    srcs: [
-        "jni/com_android_server_net_NetworkStatsFactory.cpp",
-    ],
-    path: "jni",
-    visibility: [
-        "//packages/modules/Connectivity:__subpackages__",
-    ],
-}
-
-filegroup {
-    name: "services.connectivity-netstats-jni-sources",
-    srcs: [
-        "jni/com_android_server_net_NetworkStatsFactory.cpp",
-        "jni/com_android_server_net_NetworkStatsService.cpp",
-    ],
-    path: "jni",
-    visibility: [
-        "//packages/modules/Connectivity:__subpackages__",
-    ],
-}
-
-// Nsd related libraries.
-
-filegroup {
-    name: "services.connectivity-nsd-sources",
-    srcs: [
-        "src/com/android/server/INativeDaemon*.java",
-        "src/com/android/server/NativeDaemon*.java",
-        "src/com/android/server/Nsd*.java",
-    ],
-    path: "src",
-    visibility: [
-        "//visibility:private",
-    ],
-}
-
-// IpSec related libraries.
-
-filegroup {
-    name: "services.connectivity-ipsec-sources",
-    srcs: [
-        "src/com/android/server/IpSecService.java",
-    ],
-    path: "src",
-    visibility: [
-        "//visibility:private",
-    ],
-}
-
-// Ethernet related libraries.
-
-filegroup {
-    name: "services.connectivity-ethernet-sources",
-    srcs: [
-        "src/com/android/server/net/DelayedDiskWrite.java",
-        "src/com/android/server/net/IpConfigStore.java",
-    ],
-    path: "src",
-    visibility: [
-        "//frameworks/opt/net/ethernet",
-    ],
-}
-
-// Connectivity-T common libraries.
-
-filegroup {
-    name: "services.connectivity-tiramisu-sources",
-    srcs: [
-        ":services.connectivity-ethernet-sources",
-    ],
-    path: "src",
-    visibility: ["//frameworks/base/services/core"],
-}
-
-filegroup {
-    name: "services.connectivity-tiramisu-updatable-sources",
-    srcs: [
-        ":services.connectivity-ipsec-sources",
-        ":services.connectivity-netstats-sources",
-        ":services.connectivity-nsd-sources",
-    ],
-    path: "src",
-    visibility: [
-        "//packages/modules/Connectivity:__subpackages__",
-    ],
-}
-
-cc_library_shared {
-    name: "libcom_android_net_module_util_jni",
-    min_sdk_version: "30",
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wno-unused-parameter",
-        "-Wthread-safety",
-    ],
-    srcs: [
-        "jni/onload.cpp",
-    ],
-    stl: "libc++_static",
-    static_libs: [
-        "libnet_utils_device_common_bpfjni",
-    ],
-    shared_libs: [
-        "liblog",
-        "libnativehelper",
-    ],
-    apex_available: [
-        "//apex_available:platform",
-    ],
-}
diff --git a/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsFactory.cpp b/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsFactory.cpp
deleted file mode 100644
index 8b6526ff..0000000
--- a/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsFactory.cpp
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "NetworkStats"
-
-#include <errno.h>
-#include <inttypes.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <vector>
-
-#include <jni.h>
-
-#include <nativehelper/JNIHelp.h>
-#include <nativehelper/ScopedUtfChars.h>
-#include <nativehelper/ScopedLocalRef.h>
-#include <nativehelper/ScopedPrimitiveArray.h>
-
-#include <utils/Log.h>
-#include <utils/misc.h>
-
-#include "android-base/unique_fd.h"
-#include "bpf/BpfUtils.h"
-#include "netdbpf/BpfNetworkStats.h"
-
-using android::bpf::parseBpfNetworkStatsDetail;
-using android::bpf::stats_line;
-
-namespace android {
-
-static jclass gStringClass;
-
-static struct {
-    jfieldID size;
-    jfieldID capacity;
-    jfieldID iface;
-    jfieldID uid;
-    jfieldID set;
-    jfieldID tag;
-    jfieldID metered;
-    jfieldID roaming;
-    jfieldID defaultNetwork;
-    jfieldID rxBytes;
-    jfieldID rxPackets;
-    jfieldID txBytes;
-    jfieldID txPackets;
-    jfieldID operations;
-} gNetworkStatsClassInfo;
-
-static jobjectArray get_string_array(JNIEnv* env, jobject obj, jfieldID field, int size, bool grow)
-{
-    if (!grow) {
-        jobjectArray array = (jobjectArray)env->GetObjectField(obj, field);
-        if (array != NULL) {
-            return array;
-        }
-    }
-    return env->NewObjectArray(size, gStringClass, NULL);
-}
-
-static jintArray get_int_array(JNIEnv* env, jobject obj, jfieldID field, int size, bool grow)
-{
-    if (!grow) {
-        jintArray array = (jintArray)env->GetObjectField(obj, field);
-        if (array != NULL) {
-            return array;
-        }
-    }
-    return env->NewIntArray(size);
-}
-
-static jlongArray get_long_array(JNIEnv* env, jobject obj, jfieldID field, int size, bool grow)
-{
-    if (!grow) {
-        jlongArray array = (jlongArray)env->GetObjectField(obj, field);
-        if (array != NULL) {
-            return array;
-        }
-    }
-    return env->NewLongArray(size);
-}
-
-static int legacyReadNetworkStatsDetail(std::vector<stats_line>* lines,
-                                        const std::vector<std::string>& limitIfaces,
-                                        int limitTag, int limitUid, const char* path) {
-    FILE* fp = fopen(path, "re");
-    if (fp == NULL) {
-        return -1;
-    }
-
-    int lastIdx = 1;
-    int idx;
-    char buffer[384];
-    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
-        stats_line s;
-        int64_t rawTag;
-        char* pos = buffer;
-        char* endPos;
-        // First field is the index.
-        idx = (int)strtol(pos, &endPos, 10);
-        //ALOGI("Index #%d: %s", idx, buffer);
-        if (pos == endPos) {
-            // Skip lines that don't start with in index.  In particular,
-            // this will skip the initial header line.
-            continue;
-        }
-        if (idx != lastIdx + 1) {
-            ALOGE("inconsistent idx=%d after lastIdx=%d: %s", idx, lastIdx, buffer);
-            fclose(fp);
-            return -1;
-        }
-        lastIdx = idx;
-        pos = endPos;
-        // Skip whitespace.
-        while (*pos == ' ') {
-            pos++;
-        }
-        // Next field is iface.
-        int ifaceIdx = 0;
-        while (*pos != ' ' && *pos != 0 && ifaceIdx < (int)(sizeof(s.iface)-1)) {
-            s.iface[ifaceIdx] = *pos;
-            ifaceIdx++;
-            pos++;
-        }
-        if (*pos != ' ') {
-            ALOGE("bad iface: %s", buffer);
-            fclose(fp);
-            return -1;
-        }
-        s.iface[ifaceIdx] = 0;
-        if (limitIfaces.size() > 0) {
-            // Is this an iface the caller is interested in?
-            int i = 0;
-            while (i < (int)limitIfaces.size()) {
-                if (limitIfaces[i] == s.iface) {
-                    break;
-                }
-                i++;
-            }
-            if (i >= (int)limitIfaces.size()) {
-                // Nothing matched; skip this line.
-                //ALOGI("skipping due to iface: %s", buffer);
-                continue;
-            }
-        }
-
-        // Ignore whitespace
-        while (*pos == ' ') pos++;
-
-        // Find end of tag field
-        endPos = pos;
-        while (*endPos != ' ') endPos++;
-
-        // Three digit field is always 0x0, otherwise parse
-        if (endPos - pos == 3) {
-            rawTag = 0;
-        } else {
-            if (sscanf(pos, "%" PRIx64, &rawTag) != 1) {
-                ALOGE("bad tag: %s", pos);
-                fclose(fp);
-                return -1;
-            }
-        }
-        s.tag = rawTag >> 32;
-        if (limitTag != -1 && s.tag != static_cast<uint32_t>(limitTag)) {
-            //ALOGI("skipping due to tag: %s", buffer);
-            continue;
-        }
-        pos = endPos;
-
-        // Ignore whitespace
-        while (*pos == ' ') pos++;
-
-        // Parse remaining fields.
-        if (sscanf(pos, "%u %u %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64,
-                &s.uid, &s.set, &s.rxBytes, &s.rxPackets,
-                &s.txBytes, &s.txPackets) == 6) {
-            if (limitUid != -1 && static_cast<uint32_t>(limitUid) != s.uid) {
-                //ALOGI("skipping due to uid: %s", buffer);
-                continue;
-            }
-            lines->push_back(s);
-        } else {
-            //ALOGI("skipping due to bad remaining fields: %s", pos);
-        }
-    }
-
-    if (fclose(fp) != 0) {
-        ALOGE("Failed to close netstats file");
-        return -1;
-    }
-    return 0;
-}
-
-static int statsLinesToNetworkStats(JNIEnv* env, jclass clazz, jobject stats,
-                            std::vector<stats_line>& lines) {
-    int size = lines.size();
-
-    bool grow = size > env->GetIntField(stats, gNetworkStatsClassInfo.capacity);
-
-    ScopedLocalRef<jobjectArray> iface(env, get_string_array(env, stats,
-            gNetworkStatsClassInfo.iface, size, grow));
-    if (iface.get() == NULL) return -1;
-    ScopedIntArrayRW uid(env, get_int_array(env, stats,
-            gNetworkStatsClassInfo.uid, size, grow));
-    if (uid.get() == NULL) return -1;
-    ScopedIntArrayRW set(env, get_int_array(env, stats,
-            gNetworkStatsClassInfo.set, size, grow));
-    if (set.get() == NULL) return -1;
-    ScopedIntArrayRW tag(env, get_int_array(env, stats,
-            gNetworkStatsClassInfo.tag, size, grow));
-    if (tag.get() == NULL) return -1;
-    ScopedIntArrayRW metered(env, get_int_array(env, stats,
-            gNetworkStatsClassInfo.metered, size, grow));
-    if (metered.get() == NULL) return -1;
-    ScopedIntArrayRW roaming(env, get_int_array(env, stats,
-            gNetworkStatsClassInfo.roaming, size, grow));
-    if (roaming.get() == NULL) return -1;
-    ScopedIntArrayRW defaultNetwork(env, get_int_array(env, stats,
-            gNetworkStatsClassInfo.defaultNetwork, size, grow));
-    if (defaultNetwork.get() == NULL) return -1;
-    ScopedLongArrayRW rxBytes(env, get_long_array(env, stats,
-            gNetworkStatsClassInfo.rxBytes, size, grow));
-    if (rxBytes.get() == NULL) return -1;
-    ScopedLongArrayRW rxPackets(env, get_long_array(env, stats,
-            gNetworkStatsClassInfo.rxPackets, size, grow));
-    if (rxPackets.get() == NULL) return -1;
-    ScopedLongArrayRW txBytes(env, get_long_array(env, stats,
-            gNetworkStatsClassInfo.txBytes, size, grow));
-    if (txBytes.get() == NULL) return -1;
-    ScopedLongArrayRW txPackets(env, get_long_array(env, stats,
-            gNetworkStatsClassInfo.txPackets, size, grow));
-    if (txPackets.get() == NULL) return -1;
-    ScopedLongArrayRW operations(env, get_long_array(env, stats,
-            gNetworkStatsClassInfo.operations, size, grow));
-    if (operations.get() == NULL) return -1;
-
-    for (int i = 0; i < size; i++) {
-        ScopedLocalRef<jstring> ifaceString(env, env->NewStringUTF(lines[i].iface));
-        env->SetObjectArrayElement(iface.get(), i, ifaceString.get());
-
-        uid[i] = lines[i].uid;
-        set[i] = lines[i].set;
-        tag[i] = lines[i].tag;
-        // Metered, roaming and defaultNetwork are populated in Java-land.
-        rxBytes[i] = lines[i].rxBytes;
-        rxPackets[i] = lines[i].rxPackets;
-        txBytes[i] = lines[i].txBytes;
-        txPackets[i] = lines[i].txPackets;
-    }
-
-    env->SetIntField(stats, gNetworkStatsClassInfo.size, size);
-    if (grow) {
-        env->SetIntField(stats, gNetworkStatsClassInfo.capacity, size);
-        env->SetObjectField(stats, gNetworkStatsClassInfo.iface, iface.get());
-        env->SetObjectField(stats, gNetworkStatsClassInfo.uid, uid.getJavaArray());
-        env->SetObjectField(stats, gNetworkStatsClassInfo.set, set.getJavaArray());
-        env->SetObjectField(stats, gNetworkStatsClassInfo.tag, tag.getJavaArray());
-        env->SetObjectField(stats, gNetworkStatsClassInfo.metered, metered.getJavaArray());
-        env->SetObjectField(stats, gNetworkStatsClassInfo.roaming, roaming.getJavaArray());
-        env->SetObjectField(stats, gNetworkStatsClassInfo.defaultNetwork,
-                defaultNetwork.getJavaArray());
-        env->SetObjectField(stats, gNetworkStatsClassInfo.rxBytes, rxBytes.getJavaArray());
-        env->SetObjectField(stats, gNetworkStatsClassInfo.rxPackets, rxPackets.getJavaArray());
-        env->SetObjectField(stats, gNetworkStatsClassInfo.txBytes, txBytes.getJavaArray());
-        env->SetObjectField(stats, gNetworkStatsClassInfo.txPackets, txPackets.getJavaArray());
-        env->SetObjectField(stats, gNetworkStatsClassInfo.operations, operations.getJavaArray());
-    }
-    return 0;
-}
-
-static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstring path,
-                                  jint limitUid, jobjectArray limitIfacesObj, jint limitTag,
-                                  jboolean useBpfStats) {
-
-    std::vector<std::string> limitIfaces;
-    if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) {
-        int num = env->GetArrayLength(limitIfacesObj);
-        for (int i = 0; i < num; i++) {
-            jstring string = (jstring)env->GetObjectArrayElement(limitIfacesObj, i);
-            ScopedUtfChars string8(env, string);
-            if (string8.c_str() != NULL) {
-                limitIfaces.push_back(std::string(string8.c_str()));
-            }
-        }
-    }
-    std::vector<stats_line> lines;
-
-
-    if (useBpfStats) {
-        if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0)
-            return -1;
-    } else {
-        ScopedUtfChars path8(env, path);
-        if (path8.c_str() == NULL) {
-            ALOGE("the qtaguid legacy path is invalid: %s", path8.c_str());
-            return -1;
-        }
-        if (legacyReadNetworkStatsDetail(&lines, limitIfaces, limitTag,
-                                         limitUid, path8.c_str()) < 0)
-            return -1;
-    }
-
-    return statsLinesToNetworkStats(env, clazz, stats, lines);
-}
-
-static int readNetworkStatsDev(JNIEnv* env, jclass clazz, jobject stats) {
-    std::vector<stats_line> lines;
-
-    if (parseBpfNetworkStatsDev(&lines) < 0)
-            return -1;
-
-    return statsLinesToNetworkStats(env, clazz, stats, lines);
-}
-
-static const JNINativeMethod gMethods[] = {
-        { "nativeReadNetworkStatsDetail",
-                "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;IZ)I",
-                (void*) readNetworkStatsDetail },
-        { "nativeReadNetworkStatsDev", "(Landroid/net/NetworkStats;)I",
-                (void*) readNetworkStatsDev },
-};
-
-int register_android_server_net_NetworkStatsFactory(JNIEnv* env) {
-    int err = jniRegisterNativeMethods(env, "com/android/server/net/NetworkStatsFactory", gMethods,
-            NELEM(gMethods));
-    gStringClass = env->FindClass("java/lang/String");
-    gStringClass = static_cast<jclass>(env->NewGlobalRef(gStringClass));
-
-    jclass clazz = env->FindClass("android/net/NetworkStats");
-    gNetworkStatsClassInfo.size = env->GetFieldID(clazz, "size", "I");
-    gNetworkStatsClassInfo.capacity = env->GetFieldID(clazz, "capacity", "I");
-    gNetworkStatsClassInfo.iface = env->GetFieldID(clazz, "iface", "[Ljava/lang/String;");
-    gNetworkStatsClassInfo.uid = env->GetFieldID(clazz, "uid", "[I");
-    gNetworkStatsClassInfo.set = env->GetFieldID(clazz, "set", "[I");
-    gNetworkStatsClassInfo.tag = env->GetFieldID(clazz, "tag", "[I");
-    gNetworkStatsClassInfo.metered = env->GetFieldID(clazz, "metered", "[I");
-    gNetworkStatsClassInfo.roaming = env->GetFieldID(clazz, "roaming", "[I");
-    gNetworkStatsClassInfo.defaultNetwork = env->GetFieldID(clazz, "defaultNetwork", "[I");
-    gNetworkStatsClassInfo.rxBytes = env->GetFieldID(clazz, "rxBytes", "[J");
-    gNetworkStatsClassInfo.rxPackets = env->GetFieldID(clazz, "rxPackets", "[J");
-    gNetworkStatsClassInfo.txBytes = env->GetFieldID(clazz, "txBytes", "[J");
-    gNetworkStatsClassInfo.txPackets = env->GetFieldID(clazz, "txPackets", "[J");
-    gNetworkStatsClassInfo.operations = env->GetFieldID(clazz, "operations", "[J");
-
-    return err;
-}
-
-}
diff --git a/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsService.cpp b/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsService.cpp
deleted file mode 100644
index 39cbaf7..0000000
--- a/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsService.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "NetworkStatsNative"
-
-#include <cutils/qtaguid.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <jni.h>
-#include <nativehelper/ScopedUtfChars.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <utils/Log.h>
-#include <utils/misc.h>
-
-#include "bpf/BpfUtils.h"
-#include "netdbpf/BpfNetworkStats.h"
-
-using android::bpf::bpfGetUidStats;
-using android::bpf::bpfGetIfaceStats;
-
-namespace android {
-
-// NOTE: keep these in sync with TrafficStats.java
-static const uint64_t UNKNOWN = -1;
-
-enum StatsType {
-    RX_BYTES = 0,
-    RX_PACKETS = 1,
-    TX_BYTES = 2,
-    TX_PACKETS = 3,
-    TCP_RX_PACKETS = 4,
-    TCP_TX_PACKETS = 5
-};
-
-static uint64_t getStatsType(Stats* stats, StatsType type) {
-    switch (type) {
-        case RX_BYTES:
-            return stats->rxBytes;
-        case RX_PACKETS:
-            return stats->rxPackets;
-        case TX_BYTES:
-            return stats->txBytes;
-        case TX_PACKETS:
-            return stats->txPackets;
-        case TCP_RX_PACKETS:
-            return stats->tcpRxPackets;
-        case TCP_TX_PACKETS:
-            return stats->tcpTxPackets;
-        default:
-            return UNKNOWN;
-    }
-}
-
-static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type) {
-    Stats stats = {};
-
-    if (bpfGetIfaceStats(NULL, &stats) == 0) {
-        return getStatsType(&stats, (StatsType) type);
-    } else {
-        return UNKNOWN;
-    }
-}
-
-static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type) {
-    ScopedUtfChars iface8(env, iface);
-    if (iface8.c_str() == NULL) {
-        return UNKNOWN;
-    }
-
-    Stats stats = {};
-
-    if (bpfGetIfaceStats(iface8.c_str(), &stats) == 0) {
-        return getStatsType(&stats, (StatsType) type);
-    } else {
-        return UNKNOWN;
-    }
-}
-
-static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type) {
-    Stats stats = {};
-
-    if (bpfGetUidStats(uid, &stats) == 0) {
-        return getStatsType(&stats, (StatsType) type);
-    } else {
-        return UNKNOWN;
-    }
-}
-
-static const JNINativeMethod gMethods[] = {
-        {"nativeGetTotalStat", "(I)J", (void*)getTotalStat},
-        {"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*)getIfaceStat},
-        {"nativeGetUidStat", "(II)J", (void*)getUidStat},
-};
-
-int register_android_server_net_NetworkStatsService(JNIEnv* env) {
-    return jniRegisterNativeMethods(env, "com/android/server/net/NetworkStatsService", gMethods,
-                                    NELEM(gMethods));
-}
-
-}
diff --git a/packages/ConnectivityT/service/jni/onload.cpp b/packages/ConnectivityT/service/jni/onload.cpp
deleted file mode 100644
index bca4697..0000000
--- a/packages/ConnectivityT/service/jni/onload.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.
- */
-
-#include <nativehelper/JNIHelp.h>
-#include <log/log.h>
-
-namespace android {
-
-int register_com_android_net_module_util_BpfMap(JNIEnv* env, char const* class_name);
-
-extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
-    JNIEnv *env;
-    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
-        ALOGE("GetEnv failed");
-        return JNI_ERR;
-    }
-
-    if (register_com_android_net_module_util_BpfMap(env,
-            "com/android/net/module/util/BpfMap") < 0) return JNI_ERR;
-
-    return JNI_VERSION_1_6;
-}
-
-};
-
diff --git a/packages/ConnectivityT/service/src/com/android/server/INativeDaemonConnectorCallbacks.java b/packages/ConnectivityT/service/src/com/android/server/INativeDaemonConnectorCallbacks.java
deleted file mode 100644
index 0cf9dcd..0000000
--- a/packages/ConnectivityT/service/src/com/android/server/INativeDaemonConnectorCallbacks.java
+++ /dev/null
@@ -1,25 +0,0 @@
-
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-interface INativeDaemonConnectorCallbacks {
-
-    void onDaemonConnected();
-    boolean onCheckHoldWakeLock(int code);
-    boolean onEvent(int code, String raw, String[] cooked);
-}
diff --git a/packages/ConnectivityT/service/src/com/android/server/IpSecService.java b/packages/ConnectivityT/service/src/com/android/server/IpSecService.java
deleted file mode 100644
index 4bc40ea..0000000
--- a/packages/ConnectivityT/service/src/com/android/server/IpSecService.java
+++ /dev/null
@@ -1,1878 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static android.Manifest.permission.DUMP;
-import static android.net.IpSecManager.INVALID_RESOURCE_ID;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-import static android.system.OsConstants.AF_UNSPEC;
-import static android.system.OsConstants.EINVAL;
-import static android.system.OsConstants.IPPROTO_UDP;
-import static android.system.OsConstants.SOCK_DGRAM;
-
-import android.annotation.NonNull;
-import android.app.AppOpsManager;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.net.ConnectivityManager;
-import android.net.IIpSecService;
-import android.net.INetd;
-import android.net.InetAddresses;
-import android.net.IpSecAlgorithm;
-import android.net.IpSecConfig;
-import android.net.IpSecManager;
-import android.net.IpSecSpiResponse;
-import android.net.IpSecTransform;
-import android.net.IpSecTransformResponse;
-import android.net.IpSecTunnelInterfaceResponse;
-import android.net.IpSecUdpEncapResponse;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.TrafficStats;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.ServiceSpecificException;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Range;
-import android.util.SparseArray;
-import android.util.SparseBooleanArray;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
-import com.android.net.module.util.BinderUtils;
-import com.android.net.module.util.NetdUtils;
-import com.android.net.module.util.PermissionUtils;
-
-import libcore.io.IoUtils;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * A service to manage multiple clients that want to access the IpSec API. The service is
- * responsible for maintaining a list of clients and managing the resources (and related quotas)
- * that each of them own.
- *
- * <p>Synchronization in IpSecService is done on all entrypoints due to potential race conditions at
- * the kernel/xfrm level. Further, this allows the simplifying assumption to be made that only one
- * thread is ever running at a time.
- *
- * @hide
- */
-public class IpSecService extends IIpSecService.Stub {
-    private static final String TAG = "IpSecService";
-    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
-    private static final int[] ADDRESS_FAMILIES =
-            new int[] {OsConstants.AF_INET, OsConstants.AF_INET6};
-
-    private static final int NETD_FETCH_TIMEOUT_MS = 5000; // ms
-    private static final InetAddress INADDR_ANY;
-
-    @VisibleForTesting static final int MAX_PORT_BIND_ATTEMPTS = 10;
-
-    private final INetd mNetd;
-
-    static {
-        try {
-            INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0});
-        } catch (UnknownHostException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    static final int FREE_PORT_MIN = 1024; // ports 1-1023 are reserved
-    static final int PORT_MAX = 0xFFFF; // ports are an unsigned 16-bit integer
-
-    /* Binder context for this service */
-    private final Context mContext;
-    private final Dependencies mDeps;
-
-    /**
-     * The next non-repeating global ID for tracking resources between users, this service, and
-     * kernel data structures. Accessing this variable is not thread safe, so it is only read or
-     * modified within blocks synchronized on IpSecService.this. We want to avoid -1
-     * (INVALID_RESOURCE_ID) and 0 (we probably forgot to initialize it).
-     */
-    @GuardedBy("IpSecService.this")
-    private int mNextResourceId = 1;
-
-    /**
-     * Dependencies of IpSecService, for injection in tests.
-     */
-    @VisibleForTesting
-    public static class Dependencies {
-        /**
-         * Get a reference to INetd.
-         */
-        public INetd getNetdInstance(Context context) throws RemoteException {
-            final INetd netd = INetd.Stub.asInterface((IBinder)
-                    context.getSystemService(Context.NETD_SERVICE));
-            if (netd == null) {
-                throw new RemoteException("Failed to Get Netd Instance");
-            }
-            return netd;
-        }
-    }
-
-    final UidFdTagger mUidFdTagger;
-
-    /**
-     * Interface for user-reference and kernel-resource cleanup.
-     *
-     * <p>This interface must be implemented for a resource to be reference counted.
-     */
-    @VisibleForTesting
-    public interface IResource {
-        /**
-         * Invalidates a IResource object, ensuring it is invalid for the purposes of allocating new
-         * objects dependent on it.
-         *
-         * <p>Implementations of this method are expected to remove references to the IResource
-         * object from the IpSecService's tracking arrays. The removal from the arrays ensures that
-         * the resource is considered invalid for user access or allocation or use in other
-         * resources.
-         *
-         * <p>References to the IResource object may be held by other RefcountedResource objects,
-         * and as such, the underlying resources and quota may not be cleaned up.
-         */
-        void invalidate() throws RemoteException;
-
-        /**
-         * Releases underlying resources and related quotas.
-         *
-         * <p>Implementations of this method are expected to remove all system resources that are
-         * tracked by the IResource object. Due to other RefcountedResource objects potentially
-         * having references to the IResource object, freeUnderlyingResources may not always be
-         * called from releaseIfUnreferencedRecursively().
-         */
-        void freeUnderlyingResources() throws RemoteException;
-    }
-
-    /**
-     * RefcountedResource manages references and dependencies in an exclusively acyclic graph.
-     *
-     * <p>RefcountedResource implements both explicit and implicit resource management. Creating a
-     * RefcountedResource object creates an explicit reference that must be freed by calling
-     * userRelease(). Additionally, adding this object as a child of another RefcountedResource
-     * object will add an implicit reference.
-     *
-     * <p>Resources are cleaned up when all references, both implicit and explicit, are released
-     * (ie, when userRelease() is called and when all parents have called releaseReference() on this
-     * object.)
-     */
-    @VisibleForTesting
-    public class RefcountedResource<T extends IResource> implements IBinder.DeathRecipient {
-        private final T mResource;
-        private final List<RefcountedResource> mChildren;
-        int mRefCount = 1; // starts at 1 for user's reference.
-        IBinder mBinder;
-
-        RefcountedResource(T resource, IBinder binder, RefcountedResource... children) {
-            synchronized (IpSecService.this) {
-                this.mResource = resource;
-                this.mChildren = new ArrayList<>(children.length);
-                this.mBinder = binder;
-
-                for (RefcountedResource child : children) {
-                    mChildren.add(child);
-                    child.mRefCount++;
-                }
-
-                try {
-                    mBinder.linkToDeath(this, 0);
-                } catch (RemoteException e) {
-                    binderDied();
-                    e.rethrowFromSystemServer();
-                }
-            }
-        }
-
-        /**
-         * If the Binder object dies, this function is called to free the system resources that are
-         * being tracked by this record and to subsequently release this record for garbage
-         * collection
-         */
-        @Override
-        public void binderDied() {
-            synchronized (IpSecService.this) {
-                try {
-                    userRelease();
-                } catch (Exception e) {
-                    Log.e(TAG, "Failed to release resource: " + e);
-                }
-            }
-        }
-
-        public T getResource() {
-            return mResource;
-        }
-
-        /**
-         * Unlinks from binder and performs IpSecService resource cleanup (removes from resource
-         * arrays)
-         *
-         * <p>If this method has been previously called, the RefcountedResource's binder field will
-         * be null, and the method will return without performing the cleanup a second time.
-         *
-         * <p>Note that calling this function does not imply that kernel resources will be freed at
-         * this time, or that the related quota will be returned. Such actions will only be
-         * performed upon the reference count reaching zero.
-         */
-        @GuardedBy("IpSecService.this")
-        public void userRelease() throws RemoteException {
-            // Prevent users from putting reference counts into a bad state by calling
-            // userRelease() multiple times.
-            if (mBinder == null) {
-                return;
-            }
-
-            mBinder.unlinkToDeath(this, 0);
-            mBinder = null;
-
-            mResource.invalidate();
-
-            releaseReference();
-        }
-
-        /**
-         * Removes a reference to this resource. If the resultant reference count is zero, the
-         * underlying resources are freed, and references to all child resources are also dropped
-         * recursively (resulting in them freeing their resources and children, etcetera)
-         *
-         * <p>This method also sets the reference count to an invalid value (-1) to signify that it
-         * has been fully released. Any subsequent calls to this method will result in an
-         * IllegalStateException being thrown due to resource already having been previously
-         * released
-         */
-        @VisibleForTesting
-        @GuardedBy("IpSecService.this")
-        public void releaseReference() throws RemoteException {
-            mRefCount--;
-
-            if (mRefCount > 0) {
-                return;
-            } else if (mRefCount < 0) {
-                throw new IllegalStateException(
-                        "Invalid operation - resource has already been released.");
-            }
-
-            // Cleanup own resources
-            mResource.freeUnderlyingResources();
-
-            // Cleanup child resources as needed
-            for (RefcountedResource<? extends IResource> child : mChildren) {
-                child.releaseReference();
-            }
-
-            // Enforce that resource cleanup can only be called once
-            // By decrementing the refcount (from 0 to -1), the next call will throw an
-            // IllegalStateException - it has already been released fully.
-            mRefCount--;
-        }
-
-        @Override
-        public String toString() {
-            return new StringBuilder()
-                    .append("{mResource=")
-                    .append(mResource)
-                    .append(", mRefCount=")
-                    .append(mRefCount)
-                    .append(", mChildren=")
-                    .append(mChildren)
-                    .append("}")
-                    .toString();
-        }
-    }
-
-    /**
-     * Very simple counting class that looks much like a counting semaphore
-     *
-     * <p>This class is not thread-safe, and expects that that users of this class will ensure
-     * synchronization and thread safety by holding the IpSecService.this instance lock.
-     */
-    @VisibleForTesting
-    static class ResourceTracker {
-        private final int mMax;
-        int mCurrent;
-
-        ResourceTracker(int max) {
-            mMax = max;
-            mCurrent = 0;
-        }
-
-        boolean isAvailable() {
-            return (mCurrent < mMax);
-        }
-
-        void take() {
-            if (!isAvailable()) {
-                Log.wtf(TAG, "Too many resources allocated!");
-            }
-            mCurrent++;
-        }
-
-        void give() {
-            if (mCurrent <= 0) {
-                Log.wtf(TAG, "We've released this resource too many times");
-            }
-            mCurrent--;
-        }
-
-        @Override
-        public String toString() {
-            return new StringBuilder()
-                    .append("{mCurrent=")
-                    .append(mCurrent)
-                    .append(", mMax=")
-                    .append(mMax)
-                    .append("}")
-                    .toString();
-        }
-    }
-
-    @VisibleForTesting
-    static final class UserRecord {
-        /* Maximum number of each type of resource that a single UID may possess */
-
-        // Up to 4 active VPNs/IWLAN with potential soft handover.
-        public static final int MAX_NUM_TUNNEL_INTERFACES = 8;
-        public static final int MAX_NUM_ENCAP_SOCKETS = 16;
-
-        // SPIs and Transforms are both cheap, and are 1:1 correlated.
-        public static final int MAX_NUM_TRANSFORMS = 64;
-        public static final int MAX_NUM_SPIS = 64;
-
-        /**
-         * Store each of the OwnedResource types in an (thinly wrapped) sparse array for indexing
-         * and explicit (user) reference management.
-         *
-         * <p>These are stored in separate arrays to improve debuggability and dump output clarity.
-         *
-         * <p>Resources are removed from this array when the user releases their explicit reference
-         * by calling one of the releaseResource() methods.
-         */
-        final RefcountedResourceArray<SpiRecord> mSpiRecords =
-                new RefcountedResourceArray<>(SpiRecord.class.getSimpleName());
-        final RefcountedResourceArray<TransformRecord> mTransformRecords =
-                new RefcountedResourceArray<>(TransformRecord.class.getSimpleName());
-        final RefcountedResourceArray<EncapSocketRecord> mEncapSocketRecords =
-                new RefcountedResourceArray<>(EncapSocketRecord.class.getSimpleName());
-        final RefcountedResourceArray<TunnelInterfaceRecord> mTunnelInterfaceRecords =
-                new RefcountedResourceArray<>(TunnelInterfaceRecord.class.getSimpleName());
-
-        /**
-         * Trackers for quotas for each of the OwnedResource types.
-         *
-         * <p>These trackers are separate from the resource arrays, since they are incremented and
-         * decremented at different points in time. Specifically, quota is only returned upon final
-         * resource deallocation (after all explicit and implicit references are released). Note
-         * that it is possible that calls to releaseResource() will not return the used quota if
-         * there are other resources that depend on (are parents of) the resource being released.
-         */
-        final ResourceTracker mSpiQuotaTracker = new ResourceTracker(MAX_NUM_SPIS);
-        final ResourceTracker mTransformQuotaTracker = new ResourceTracker(MAX_NUM_TRANSFORMS);
-        final ResourceTracker mSocketQuotaTracker = new ResourceTracker(MAX_NUM_ENCAP_SOCKETS);
-        final ResourceTracker mTunnelQuotaTracker = new ResourceTracker(MAX_NUM_TUNNEL_INTERFACES);
-
-        void removeSpiRecord(int resourceId) {
-            mSpiRecords.remove(resourceId);
-        }
-
-        void removeTransformRecord(int resourceId) {
-            mTransformRecords.remove(resourceId);
-        }
-
-        void removeTunnelInterfaceRecord(int resourceId) {
-            mTunnelInterfaceRecords.remove(resourceId);
-        }
-
-        void removeEncapSocketRecord(int resourceId) {
-            mEncapSocketRecords.remove(resourceId);
-        }
-
-        @Override
-        public String toString() {
-            return new StringBuilder()
-                    .append("{mSpiQuotaTracker=")
-                    .append(mSpiQuotaTracker)
-                    .append(", mTransformQuotaTracker=")
-                    .append(mTransformQuotaTracker)
-                    .append(", mSocketQuotaTracker=")
-                    .append(mSocketQuotaTracker)
-                    .append(", mTunnelQuotaTracker=")
-                    .append(mTunnelQuotaTracker)
-                    .append(", mSpiRecords=")
-                    .append(mSpiRecords)
-                    .append(", mTransformRecords=")
-                    .append(mTransformRecords)
-                    .append(", mEncapSocketRecords=")
-                    .append(mEncapSocketRecords)
-                    .append(", mTunnelInterfaceRecords=")
-                    .append(mTunnelInterfaceRecords)
-                    .append("}")
-                    .toString();
-        }
-    }
-
-    /**
-     * This class is not thread-safe, and expects that that users of this class will ensure
-     * synchronization and thread safety by holding the IpSecService.this instance lock.
-     */
-    @VisibleForTesting
-    static final class UserResourceTracker {
-        private final SparseArray<UserRecord> mUserRecords = new SparseArray<>();
-
-        /** Lazy-initialization/getter that populates or retrieves the UserRecord as needed */
-        public UserRecord getUserRecord(int uid) {
-            checkCallerUid(uid);
-
-            UserRecord r = mUserRecords.get(uid);
-            if (r == null) {
-                r = new UserRecord();
-                mUserRecords.put(uid, r);
-            }
-            return r;
-        }
-
-        /** Safety method; guards against access of other user's UserRecords */
-        private void checkCallerUid(int uid) {
-            if (uid != Binder.getCallingUid() && Process.SYSTEM_UID != Binder.getCallingUid()) {
-                throw new SecurityException("Attempted access of unowned resources");
-            }
-        }
-
-        @Override
-        public String toString() {
-            return mUserRecords.toString();
-        }
-    }
-
-    @VisibleForTesting final UserResourceTracker mUserResourceTracker = new UserResourceTracker();
-
-    /**
-     * The OwnedResourceRecord class provides a facility to cleanly and reliably track system
-     * resources. It relies on a provided resourceId that should uniquely identify the kernel
-     * resource. To use this class, the user should implement the invalidate() and
-     * freeUnderlyingResources() methods that are responsible for cleaning up IpSecService resource
-     * tracking arrays and kernel resources, respectively.
-     *
-     * <p>This class associates kernel resources with the UID that owns and controls them.
-     */
-    private abstract class OwnedResourceRecord implements IResource {
-        final int mPid;
-        final int mUid;
-        protected final int mResourceId;
-
-        OwnedResourceRecord(int resourceId) {
-            super();
-            if (resourceId == INVALID_RESOURCE_ID) {
-                throw new IllegalArgumentException("Resource ID must not be INVALID_RESOURCE_ID");
-            }
-            mResourceId = resourceId;
-            mPid = Binder.getCallingPid();
-            mUid = Binder.getCallingUid();
-
-            getResourceTracker().take();
-        }
-
-        @Override
-        public abstract void invalidate() throws RemoteException;
-
-        /** Convenience method; retrieves the user resource record for the stored UID. */
-        protected UserRecord getUserRecord() {
-            return mUserResourceTracker.getUserRecord(mUid);
-        }
-
-        @Override
-        public abstract void freeUnderlyingResources() throws RemoteException;
-
-        /** Get the resource tracker for this resource */
-        protected abstract ResourceTracker getResourceTracker();
-
-        @Override
-        public String toString() {
-            return new StringBuilder()
-                    .append("{mResourceId=")
-                    .append(mResourceId)
-                    .append(", pid=")
-                    .append(mPid)
-                    .append(", uid=")
-                    .append(mUid)
-                    .append("}")
-                    .toString();
-        }
-    };
-
-    /**
-     * Thin wrapper over SparseArray to ensure resources exist, and simplify generic typing.
-     *
-     * <p>RefcountedResourceArray prevents null insertions, and throws an IllegalArgumentException
-     * if a key is not found during a retrieval process.
-     */
-    static class RefcountedResourceArray<T extends IResource> {
-        SparseArray<RefcountedResource<T>> mArray = new SparseArray<>();
-        private final String mTypeName;
-
-        RefcountedResourceArray(String typeName) {
-            this.mTypeName = typeName;
-        }
-
-        /**
-         * Accessor method to get inner resource object.
-         *
-         * @throws IllegalArgumentException if no resource with provided key is found.
-         */
-        T getResourceOrThrow(int key) {
-            return getRefcountedResourceOrThrow(key).getResource();
-        }
-
-        /**
-         * Accessor method to get reference counting wrapper.
-         *
-         * @throws IllegalArgumentException if no resource with provided key is found.
-         */
-        RefcountedResource<T> getRefcountedResourceOrThrow(int key) {
-            RefcountedResource<T> resource = mArray.get(key);
-            if (resource == null) {
-                throw new IllegalArgumentException(
-                        String.format("No such %s found for given id: %d", mTypeName, key));
-            }
-
-            return resource;
-        }
-
-        void put(int key, RefcountedResource<T> obj) {
-            Objects.requireNonNull(obj, "Null resources cannot be added");
-            mArray.put(key, obj);
-        }
-
-        void remove(int key) {
-            mArray.remove(key);
-        }
-
-        @Override
-        public String toString() {
-            return mArray.toString();
-        }
-    }
-
-    /**
-     * Tracks an SA in the kernel, and manages cleanup paths. Once a TransformRecord is
-     * created, the SpiRecord that originally tracked the SAs will reliquish the
-     * responsibility of freeing the underlying SA to this class via the mOwnedByTransform flag.
-     */
-    private final class TransformRecord extends OwnedResourceRecord {
-        private final IpSecConfig mConfig;
-        private final SpiRecord mSpi;
-        private final EncapSocketRecord mSocket;
-
-        TransformRecord(
-                int resourceId, IpSecConfig config, SpiRecord spi, EncapSocketRecord socket) {
-            super(resourceId);
-            mConfig = config;
-            mSpi = spi;
-            mSocket = socket;
-
-            spi.setOwnedByTransform();
-        }
-
-        public IpSecConfig getConfig() {
-            return mConfig;
-        }
-
-        public SpiRecord getSpiRecord() {
-            return mSpi;
-        }
-
-        public EncapSocketRecord getSocketRecord() {
-            return mSocket;
-        }
-
-        /** always guarded by IpSecService#this */
-        @Override
-        public void freeUnderlyingResources() {
-            int spi = mSpi.getSpi();
-            try {
-                mNetd.ipSecDeleteSecurityAssociation(
-                        mUid,
-                        mConfig.getSourceAddress(),
-                        mConfig.getDestinationAddress(),
-                        spi,
-                        mConfig.getMarkValue(),
-                        mConfig.getMarkMask(),
-                        mConfig.getXfrmInterfaceId());
-            } catch (RemoteException | ServiceSpecificException e) {
-                Log.e(TAG, "Failed to delete SA with ID: " + mResourceId, e);
-            }
-
-            getResourceTracker().give();
-        }
-
-        @Override
-        public void invalidate() throws RemoteException {
-            getUserRecord().removeTransformRecord(mResourceId);
-        }
-
-        @Override
-        protected ResourceTracker getResourceTracker() {
-            return getUserRecord().mTransformQuotaTracker;
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder strBuilder = new StringBuilder();
-            strBuilder
-                    .append("{super=")
-                    .append(super.toString())
-                    .append(", mSocket=")
-                    .append(mSocket)
-                    .append(", mSpi.mResourceId=")
-                    .append(mSpi.mResourceId)
-                    .append(", mConfig=")
-                    .append(mConfig)
-                    .append("}");
-            return strBuilder.toString();
-        }
-    }
-
-    /**
-     * Tracks a single SA in the kernel, and manages cleanup paths. Once used in a Transform, the
-     * responsibility for cleaning up underlying resources will be passed to the TransformRecord
-     * object
-     */
-    private final class SpiRecord extends OwnedResourceRecord {
-        private final String mSourceAddress;
-        private final String mDestinationAddress;
-        private int mSpi;
-
-        private boolean mOwnedByTransform = false;
-
-        SpiRecord(int resourceId, String sourceAddress,
-                String destinationAddress, int spi) {
-            super(resourceId);
-            mSourceAddress = sourceAddress;
-            mDestinationAddress = destinationAddress;
-            mSpi = spi;
-        }
-
-        /** always guarded by IpSecService#this */
-        @Override
-        public void freeUnderlyingResources() {
-            try {
-                if (!mOwnedByTransform) {
-                    mNetd.ipSecDeleteSecurityAssociation(
-                            mUid, mSourceAddress, mDestinationAddress, mSpi, 0 /* mark */,
-                            0 /* mask */, 0 /* if_id */);
-                }
-            } catch (ServiceSpecificException | RemoteException e) {
-                Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId, e);
-            }
-
-            mSpi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
-
-            getResourceTracker().give();
-        }
-
-        public int getSpi() {
-            return mSpi;
-        }
-
-        public String getDestinationAddress() {
-            return mDestinationAddress;
-        }
-
-        public void setOwnedByTransform() {
-            if (mOwnedByTransform) {
-                // Programming error
-                throw new IllegalStateException("Cannot own an SPI twice!");
-            }
-
-            mOwnedByTransform = true;
-        }
-
-        public boolean getOwnedByTransform() {
-            return mOwnedByTransform;
-        }
-
-        @Override
-        public void invalidate() throws RemoteException {
-            getUserRecord().removeSpiRecord(mResourceId);
-        }
-
-        @Override
-        protected ResourceTracker getResourceTracker() {
-            return getUserRecord().mSpiQuotaTracker;
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder strBuilder = new StringBuilder();
-            strBuilder
-                    .append("{super=")
-                    .append(super.toString())
-                    .append(", mSpi=")
-                    .append(mSpi)
-                    .append(", mSourceAddress=")
-                    .append(mSourceAddress)
-                    .append(", mDestinationAddress=")
-                    .append(mDestinationAddress)
-                    .append(", mOwnedByTransform=")
-                    .append(mOwnedByTransform)
-                    .append("}");
-            return strBuilder.toString();
-        }
-    }
-
-    private final SparseBooleanArray mTunnelNetIds = new SparseBooleanArray();
-    final Range<Integer> mNetIdRange = ConnectivityManager.getIpSecNetIdRange();
-    private int mNextTunnelNetId = mNetIdRange.getLower();
-
-    /**
-     * Reserves a netId within the range of netIds allocated for IPsec tunnel interfaces
-     *
-     * <p>This method should only be called from Binder threads. Do not call this from within the
-     * system server as it will crash the system on failure.
-     *
-     * @return an integer key within the netId range, if successful
-     * @throws IllegalStateException if unsuccessful (all netId are currently reserved)
-     */
-    @VisibleForTesting
-    int reserveNetId() {
-        final int range = mNetIdRange.getUpper() - mNetIdRange.getLower() + 1;
-        synchronized (mTunnelNetIds) {
-            for (int i = 0; i < range; i++) {
-                final int netId = mNextTunnelNetId;
-                if (++mNextTunnelNetId > mNetIdRange.getUpper()) {
-                    mNextTunnelNetId = mNetIdRange.getLower();
-                }
-                if (!mTunnelNetIds.get(netId)) {
-                    mTunnelNetIds.put(netId, true);
-                    return netId;
-                }
-            }
-        }
-        throw new IllegalStateException("No free netIds to allocate");
-    }
-
-    @VisibleForTesting
-    void releaseNetId(int netId) {
-        synchronized (mTunnelNetIds) {
-            mTunnelNetIds.delete(netId);
-        }
-    }
-
-    /**
-     * Tracks an tunnel interface, and manages cleanup paths.
-     *
-     * <p>This class is not thread-safe, and expects that that users of this class will ensure
-     * synchronization and thread safety by holding the IpSecService.this instance lock
-     */
-    @VisibleForTesting
-    final class TunnelInterfaceRecord extends OwnedResourceRecord {
-        private final String mInterfaceName;
-
-        // outer addresses
-        private final String mLocalAddress;
-        private final String mRemoteAddress;
-
-        private final int mIkey;
-        private final int mOkey;
-
-        private final int mIfId;
-
-        private Network mUnderlyingNetwork;
-
-        TunnelInterfaceRecord(
-                int resourceId,
-                String interfaceName,
-                Network underlyingNetwork,
-                String localAddr,
-                String remoteAddr,
-                int ikey,
-                int okey,
-                int intfId) {
-            super(resourceId);
-
-            mInterfaceName = interfaceName;
-            mUnderlyingNetwork = underlyingNetwork;
-            mLocalAddress = localAddr;
-            mRemoteAddress = remoteAddr;
-            mIkey = ikey;
-            mOkey = okey;
-            mIfId = intfId;
-        }
-
-        /** always guarded by IpSecService#this */
-        @Override
-        public void freeUnderlyingResources() {
-            // Calls to netd
-            //       Teardown VTI
-            //       Delete global policies
-            try {
-                mNetd.ipSecRemoveTunnelInterface(mInterfaceName);
-
-                for (int selAddrFamily : ADDRESS_FAMILIES) {
-                    mNetd.ipSecDeleteSecurityPolicy(
-                            mUid,
-                            selAddrFamily,
-                            IpSecManager.DIRECTION_OUT,
-                            mOkey,
-                            0xffffffff,
-                            mIfId);
-                    mNetd.ipSecDeleteSecurityPolicy(
-                            mUid,
-                            selAddrFamily,
-                            IpSecManager.DIRECTION_IN,
-                            mIkey,
-                            0xffffffff,
-                            mIfId);
-                }
-            } catch (ServiceSpecificException | RemoteException e) {
-                Log.e(
-                        TAG,
-                        "Failed to delete VTI with interface name: "
-                                + mInterfaceName
-                                + " and id: "
-                                + mResourceId, e);
-            }
-
-            getResourceTracker().give();
-            releaseNetId(mIkey);
-            releaseNetId(mOkey);
-        }
-
-        @GuardedBy("IpSecService.this")
-        public void setUnderlyingNetwork(Network underlyingNetwork) {
-            // When #applyTunnelModeTransform is called, this new underlying network will be used to
-            // update the output mark of the input transform.
-            mUnderlyingNetwork = underlyingNetwork;
-        }
-
-        @GuardedBy("IpSecService.this")
-        public Network getUnderlyingNetwork() {
-            return mUnderlyingNetwork;
-        }
-
-        public String getInterfaceName() {
-            return mInterfaceName;
-        }
-
-        /** Returns the local, outer address for the tunnelInterface */
-        public String getLocalAddress() {
-            return mLocalAddress;
-        }
-
-        /** Returns the remote, outer address for the tunnelInterface */
-        public String getRemoteAddress() {
-            return mRemoteAddress;
-        }
-
-        public int getIkey() {
-            return mIkey;
-        }
-
-        public int getOkey() {
-            return mOkey;
-        }
-
-        public int getIfId() {
-            return mIfId;
-        }
-
-        @Override
-        protected ResourceTracker getResourceTracker() {
-            return getUserRecord().mTunnelQuotaTracker;
-        }
-
-        @Override
-        public void invalidate() {
-            getUserRecord().removeTunnelInterfaceRecord(mResourceId);
-        }
-
-        @Override
-        public String toString() {
-            return new StringBuilder()
-                    .append("{super=")
-                    .append(super.toString())
-                    .append(", mInterfaceName=")
-                    .append(mInterfaceName)
-                    .append(", mUnderlyingNetwork=")
-                    .append(mUnderlyingNetwork)
-                    .append(", mLocalAddress=")
-                    .append(mLocalAddress)
-                    .append(", mRemoteAddress=")
-                    .append(mRemoteAddress)
-                    .append(", mIkey=")
-                    .append(mIkey)
-                    .append(", mOkey=")
-                    .append(mOkey)
-                    .append("}")
-                    .toString();
-        }
-    }
-
-    /**
-     * Tracks a UDP encap socket, and manages cleanup paths
-     *
-     * <p>While this class does not manage non-kernel resources, race conditions around socket
-     * binding require that the service creates the encap socket, binds it and applies the socket
-     * policy before handing it to a user.
-     */
-    private final class EncapSocketRecord extends OwnedResourceRecord {
-        private FileDescriptor mSocket;
-        private final int mPort;
-
-        EncapSocketRecord(int resourceId, FileDescriptor socket, int port) {
-            super(resourceId);
-            mSocket = socket;
-            mPort = port;
-        }
-
-        /** always guarded by IpSecService#this */
-        @Override
-        public void freeUnderlyingResources() {
-            Log.d(TAG, "Closing port " + mPort);
-            IoUtils.closeQuietly(mSocket);
-            mSocket = null;
-
-            getResourceTracker().give();
-        }
-
-        public int getPort() {
-            return mPort;
-        }
-
-        public FileDescriptor getFileDescriptor() {
-            return mSocket;
-        }
-
-        @Override
-        protected ResourceTracker getResourceTracker() {
-            return getUserRecord().mSocketQuotaTracker;
-        }
-
-        @Override
-        public void invalidate() {
-            getUserRecord().removeEncapSocketRecord(mResourceId);
-        }
-
-        @Override
-        public String toString() {
-            return new StringBuilder()
-                    .append("{super=")
-                    .append(super.toString())
-                    .append(", mSocket=")
-                    .append(mSocket)
-                    .append(", mPort=")
-                    .append(mPort)
-                    .append("}")
-                    .toString();
-        }
-    }
-
-    /**
-     * Constructs a new IpSecService instance
-     *
-     * @param context Binder context for this service
-     */
-    public IpSecService(Context context) {
-        this(context, new Dependencies());
-    }
-
-    @NonNull
-    private AppOpsManager getAppOpsManager() {
-        AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
-        if (appOps == null) throw new RuntimeException("System Server couldn't get AppOps");
-        return appOps;
-    }
-
-    /** @hide */
-    @VisibleForTesting
-    public IpSecService(Context context, Dependencies deps) {
-        this(
-                context,
-                deps,
-                (fd, uid) -> {
-                    try {
-                        TrafficStats.setThreadStatsUid(uid);
-                        TrafficStats.tagFileDescriptor(fd);
-                    } finally {
-                        TrafficStats.clearThreadStatsUid();
-                    }
-                });
-    }
-
-    /** @hide */
-    @VisibleForTesting
-    public IpSecService(Context context, Dependencies deps, UidFdTagger uidFdTagger) {
-        mContext = context;
-        mDeps = Objects.requireNonNull(deps, "Missing dependencies.");
-        mUidFdTagger = uidFdTagger;
-        try {
-            mNetd = mDeps.getNetdInstance(mContext);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Checks that the provided InetAddress is valid for use in an IPsec SA. The address must not be
-     * a wildcard address and must be in a numeric form such as 1.2.3.4 or 2001::1.
-     */
-    private static void checkInetAddress(String inetAddress) {
-        if (TextUtils.isEmpty(inetAddress)) {
-            throw new IllegalArgumentException("Unspecified address");
-        }
-
-        InetAddress checkAddr = InetAddresses.parseNumericAddress(inetAddress);
-
-        if (checkAddr.isAnyLocalAddress()) {
-            throw new IllegalArgumentException("Inappropriate wildcard address: " + inetAddress);
-        }
-    }
-
-    /**
-     * Checks the user-provided direction field and throws an IllegalArgumentException if it is not
-     * DIRECTION_IN or DIRECTION_OUT
-     */
-    private void checkDirection(int direction) {
-        switch (direction) {
-            case IpSecManager.DIRECTION_OUT:
-            case IpSecManager.DIRECTION_IN:
-                return;
-            case IpSecManager.DIRECTION_FWD:
-                // Only NETWORK_STACK or MAINLINE_NETWORK_STACK allowed to use forward policies
-                PermissionUtils.enforceNetworkStackPermission(mContext);
-                return;
-        }
-        throw new IllegalArgumentException("Invalid Direction: " + direction);
-    }
-
-    /** Get a new SPI and maintain the reservation in the system server */
-    @Override
-    public synchronized IpSecSpiResponse allocateSecurityParameterIndex(
-            String destinationAddress, int requestedSpi, IBinder binder) throws RemoteException {
-        checkInetAddress(destinationAddress);
-        // RFC 4303 Section 2.1 - 0=local, 1-255=reserved.
-        if (requestedSpi > 0 && requestedSpi < 256) {
-            throw new IllegalArgumentException("ESP SPI must not be in the range of 0-255.");
-        }
-        Objects.requireNonNull(binder, "Null Binder passed to allocateSecurityParameterIndex");
-
-        int callingUid = Binder.getCallingUid();
-        UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid);
-        final int resourceId = mNextResourceId++;
-
-        int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
-        try {
-            if (!userRecord.mSpiQuotaTracker.isAvailable()) {
-                return new IpSecSpiResponse(
-                        IpSecManager.Status.RESOURCE_UNAVAILABLE, INVALID_RESOURCE_ID, spi);
-            }
-
-            spi = mNetd.ipSecAllocateSpi(callingUid, "", destinationAddress, requestedSpi);
-            Log.d(TAG, "Allocated SPI " + spi);
-            userRecord.mSpiRecords.put(
-                    resourceId,
-                    new RefcountedResource<SpiRecord>(
-                            new SpiRecord(resourceId, "",
-                            destinationAddress, spi), binder));
-        } catch (ServiceSpecificException e) {
-            if (e.errorCode == OsConstants.ENOENT) {
-                return new IpSecSpiResponse(
-                        IpSecManager.Status.SPI_UNAVAILABLE, INVALID_RESOURCE_ID, spi);
-            }
-            throw e;
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-        return new IpSecSpiResponse(IpSecManager.Status.OK, resourceId, spi);
-    }
-
-    /* This method should only be called from Binder threads. Do not call this from
-     * within the system server as it will crash the system on failure.
-     */
-    private void releaseResource(RefcountedResourceArray resArray, int resourceId)
-            throws RemoteException {
-        resArray.getRefcountedResourceOrThrow(resourceId).userRelease();
-    }
-
-    /** Release a previously allocated SPI that has been registered with the system server */
-    @Override
-    public synchronized void releaseSecurityParameterIndex(int resourceId) throws RemoteException {
-        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
-        releaseResource(userRecord.mSpiRecords, resourceId);
-    }
-
-    /**
-     * This function finds and forcibly binds to a random system port, ensuring that the port cannot
-     * be unbound.
-     *
-     * <p>A socket cannot be un-bound from a port if it was bound to that port by number. To select
-     * a random open port and then bind by number, this function creates a temp socket, binds to a
-     * random port (specifying 0), gets that port number, and then uses is to bind the user's UDP
-     * Encapsulation Socket forcibly, so that it cannot be un-bound by the user with the returned
-     * FileHandle.
-     *
-     * <p>The loop in this function handles the inherent race window between un-binding to a port
-     * and re-binding, during which the system could *technically* hand that port out to someone
-     * else.
-     */
-    private int bindToRandomPort(FileDescriptor sockFd) throws IOException {
-        for (int i = MAX_PORT_BIND_ATTEMPTS; i > 0; i--) {
-            try {
-                FileDescriptor probeSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-                Os.bind(probeSocket, INADDR_ANY, 0);
-                int port = ((InetSocketAddress) Os.getsockname(probeSocket)).getPort();
-                Os.close(probeSocket);
-                Log.v(TAG, "Binding to port " + port);
-                Os.bind(sockFd, INADDR_ANY, port);
-                return port;
-            } catch (ErrnoException e) {
-                // Someone miraculously claimed the port just after we closed probeSocket.
-                if (e.errno == OsConstants.EADDRINUSE) {
-                    continue;
-                }
-                throw e.rethrowAsIOException();
-            }
-        }
-        throw new IOException("Failed " + MAX_PORT_BIND_ATTEMPTS + " attempts to bind to a port");
-    }
-
-    /**
-     * Functional interface to do traffic tagging of given sockets to UIDs.
-     *
-     * <p>Specifically used by openUdpEncapsulationSocket to ensure data usage on the UDP encap
-     * sockets are billed to the UID that the UDP encap socket was created on behalf of.
-     *
-     * <p>Separate class so that the socket tagging logic can be mocked; TrafficStats uses static
-     * methods that cannot be easily mocked/tested.
-     */
-    @VisibleForTesting
-    public interface UidFdTagger {
-        /**
-         * Sets socket tag to assign all traffic to the provided UID.
-         *
-         * <p>Since the socket is created on behalf of an unprivileged application, all traffic
-         * should be accounted to the UID of the unprivileged application.
-         */
-        void tag(FileDescriptor fd, int uid) throws IOException;
-    }
-
-    /**
-     * Open a socket via the system server and bind it to the specified port (random if port=0).
-     * This will return a PFD to the user that represent a bound UDP socket. The system server will
-     * cache the socket and a record of its owner so that it can and must be freed when no longer
-     * needed.
-     */
-    @Override
-    public synchronized IpSecUdpEncapResponse openUdpEncapsulationSocket(int port, IBinder binder)
-            throws RemoteException {
-        if (port != 0 && (port < FREE_PORT_MIN || port > PORT_MAX)) {
-            throw new IllegalArgumentException(
-                    "Specified port number must be a valid non-reserved UDP port");
-        }
-        Objects.requireNonNull(binder, "Null Binder passed to openUdpEncapsulationSocket");
-
-        int callingUid = Binder.getCallingUid();
-        UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid);
-        final int resourceId = mNextResourceId++;
-
-        ParcelFileDescriptor pFd = null;
-        try {
-            if (!userRecord.mSocketQuotaTracker.isAvailable()) {
-                return new IpSecUdpEncapResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
-            }
-
-            FileDescriptor sockFd = null;
-            try {
-                sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-                pFd = ParcelFileDescriptor.dup(sockFd);
-            } finally {
-                IoUtils.closeQuietly(sockFd);
-            }
-
-            mUidFdTagger.tag(pFd.getFileDescriptor(), callingUid);
-            // This code is common to both the unspecified and specified port cases
-            Os.setsockoptInt(
-                    pFd.getFileDescriptor(),
-                    OsConstants.IPPROTO_UDP,
-                    OsConstants.UDP_ENCAP,
-                    OsConstants.UDP_ENCAP_ESPINUDP);
-
-            mNetd.ipSecSetEncapSocketOwner(pFd, callingUid);
-            if (port != 0) {
-                Log.v(TAG, "Binding to port " + port);
-                Os.bind(pFd.getFileDescriptor(), INADDR_ANY, port);
-            } else {
-                port = bindToRandomPort(pFd.getFileDescriptor());
-            }
-
-            userRecord.mEncapSocketRecords.put(
-                    resourceId,
-                    new RefcountedResource<EncapSocketRecord>(
-                            new EncapSocketRecord(resourceId, pFd.getFileDescriptor(), port),
-                            binder));
-            return new IpSecUdpEncapResponse(IpSecManager.Status.OK, resourceId, port,
-                    pFd.getFileDescriptor());
-        } catch (IOException | ErrnoException e) {
-            try {
-                if (pFd != null) {
-                    pFd.close();
-                }
-            } catch (IOException ex) {
-                // Nothing can be done at this point
-                Log.e(TAG, "Failed to close pFd.");
-            }
-        }
-        // If we make it to here, then something has gone wrong and we couldn't open a socket.
-        // The only reasonable condition that would cause that is resource unavailable.
-        return new IpSecUdpEncapResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
-    }
-
-    /** close a socket that has been been allocated by and registered with the system server */
-    @Override
-    public synchronized void closeUdpEncapsulationSocket(int resourceId) throws RemoteException {
-        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
-        releaseResource(userRecord.mEncapSocketRecords, resourceId);
-    }
-
-    /**
-     * Create a tunnel interface for use in IPSec tunnel mode. The system server will cache the
-     * tunnel interface and a record of its owner so that it can and must be freed when no longer
-     * needed.
-     */
-    @Override
-    public synchronized IpSecTunnelInterfaceResponse createTunnelInterface(
-            String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder,
-            String callingPackage) {
-        enforceTunnelFeatureAndPermissions(callingPackage);
-        Objects.requireNonNull(binder, "Null Binder passed to createTunnelInterface");
-        Objects.requireNonNull(underlyingNetwork, "No underlying network was specified");
-        checkInetAddress(localAddr);
-        checkInetAddress(remoteAddr);
-
-        // TODO: Check that underlying network exists, and IP addresses not assigned to a different
-        //       network (b/72316676).
-
-        int callerUid = Binder.getCallingUid();
-        UserRecord userRecord = mUserResourceTracker.getUserRecord(callerUid);
-        if (!userRecord.mTunnelQuotaTracker.isAvailable()) {
-            return new IpSecTunnelInterfaceResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
-        }
-
-        final int resourceId = mNextResourceId++;
-        final int ikey = reserveNetId();
-        final int okey = reserveNetId();
-        String intfName = String.format("%s%d", INetd.IPSEC_INTERFACE_PREFIX, resourceId);
-
-        try {
-            // Calls to netd:
-            //       Create VTI
-            //       Add inbound/outbound global policies
-            //              (use reqid = 0)
-            mNetd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId);
-
-            BinderUtils.withCleanCallingIdentity(() -> {
-                NetdUtils.setInterfaceUp(mNetd, intfName);
-            });
-
-            for (int selAddrFamily : ADDRESS_FAMILIES) {
-                // Always send down correct local/remote addresses for template.
-                mNetd.ipSecAddSecurityPolicy(
-                        callerUid,
-                        selAddrFamily,
-                        IpSecManager.DIRECTION_OUT,
-                        localAddr,
-                        remoteAddr,
-                        0,
-                        okey,
-                        0xffffffff,
-                        resourceId);
-                mNetd.ipSecAddSecurityPolicy(
-                        callerUid,
-                        selAddrFamily,
-                        IpSecManager.DIRECTION_IN,
-                        remoteAddr,
-                        localAddr,
-                        0,
-                        ikey,
-                        0xffffffff,
-                        resourceId);
-
-                // Add a forwarding policy on the tunnel interface. In order to support forwarding
-                // the IpSecTunnelInterface must have a forwarding policy matching the incoming SA.
-                //
-                // Unless a IpSecTransform is also applied against this interface in DIRECTION_FWD,
-                // forwarding will be blocked by default (as would be the case if this policy was
-                // absent).
-                //
-                // This is necessary only on the tunnel interface, and not any the interface to
-                // which traffic will be forwarded to.
-                mNetd.ipSecAddSecurityPolicy(
-                        callerUid,
-                        selAddrFamily,
-                        IpSecManager.DIRECTION_FWD,
-                        remoteAddr,
-                        localAddr,
-                        0,
-                        ikey,
-                        0xffffffff,
-                        resourceId);
-            }
-
-            userRecord.mTunnelInterfaceRecords.put(
-                    resourceId,
-                    new RefcountedResource<TunnelInterfaceRecord>(
-                            new TunnelInterfaceRecord(
-                                    resourceId,
-                                    intfName,
-                                    underlyingNetwork,
-                                    localAddr,
-                                    remoteAddr,
-                                    ikey,
-                                    okey,
-                                    resourceId),
-                            binder));
-            return new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName);
-        } catch (RemoteException e) {
-            // Release keys if we got an error.
-            releaseNetId(ikey);
-            releaseNetId(okey);
-            throw e.rethrowFromSystemServer();
-        } catch (Throwable t) {
-            // Release keys if we got an error.
-            releaseNetId(ikey);
-            releaseNetId(okey);
-            throw t;
-        }
-    }
-
-    /**
-     * Adds a new local address to the tunnel interface. This allows packets to be sent and received
-     * from multiple local IP addresses over the same tunnel.
-     */
-    @Override
-    public synchronized void addAddressToTunnelInterface(
-            int tunnelResourceId, LinkAddress localAddr, String callingPackage) {
-        enforceTunnelFeatureAndPermissions(callingPackage);
-        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
-
-        // Get tunnelInterface record; if no such interface is found, will throw
-        // IllegalArgumentException
-        TunnelInterfaceRecord tunnelInterfaceInfo =
-                userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId);
-
-        try {
-            // We can assume general validity of the IP address, since we get them as a
-            // LinkAddress, which does some validation.
-            mNetd.interfaceAddAddress(
-                    tunnelInterfaceInfo.mInterfaceName,
-                    localAddr.getAddress().getHostAddress(),
-                    localAddr.getPrefixLength());
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Remove a new local address from the tunnel interface. After removal, the address will no
-     * longer be available to send from, or receive on.
-     */
-    @Override
-    public synchronized void removeAddressFromTunnelInterface(
-            int tunnelResourceId, LinkAddress localAddr, String callingPackage) {
-        enforceTunnelFeatureAndPermissions(callingPackage);
-
-        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
-        // Get tunnelInterface record; if no such interface is found, will throw
-        // IllegalArgumentException
-        TunnelInterfaceRecord tunnelInterfaceInfo =
-                userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId);
-
-        try {
-            // We can assume general validity of the IP address, since we get them as a
-            // LinkAddress, which does some validation.
-            mNetd.interfaceDelAddress(
-                            tunnelInterfaceInfo.mInterfaceName,
-                            localAddr.getAddress().getHostAddress(),
-                            localAddr.getPrefixLength());
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /** Set TunnelInterface to use a specific underlying network. */
-    @Override
-    public synchronized void setNetworkForTunnelInterface(
-            int tunnelResourceId, Network underlyingNetwork, String callingPackage) {
-        enforceTunnelFeatureAndPermissions(callingPackage);
-        Objects.requireNonNull(underlyingNetwork, "No underlying network was specified");
-
-        final UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
-
-        // Get tunnelInterface record; if no such interface is found, will throw
-        // IllegalArgumentException. userRecord.mTunnelInterfaceRecords is never null
-        final TunnelInterfaceRecord tunnelInterfaceInfo =
-                userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId);
-
-        final ConnectivityManager connectivityManager =
-                mContext.getSystemService(ConnectivityManager.class);
-        final LinkProperties lp = connectivityManager.getLinkProperties(underlyingNetwork);
-        if (tunnelInterfaceInfo.getInterfaceName().equals(lp.getInterfaceName())) {
-            throw new IllegalArgumentException(
-                    "Underlying network cannot be the network being exposed by this tunnel");
-        }
-
-        // It is meaningless to check if the network exists or is valid because the network might
-        // disconnect at any time after it passes the check.
-
-        tunnelInterfaceInfo.setUnderlyingNetwork(underlyingNetwork);
-    }
-
-    /**
-     * Delete a TunnelInterface that has been been allocated by and registered with the system
-     * server
-     */
-    @Override
-    public synchronized void deleteTunnelInterface(
-            int resourceId, String callingPackage) throws RemoteException {
-        enforceTunnelFeatureAndPermissions(callingPackage);
-        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
-        releaseResource(userRecord.mTunnelInterfaceRecords, resourceId);
-    }
-
-    @VisibleForTesting
-    void validateAlgorithms(IpSecConfig config) throws IllegalArgumentException {
-        IpSecAlgorithm auth = config.getAuthentication();
-        IpSecAlgorithm crypt = config.getEncryption();
-        IpSecAlgorithm aead = config.getAuthenticatedEncryption();
-
-        // Validate the algorithm set
-        Preconditions.checkArgument(
-                aead != null || crypt != null || auth != null,
-                "No Encryption or Authentication algorithms specified");
-        Preconditions.checkArgument(
-                auth == null || auth.isAuthentication(),
-                "Unsupported algorithm for Authentication");
-        Preconditions.checkArgument(
-                crypt == null || crypt.isEncryption(), "Unsupported algorithm for Encryption");
-        Preconditions.checkArgument(
-                aead == null || aead.isAead(),
-                "Unsupported algorithm for Authenticated Encryption");
-        Preconditions.checkArgument(
-                aead == null || (auth == null && crypt == null),
-                "Authenticated Encryption is mutually exclusive with other Authentication "
-                        + "or Encryption algorithms");
-    }
-
-    private int getFamily(String inetAddress) {
-        int family = AF_UNSPEC;
-        InetAddress checkAddress = InetAddresses.parseNumericAddress(inetAddress);
-        if (checkAddress instanceof Inet4Address) {
-            family = AF_INET;
-        } else if (checkAddress instanceof Inet6Address) {
-            family = AF_INET6;
-        }
-        return family;
-    }
-
-    /**
-     * Checks an IpSecConfig parcel to ensure that the contents are valid and throws an
-     * IllegalArgumentException if they are not.
-     */
-    private void checkIpSecConfig(IpSecConfig config) {
-        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
-
-        switch (config.getEncapType()) {
-            case IpSecTransform.ENCAP_NONE:
-                break;
-            case IpSecTransform.ENCAP_ESPINUDP:
-            case IpSecTransform.ENCAP_ESPINUDP_NON_IKE:
-                // Retrieve encap socket record; will throw IllegalArgumentException if not found
-                userRecord.mEncapSocketRecords.getResourceOrThrow(
-                        config.getEncapSocketResourceId());
-
-                int port = config.getEncapRemotePort();
-                if (port <= 0 || port > 0xFFFF) {
-                    throw new IllegalArgumentException("Invalid remote UDP port: " + port);
-                }
-                break;
-            default:
-                throw new IllegalArgumentException("Invalid Encap Type: " + config.getEncapType());
-        }
-
-        validateAlgorithms(config);
-
-        // Retrieve SPI record; will throw IllegalArgumentException if not found
-        SpiRecord s = userRecord.mSpiRecords.getResourceOrThrow(config.getSpiResourceId());
-
-        // Check to ensure that SPI has not already been used.
-        if (s.getOwnedByTransform()) {
-            throw new IllegalStateException("SPI already in use; cannot be used in new Transforms");
-        }
-
-        // If no remote address is supplied, then use one from the SPI.
-        if (TextUtils.isEmpty(config.getDestinationAddress())) {
-            config.setDestinationAddress(s.getDestinationAddress());
-        }
-
-        // All remote addresses must match
-        if (!config.getDestinationAddress().equals(s.getDestinationAddress())) {
-            throw new IllegalArgumentException("Mismatched remote addresseses.");
-        }
-
-        // This check is technically redundant due to the chain of custody between the SPI and
-        // the IpSecConfig, but in the future if the dest is allowed to be set explicitly in
-        // the transform, this will prevent us from messing up.
-        checkInetAddress(config.getDestinationAddress());
-
-        // Require a valid source address for all transforms.
-        checkInetAddress(config.getSourceAddress());
-
-        // Check to ensure source and destination have the same address family.
-        String sourceAddress = config.getSourceAddress();
-        String destinationAddress = config.getDestinationAddress();
-        int sourceFamily = getFamily(sourceAddress);
-        int destinationFamily = getFamily(destinationAddress);
-        if (sourceFamily != destinationFamily) {
-            throw new IllegalArgumentException(
-                    "Source address ("
-                            + sourceAddress
-                            + ") and destination address ("
-                            + destinationAddress
-                            + ") have different address families.");
-        }
-
-        // Throw an error if UDP Encapsulation is not used in IPv4.
-        if (config.getEncapType() != IpSecTransform.ENCAP_NONE && sourceFamily != AF_INET) {
-            throw new IllegalArgumentException(
-                    "UDP Encapsulation is not supported for this address family");
-        }
-
-        switch (config.getMode()) {
-            case IpSecTransform.MODE_TRANSPORT:
-                break;
-            case IpSecTransform.MODE_TUNNEL:
-                break;
-            default:
-                throw new IllegalArgumentException(
-                        "Invalid IpSecTransform.mode: " + config.getMode());
-        }
-
-        config.setMarkValue(0);
-        config.setMarkMask(0);
-    }
-
-    private static final String TUNNEL_OP = AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS;
-
-    private void enforceTunnelFeatureAndPermissions(String callingPackage) {
-        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS)) {
-            throw new UnsupportedOperationException(
-                    "IPsec Tunnel Mode requires PackageManager.FEATURE_IPSEC_TUNNELS");
-        }
-
-        Objects.requireNonNull(callingPackage, "Null calling package cannot create IpSec tunnels");
-
-        // OP_MANAGE_IPSEC_TUNNELS will return MODE_ERRORED by default, including for the system
-        // server. If the appop is not granted, require that the caller has the MANAGE_IPSEC_TUNNELS
-        // permission or is the System Server.
-        if (AppOpsManager.MODE_ALLOWED == getAppOpsManager().noteOpNoThrow(
-                TUNNEL_OP, Binder.getCallingUid(), callingPackage)) {
-            return;
-        }
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService");
-    }
-
-    private void createOrUpdateTransform(
-            IpSecConfig c, int resourceId, SpiRecord spiRecord, EncapSocketRecord socketRecord)
-            throws RemoteException {
-
-        int encapType = c.getEncapType(), encapLocalPort = 0, encapRemotePort = 0;
-        if (encapType != IpSecTransform.ENCAP_NONE) {
-            encapLocalPort = socketRecord.getPort();
-            encapRemotePort = c.getEncapRemotePort();
-        }
-
-        IpSecAlgorithm auth = c.getAuthentication();
-        IpSecAlgorithm crypt = c.getEncryption();
-        IpSecAlgorithm authCrypt = c.getAuthenticatedEncryption();
-
-        String cryptName;
-        if (crypt == null) {
-            cryptName = (authCrypt == null) ? IpSecAlgorithm.CRYPT_NULL : "";
-        } else {
-            cryptName = crypt.getName();
-        }
-
-        mNetd.ipSecAddSecurityAssociation(
-                Binder.getCallingUid(),
-                c.getMode(),
-                c.getSourceAddress(),
-                c.getDestinationAddress(),
-                (c.getNetwork() != null) ? c.getNetwork().getNetId() : 0,
-                spiRecord.getSpi(),
-                c.getMarkValue(),
-                c.getMarkMask(),
-                (auth != null) ? auth.getName() : "",
-                (auth != null) ? auth.getKey() : new byte[] {},
-                (auth != null) ? auth.getTruncationLengthBits() : 0,
-                cryptName,
-                (crypt != null) ? crypt.getKey() : new byte[] {},
-                (crypt != null) ? crypt.getTruncationLengthBits() : 0,
-                (authCrypt != null) ? authCrypt.getName() : "",
-                (authCrypt != null) ? authCrypt.getKey() : new byte[] {},
-                (authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0,
-                encapType,
-                encapLocalPort,
-                encapRemotePort,
-                c.getXfrmInterfaceId());
-    }
-
-    /**
-     * Create a IPsec transform, which represents a single security association in the kernel. The
-     * transform will be cached by the system server and must be freed when no longer needed. It is
-     * possible to free one, deleting the SA from underneath sockets that are using it, which will
-     * result in all of those sockets becoming unable to send or receive data.
-     */
-    @Override
-    public synchronized IpSecTransformResponse createTransform(
-            IpSecConfig c, IBinder binder, String callingPackage) throws RemoteException {
-        Objects.requireNonNull(c);
-        if (c.getMode() == IpSecTransform.MODE_TUNNEL) {
-            enforceTunnelFeatureAndPermissions(callingPackage);
-        }
-        checkIpSecConfig(c);
-        Objects.requireNonNull(binder, "Null Binder passed to createTransform");
-        final int resourceId = mNextResourceId++;
-
-        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
-        List<RefcountedResource> dependencies = new ArrayList<>();
-
-        if (!userRecord.mTransformQuotaTracker.isAvailable()) {
-            return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
-        }
-
-        EncapSocketRecord socketRecord = null;
-        if (c.getEncapType() != IpSecTransform.ENCAP_NONE) {
-            RefcountedResource<EncapSocketRecord> refcountedSocketRecord =
-                    userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(
-                            c.getEncapSocketResourceId());
-            dependencies.add(refcountedSocketRecord);
-            socketRecord = refcountedSocketRecord.getResource();
-        }
-
-        RefcountedResource<SpiRecord> refcountedSpiRecord =
-                userRecord.mSpiRecords.getRefcountedResourceOrThrow(c.getSpiResourceId());
-        dependencies.add(refcountedSpiRecord);
-        SpiRecord spiRecord = refcountedSpiRecord.getResource();
-
-        createOrUpdateTransform(c, resourceId, spiRecord, socketRecord);
-
-        // SA was created successfully, time to construct a record and lock it away
-        userRecord.mTransformRecords.put(
-                resourceId,
-                new RefcountedResource<TransformRecord>(
-                        new TransformRecord(resourceId, c, spiRecord, socketRecord),
-                        binder,
-                        dependencies.toArray(new RefcountedResource[dependencies.size()])));
-        return new IpSecTransformResponse(IpSecManager.Status.OK, resourceId);
-    }
-
-    /**
-     * Delete a transport mode transform that was previously allocated by + registered with the
-     * system server. If this is called on an inactive (or non-existent) transform, it will not
-     * return an error. It's safe to de-allocate transforms that may have already been deleted for
-     * other reasons.
-     */
-    @Override
-    public synchronized void deleteTransform(int resourceId) throws RemoteException {
-        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
-        releaseResource(userRecord.mTransformRecords, resourceId);
-    }
-
-    /**
-     * Apply an active transport mode transform to a socket, which will apply the IPsec security
-     * association as a correspondent policy to the provided socket
-     */
-    @Override
-    public synchronized void applyTransportModeTransform(
-            ParcelFileDescriptor socket, int direction, int resourceId) throws RemoteException {
-        int callingUid = Binder.getCallingUid();
-        UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid);
-        checkDirection(direction);
-        // Get transform record; if no transform is found, will throw IllegalArgumentException
-        TransformRecord info = userRecord.mTransformRecords.getResourceOrThrow(resourceId);
-
-        // TODO: make this a function.
-        if (info.mPid != getCallingPid() || info.mUid != callingUid) {
-            throw new SecurityException("Only the owner of an IpSec Transform may apply it!");
-        }
-
-        // Get config and check that to-be-applied transform has the correct mode
-        IpSecConfig c = info.getConfig();
-        Preconditions.checkArgument(
-                c.getMode() == IpSecTransform.MODE_TRANSPORT,
-                "Transform mode was not Transport mode; cannot be applied to a socket");
-
-        mNetd.ipSecApplyTransportModeTransform(
-                socket,
-                callingUid,
-                direction,
-                c.getSourceAddress(),
-                c.getDestinationAddress(),
-                info.getSpiRecord().getSpi());
-    }
-
-    /**
-     * Remove transport mode transforms from a socket, applying the default (empty) policy. This
-     * ensures that NO IPsec policy is applied to the socket (would be the equivalent of applying a
-     * policy that performs no IPsec). Today the resourceId parameter is passed but not used:
-     * reserved for future improved input validation.
-     */
-    @Override
-    public synchronized void removeTransportModeTransforms(ParcelFileDescriptor socket)
-            throws RemoteException {
-        mNetd.ipSecRemoveTransportModeTransform(socket);
-    }
-
-    /**
-     * Apply an active tunnel mode transform to a TunnelInterface, which will apply the IPsec
-     * security association as a correspondent policy to the provided interface
-     */
-    @Override
-    public synchronized void applyTunnelModeTransform(
-            int tunnelResourceId, int direction,
-            int transformResourceId, String callingPackage) throws RemoteException {
-        enforceTunnelFeatureAndPermissions(callingPackage);
-        checkDirection(direction);
-
-        int callingUid = Binder.getCallingUid();
-        UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid);
-
-        // Get transform record; if no transform is found, will throw IllegalArgumentException
-        TransformRecord transformInfo =
-                userRecord.mTransformRecords.getResourceOrThrow(transformResourceId);
-
-        // Get tunnelInterface record; if no such interface is found, will throw
-        // IllegalArgumentException
-        TunnelInterfaceRecord tunnelInterfaceInfo =
-                userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId);
-
-        // Get config and check that to-be-applied transform has the correct mode
-        IpSecConfig c = transformInfo.getConfig();
-        Preconditions.checkArgument(
-                c.getMode() == IpSecTransform.MODE_TUNNEL,
-                "Transform mode was not Tunnel mode; cannot be applied to a tunnel interface");
-
-        EncapSocketRecord socketRecord = null;
-        if (c.getEncapType() != IpSecTransform.ENCAP_NONE) {
-            socketRecord =
-                    userRecord.mEncapSocketRecords.getResourceOrThrow(c.getEncapSocketResourceId());
-        }
-        SpiRecord spiRecord = transformInfo.getSpiRecord();
-
-        int mark =
-                (direction == IpSecManager.DIRECTION_OUT)
-                        ? tunnelInterfaceInfo.getOkey()
-                        : tunnelInterfaceInfo.getIkey(); // Ikey also used for FWD policies
-
-        try {
-            // Default to using the invalid SPI of 0 for inbound SAs. This allows policies to skip
-            // SPI matching as part of the template resolution.
-            int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
-            c.setXfrmInterfaceId(tunnelInterfaceInfo.getIfId());
-
-            // TODO: enable this when UPDSA supports updating marks. Adding kernel support upstream
-            //     (and backporting) would allow us to narrow the mark space, and ensure that the SA
-            //     and SPs have matching marks (as VTI are meant to be built).
-            // Currently update does nothing with marks. Leave empty (defaulting to 0) to ensure the
-            //     config matches the actual allocated resources in the kernel.
-            // All SAs will have zero marks (from creation time), and any policy that matches the
-            //     same src/dst could match these SAs. Non-IpSecService governed processes that
-            //     establish floating policies with the same src/dst may result in undefined
-            //     behavior. This is generally limited to vendor code due to the permissions
-            //     (CAP_NET_ADMIN) required.
-            //
-            // c.setMarkValue(mark);
-            // c.setMarkMask(0xffffffff);
-
-            if (direction == IpSecManager.DIRECTION_OUT) {
-                // Set output mark via underlying network (output only)
-                c.setNetwork(tunnelInterfaceInfo.getUnderlyingNetwork());
-
-                // Set outbound SPI only. We want inbound to use any valid SA (old, new) on rekeys,
-                // but want to guarantee outbound packets are sent over the new SA.
-                spi = spiRecord.getSpi();
-            }
-
-            // Always update the policy with the relevant XFRM_IF_ID
-            for (int selAddrFamily : ADDRESS_FAMILIES) {
-                mNetd.ipSecUpdateSecurityPolicy(
-                        callingUid,
-                        selAddrFamily,
-                        direction,
-                        transformInfo.getConfig().getSourceAddress(),
-                        transformInfo.getConfig().getDestinationAddress(),
-                        spi, // If outbound, also add SPI to the policy.
-                        mark, // Must always set policy mark; ikey/okey for VTIs
-                        0xffffffff,
-                        c.getXfrmInterfaceId());
-            }
-
-            // Update SA with tunnel mark (ikey or okey based on direction)
-            createOrUpdateTransform(c, transformResourceId, spiRecord, socketRecord);
-        } catch (ServiceSpecificException e) {
-            if (e.errorCode == EINVAL) {
-                throw new IllegalArgumentException(e.toString());
-            } else {
-                throw e;
-            }
-        }
-    }
-
-    @Override
-    protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        mContext.enforceCallingOrSelfPermission(DUMP, TAG);
-
-        pw.println("IpSecService dump:");
-        pw.println();
-
-        pw.println("mUserResourceTracker:");
-        pw.println(mUserResourceTracker);
-    }
-}
diff --git a/packages/ConnectivityT/service/src/com/android/server/NativeDaemonConnector.java b/packages/ConnectivityT/service/src/com/android/server/NativeDaemonConnector.java
deleted file mode 100644
index ec8d779..0000000
--- a/packages/ConnectivityT/service/src/com/android/server/NativeDaemonConnector.java
+++ /dev/null
@@ -1,704 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
-import android.os.Build;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.SystemClock;
-import android.util.LocalLog;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.Objects;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Generic connector class for interfacing with a native daemon which uses the
- * {@code libsysutils} FrameworkListener protocol.
- */
-final class NativeDaemonConnector implements Runnable, Handler.Callback {
-    private final static boolean VDBG = false;
-
-    private final String TAG;
-
-    private String mSocket;
-    private OutputStream mOutputStream;
-    private LocalLog mLocalLog;
-
-    private volatile boolean mDebug = false;
-    private volatile Object mWarnIfHeld;
-
-    private final ResponseQueue mResponseQueue;
-
-    private final PowerManager.WakeLock mWakeLock;
-
-    private final Looper mLooper;
-
-    private INativeDaemonConnectorCallbacks mCallbacks;
-    private Handler mCallbackHandler;
-
-    private AtomicInteger mSequenceNumber;
-
-    private static final long DEFAULT_TIMEOUT = 1 * 60 * 1000; /* 1 minute */
-    private static final long WARN_EXECUTE_DELAY_MS = 500; /* .5 sec */
-
-    /** Lock held whenever communicating with native daemon. */
-    private final Object mDaemonLock = new Object();
-
-    private final int BUFFER_SIZE = 4096;
-
-    NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,
-            int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl) {
-        mCallbacks = callbacks;
-        mSocket = socket;
-        mResponseQueue = new ResponseQueue(responseQueueSize);
-        mWakeLock = wl;
-        if (mWakeLock != null) {
-            mWakeLock.setReferenceCounted(true);
-        }
-        mSequenceNumber = new AtomicInteger(0);
-        TAG = logTag != null ? logTag : "NativeDaemonConnector";
-        mLocalLog = new LocalLog(maxLogSize);
-        final HandlerThread thread = new HandlerThread(TAG);
-        thread.start();
-        mLooper = thread.getLooper();
-    }
-
-    /**
-     * Enable Set debugging mode, which causes messages to also be written to both
-     * {@link Log} in addition to internal log.
-     */
-    public void setDebug(boolean debug) {
-        mDebug = debug;
-    }
-
-    /**
-     * Like SystemClock.uptimeMillis, except truncated to an int so it will fit in a message arg.
-     * Inaccurate across 49.7 days of uptime, but only used for debugging.
-     */
-    private int uptimeMillisInt() {
-        return (int) SystemClock.uptimeMillis() & Integer.MAX_VALUE;
-    }
-
-    /**
-     * Yell loudly if someone tries making future {@link #execute(Command)}
-     * calls while holding a lock on the given object.
-     */
-    public void setWarnIfHeld(Object warnIfHeld) {
-        if (mWarnIfHeld != null) {
-            throw new IllegalStateException("warnIfHeld is already set.");
-        }
-        mWarnIfHeld = Objects.requireNonNull(warnIfHeld);
-    }
-
-    @Override
-    public void run() {
-        mCallbackHandler = new Handler(mLooper, this);
-
-        while (true) {
-            try {
-                listenToSocket();
-            } catch (Exception e) {
-                loge("Error in NativeDaemonConnector: " + e);
-                SystemClock.sleep(5000);
-            }
-        }
-    }
-
-    @Override
-    public boolean handleMessage(Message msg) {
-        final String event = (String) msg.obj;
-        final int start = uptimeMillisInt();
-        final int sent = msg.arg1;
-        try {
-            if (!mCallbacks.onEvent(msg.what, event, NativeDaemonEvent.unescapeArgs(event))) {
-                log(String.format("Unhandled event '%s'", event));
-            }
-        } catch (Exception e) {
-            loge("Error handling '" + event + "': " + e);
-        } finally {
-            if (mCallbacks.onCheckHoldWakeLock(msg.what) && mWakeLock != null) {
-                mWakeLock.release();
-            }
-            final int end = uptimeMillisInt();
-            if (start > sent && start - sent > WARN_EXECUTE_DELAY_MS) {
-                loge(String.format("NDC event {%s} processed too late: %dms", event, start - sent));
-            }
-            if (end > start && end - start > WARN_EXECUTE_DELAY_MS) {
-                loge(String.format("NDC event {%s} took too long: %dms", event, end - start));
-            }
-        }
-        return true;
-    }
-
-    private LocalSocketAddress determineSocketAddress() {
-        // If we're testing, set up a socket in a namespace that's accessible to test code.
-        // In order to ensure that unprivileged apps aren't able to impersonate native daemons on
-        // production devices, even if said native daemons ill-advisedly pick a socket name that
-        // starts with __test__, only allow this on debug builds.
-        if (mSocket.startsWith("__test__") && Build.isDebuggable()) {
-            return new LocalSocketAddress(mSocket);
-        } else {
-            return new LocalSocketAddress(mSocket, LocalSocketAddress.Namespace.RESERVED);
-        }
-    }
-
-    private void listenToSocket() throws IOException {
-        LocalSocket socket = null;
-
-        try {
-            socket = new LocalSocket();
-            LocalSocketAddress address = determineSocketAddress();
-
-            socket.connect(address);
-
-            InputStream inputStream = socket.getInputStream();
-            synchronized (mDaemonLock) {
-                mOutputStream = socket.getOutputStream();
-            }
-
-            mCallbacks.onDaemonConnected();
-
-            FileDescriptor[] fdList = null;
-            byte[] buffer = new byte[BUFFER_SIZE];
-            int start = 0;
-
-            while (true) {
-                int count = inputStream.read(buffer, start, BUFFER_SIZE - start);
-                if (count < 0) {
-                    loge("got " + count + " reading with start = " + start);
-                    break;
-                }
-                fdList = socket.getAncillaryFileDescriptors();
-
-                // Add our starting point to the count and reset the start.
-                count += start;
-                start = 0;
-
-                for (int i = 0; i < count; i++) {
-                    if (buffer[i] == 0) {
-                        // Note - do not log this raw message since it may contain
-                        // sensitive data
-                        final String rawEvent = new String(
-                                buffer, start, i - start, StandardCharsets.UTF_8);
-
-                        boolean releaseWl = false;
-                        try {
-                            final NativeDaemonEvent event =
-                                    NativeDaemonEvent.parseRawEvent(rawEvent, fdList);
-
-                            log("RCV <- {" + event + "}");
-
-                            if (event.isClassUnsolicited()) {
-                                // TODO: migrate to sending NativeDaemonEvent instances
-                                if (mCallbacks.onCheckHoldWakeLock(event.getCode())
-                                        && mWakeLock != null) {
-                                    mWakeLock.acquire();
-                                    releaseWl = true;
-                                }
-                                Message msg = mCallbackHandler.obtainMessage(
-                                        event.getCode(), uptimeMillisInt(), 0, event.getRawEvent());
-                                if (mCallbackHandler.sendMessage(msg)) {
-                                    releaseWl = false;
-                                }
-                            } else {
-                                mResponseQueue.add(event.getCmdNumber(), event);
-                            }
-                        } catch (IllegalArgumentException e) {
-                            log("Problem parsing message " + e);
-                        } finally {
-                            if (releaseWl) {
-                                mWakeLock.release();
-                            }
-                        }
-
-                        start = i + 1;
-                    }
-                }
-
-                if (start == 0) {
-                    log("RCV incomplete");
-                }
-
-                // We should end at the amount we read. If not, compact then
-                // buffer and read again.
-                if (start != count) {
-                    final int remaining = BUFFER_SIZE - start;
-                    System.arraycopy(buffer, start, buffer, 0, remaining);
-                    start = remaining;
-                } else {
-                    start = 0;
-                }
-            }
-        } catch (IOException ex) {
-            loge("Communications error: " + ex);
-            throw ex;
-        } finally {
-            synchronized (mDaemonLock) {
-                if (mOutputStream != null) {
-                    try {
-                        loge("closing stream for " + mSocket);
-                        mOutputStream.close();
-                    } catch (IOException e) {
-                        loge("Failed closing output stream: " + e);
-                    }
-                    mOutputStream = null;
-                }
-            }
-
-            try {
-                if (socket != null) {
-                    socket.close();
-                }
-            } catch (IOException ex) {
-                loge("Failed closing socket: " + ex);
-            }
-        }
-    }
-
-    /**
-     * Wrapper around argument that indicates it's sensitive and shouldn't be
-     * logged.
-     */
-    public static class SensitiveArg {
-        private final Object mArg;
-
-        public SensitiveArg(Object arg) {
-            mArg = arg;
-        }
-
-        @Override
-        public String toString() {
-            return String.valueOf(mArg);
-        }
-    }
-
-    /**
-     * Make command for daemon, escaping arguments as needed.
-     */
-    @VisibleForTesting
-    static void makeCommand(StringBuilder rawBuilder, StringBuilder logBuilder, int sequenceNumber,
-            String cmd, Object... args) {
-        if (cmd.indexOf('\0') >= 0) {
-            throw new IllegalArgumentException("Unexpected command: " + cmd);
-        }
-        if (cmd.indexOf(' ') >= 0) {
-            throw new IllegalArgumentException("Arguments must be separate from command");
-        }
-
-        rawBuilder.append(sequenceNumber).append(' ').append(cmd);
-        logBuilder.append(sequenceNumber).append(' ').append(cmd);
-        for (Object arg : args) {
-            final String argString = String.valueOf(arg);
-            if (argString.indexOf('\0') >= 0) {
-                throw new IllegalArgumentException("Unexpected argument: " + arg);
-            }
-
-            rawBuilder.append(' ');
-            logBuilder.append(' ');
-
-            appendEscaped(rawBuilder, argString);
-            if (arg instanceof SensitiveArg) {
-                logBuilder.append("[scrubbed]");
-            } else {
-                appendEscaped(logBuilder, argString);
-            }
-        }
-
-        rawBuilder.append('\0');
-    }
-
-    /**
-     * Method that waits until all asychronous notifications sent by the native daemon have
-     * been processed. This method must not be called on the notification thread or an
-     * exception will be thrown.
-     */
-    public void waitForCallbacks() {
-        if (Thread.currentThread() == mLooper.getThread()) {
-            throw new IllegalStateException("Must not call this method on callback thread");
-        }
-
-        final CountDownLatch latch = new CountDownLatch(1);
-        mCallbackHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                latch.countDown();
-            }
-        });
-        try {
-            latch.await();
-        } catch (InterruptedException e) {
-            Log.wtf(TAG, "Interrupted while waiting for unsolicited response handling", e);
-        }
-    }
-
-    /**
-     * Issue the given command to the native daemon and return a single expected
-     * response.
-     *
-     * @throws NativeDaemonConnectorException when problem communicating with
-     *             native daemon, or if the response matches
-     *             {@link NativeDaemonEvent#isClassClientError()} or
-     *             {@link NativeDaemonEvent#isClassServerError()}.
-     */
-    public NativeDaemonEvent execute(Command cmd) throws NativeDaemonConnectorException {
-        return execute(cmd.mCmd, cmd.mArguments.toArray());
-    }
-
-    /**
-     * Issue the given command to the native daemon and return a single expected
-     * response. Any arguments must be separated from base command so they can
-     * be properly escaped.
-     *
-     * @throws NativeDaemonConnectorException when problem communicating with
-     *             native daemon, or if the response matches
-     *             {@link NativeDaemonEvent#isClassClientError()} or
-     *             {@link NativeDaemonEvent#isClassServerError()}.
-     */
-    public NativeDaemonEvent execute(String cmd, Object... args)
-            throws NativeDaemonConnectorException {
-        return execute(DEFAULT_TIMEOUT, cmd, args);
-    }
-
-    public NativeDaemonEvent execute(long timeoutMs, String cmd, Object... args)
-            throws NativeDaemonConnectorException {
-        final NativeDaemonEvent[] events = executeForList(timeoutMs, cmd, args);
-        if (events.length != 1) {
-            throw new NativeDaemonConnectorException(
-                    "Expected exactly one response, but received " + events.length);
-        }
-        return events[0];
-    }
-
-    /**
-     * Issue the given command to the native daemon and return any
-     * {@link NativeDaemonEvent#isClassContinue()} responses, including the
-     * final terminal response.
-     *
-     * @throws NativeDaemonConnectorException when problem communicating with
-     *             native daemon, or if the response matches
-     *             {@link NativeDaemonEvent#isClassClientError()} or
-     *             {@link NativeDaemonEvent#isClassServerError()}.
-     */
-    public NativeDaemonEvent[] executeForList(Command cmd) throws NativeDaemonConnectorException {
-        return executeForList(cmd.mCmd, cmd.mArguments.toArray());
-    }
-
-    /**
-     * Issue the given command to the native daemon and return any
-     * {@link NativeDaemonEvent#isClassContinue()} responses, including the
-     * final terminal response. Any arguments must be separated from base
-     * command so they can be properly escaped.
-     *
-     * @throws NativeDaemonConnectorException when problem communicating with
-     *             native daemon, or if the response matches
-     *             {@link NativeDaemonEvent#isClassClientError()} or
-     *             {@link NativeDaemonEvent#isClassServerError()}.
-     */
-    public NativeDaemonEvent[] executeForList(String cmd, Object... args)
-            throws NativeDaemonConnectorException {
-        return executeForList(DEFAULT_TIMEOUT, cmd, args);
-    }
-
-    /**
-     * Issue the given command to the native daemon and return any {@linke
-     * NativeDaemonEvent@isClassContinue()} responses, including the final
-     * terminal response. Note that the timeout does not count time in deep
-     * sleep. Any arguments must be separated from base command so they can be
-     * properly escaped.
-     *
-     * @throws NativeDaemonConnectorException when problem communicating with
-     *             native daemon, or if the response matches
-     *             {@link NativeDaemonEvent#isClassClientError()} or
-     *             {@link NativeDaemonEvent#isClassServerError()}.
-     */
-    public NativeDaemonEvent[] executeForList(long timeoutMs, String cmd, Object... args)
-            throws NativeDaemonConnectorException {
-        if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
-            Log.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
-                    + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
-        }
-
-        final long startTime = SystemClock.elapsedRealtime();
-
-        final ArrayList<NativeDaemonEvent> events = new ArrayList<>();
-
-        final StringBuilder rawBuilder = new StringBuilder();
-        final StringBuilder logBuilder = new StringBuilder();
-        final int sequenceNumber = mSequenceNumber.incrementAndGet();
-
-        makeCommand(rawBuilder, logBuilder, sequenceNumber, cmd, args);
-
-        final String rawCmd = rawBuilder.toString();
-        final String logCmd = logBuilder.toString();
-
-        log("SND -> {" + logCmd + "}");
-
-        synchronized (mDaemonLock) {
-            if (mOutputStream == null) {
-                throw new NativeDaemonConnectorException("missing output stream");
-            } else {
-                try {
-                    mOutputStream.write(rawCmd.getBytes(StandardCharsets.UTF_8));
-                } catch (IOException e) {
-                    throw new NativeDaemonConnectorException("problem sending command", e);
-                }
-            }
-        }
-
-        NativeDaemonEvent event = null;
-        do {
-            event = mResponseQueue.remove(sequenceNumber, timeoutMs, logCmd);
-            if (event == null) {
-                loge("timed-out waiting for response to " + logCmd);
-                throw new NativeDaemonTimeoutException(logCmd, event);
-            }
-            if (VDBG) log("RMV <- {" + event + "}");
-            events.add(event);
-        } while (event.isClassContinue());
-
-        final long endTime = SystemClock.elapsedRealtime();
-        if (endTime - startTime > WARN_EXECUTE_DELAY_MS) {
-            loge("NDC Command {" + logCmd + "} took too long (" + (endTime - startTime) + "ms)");
-        }
-
-        if (event.isClassClientError()) {
-            throw new NativeDaemonArgumentException(logCmd, event);
-        }
-        if (event.isClassServerError()) {
-            throw new NativeDaemonFailureException(logCmd, event);
-        }
-
-        return events.toArray(new NativeDaemonEvent[events.size()]);
-    }
-
-    /**
-     * Append the given argument to {@link StringBuilder}, escaping as needed,
-     * and surrounding with quotes when it contains spaces.
-     */
-    @VisibleForTesting
-    static void appendEscaped(StringBuilder builder, String arg) {
-        final boolean hasSpaces = arg.indexOf(' ') >= 0;
-        if (hasSpaces) {
-            builder.append('"');
-        }
-
-        final int length = arg.length();
-        for (int i = 0; i < length; i++) {
-            final char c = arg.charAt(i);
-
-            if (c == '"') {
-                builder.append("\\\"");
-            } else if (c == '\\') {
-                builder.append("\\\\");
-            } else {
-                builder.append(c);
-            }
-        }
-
-        if (hasSpaces) {
-            builder.append('"');
-        }
-    }
-
-    private static class NativeDaemonArgumentException extends NativeDaemonConnectorException {
-        public NativeDaemonArgumentException(String command, NativeDaemonEvent event) {
-            super(command, event);
-        }
-
-        @Override
-        public IllegalArgumentException rethrowAsParcelableException() {
-            throw new IllegalArgumentException(getMessage(), this);
-        }
-    }
-
-    private static class NativeDaemonFailureException extends NativeDaemonConnectorException {
-        public NativeDaemonFailureException(String command, NativeDaemonEvent event) {
-            super(command, event);
-        }
-    }
-
-    /**
-     * Command builder that handles argument list building. Any arguments must
-     * be separated from base command so they can be properly escaped.
-     */
-    public static class Command {
-        private String mCmd;
-        private ArrayList<Object> mArguments = new ArrayList<>();
-
-        public Command(String cmd, Object... args) {
-            mCmd = cmd;
-            for (Object arg : args) {
-                appendArg(arg);
-            }
-        }
-
-        public Command appendArg(Object arg) {
-            mArguments.add(arg);
-            return this;
-        }
-    }
-
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        mLocalLog.dump(fd, pw, args);
-        pw.println();
-        mResponseQueue.dump(fd, pw, args);
-    }
-
-    private void log(String logstring) {
-        if (mDebug) Log.d(TAG, logstring);
-        mLocalLog.log(logstring);
-    }
-
-    private void loge(String logstring) {
-        Log.e(TAG, logstring);
-        mLocalLog.log(logstring);
-    }
-
-    private static class ResponseQueue {
-
-        private static class PendingCmd {
-            public final int cmdNum;
-            public final String logCmd;
-
-            public BlockingQueue<NativeDaemonEvent> responses =
-                    new ArrayBlockingQueue<NativeDaemonEvent>(10);
-
-            // The availableResponseCount member is used to track when we can remove this
-            // instance from the ResponseQueue.
-            // This is used under the protection of a sync of the mPendingCmds object.
-            // A positive value means we've had more writers retreive this object while
-            // a negative value means we've had more readers.  When we've had an equal number
-            // (it goes to zero) we can remove this object from the mPendingCmds list.
-            // Note that we may have more responses for this command (and more readers
-            // coming), but that would result in a new PendingCmd instance being created
-            // and added with the same cmdNum.
-            // Also note that when this goes to zero it just means a parity of readers and
-            // writers have retrieved this object - not that they are done using it.  The
-            // responses queue may well have more responses yet to be read or may get more
-            // responses added to it.  But all those readers/writers have retreived and
-            // hold references to this instance already so it can be removed from
-            // mPendingCmds queue.
-            public int availableResponseCount;
-
-            public PendingCmd(int cmdNum, String logCmd) {
-                this.cmdNum = cmdNum;
-                this.logCmd = logCmd;
-            }
-        }
-
-        private final LinkedList<PendingCmd> mPendingCmds;
-        private int mMaxCount;
-
-        ResponseQueue(int maxCount) {
-            mPendingCmds = new LinkedList<PendingCmd>();
-            mMaxCount = maxCount;
-        }
-
-        public void add(int cmdNum, NativeDaemonEvent response) {
-            PendingCmd found = null;
-            synchronized (mPendingCmds) {
-                for (PendingCmd pendingCmd : mPendingCmds) {
-                    if (pendingCmd.cmdNum == cmdNum) {
-                        found = pendingCmd;
-                        break;
-                    }
-                }
-                if (found == null) {
-                    // didn't find it - make sure our queue isn't too big before adding
-                    while (mPendingCmds.size() >= mMaxCount) {
-                        Log.e("NativeDaemonConnector.ResponseQueue",
-                                "more buffered than allowed: " + mPendingCmds.size() +
-                                " >= " + mMaxCount);
-                        // let any waiter timeout waiting for this
-                        PendingCmd pendingCmd = mPendingCmds.remove();
-                        Log.e("NativeDaemonConnector.ResponseQueue",
-                                "Removing request: " + pendingCmd.logCmd + " (" +
-                                pendingCmd.cmdNum + ")");
-                    }
-                    found = new PendingCmd(cmdNum, null);
-                    mPendingCmds.add(found);
-                }
-                found.availableResponseCount++;
-                // if a matching remove call has already retrieved this we can remove this
-                // instance from our list
-                if (found.availableResponseCount == 0) mPendingCmds.remove(found);
-            }
-            try {
-                found.responses.put(response);
-            } catch (InterruptedException e) { }
-        }
-
-        // note that the timeout does not count time in deep sleep.  If you don't want
-        // the device to sleep, hold a wakelock
-        public NativeDaemonEvent remove(int cmdNum, long timeoutMs, String logCmd) {
-            PendingCmd found = null;
-            synchronized (mPendingCmds) {
-                for (PendingCmd pendingCmd : mPendingCmds) {
-                    if (pendingCmd.cmdNum == cmdNum) {
-                        found = pendingCmd;
-                        break;
-                    }
-                }
-                if (found == null) {
-                    found = new PendingCmd(cmdNum, logCmd);
-                    mPendingCmds.add(found);
-                }
-                found.availableResponseCount--;
-                // if a matching add call has already retrieved this we can remove this
-                // instance from our list
-                if (found.availableResponseCount == 0) mPendingCmds.remove(found);
-            }
-            NativeDaemonEvent result = null;
-            try {
-                result = found.responses.poll(timeoutMs, TimeUnit.MILLISECONDS);
-            } catch (InterruptedException e) {}
-            if (result == null) {
-                Log.e("NativeDaemonConnector.ResponseQueue", "Timeout waiting for response");
-            }
-            return result;
-        }
-
-        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-            pw.println("Pending requests:");
-            synchronized (mPendingCmds) {
-                for (PendingCmd pendingCmd : mPendingCmds) {
-                    pw.println("  Cmd " + pendingCmd.cmdNum + " - " + pendingCmd.logCmd);
-                }
-            }
-        }
-    }
-}
diff --git a/packages/ConnectivityT/service/src/com/android/server/NativeDaemonConnectorException.java b/packages/ConnectivityT/service/src/com/android/server/NativeDaemonConnectorException.java
deleted file mode 100644
index 4d8881c..0000000
--- a/packages/ConnectivityT/service/src/com/android/server/NativeDaemonConnectorException.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.os.Parcel;
-
-/**
- * An exception that indicates there was an error with a
- * {@link NativeDaemonConnector} operation.
- */
-public class NativeDaemonConnectorException extends Exception {
-    private String mCmd;
-    private NativeDaemonEvent mEvent;
-
-    public NativeDaemonConnectorException(String detailMessage) {
-        super(detailMessage);
-    }
-
-    public NativeDaemonConnectorException(String detailMessage, Throwable throwable) {
-        super(detailMessage, throwable);
-    }
-
-    public NativeDaemonConnectorException(String cmd, NativeDaemonEvent event) {
-        super("command '" + cmd + "' failed with '" + event + "'");
-        mCmd = cmd;
-        mEvent = event;
-    }
-
-    public int getCode() {
-        return mEvent != null ? mEvent.getCode() : -1;
-    }
-
-    public String getCmd() {
-        return mCmd;
-    }
-
-    /**
-     * Rethrow as a {@link RuntimeException} subclass that is handled by
-     * {@link Parcel#writeException(Exception)}.
-     */
-    public IllegalArgumentException rethrowAsParcelableException() {
-        throw new IllegalStateException(getMessage(), this);
-    }
-}
diff --git a/packages/ConnectivityT/service/src/com/android/server/NativeDaemonEvent.java b/packages/ConnectivityT/service/src/com/android/server/NativeDaemonEvent.java
deleted file mode 100644
index 5683694..0000000
--- a/packages/ConnectivityT/service/src/com/android/server/NativeDaemonEvent.java
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.util.ArrayList;
-
-/**
- * Parsed event from native side of {@link NativeDaemonConnector}.
- */
-public class NativeDaemonEvent {
-
-    // TODO: keep class ranges in sync with ResponseCode.h
-    // TODO: swap client and server error ranges to roughly mirror HTTP spec
-
-    private final int mCmdNumber;
-    private final int mCode;
-    private final String mMessage;
-    private final String mRawEvent;
-    private final String mLogMessage;
-    private String[] mParsed;
-    private FileDescriptor[] mFdList;
-
-    private NativeDaemonEvent(int cmdNumber, int code, String message,
-                              String rawEvent, String logMessage, FileDescriptor[] fdList) {
-        mCmdNumber = cmdNumber;
-        mCode = code;
-        mMessage = message;
-        mRawEvent = rawEvent;
-        mLogMessage = logMessage;
-        mParsed = null;
-        mFdList = fdList;
-    }
-
-    static public final String SENSITIVE_MARKER = "{{sensitive}}";
-
-    public int getCmdNumber() {
-        return mCmdNumber;
-    }
-
-    public int getCode() {
-        return mCode;
-    }
-
-    public String getMessage() {
-        return mMessage;
-    }
-
-    public FileDescriptor[] getFileDescriptors() {
-        return mFdList;
-    }
-
-    @Deprecated
-    public String getRawEvent() {
-        return mRawEvent;
-    }
-
-    @Override
-    public String toString() {
-        return mLogMessage;
-    }
-
-    /**
-     * Test if event represents a partial response which is continued in
-     * additional subsequent events.
-     */
-    public boolean isClassContinue() {
-        return mCode >= 100 && mCode < 200;
-    }
-
-    /**
-     * Test if event represents a command success.
-     */
-    public boolean isClassOk() {
-        return mCode >= 200 && mCode < 300;
-    }
-
-    /**
-     * Test if event represents a remote native daemon error.
-     */
-    public boolean isClassServerError() {
-        return mCode >= 400 && mCode < 500;
-    }
-
-    /**
-     * Test if event represents a command syntax or argument error.
-     */
-    public boolean isClassClientError() {
-        return mCode >= 500 && mCode < 600;
-    }
-
-    /**
-     * Test if event represents an unsolicited event from native daemon.
-     */
-    public boolean isClassUnsolicited() {
-        return isClassUnsolicited(mCode);
-    }
-
-    private static boolean isClassUnsolicited(int code) {
-        return code >= 600 && code < 700;
-    }
-
-    /**
-     * Verify this event matches the given code.
-     *
-     * @throws IllegalStateException if {@link #getCode()} doesn't match.
-     */
-    public void checkCode(int code) {
-        if (mCode != code) {
-            throw new IllegalStateException("Expected " + code + " but was: " + this);
-        }
-    }
-
-    /**
-     * Parse the given raw event into {@link NativeDaemonEvent} instance.
-     *
-     * @throws IllegalArgumentException when line doesn't match format expected
-     *             from native side.
-     */
-    public static NativeDaemonEvent parseRawEvent(String rawEvent, FileDescriptor[] fdList) {
-        final String[] parsed = rawEvent.split(" ");
-        if (parsed.length < 2) {
-            throw new IllegalArgumentException("Insufficient arguments");
-        }
-
-        int skiplength = 0;
-
-        final int code;
-        try {
-            code = Integer.parseInt(parsed[0]);
-            skiplength = parsed[0].length() + 1;
-        } catch (NumberFormatException e) {
-            throw new IllegalArgumentException("problem parsing code", e);
-        }
-
-        int cmdNumber = -1;
-        if (isClassUnsolicited(code) == false) {
-            if (parsed.length < 3) {
-                throw new IllegalArgumentException("Insufficient arguemnts");
-            }
-            try {
-                cmdNumber = Integer.parseInt(parsed[1]);
-                skiplength += parsed[1].length() + 1;
-            } catch (NumberFormatException e) {
-                throw new IllegalArgumentException("problem parsing cmdNumber", e);
-            }
-        }
-
-        String logMessage = rawEvent;
-        if (parsed.length > 2 && parsed[2].equals(SENSITIVE_MARKER)) {
-            skiplength += parsed[2].length() + 1;
-            logMessage = parsed[0] + " " + parsed[1] + " {}";
-        }
-
-        final String message = rawEvent.substring(skiplength);
-
-        return new NativeDaemonEvent(cmdNumber, code, message, rawEvent, logMessage, fdList);
-    }
-
-    /**
-     * Filter the given {@link NativeDaemonEvent} list, returning
-     * {@link #getMessage()} for any events matching the requested code.
-     */
-    public static String[] filterMessageList(NativeDaemonEvent[] events, int matchCode) {
-        final ArrayList<String> result = new ArrayList<>();
-        for (NativeDaemonEvent event : events) {
-            if (event.getCode() == matchCode) {
-                result.add(event.getMessage());
-            }
-        }
-        return result.toArray(new String[result.size()]);
-    }
-
-    /**
-     * Find the Nth field of the event.
-     *
-     * This ignores and code or cmdNum, the first return value is given for N=0.
-     * Also understands "\"quoted\" multiword responses" and tries them as a single field
-     */
-    public String getField(int n) {
-        if (mParsed == null) {
-            mParsed = unescapeArgs(mRawEvent);
-        }
-        n += 2; // skip code and command#
-        if (n > mParsed.length) return null;
-            return mParsed[n];
-        }
-
-    public static String[] unescapeArgs(String rawEvent) {
-        final boolean DEBUG_ROUTINE = false;
-        final String LOGTAG = "unescapeArgs";
-        final ArrayList<String> parsed = new ArrayList<String>();
-        final int length = rawEvent.length();
-        int current = 0;
-        int wordEnd = -1;
-        boolean quoted = false;
-
-        if (DEBUG_ROUTINE) Log.e(LOGTAG, "parsing '" + rawEvent + "'");
-        if (rawEvent.charAt(current) == '\"') {
-            quoted = true;
-            current++;
-        }
-        while (current < length) {
-            // find the end of the word
-            char terminator = quoted ? '\"' : ' ';
-            wordEnd = current;
-            while (wordEnd < length && rawEvent.charAt(wordEnd) != terminator) {
-                if (rawEvent.charAt(wordEnd) == '\\') {
-                    // skip the escaped char
-                    ++wordEnd;
-                }
-                ++wordEnd;
-            }
-            if (wordEnd > length) wordEnd = length;
-            String word = rawEvent.substring(current, wordEnd);
-            current += word.length();
-            if (!quoted) {
-                word = word.trim();
-            } else {
-                current++;  // skip the trailing quote
-            }
-            // unescape stuff within the word
-            word = word.replace("\\\\", "\\");
-            word = word.replace("\\\"", "\"");
-
-            if (DEBUG_ROUTINE) Log.e(LOGTAG, "found '" + word + "'");
-            parsed.add(word);
-
-            // find the beginning of the next word - either of these options
-            int nextSpace = rawEvent.indexOf(' ', current);
-            int nextQuote = rawEvent.indexOf(" \"", current);
-            if (DEBUG_ROUTINE) {
-                Log.e(LOGTAG, "nextSpace=" + nextSpace + ", nextQuote=" + nextQuote);
-            }
-            if (nextQuote > -1 && nextQuote <= nextSpace) {
-                quoted = true;
-                current = nextQuote + 2;
-            } else {
-                quoted = false;
-                if (nextSpace > -1) {
-                    current = nextSpace + 1;
-                }
-            } // else we just start the next word after the current and read til the end
-            if (DEBUG_ROUTINE) {
-                Log.e(LOGTAG, "next loop - current=" + current
-                        + ", length=" + length + ", quoted=" + quoted);
-            }
-        }
-        return parsed.toArray(new String[parsed.size()]);
-    }
-}
diff --git a/packages/ConnectivityT/service/src/com/android/server/NativeDaemonTimeoutException.java b/packages/ConnectivityT/service/src/com/android/server/NativeDaemonTimeoutException.java
deleted file mode 100644
index 658f7d6..0000000
--- a/packages/ConnectivityT/service/src/com/android/server/NativeDaemonTimeoutException.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-/**
- * An exception that indicates there was a timeout with a
- * {@link NativeDaemonConnector} operation.
- */
-public class NativeDaemonTimeoutException extends NativeDaemonConnectorException {
-    public NativeDaemonTimeoutException(String command, NativeDaemonEvent event) {
-        super(command, event);
-    }
-}
-
diff --git a/packages/ConnectivityT/service/src/com/android/server/NsdService.java b/packages/ConnectivityT/service/src/com/android/server/NsdService.java
deleted file mode 100644
index ddf6d2c..0000000
--- a/packages/ConnectivityT/service/src/com/android/server/NsdService.java
+++ /dev/null
@@ -1,1146 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.net.ConnectivityManager;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.nsd.INsdManager;
-import android.net.nsd.INsdManagerCallback;
-import android.net.nsd.INsdServiceConnector;
-import android.net.nsd.NsdManager;
-import android.net.nsd.NsdServiceInfo;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.Base64;
-import android.util.Log;
-import android.util.Pair;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.State;
-import com.android.internal.util.StateMachine;
-import com.android.net.module.util.DnsSdTxtRecord;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.concurrent.CountDownLatch;
-
-/**
- * Network Service Discovery Service handles remote service discovery operation requests by
- * implementing the INsdManager interface.
- *
- * @hide
- */
-public class NsdService extends INsdManager.Stub {
-    private static final String TAG = "NsdService";
-    private static final String MDNS_TAG = "mDnsConnector";
-
-    private static final boolean DBG = true;
-    private static final long CLEANUP_DELAY_MS = 10000;
-    private static final int IFACE_IDX_ANY = 0;
-
-    private final Context mContext;
-    private final NsdStateMachine mNsdStateMachine;
-    private final DaemonConnection mDaemon;
-    private final NativeCallbackReceiver mDaemonCallback;
-
-    /**
-     * Clients receiving asynchronous messages
-     */
-    private final HashMap<NsdServiceConnector, ClientInfo> mClients = new HashMap<>();
-
-    /* A map from unique id to client info */
-    private final SparseArray<ClientInfo> mIdToClientInfoMap= new SparseArray<>();
-
-    private final long mCleanupDelayMs;
-
-    private static final int INVALID_ID = 0;
-    private int mUniqueId = 1;
-    // The count of the connected legacy clients.
-    private int mLegacyClientCount = 0;
-
-    private class NsdStateMachine extends StateMachine {
-
-        private final DefaultState mDefaultState = new DefaultState();
-        private final DisabledState mDisabledState = new DisabledState();
-        private final EnabledState mEnabledState = new EnabledState();
-
-        @Override
-        protected String getWhatToString(int what) {
-            return NsdManager.nameOf(what);
-        }
-
-        private void maybeStartDaemon() {
-            mDaemon.maybeStart();
-            maybeScheduleStop();
-        }
-
-        private boolean isAnyRequestActive() {
-            return mIdToClientInfoMap.size() != 0;
-        }
-
-        private void scheduleStop() {
-            sendMessageDelayed(NsdManager.DAEMON_CLEANUP, mCleanupDelayMs);
-        }
-        private void maybeScheduleStop() {
-            // The native daemon should stay alive and can't be cleanup
-            // if any legacy client connected.
-            if (!isAnyRequestActive() && mLegacyClientCount == 0) {
-                scheduleStop();
-            }
-        }
-
-        private void cancelStop() {
-            this.removeMessages(NsdManager.DAEMON_CLEANUP);
-        }
-
-        NsdStateMachine(String name, Handler handler) {
-            super(name, handler);
-            addState(mDefaultState);
-                addState(mDisabledState, mDefaultState);
-                addState(mEnabledState, mDefaultState);
-            State initialState = mEnabledState;
-            setInitialState(initialState);
-            setLogRecSize(25);
-        }
-
-        class DefaultState extends State {
-            @Override
-            public boolean processMessage(Message msg) {
-                final ClientInfo cInfo;
-                final int clientId = msg.arg2;
-                switch (msg.what) {
-                    case NsdManager.REGISTER_CLIENT:
-                        final Pair<NsdServiceConnector, INsdManagerCallback> arg =
-                                (Pair<NsdServiceConnector, INsdManagerCallback>) msg.obj;
-                        final INsdManagerCallback cb = arg.second;
-                        try {
-                            cb.asBinder().linkToDeath(arg.first, 0);
-                            cInfo = new ClientInfo(cb);
-                            mClients.put(arg.first, cInfo);
-                        } catch (RemoteException e) {
-                            Log.w(TAG, "Client " + clientId + " has already died");
-                        }
-                        break;
-                    case NsdManager.UNREGISTER_CLIENT:
-                        final NsdServiceConnector connector = (NsdServiceConnector) msg.obj;
-                        cInfo = mClients.remove(connector);
-                        if (cInfo != null) {
-                            cInfo.expungeAllRequests();
-                            if (cInfo.isLegacy()) {
-                                mLegacyClientCount -= 1;
-                            }
-                        }
-                        maybeScheduleStop();
-                        break;
-                    case NsdManager.DISCOVER_SERVICES:
-                        cInfo = getClientInfoForReply(msg);
-                        if (cInfo != null) {
-                            cInfo.onDiscoverServicesFailed(
-                                    clientId, NsdManager.FAILURE_INTERNAL_ERROR);
-                        }
-                       break;
-                    case NsdManager.STOP_DISCOVERY:
-                        cInfo = getClientInfoForReply(msg);
-                        if (cInfo != null) {
-                            cInfo.onStopDiscoveryFailed(
-                                    clientId, NsdManager.FAILURE_INTERNAL_ERROR);
-                        }
-                        break;
-                    case NsdManager.REGISTER_SERVICE:
-                        cInfo = getClientInfoForReply(msg);
-                        if (cInfo != null) {
-                            cInfo.onRegisterServiceFailed(
-                                    clientId, NsdManager.FAILURE_INTERNAL_ERROR);
-                        }
-                        break;
-                    case NsdManager.UNREGISTER_SERVICE:
-                        cInfo = getClientInfoForReply(msg);
-                        if (cInfo != null) {
-                            cInfo.onUnregisterServiceFailed(
-                                    clientId, NsdManager.FAILURE_INTERNAL_ERROR);
-                        }
-                        break;
-                    case NsdManager.RESOLVE_SERVICE:
-                        cInfo = getClientInfoForReply(msg);
-                        if (cInfo != null) {
-                            cInfo.onResolveServiceFailed(
-                                    clientId, NsdManager.FAILURE_INTERNAL_ERROR);
-                        }
-                        break;
-                    case NsdManager.DAEMON_CLEANUP:
-                        mDaemon.maybeStop();
-                        break;
-                    // This event should be only sent by the legacy (target SDK < S) clients.
-                    // Mark the sending client as legacy.
-                    case NsdManager.DAEMON_STARTUP:
-                        cInfo = getClientInfoForReply(msg);
-                        if (cInfo != null) {
-                            cancelStop();
-                            cInfo.setLegacy();
-                            mLegacyClientCount += 1;
-                            maybeStartDaemon();
-                        }
-                        break;
-                    case NsdManager.NATIVE_DAEMON_EVENT:
-                    default:
-                        Log.e(TAG, "Unhandled " + msg);
-                        return NOT_HANDLED;
-                }
-                return HANDLED;
-            }
-
-            private ClientInfo getClientInfoForReply(Message msg) {
-                final ListenerArgs args = (ListenerArgs) msg.obj;
-                return mClients.get(args.connector);
-            }
-        }
-
-        class DisabledState extends State {
-            @Override
-            public void enter() {
-                sendNsdStateChangeBroadcast(false);
-            }
-
-            @Override
-            public boolean processMessage(Message msg) {
-                switch (msg.what) {
-                    case NsdManager.ENABLE:
-                        transitionTo(mEnabledState);
-                        break;
-                    default:
-                        return NOT_HANDLED;
-                }
-                return HANDLED;
-            }
-        }
-
-        class EnabledState extends State {
-            @Override
-            public void enter() {
-                sendNsdStateChangeBroadcast(true);
-            }
-
-            @Override
-            public void exit() {
-                // TODO: it is incorrect to stop the daemon without expunging all requests
-                // and sending error callbacks to clients.
-                scheduleStop();
-            }
-
-            private boolean requestLimitReached(ClientInfo clientInfo) {
-                if (clientInfo.mClientIds.size() >= ClientInfo.MAX_LIMIT) {
-                    if (DBG) Log.d(TAG, "Exceeded max outstanding requests " + clientInfo);
-                    return true;
-                }
-                return false;
-            }
-
-            private void storeRequestMap(int clientId, int globalId, ClientInfo clientInfo, int what) {
-                clientInfo.mClientIds.put(clientId, globalId);
-                clientInfo.mClientRequests.put(clientId, what);
-                mIdToClientInfoMap.put(globalId, clientInfo);
-                // Remove the cleanup event because here comes a new request.
-                cancelStop();
-            }
-
-            private void removeRequestMap(int clientId, int globalId, ClientInfo clientInfo) {
-                clientInfo.mClientIds.delete(clientId);
-                clientInfo.mClientRequests.delete(clientId);
-                mIdToClientInfoMap.remove(globalId);
-                maybeScheduleStop();
-            }
-
-            @Override
-            public boolean processMessage(Message msg) {
-                final ClientInfo clientInfo;
-                final int id;
-                final int clientId = msg.arg2;
-                final ListenerArgs args;
-                switch (msg.what) {
-                    case NsdManager.DISABLE:
-                        //TODO: cleanup clients
-                        transitionTo(mDisabledState);
-                        break;
-                    case NsdManager.DISCOVER_SERVICES:
-                        if (DBG) Log.d(TAG, "Discover services");
-                        args = (ListenerArgs) msg.obj;
-                        clientInfo = mClients.get(args.connector);
-
-                        if (requestLimitReached(clientInfo)) {
-                            clientInfo.onDiscoverServicesFailed(
-                                    clientId, NsdManager.FAILURE_MAX_LIMIT);
-                            break;
-                        }
-
-                        maybeStartDaemon();
-                        id = getUniqueId();
-                        if (discoverServices(id, args.serviceInfo)) {
-                            if (DBG) {
-                                Log.d(TAG, "Discover " + msg.arg2 + " " + id
-                                        + args.serviceInfo.getServiceType());
-                            }
-                            storeRequestMap(clientId, id, clientInfo, msg.what);
-                            clientInfo.onDiscoverServicesStarted(clientId, args.serviceInfo);
-                        } else {
-                            stopServiceDiscovery(id);
-                            clientInfo.onDiscoverServicesFailed(clientId,
-                                    NsdManager.FAILURE_INTERNAL_ERROR);
-                        }
-                        break;
-                    case NsdManager.STOP_DISCOVERY:
-                        if (DBG) Log.d(TAG, "Stop service discovery");
-                        args = (ListenerArgs) msg.obj;
-                        clientInfo = mClients.get(args.connector);
-
-                        try {
-                            id = clientInfo.mClientIds.get(clientId);
-                        } catch (NullPointerException e) {
-                            clientInfo.onStopDiscoveryFailed(
-                                    clientId, NsdManager.FAILURE_INTERNAL_ERROR);
-                            break;
-                        }
-                        removeRequestMap(clientId, id, clientInfo);
-                        if (stopServiceDiscovery(id)) {
-                            clientInfo.onStopDiscoverySucceeded(clientId);
-                        } else {
-                            clientInfo.onStopDiscoveryFailed(
-                                    clientId, NsdManager.FAILURE_INTERNAL_ERROR);
-                        }
-                        break;
-                    case NsdManager.REGISTER_SERVICE:
-                        if (DBG) Log.d(TAG, "Register service");
-                        args = (ListenerArgs) msg.obj;
-                        clientInfo = mClients.get(args.connector);
-                        if (requestLimitReached(clientInfo)) {
-                            clientInfo.onRegisterServiceFailed(
-                                    clientId, NsdManager.FAILURE_MAX_LIMIT);
-                            break;
-                        }
-
-                        maybeStartDaemon();
-                        id = getUniqueId();
-                        if (registerService(id, args.serviceInfo)) {
-                            if (DBG) Log.d(TAG, "Register " + clientId + " " + id);
-                            storeRequestMap(clientId, id, clientInfo, msg.what);
-                            // Return success after mDns reports success
-                        } else {
-                            unregisterService(id);
-                            clientInfo.onRegisterServiceFailed(
-                                    clientId, NsdManager.FAILURE_INTERNAL_ERROR);
-                        }
-                        break;
-                    case NsdManager.UNREGISTER_SERVICE:
-                        if (DBG) Log.d(TAG, "unregister service");
-                        args = (ListenerArgs) msg.obj;
-                        clientInfo = mClients.get(args.connector);
-                        if (clientInfo == null) {
-                            Log.e(TAG, "Unknown connector in unregistration");
-                            break;
-                        }
-                        id = clientInfo.mClientIds.get(clientId);
-                        removeRequestMap(clientId, id, clientInfo);
-                        if (unregisterService(id)) {
-                            clientInfo.onUnregisterServiceSucceeded(clientId);
-                        } else {
-                            clientInfo.onUnregisterServiceFailed(
-                                    clientId, NsdManager.FAILURE_INTERNAL_ERROR);
-                        }
-                        break;
-                    case NsdManager.RESOLVE_SERVICE:
-                        if (DBG) Log.d(TAG, "Resolve service");
-                        args = (ListenerArgs) msg.obj;
-                        clientInfo = mClients.get(args.connector);
-
-                        if (clientInfo.mResolvedService != null) {
-                            clientInfo.onResolveServiceFailed(
-                                    clientId, NsdManager.FAILURE_ALREADY_ACTIVE);
-                            break;
-                        }
-
-                        maybeStartDaemon();
-                        id = getUniqueId();
-                        if (resolveService(id, args.serviceInfo)) {
-                            clientInfo.mResolvedService = new NsdServiceInfo();
-                            storeRequestMap(clientId, id, clientInfo, msg.what);
-                        } else {
-                            clientInfo.onResolveServiceFailed(
-                                    clientId, NsdManager.FAILURE_INTERNAL_ERROR);
-                        }
-                        break;
-                    case NsdManager.NATIVE_DAEMON_EVENT:
-                        NativeEvent event = (NativeEvent) msg.obj;
-                        if (!handleNativeEvent(event.code, event.raw, event.cooked)) {
-                            return NOT_HANDLED;
-                        }
-                        break;
-                    default:
-                        return NOT_HANDLED;
-                }
-                return HANDLED;
-            }
-
-            private boolean handleNativeEvent(int code, String raw, String[] cooked) {
-                NsdServiceInfo servInfo;
-                int id = Integer.parseInt(cooked[1]);
-                ClientInfo clientInfo = mIdToClientInfoMap.get(id);
-                if (clientInfo == null) {
-                    String name = NativeResponseCode.nameOf(code);
-                    Log.e(TAG, String.format("id %d for %s has no client mapping", id, name));
-                    return false;
-                }
-
-                /* This goes in response as msg.arg2 */
-                int clientId = clientInfo.getClientId(id);
-                if (clientId < 0) {
-                    // This can happen because of race conditions. For example,
-                    // SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY,
-                    // and we may get in this situation.
-                    String name = NativeResponseCode.nameOf(code);
-                    Log.d(TAG, String.format(
-                            "Notification %s for listener id %d that is no longer active",
-                            name, id));
-                    return false;
-                }
-                if (DBG) {
-                    String name = NativeResponseCode.nameOf(code);
-                    Log.d(TAG, String.format("Native daemon message %s: %s", name, raw));
-                }
-                switch (code) {
-                    case NativeResponseCode.SERVICE_FOUND:
-                        /* NNN uniqueId serviceName regType domain interfaceIdx netId */
-                        servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
-                        final int foundNetId;
-                        try {
-                            foundNetId = Integer.parseInt(cooked[6]);
-                        } catch (NumberFormatException e) {
-                            Log.wtf(TAG, "Invalid network received from mdnsd: " + cooked[6]);
-                            break;
-                        }
-                        if (foundNetId == 0L) {
-                            // Ignore services that do not have a Network: they are not usable
-                            // by apps, as they would need privileged permissions to use
-                            // interfaces that do not have an associated Network.
-                            break;
-                        }
-                        servInfo.setNetwork(new Network(foundNetId));
-                        clientInfo.onServiceFound(clientId, servInfo);
-                        break;
-                    case NativeResponseCode.SERVICE_LOST:
-                        /* NNN uniqueId serviceName regType domain interfaceIdx netId */
-                        final int lostNetId;
-                        try {
-                            lostNetId = Integer.parseInt(cooked[6]);
-                        } catch (NumberFormatException e) {
-                            Log.wtf(TAG, "Invalid network received from mdnsd: " + cooked[6]);
-                            break;
-                        }
-                        servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
-                        // The network could be null if it was torn down when the service is lost
-                        // TODO: avoid returning null in that case, possibly by remembering found
-                        // services on the same interface index and their network at the time
-                        servInfo.setNetwork(lostNetId == 0 ? null : new Network(lostNetId));
-                        clientInfo.onServiceLost(clientId, servInfo);
-                        break;
-                    case NativeResponseCode.SERVICE_DISCOVERY_FAILED:
-                        /* NNN uniqueId errorCode */
-                        clientInfo.onDiscoverServicesFailed(
-                                clientId, NsdManager.FAILURE_INTERNAL_ERROR);
-                        break;
-                    case NativeResponseCode.SERVICE_REGISTERED:
-                        /* NNN regId serviceName regType */
-                        servInfo = new NsdServiceInfo(cooked[2], null);
-                        clientInfo.onRegisterServiceSucceeded(clientId, servInfo);
-                        break;
-                    case NativeResponseCode.SERVICE_REGISTRATION_FAILED:
-                        /* NNN regId errorCode */
-                        clientInfo.onRegisterServiceFailed(
-                                clientId, NsdManager.FAILURE_INTERNAL_ERROR);
-                        break;
-                    case NativeResponseCode.SERVICE_UPDATED:
-                        /* NNN regId */
-                        break;
-                    case NativeResponseCode.SERVICE_UPDATE_FAILED:
-                        /* NNN regId errorCode */
-                        break;
-                    case NativeResponseCode.SERVICE_RESOLVED:
-                        /* NNN resolveId fullName hostName port txtlen txtdata interfaceIdx */
-                        int index = 0;
-                        while (index < cooked[2].length() && cooked[2].charAt(index) != '.') {
-                            if (cooked[2].charAt(index) == '\\') {
-                                ++index;
-                            }
-                            ++index;
-                        }
-                        if (index >= cooked[2].length()) {
-                            Log.e(TAG, "Invalid service found " + raw);
-                            break;
-                        }
-
-                        String name = cooked[2].substring(0, index);
-                        String rest = cooked[2].substring(index);
-                        String type = rest.replace(".local.", "");
-
-                        name = unescape(name);
-
-                        clientInfo.mResolvedService.setServiceName(name);
-                        clientInfo.mResolvedService.setServiceType(type);
-                        clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4]));
-                        clientInfo.mResolvedService.setTxtRecords(cooked[6]);
-                        // Network will be added after SERVICE_GET_ADDR_SUCCESS
-
-                        stopResolveService(id);
-                        removeRequestMap(clientId, id, clientInfo);
-
-                        int id2 = getUniqueId();
-                        if (getAddrInfo(id2, cooked[3], cooked[7] /* interfaceIdx */)) {
-                            storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE);
-                        } else {
-                            clientInfo.onResolveServiceFailed(
-                                    clientId, NsdManager.FAILURE_INTERNAL_ERROR);
-                            clientInfo.mResolvedService = null;
-                        }
-                        break;
-                    case NativeResponseCode.SERVICE_RESOLUTION_FAILED:
-                        /* NNN resolveId errorCode */
-                        stopResolveService(id);
-                        removeRequestMap(clientId, id, clientInfo);
-                        clientInfo.mResolvedService = null;
-                        clientInfo.onResolveServiceFailed(
-                                clientId, NsdManager.FAILURE_INTERNAL_ERROR);
-                        break;
-                    case NativeResponseCode.SERVICE_GET_ADDR_FAILED:
-                        /* NNN resolveId errorCode */
-                        stopGetAddrInfo(id);
-                        removeRequestMap(clientId, id, clientInfo);
-                        clientInfo.mResolvedService = null;
-                        clientInfo.onResolveServiceFailed(
-                                clientId, NsdManager.FAILURE_INTERNAL_ERROR);
-                        break;
-                    case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS:
-                        /* NNN resolveId hostname ttl addr interfaceIdx netId */
-                        Network network = null;
-                        try {
-                            final int netId = Integer.parseInt(cooked[6]);
-                            network = netId == 0L ? null : new Network(netId);
-                        } catch (NumberFormatException e) {
-                            Log.wtf(TAG, "Invalid network in GET_ADDR_SUCCESS: " + cooked[6], e);
-                        }
-
-                        InetAddress serviceHost = null;
-                        try {
-                            serviceHost = InetAddress.getByName(cooked[4]);
-                        } catch (UnknownHostException e) {
-                            Log.wtf(TAG, "Invalid host in GET_ADDR_SUCCESS", e);
-                        }
-
-                        // If the resolved service is on an interface without a network, consider it
-                        // as a failure: it would not be usable by apps as they would need
-                        // privileged permissions.
-                        if (network != null && serviceHost != null) {
-                            clientInfo.mResolvedService.setHost(serviceHost);
-                            clientInfo.mResolvedService.setNetwork(network);
-                            clientInfo.onResolveServiceSucceeded(
-                                    clientId, clientInfo.mResolvedService);
-                        } else {
-                            clientInfo.onResolveServiceFailed(
-                                    clientId, NsdManager.FAILURE_INTERNAL_ERROR);
-                        }
-                        stopGetAddrInfo(id);
-                        removeRequestMap(clientId, id, clientInfo);
-                        clientInfo.mResolvedService = null;
-                        break;
-                    default:
-                        return false;
-                }
-                return true;
-            }
-       }
-    }
-
-    private String unescape(String s) {
-        StringBuilder sb = new StringBuilder(s.length());
-        for (int i = 0; i < s.length(); ++i) {
-            char c = s.charAt(i);
-            if (c == '\\') {
-                if (++i >= s.length()) {
-                    Log.e(TAG, "Unexpected end of escape sequence in: " + s);
-                    break;
-                }
-                c = s.charAt(i);
-                if (c != '.' && c != '\\') {
-                    if (i + 2 >= s.length()) {
-                        Log.e(TAG, "Unexpected end of escape sequence in: " + s);
-                        break;
-                    }
-                    c = (char) ((c-'0') * 100 + (s.charAt(i+1)-'0') * 10 + (s.charAt(i+2)-'0'));
-                    i += 2;
-                }
-            }
-            sb.append(c);
-        }
-        return sb.toString();
-    }
-
-    @VisibleForTesting
-    NsdService(Context ctx, Handler handler, DaemonConnectionSupplier fn, long cleanupDelayMs) {
-        mCleanupDelayMs = cleanupDelayMs;
-        mContext = ctx;
-        mNsdStateMachine = new NsdStateMachine(TAG, handler);
-        mNsdStateMachine.start();
-        mDaemonCallback = new NativeCallbackReceiver();
-        mDaemon = fn.get(mDaemonCallback);
-    }
-
-    public static NsdService create(Context context) throws InterruptedException {
-        HandlerThread thread = new HandlerThread(TAG);
-        thread.start();
-        Handler handler = new Handler(thread.getLooper());
-        NsdService service =
-                new NsdService(context, handler, DaemonConnection::new, CLEANUP_DELAY_MS);
-        service.mDaemonCallback.awaitConnection();
-        return service;
-    }
-
-    @Override
-    public INsdServiceConnector connect(INsdManagerCallback cb) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET, "NsdService");
-        final INsdServiceConnector connector = new NsdServiceConnector();
-        mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
-                NsdManager.REGISTER_CLIENT, new Pair<>(connector, cb)));
-        return connector;
-    }
-
-    private static class ListenerArgs {
-        public final NsdServiceConnector connector;
-        public final NsdServiceInfo serviceInfo;
-        ListenerArgs(NsdServiceConnector connector, NsdServiceInfo serviceInfo) {
-            this.connector = connector;
-            this.serviceInfo = serviceInfo;
-        }
-    }
-
-    private class NsdServiceConnector extends INsdServiceConnector.Stub
-            implements IBinder.DeathRecipient  {
-        @Override
-        public void registerService(int listenerKey, NsdServiceInfo serviceInfo) {
-            mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
-                    NsdManager.REGISTER_SERVICE, 0, listenerKey,
-                    new ListenerArgs(this, serviceInfo)));
-        }
-
-        @Override
-        public void unregisterService(int listenerKey) {
-            mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
-                    NsdManager.UNREGISTER_SERVICE, 0, listenerKey,
-                    new ListenerArgs(this, null)));
-        }
-
-        @Override
-        public void discoverServices(int listenerKey, NsdServiceInfo serviceInfo) {
-            mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
-                    NsdManager.DISCOVER_SERVICES, 0, listenerKey,
-                    new ListenerArgs(this, serviceInfo)));
-        }
-
-        @Override
-        public void stopDiscovery(int listenerKey) {
-            mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
-                    NsdManager.STOP_DISCOVERY, 0, listenerKey, new ListenerArgs(this, null)));
-        }
-
-        @Override
-        public void resolveService(int listenerKey, NsdServiceInfo serviceInfo) {
-            mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
-                    NsdManager.RESOLVE_SERVICE, 0, listenerKey,
-                    new ListenerArgs(this, serviceInfo)));
-        }
-
-        @Override
-        public void startDaemon() {
-            mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
-                    NsdManager.DAEMON_STARTUP, new ListenerArgs(this, null)));
-        }
-
-        @Override
-        public void binderDied() {
-            mNsdStateMachine.sendMessage(
-                    mNsdStateMachine.obtainMessage(NsdManager.UNREGISTER_CLIENT, this));
-        }
-    }
-
-    private void sendNsdStateChangeBroadcast(boolean isEnabled) {
-        final Intent intent = new Intent(NsdManager.ACTION_NSD_STATE_CHANGED);
-        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-        int nsdState = isEnabled ? NsdManager.NSD_STATE_ENABLED : NsdManager.NSD_STATE_DISABLED;
-        intent.putExtra(NsdManager.EXTRA_NSD_STATE, nsdState);
-        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
-    }
-
-    private int getUniqueId() {
-        if (++mUniqueId == INVALID_ID) return ++mUniqueId;
-        return mUniqueId;
-    }
-
-    /* These should be in sync with system/netd/server/ResponseCode.h */
-    static final class NativeResponseCode {
-        public static final int SERVICE_DISCOVERY_FAILED    =   602;
-        public static final int SERVICE_FOUND               =   603;
-        public static final int SERVICE_LOST                =   604;
-
-        public static final int SERVICE_REGISTRATION_FAILED =   605;
-        public static final int SERVICE_REGISTERED          =   606;
-
-        public static final int SERVICE_RESOLUTION_FAILED   =   607;
-        public static final int SERVICE_RESOLVED            =   608;
-
-        public static final int SERVICE_UPDATED             =   609;
-        public static final int SERVICE_UPDATE_FAILED       =   610;
-
-        public static final int SERVICE_GET_ADDR_FAILED     =   611;
-        public static final int SERVICE_GET_ADDR_SUCCESS    =   612;
-
-        private static final SparseArray<String> CODE_NAMES = new SparseArray<>();
-        static {
-            CODE_NAMES.put(SERVICE_DISCOVERY_FAILED, "SERVICE_DISCOVERY_FAILED");
-            CODE_NAMES.put(SERVICE_FOUND, "SERVICE_FOUND");
-            CODE_NAMES.put(SERVICE_LOST, "SERVICE_LOST");
-            CODE_NAMES.put(SERVICE_REGISTRATION_FAILED, "SERVICE_REGISTRATION_FAILED");
-            CODE_NAMES.put(SERVICE_REGISTERED, "SERVICE_REGISTERED");
-            CODE_NAMES.put(SERVICE_RESOLUTION_FAILED, "SERVICE_RESOLUTION_FAILED");
-            CODE_NAMES.put(SERVICE_RESOLVED, "SERVICE_RESOLVED");
-            CODE_NAMES.put(SERVICE_UPDATED, "SERVICE_UPDATED");
-            CODE_NAMES.put(SERVICE_UPDATE_FAILED, "SERVICE_UPDATE_FAILED");
-            CODE_NAMES.put(SERVICE_GET_ADDR_FAILED, "SERVICE_GET_ADDR_FAILED");
-            CODE_NAMES.put(SERVICE_GET_ADDR_SUCCESS, "SERVICE_GET_ADDR_SUCCESS");
-        }
-
-        static String nameOf(int code) {
-            String name = CODE_NAMES.get(code);
-            if (name == null) {
-                return Integer.toString(code);
-            }
-            return name;
-        }
-    }
-
-    private class NativeEvent {
-        final int code;
-        final String raw;
-        final String[] cooked;
-
-        NativeEvent(int code, String raw, String[] cooked) {
-            this.code = code;
-            this.raw = raw;
-            this.cooked = cooked;
-        }
-    }
-
-    class NativeCallbackReceiver implements INativeDaemonConnectorCallbacks {
-        private final CountDownLatch connected = new CountDownLatch(1);
-
-        public void awaitConnection() throws InterruptedException {
-            connected.await();
-        }
-
-        @Override
-        public void onDaemonConnected() {
-            connected.countDown();
-        }
-
-        @Override
-        public boolean onCheckHoldWakeLock(int code) {
-            return false;
-        }
-
-        @Override
-        public boolean onEvent(int code, String raw, String[] cooked) {
-            // TODO: NDC translates a message to a callback, we could enhance NDC to
-            // directly interact with a state machine through messages
-            NativeEvent event = new NativeEvent(code, raw, cooked);
-            mNsdStateMachine.sendMessage(NsdManager.NATIVE_DAEMON_EVENT, event);
-            return true;
-        }
-    }
-
-    interface DaemonConnectionSupplier {
-        DaemonConnection get(NativeCallbackReceiver callback);
-    }
-
-    @VisibleForTesting
-    public static class DaemonConnection {
-        final NativeDaemonConnector mNativeConnector;
-        boolean mIsStarted = false;
-
-        DaemonConnection(NativeCallbackReceiver callback) {
-            mNativeConnector = new NativeDaemonConnector(callback, "mdns", 10, MDNS_TAG, 25, null);
-            new Thread(mNativeConnector, MDNS_TAG).start();
-        }
-
-        /**
-         * Executes the specified cmd on the daemon.
-         */
-        public boolean execute(Object... args) {
-            if (DBG) {
-                Log.d(TAG, "mdnssd " + Arrays.toString(args));
-            }
-            try {
-                mNativeConnector.execute("mdnssd", args);
-            } catch (NativeDaemonConnectorException e) {
-                Log.e(TAG, "Failed to execute mdnssd " + Arrays.toString(args), e);
-                return false;
-            }
-            return true;
-        }
-
-        /**
-         * Starts the daemon if it is not already started.
-         */
-        public void maybeStart() {
-            if (mIsStarted) {
-                return;
-            }
-            execute("start-service");
-            mIsStarted = true;
-        }
-
-        /**
-         * Stops the daemon if it is started.
-         */
-        public void maybeStop() {
-            if (!mIsStarted) {
-                return;
-            }
-            execute("stop-service");
-            mIsStarted = false;
-        }
-    }
-
-    private boolean registerService(int regId, NsdServiceInfo service) {
-        if (DBG) {
-            Log.d(TAG, "registerService: " + regId + " " + service);
-        }
-        String name = service.getServiceName();
-        String type = service.getServiceType();
-        int port = service.getPort();
-        byte[] textRecord = service.getTxtRecord();
-        String record = Base64.encodeToString(textRecord, Base64.DEFAULT).replace("\n", "");
-        return mDaemon.execute("register", regId, name, type, port, record);
-    }
-
-    private boolean unregisterService(int regId) {
-        return mDaemon.execute("stop-register", regId);
-    }
-
-    private boolean updateService(int regId, DnsSdTxtRecord t) {
-        if (t == null) {
-            return false;
-        }
-        return mDaemon.execute("update", regId, t.size(), t.getRawData());
-    }
-
-    private boolean discoverServices(int discoveryId, NsdServiceInfo serviceInfo) {
-        final Network network = serviceInfo.getNetwork();
-        final int discoverInterface = getNetworkInterfaceIndex(network);
-        if (network != null && discoverInterface == IFACE_IDX_ANY) {
-            Log.e(TAG, "Interface to discover service on not found");
-            return false;
-        }
-        return mDaemon.execute("discover", discoveryId, serviceInfo.getServiceType(),
-                discoverInterface);
-    }
-
-    private boolean stopServiceDiscovery(int discoveryId) {
-        return mDaemon.execute("stop-discover", discoveryId);
-    }
-
-    private boolean resolveService(int resolveId, NsdServiceInfo service) {
-        final String name = service.getServiceName();
-        final String type = service.getServiceType();
-        final Network network = service.getNetwork();
-        final int resolveInterface = getNetworkInterfaceIndex(network);
-        if (network != null && resolveInterface == IFACE_IDX_ANY) {
-            Log.e(TAG, "Interface to resolve service on not found");
-            return false;
-        }
-        return mDaemon.execute("resolve", resolveId, name, type, "local.", resolveInterface);
-    }
-
-    /**
-     * Guess the interface to use to resolve or discover a service on a specific network.
-     *
-     * This is an imperfect guess, as for example the network may be gone or not yet fully
-     * registered. This is fine as failing is correct if the network is gone, and a client
-     * attempting to resolve/discover on a network not yet setup would have a bad time anyway; also
-     * this is to support the legacy mdnsresponder implementation, which historically resolved
-     * services on an unspecified network.
-     */
-    private int getNetworkInterfaceIndex(Network network) {
-        if (network == null) return IFACE_IDX_ANY;
-
-        final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
-        if (cm == null) {
-            Log.wtf(TAG, "No ConnectivityManager for resolveService");
-            return IFACE_IDX_ANY;
-        }
-        final LinkProperties lp = cm.getLinkProperties(network);
-        if (lp == null) return IFACE_IDX_ANY;
-
-        // Only resolve on non-stacked interfaces
-        final NetworkInterface iface;
-        try {
-            iface = NetworkInterface.getByName(lp.getInterfaceName());
-        } catch (SocketException e) {
-            Log.e(TAG, "Error querying interface", e);
-            return IFACE_IDX_ANY;
-        }
-
-        if (iface == null) {
-            Log.e(TAG, "Interface not found: " + lp.getInterfaceName());
-            return IFACE_IDX_ANY;
-        }
-
-        return iface.getIndex();
-    }
-
-    private boolean stopResolveService(int resolveId) {
-        return mDaemon.execute("stop-resolve", resolveId);
-    }
-
-    private boolean getAddrInfo(int resolveId, String hostname, String interfaceIdx) {
-        // interfaceIdx is always obtained (as string) from the service resolved callback
-        return mDaemon.execute("getaddrinfo", resolveId, hostname, interfaceIdx);
-    }
-
-    private boolean stopGetAddrInfo(int resolveId) {
-        return mDaemon.execute("stop-getaddrinfo", resolveId);
-    }
-
-    @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
-                != PackageManager.PERMISSION_GRANTED) {
-            pw.println("Permission Denial: can't dump " + TAG
-                    + " due to missing android.permission.DUMP permission");
-            return;
-        }
-
-        for (ClientInfo client : mClients.values()) {
-            pw.println("Client Info");
-            pw.println(client);
-        }
-
-        mNsdStateMachine.dump(fd, pw, args);
-    }
-
-    /* Information tracked per client */
-    private class ClientInfo {
-
-        private static final int MAX_LIMIT = 10;
-        private final INsdManagerCallback mCb;
-        /* Remembers a resolved service until getaddrinfo completes */
-        private NsdServiceInfo mResolvedService;
-
-        /* A map from client id to unique id sent to mDns */
-        private final SparseIntArray mClientIds = new SparseIntArray();
-
-        /* A map from client id to the type of the request we had received */
-        private final SparseIntArray mClientRequests = new SparseIntArray();
-
-        // The target SDK of this client < Build.VERSION_CODES.S
-        private boolean mIsLegacy = false;
-
-        private ClientInfo(INsdManagerCallback cb) {
-            mCb = cb;
-            if (DBG) Log.d(TAG, "New client");
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder sb = new StringBuilder();
-            sb.append("mResolvedService ").append(mResolvedService).append("\n");
-            sb.append("mIsLegacy ").append(mIsLegacy).append("\n");
-            for(int i = 0; i< mClientIds.size(); i++) {
-                int clientID = mClientIds.keyAt(i);
-                sb.append("clientId ").append(clientID).
-                    append(" mDnsId ").append(mClientIds.valueAt(i)).
-                    append(" type ").append(mClientRequests.get(clientID)).append("\n");
-            }
-            return sb.toString();
-        }
-
-        private boolean isLegacy() {
-            return mIsLegacy;
-        }
-
-        private void setLegacy() {
-            mIsLegacy = true;
-        }
-
-        // Remove any pending requests from the global map when we get rid of a client,
-        // and send cancellations to the daemon.
-        private void expungeAllRequests() {
-            int globalId, clientId, i;
-            // TODO: to keep handler responsive, do not clean all requests for that client at once.
-            for (i = 0; i < mClientIds.size(); i++) {
-                clientId = mClientIds.keyAt(i);
-                globalId = mClientIds.valueAt(i);
-                mIdToClientInfoMap.remove(globalId);
-                if (DBG) {
-                    Log.d(TAG, "Terminating client-ID " + clientId
-                            + " global-ID " + globalId + " type " + mClientRequests.get(clientId));
-                }
-                switch (mClientRequests.get(clientId)) {
-                    case NsdManager.DISCOVER_SERVICES:
-                        stopServiceDiscovery(globalId);
-                        break;
-                    case NsdManager.RESOLVE_SERVICE:
-                        stopResolveService(globalId);
-                        break;
-                    case NsdManager.REGISTER_SERVICE:
-                        unregisterService(globalId);
-                        break;
-                    default:
-                        break;
-                }
-            }
-            mClientIds.clear();
-            mClientRequests.clear();
-        }
-
-        // mClientIds is a sparse array of listener id -> mDnsClient id.  For a given mDnsClient id,
-        // return the corresponding listener id.  mDnsClient id is also called a global id.
-        private int getClientId(final int globalId) {
-            int idx = mClientIds.indexOfValue(globalId);
-            if (idx < 0) {
-                return idx;
-            }
-            return mClientIds.keyAt(idx);
-        }
-
-        void onDiscoverServicesStarted(int listenerKey, NsdServiceInfo info) {
-            try {
-                mCb.onDiscoverServicesStarted(listenerKey, info);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error calling onDiscoverServicesStarted", e);
-            }
-        }
-
-        void onDiscoverServicesFailed(int listenerKey, int error) {
-            try {
-                mCb.onDiscoverServicesFailed(listenerKey, error);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error calling onDiscoverServicesFailed", e);
-            }
-        }
-
-        void onServiceFound(int listenerKey, NsdServiceInfo info) {
-            try {
-                mCb.onServiceFound(listenerKey, info);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error calling onServiceFound(", e);
-            }
-        }
-
-        void onServiceLost(int listenerKey, NsdServiceInfo info) {
-            try {
-                mCb.onServiceLost(listenerKey, info);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error calling onServiceLost(", e);
-            }
-        }
-
-        void onStopDiscoveryFailed(int listenerKey, int error) {
-            try {
-                mCb.onStopDiscoveryFailed(listenerKey, error);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error calling onStopDiscoveryFailed", e);
-            }
-        }
-
-        void onStopDiscoverySucceeded(int listenerKey) {
-            try {
-                mCb.onStopDiscoverySucceeded(listenerKey);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error calling onStopDiscoverySucceeded", e);
-            }
-        }
-
-        void onRegisterServiceFailed(int listenerKey, int error) {
-            try {
-                mCb.onRegisterServiceFailed(listenerKey, error);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error calling onRegisterServiceFailed", e);
-            }
-        }
-
-        void onRegisterServiceSucceeded(int listenerKey, NsdServiceInfo info) {
-            try {
-                mCb.onRegisterServiceSucceeded(listenerKey, info);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error calling onRegisterServiceSucceeded", e);
-            }
-        }
-
-        void onUnregisterServiceFailed(int listenerKey, int error) {
-            try {
-                mCb.onUnregisterServiceFailed(listenerKey, error);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error calling onUnregisterServiceFailed", e);
-            }
-        }
-
-        void onUnregisterServiceSucceeded(int listenerKey) {
-            try {
-                mCb.onUnregisterServiceSucceeded(listenerKey);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error calling onUnregisterServiceSucceeded", e);
-            }
-        }
-
-        void onResolveServiceFailed(int listenerKey, int error) {
-            try {
-                mCb.onResolveServiceFailed(listenerKey, error);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error calling onResolveServiceFailed", e);
-            }
-        }
-
-        void onResolveServiceSucceeded(int listenerKey, NsdServiceInfo info) {
-            try {
-                mCb.onResolveServiceSucceeded(listenerKey, info);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error calling onResolveServiceSucceeded", e);
-            }
-        }
-    }
-}
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/BpfInterfaceMapUpdater.java b/packages/ConnectivityT/service/src/com/android/server/net/BpfInterfaceMapUpdater.java
deleted file mode 100644
index 25c88eb..0000000
--- a/packages/ConnectivityT/service/src/com/android/server/net/BpfInterfaceMapUpdater.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * 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.server.net;
-
-import android.content.Context;
-import android.net.INetd;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ServiceSpecificException;
-import android.system.ErrnoException;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.net.module.util.BaseNetdUnsolicitedEventListener;
-import com.android.net.module.util.BpfMap;
-import com.android.net.module.util.IBpfMap;
-import com.android.net.module.util.InterfaceParams;
-import com.android.net.module.util.Struct.U32;
-
-/**
- * Monitor interface added (without removed) and right interface name and its index to bpf map.
- */
-public class BpfInterfaceMapUpdater {
-    private static final String TAG = BpfInterfaceMapUpdater.class.getSimpleName();
-    // This is current path but may be changed soon.
-    private static final String IFACE_INDEX_NAME_MAP_PATH =
-            "/sys/fs/bpf/map_netd_iface_index_name_map";
-    private final IBpfMap<U32, InterfaceMapValue> mBpfMap;
-    private final INetd mNetd;
-    private final Handler mHandler;
-    private final Dependencies mDeps;
-
-    public BpfInterfaceMapUpdater(Context ctx, Handler handler) {
-        this(ctx, handler, new Dependencies());
-    }
-
-    @VisibleForTesting
-    public BpfInterfaceMapUpdater(Context ctx, Handler handler, Dependencies deps) {
-        mDeps = deps;
-        mBpfMap = deps.getInterfaceMap();
-        mNetd = deps.getINetd(ctx);
-        mHandler = handler;
-    }
-
-    /**
-     * Dependencies of BpfInerfaceMapUpdater, for injection in tests.
-     */
-    @VisibleForTesting
-    public static class Dependencies {
-        /** Create BpfMap for updating interface and index mapping. */
-        public IBpfMap<U32, InterfaceMapValue> getInterfaceMap() {
-            try {
-                return new BpfMap<>(IFACE_INDEX_NAME_MAP_PATH, BpfMap.BPF_F_RDWR,
-                    U32.class, InterfaceMapValue.class);
-            } catch (ErrnoException e) {
-                Log.e(TAG, "Cannot create interface map: " + e);
-                return null;
-            }
-        }
-
-        /** Get InterfaceParams for giving interface name. */
-        public InterfaceParams getInterfaceParams(String ifaceName) {
-            return InterfaceParams.getByName(ifaceName);
-        }
-
-        /** Get INetd binder object. */
-        public INetd getINetd(Context ctx) {
-            return INetd.Stub.asInterface((IBinder) ctx.getSystemService(Context.NETD_SERVICE));
-        }
-    }
-
-    /**
-     * Start listening interface update event.
-     * Query current interface names before listening.
-     */
-    public void start() {
-        mHandler.post(() -> {
-            if (mBpfMap == null) {
-                Log.wtf(TAG, "Fail to start: Null bpf map");
-                return;
-            }
-
-            try {
-                // TODO: use a NetlinkMonitor and listen for RTM_NEWLINK messages instead.
-                mNetd.registerUnsolicitedEventListener(new InterfaceChangeObserver());
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Unable to register netd UnsolicitedEventListener, " + e);
-            }
-
-            final String[] ifaces;
-            try {
-                // TODO: use a netlink dump to get the current interface list.
-                ifaces = mNetd.interfaceGetList();
-            } catch (RemoteException | ServiceSpecificException e) {
-                Log.wtf(TAG, "Unable to query interface names by netd, " + e);
-                return;
-            }
-
-            for (String ifaceName : ifaces) {
-                addInterface(ifaceName);
-            }
-        });
-    }
-
-    private void addInterface(String ifaceName) {
-        final InterfaceParams iface = mDeps.getInterfaceParams(ifaceName);
-        if (iface == null) {
-            Log.e(TAG, "Unable to get InterfaceParams for " + ifaceName);
-            return;
-        }
-
-        try {
-            mBpfMap.updateEntry(new U32(iface.index), new InterfaceMapValue(ifaceName));
-        } catch (ErrnoException e) {
-            Log.e(TAG, "Unable to update entry for " + ifaceName + ", " + e);
-        }
-    }
-
-    private class InterfaceChangeObserver extends BaseNetdUnsolicitedEventListener {
-        @Override
-        public void onInterfaceAdded(String ifName) {
-            mHandler.post(() -> addInterface(ifName));
-        }
-    }
-}
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapKey.java b/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapKey.java
deleted file mode 100644
index 443e5b3..0000000
--- a/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapKey.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.server.net;
-
-import com.android.net.module.util.Struct;
-import com.android.net.module.util.Struct.Field;
-import com.android.net.module.util.Struct.Type;
-
-/**
- * Key for cookie tag map.
- */
-public class CookieTagMapKey extends Struct {
-    @Field(order = 0, type = Type.S64)
-    public final long socketCookie;
-
-    public CookieTagMapKey(final long socketCookie) {
-        this.socketCookie = socketCookie;
-    }
-}
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapValue.java b/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapValue.java
deleted file mode 100644
index 93b9195..0000000
--- a/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapValue.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.server.net;
-
-import com.android.net.module.util.Struct;
-import com.android.net.module.util.Struct.Field;
-import com.android.net.module.util.Struct.Type;
-
-/**
- * Value for cookie tag map.
- */
-public class CookieTagMapValue extends Struct {
-    @Field(order = 0, type = Type.U32)
-    public final long uid;
-
-    @Field(order = 1, type = Type.U32)
-    public final long tag;
-
-    public CookieTagMapValue(final long uid, final long tag) {
-        this.uid = uid;
-        this.tag = tag;
-    }
-}
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/DelayedDiskWrite.java b/packages/ConnectivityT/service/src/com/android/server/net/DelayedDiskWrite.java
deleted file mode 100644
index 35dc455..0000000
--- a/packages/ConnectivityT/service/src/com/android/server/net/DelayedDiskWrite.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.net;
-
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.io.BufferedOutputStream;
-import java.io.DataOutputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-/**
- * This class provides APIs to do a delayed data write to a given {@link OutputStream}.
- */
-public class DelayedDiskWrite {
-    private static final String TAG = "DelayedDiskWrite";
-
-    private HandlerThread mDiskWriteHandlerThread;
-    private Handler mDiskWriteHandler;
-    /* Tracks multiple writes on the same thread */
-    private int mWriteSequence = 0;
-
-    /**
-     * Used to do a delayed data write to a given {@link OutputStream}.
-     */
-    public interface Writer {
-        /**
-         * write data to a given {@link OutputStream}.
-         */
-        void onWriteCalled(DataOutputStream out) throws IOException;
-    }
-
-    /**
-     * Do a delayed data write to a given output stream opened from filePath.
-     */
-    public void write(final String filePath, final Writer w) {
-        write(filePath, w, true);
-    }
-
-    /**
-     * Do a delayed data write to a given output stream opened from filePath.
-     */
-    public void write(final String filePath, final Writer w, final boolean open) {
-        if (TextUtils.isEmpty(filePath)) {
-            throw new IllegalArgumentException("empty file path");
-        }
-
-        /* Do a delayed write to disk on a separate handler thread */
-        synchronized (this) {
-            if (++mWriteSequence == 1) {
-                mDiskWriteHandlerThread = new HandlerThread("DelayedDiskWriteThread");
-                mDiskWriteHandlerThread.start();
-                mDiskWriteHandler = new Handler(mDiskWriteHandlerThread.getLooper());
-            }
-        }
-
-        mDiskWriteHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                doWrite(filePath, w, open);
-            }
-        });
-    }
-
-    private void doWrite(String filePath, Writer w, boolean open) {
-        DataOutputStream out = null;
-        try {
-            if (open) {
-                out = new DataOutputStream(new BufferedOutputStream(
-                        new FileOutputStream(filePath)));
-            }
-            w.onWriteCalled(out);
-        } catch (IOException e) {
-            loge("Error writing data file " + filePath);
-        } finally {
-            if (out != null) {
-                try {
-                    out.close();
-                } catch (Exception e) { }
-            }
-
-            // Quit if no more writes sent
-            synchronized (this) {
-                if (--mWriteSequence == 0) {
-                    mDiskWriteHandler.getLooper().quit();
-                    mDiskWriteHandler = null;
-                    mDiskWriteHandlerThread = null;
-                }
-            }
-        }
-    }
-
-    private void loge(String s) {
-        Log.e(TAG, s);
-    }
-}
-
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/InterfaceMapValue.java b/packages/ConnectivityT/service/src/com/android/server/net/InterfaceMapValue.java
deleted file mode 100644
index 42c0044..0000000
--- a/packages/ConnectivityT/service/src/com/android/server/net/InterfaceMapValue.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.server.net;
-
-import com.android.net.module.util.Struct;
-import com.android.net.module.util.Struct.Field;
-import com.android.net.module.util.Struct.Type;
-
-/**
- * The value of bpf interface index map which is used for NetworkStatsService.
- */
-public class InterfaceMapValue extends Struct {
-    @Field(order = 0, type = Type.ByteArray, arraysize = 16)
-    public final byte[] interfaceName;
-
-    public InterfaceMapValue(String iface) {
-        final byte[] ifaceArray = iface.getBytes();
-        interfaceName = new byte[16];
-        // All array bytes after the interface name, if any, must be 0.
-        System.arraycopy(ifaceArray, 0, interfaceName, 0, ifaceArray.length);
-    }
-}
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/IpConfigStore.java b/packages/ConnectivityT/service/src/com/android/server/net/IpConfigStore.java
deleted file mode 100644
index 3a9a544..0000000
--- a/packages/ConnectivityT/service/src/com/android/server/net/IpConfigStore.java
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.net;
-
-import android.net.InetAddresses;
-import android.net.IpConfiguration;
-import android.net.IpConfiguration.IpAssignment;
-import android.net.IpConfiguration.ProxySettings;
-import android.net.LinkAddress;
-import android.net.ProxyInfo;
-import android.net.StaticIpConfiguration;
-import android.net.Uri;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.net.module.util.ProxyUtils;
-
-import java.io.BufferedInputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.EOFException;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * This class provides an API to store and manage L3 network IP configuration.
- */
-public class IpConfigStore {
-    private static final String TAG = "IpConfigStore";
-    private static final boolean DBG = false;
-
-    protected final DelayedDiskWrite mWriter;
-
-    /* IP and proxy configuration keys */
-    protected static final String ID_KEY = "id";
-    protected static final String IP_ASSIGNMENT_KEY = "ipAssignment";
-    protected static final String LINK_ADDRESS_KEY = "linkAddress";
-    protected static final String GATEWAY_KEY = "gateway";
-    protected static final String DNS_KEY = "dns";
-    protected static final String PROXY_SETTINGS_KEY = "proxySettings";
-    protected static final String PROXY_HOST_KEY = "proxyHost";
-    protected static final String PROXY_PORT_KEY = "proxyPort";
-    protected static final String PROXY_PAC_FILE = "proxyPac";
-    protected static final String EXCLUSION_LIST_KEY = "exclusionList";
-    protected static final String EOS = "eos";
-
-    protected static final int IPCONFIG_FILE_VERSION = 3;
-
-    public IpConfigStore(DelayedDiskWrite writer) {
-        mWriter = writer;
-    }
-
-    public IpConfigStore() {
-        this(new DelayedDiskWrite());
-    }
-
-    private static boolean writeConfig(DataOutputStream out, String configKey,
-            IpConfiguration config) throws IOException {
-        return writeConfig(out, configKey, config, IPCONFIG_FILE_VERSION);
-    }
-
-    /**
-     *  Write the IP configuration with the given parameters to {@link DataOutputStream}.
-     */
-    @VisibleForTesting
-    public static boolean writeConfig(DataOutputStream out, String configKey,
-                                IpConfiguration config, int version) throws IOException {
-        boolean written = false;
-
-        try {
-            switch (config.getIpAssignment()) {
-                case STATIC:
-                    out.writeUTF(IP_ASSIGNMENT_KEY);
-                    out.writeUTF(config.getIpAssignment().toString());
-                    StaticIpConfiguration staticIpConfiguration = config.getStaticIpConfiguration();
-                    if (staticIpConfiguration != null) {
-                        if (staticIpConfiguration.getIpAddress() != null) {
-                            LinkAddress ipAddress = staticIpConfiguration.getIpAddress();
-                            out.writeUTF(LINK_ADDRESS_KEY);
-                            out.writeUTF(ipAddress.getAddress().getHostAddress());
-                            out.writeInt(ipAddress.getPrefixLength());
-                        }
-                        if (staticIpConfiguration.getGateway() != null) {
-                            out.writeUTF(GATEWAY_KEY);
-                            out.writeInt(0);  // Default route.
-                            out.writeInt(1);  // Have a gateway.
-                            out.writeUTF(staticIpConfiguration.getGateway().getHostAddress());
-                        }
-                        for (InetAddress inetAddr : staticIpConfiguration.getDnsServers()) {
-                            out.writeUTF(DNS_KEY);
-                            out.writeUTF(inetAddr.getHostAddress());
-                        }
-                    }
-                    written = true;
-                    break;
-                case DHCP:
-                    out.writeUTF(IP_ASSIGNMENT_KEY);
-                    out.writeUTF(config.getIpAssignment().toString());
-                    written = true;
-                    break;
-                case UNASSIGNED:
-                /* Ignore */
-                    break;
-                default:
-                    loge("Ignore invalid ip assignment while writing");
-                    break;
-            }
-
-            switch (config.getProxySettings()) {
-                case STATIC:
-                    ProxyInfo proxyProperties = config.getHttpProxy();
-                    String exclusionList = ProxyUtils.exclusionListAsString(
-                            proxyProperties.getExclusionList());
-                    out.writeUTF(PROXY_SETTINGS_KEY);
-                    out.writeUTF(config.getProxySettings().toString());
-                    out.writeUTF(PROXY_HOST_KEY);
-                    out.writeUTF(proxyProperties.getHost());
-                    out.writeUTF(PROXY_PORT_KEY);
-                    out.writeInt(proxyProperties.getPort());
-                    if (exclusionList != null) {
-                        out.writeUTF(EXCLUSION_LIST_KEY);
-                        out.writeUTF(exclusionList);
-                    }
-                    written = true;
-                    break;
-                case PAC:
-                    ProxyInfo proxyPacProperties = config.getHttpProxy();
-                    out.writeUTF(PROXY_SETTINGS_KEY);
-                    out.writeUTF(config.getProxySettings().toString());
-                    out.writeUTF(PROXY_PAC_FILE);
-                    out.writeUTF(proxyPacProperties.getPacFileUrl().toString());
-                    written = true;
-                    break;
-                case NONE:
-                    out.writeUTF(PROXY_SETTINGS_KEY);
-                    out.writeUTF(config.getProxySettings().toString());
-                    written = true;
-                    break;
-                case UNASSIGNED:
-                    /* Ignore */
-                    break;
-                default:
-                    loge("Ignore invalid proxy settings while writing");
-                    break;
-            }
-
-            if (written) {
-                out.writeUTF(ID_KEY);
-                if (version < 3) {
-                    out.writeInt(Integer.valueOf(configKey));
-                } else {
-                    out.writeUTF(configKey);
-                }
-            }
-        } catch (NullPointerException e) {
-            loge("Failure in writing " + config + e);
-        }
-        out.writeUTF(EOS);
-
-        return written;
-    }
-
-    /**
-     * @deprecated use {@link #writeIpConfigurations(String, ArrayMap)} instead.
-     * New method uses string as network identifier which could be interface name or MAC address or
-     * other token.
-     */
-    @Deprecated
-    public void writeIpAndProxyConfigurationsToFile(String filePath,
-                                              final SparseArray<IpConfiguration> networks) {
-        mWriter.write(filePath, out -> {
-            out.writeInt(IPCONFIG_FILE_VERSION);
-            for (int i = 0; i < networks.size(); i++) {
-                writeConfig(out, String.valueOf(networks.keyAt(i)), networks.valueAt(i));
-            }
-        });
-    }
-
-    /**
-     *  Write the IP configuration associated to the target networks to the destination path.
-     */
-    public void writeIpConfigurations(String filePath,
-                                      ArrayMap<String, IpConfiguration> networks) {
-        mWriter.write(filePath, out -> {
-            out.writeInt(IPCONFIG_FILE_VERSION);
-            for (int i = 0; i < networks.size(); i++) {
-                writeConfig(out, networks.keyAt(i), networks.valueAt(i));
-            }
-        });
-    }
-
-    /**
-     * Read the IP configuration from the destination path to {@link BufferedInputStream}.
-     */
-    public static ArrayMap<String, IpConfiguration> readIpConfigurations(String filePath) {
-        BufferedInputStream bufferedInputStream;
-        try {
-            bufferedInputStream = new BufferedInputStream(new FileInputStream(filePath));
-        } catch (FileNotFoundException e) {
-            // Return an empty array here because callers expect an empty array when the file is
-            // not present.
-            loge("Error opening configuration file: " + e);
-            return new ArrayMap<>(0);
-        }
-        return readIpConfigurations(bufferedInputStream);
-    }
-
-    /** @deprecated use {@link #readIpConfigurations(String)} */
-    @Deprecated
-    public static SparseArray<IpConfiguration> readIpAndProxyConfigurations(String filePath) {
-        BufferedInputStream bufferedInputStream;
-        try {
-            bufferedInputStream = new BufferedInputStream(new FileInputStream(filePath));
-        } catch (FileNotFoundException e) {
-            // Return an empty array here because callers expect an empty array when the file is
-            // not present.
-            loge("Error opening configuration file: " + e);
-            return new SparseArray<>();
-        }
-        return readIpAndProxyConfigurations(bufferedInputStream);
-    }
-
-    /** @deprecated use {@link #readIpConfigurations(InputStream)} */
-    @Deprecated
-    public static SparseArray<IpConfiguration> readIpAndProxyConfigurations(
-            InputStream inputStream) {
-        ArrayMap<String, IpConfiguration> networks = readIpConfigurations(inputStream);
-        if (networks == null) {
-            return null;
-        }
-
-        SparseArray<IpConfiguration> networksById = new SparseArray<>();
-        for (int i = 0; i < networks.size(); i++) {
-            int id = Integer.valueOf(networks.keyAt(i));
-            networksById.put(id, networks.valueAt(i));
-        }
-
-        return networksById;
-    }
-
-    /** Returns a map of network identity token and {@link IpConfiguration}. */
-    public static ArrayMap<String, IpConfiguration> readIpConfigurations(
-            InputStream inputStream) {
-        ArrayMap<String, IpConfiguration> networks = new ArrayMap<>();
-        DataInputStream in = null;
-        try {
-            in = new DataInputStream(inputStream);
-
-            int version = in.readInt();
-            if (version != 3 && version != 2 && version != 1) {
-                loge("Bad version on IP configuration file, ignore read");
-                return null;
-            }
-
-            while (true) {
-                String uniqueToken = null;
-                // Default is DHCP with no proxy
-                IpAssignment ipAssignment = IpAssignment.DHCP;
-                ProxySettings proxySettings = ProxySettings.NONE;
-                StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration();
-                LinkAddress linkAddress = null;
-                InetAddress gatewayAddress = null;
-                String proxyHost = null;
-                String pacFileUrl = null;
-                int proxyPort = -1;
-                String exclusionList = null;
-                String key;
-                final List<InetAddress> dnsServers = new ArrayList<>();
-
-                do {
-                    key = in.readUTF();
-                    try {
-                        if (key.equals(ID_KEY)) {
-                            if (version < 3) {
-                                int id = in.readInt();
-                                uniqueToken = String.valueOf(id);
-                            } else {
-                                uniqueToken = in.readUTF();
-                            }
-                        } else if (key.equals(IP_ASSIGNMENT_KEY)) {
-                            ipAssignment = IpAssignment.valueOf(in.readUTF());
-                        } else if (key.equals(LINK_ADDRESS_KEY)) {
-                            LinkAddress parsedLinkAddress =
-                                    new LinkAddress(
-                                            InetAddresses.parseNumericAddress(in.readUTF()),
-                                            in.readInt());
-                            if (parsedLinkAddress.getAddress() instanceof Inet4Address
-                                    && linkAddress == null) {
-                                linkAddress = parsedLinkAddress;
-                            } else {
-                                loge("Non-IPv4 or duplicate address: " + parsedLinkAddress);
-                            }
-                        } else if (key.equals(GATEWAY_KEY)) {
-                            LinkAddress dest = null;
-                            InetAddress gateway = null;
-                            if (version == 1) {
-                                // only supported default gateways - leave the dest/prefix empty
-                                gateway = InetAddresses.parseNumericAddress(in.readUTF());
-                                if (gatewayAddress == null) {
-                                    gatewayAddress = gateway;
-                                } else {
-                                    loge("Duplicate gateway: " + gateway.getHostAddress());
-                                }
-                            } else {
-                                if (in.readInt() == 1) {
-                                    dest =
-                                            new LinkAddress(
-                                                    InetAddresses.parseNumericAddress(in.readUTF()),
-                                                    in.readInt());
-                                }
-                                if (in.readInt() == 1) {
-                                    gateway = InetAddresses.parseNumericAddress(in.readUTF());
-                                }
-                                // If the destination is a default IPv4 route, use the gateway
-                                // address unless already set. If there is no destination, assume
-                                // it is default route and use the gateway address in all cases.
-                                if (dest == null) {
-                                    gatewayAddress = gateway;
-                                } else if (dest.getAddress() instanceof Inet4Address
-                                        && dest.getPrefixLength() == 0 && gatewayAddress == null) {
-                                    gatewayAddress = gateway;
-                                } else {
-                                    loge("Non-IPv4 default or duplicate route: "
-                                            + dest.getAddress());
-                                }
-                            }
-                        } else if (key.equals(DNS_KEY)) {
-                            dnsServers.add(InetAddresses.parseNumericAddress(in.readUTF()));
-                        } else if (key.equals(PROXY_SETTINGS_KEY)) {
-                            proxySettings = ProxySettings.valueOf(in.readUTF());
-                        } else if (key.equals(PROXY_HOST_KEY)) {
-                            proxyHost = in.readUTF();
-                        } else if (key.equals(PROXY_PORT_KEY)) {
-                            proxyPort = in.readInt();
-                        } else if (key.equals(PROXY_PAC_FILE)) {
-                            pacFileUrl = in.readUTF();
-                        } else if (key.equals(EXCLUSION_LIST_KEY)) {
-                            exclusionList = in.readUTF();
-                        } else if (key.equals(EOS)) {
-                            break;
-                        } else {
-                            loge("Ignore unknown key " + key + "while reading");
-                        }
-                    } catch (IllegalArgumentException e) {
-                        loge("Ignore invalid address while reading" + e);
-                    }
-                } while (true);
-
-                staticIpConfiguration = new StaticIpConfiguration.Builder()
-                    .setIpAddress(linkAddress)
-                    .setGateway(gatewayAddress)
-                    .setDnsServers(dnsServers)
-                    .build();
-
-                if (uniqueToken != null) {
-                    IpConfiguration config = new IpConfiguration();
-                    networks.put(uniqueToken, config);
-
-                    switch (ipAssignment) {
-                        case STATIC:
-                            config.setStaticIpConfiguration(staticIpConfiguration);
-                            config.setIpAssignment(ipAssignment);
-                            break;
-                        case DHCP:
-                            config.setIpAssignment(ipAssignment);
-                            break;
-                        case UNASSIGNED:
-                            loge("BUG: Found UNASSIGNED IP on file, use DHCP");
-                            config.setIpAssignment(IpAssignment.DHCP);
-                            break;
-                        default:
-                            loge("Ignore invalid ip assignment while reading.");
-                            config.setIpAssignment(IpAssignment.UNASSIGNED);
-                            break;
-                    }
-
-                    switch (proxySettings) {
-                        case STATIC:
-                            ProxyInfo proxyInfo = ProxyInfo.buildDirectProxy(proxyHost, proxyPort,
-                                    ProxyUtils.exclusionStringAsList(exclusionList));
-                            config.setProxySettings(proxySettings);
-                            config.setHttpProxy(proxyInfo);
-                            break;
-                        case PAC:
-                            ProxyInfo proxyPacProperties =
-                                    ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl));
-                            config.setProxySettings(proxySettings);
-                            config.setHttpProxy(proxyPacProperties);
-                            break;
-                        case NONE:
-                            config.setProxySettings(proxySettings);
-                            break;
-                        case UNASSIGNED:
-                            loge("BUG: Found UNASSIGNED proxy on file, use NONE");
-                            config.setProxySettings(ProxySettings.NONE);
-                            break;
-                        default:
-                            loge("Ignore invalid proxy settings while reading");
-                            config.setProxySettings(ProxySettings.UNASSIGNED);
-                            break;
-                    }
-                } else {
-                    if (DBG) log("Missing id while parsing configuration");
-                }
-            }
-        } catch (EOFException ignore) {
-        } catch (IOException e) {
-            loge("Error parsing configuration: " + e);
-        } finally {
-            if (in != null) {
-                try {
-                    in.close();
-                } catch (Exception e) { }
-            }
-        }
-
-        return networks;
-    }
-
-    protected static void loge(String s) {
-        Log.e(TAG, s);
-    }
-
-    protected static void log(String s) {
-        Log.d(TAG, s);
-    }
-}
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java
deleted file mode 100644
index 3b93f1a..0000000
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java
+++ /dev/null
@@ -1,505 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.net;
-
-import static android.net.NetworkStats.INTERFACES_ALL;
-import static android.net.NetworkStats.SET_ALL;
-import static android.net.NetworkStats.TAG_ALL;
-import static android.net.NetworkStats.TAG_NONE;
-import static android.net.NetworkStats.UID_ALL;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.net.NetworkStats;
-import android.net.UnderlyingNetworkInfo;
-import android.os.ServiceSpecificException;
-import android.os.StrictMode;
-import android.os.SystemClock;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ProcFileReader;
-import com.android.net.module.util.CollectionUtils;
-import com.android.server.BpfNetMaps;
-
-import libcore.io.IoUtils;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.net.ProtocolException;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Creates {@link NetworkStats} instances by parsing various {@code /proc/}
- * files as needed.
- *
- * @hide
- */
-public class NetworkStatsFactory {
-    static {
-        System.loadLibrary("service-connectivity");
-    }
-
-    private static final String TAG = "NetworkStatsFactory";
-
-    private static final boolean USE_NATIVE_PARSING = true;
-    private static final boolean VALIDATE_NATIVE_STATS = false;
-
-    /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */
-    private final File mStatsXtIfaceAll;
-    /** Path to {@code /proc/net/xt_qtaguid/iface_stat_fmt}. */
-    private final File mStatsXtIfaceFmt;
-    /** Path to {@code /proc/net/xt_qtaguid/stats}. */
-    private final File mStatsXtUid;
-
-    private final boolean mUseBpfStats;
-
-    private final Context mContext;
-
-    private final BpfNetMaps mBpfNetMaps;
-
-    /**
-     * Guards persistent data access in this class
-     *
-     * <p>In order to prevent deadlocks, critical sections protected by this lock SHALL NOT call out
-     * to other code that will acquire other locks within the system server. See b/134244752.
-     */
-    private final Object mPersistentDataLock = new Object();
-
-    /** Set containing info about active VPNs and their underlying networks. */
-    private volatile UnderlyingNetworkInfo[] mUnderlyingNetworkInfos = new UnderlyingNetworkInfo[0];
-
-    // A persistent snapshot of cumulative stats since device start
-    @GuardedBy("mPersistentDataLock")
-    private NetworkStats mPersistSnapshot;
-
-    // The persistent snapshot of tun and 464xlat adjusted stats since device start
-    @GuardedBy("mPersistentDataLock")
-    private NetworkStats mTunAnd464xlatAdjustedStats;
-
-    /**
-     * (Stacked interface) -> (base interface) association for all connected ifaces since boot.
-     *
-     * Because counters must never roll backwards, once a given interface is stacked on top of an
-     * underlying interface, the stacked interface can never be stacked on top of
-     * another interface. */
-    private final ConcurrentHashMap<String, String> mStackedIfaces
-            = new ConcurrentHashMap<>();
-
-    /** Informs the factory of a new stacked interface. */
-    public void noteStackedIface(String stackedIface, String baseIface) {
-        if (stackedIface != null && baseIface != null) {
-            mStackedIfaces.put(stackedIface, baseIface);
-        }
-    }
-
-    /**
-     * Set active VPN information for data usage migration purposes
-     *
-     * <p>Traffic on TUN-based VPNs inherently all appear to be originated from the VPN providing
-     * app's UID. This method is used to support migration of VPN data usage, ensuring data is
-     * accurately billed to the real owner of the traffic.
-     *
-     * @param vpnArray The snapshot of the currently-running VPNs.
-     */
-    public void updateUnderlyingNetworkInfos(UnderlyingNetworkInfo[] vpnArray) {
-        mUnderlyingNetworkInfos = vpnArray.clone();
-    }
-
-    /**
-     * Get a set of interfaces containing specified ifaces and stacked interfaces.
-     *
-     * <p>The added stacked interfaces are ifaces stacked on top of the specified ones, or ifaces
-     * on which the specified ones are stacked. Stacked interfaces are those noted with
-     * {@link #noteStackedIface(String, String)}, but only interfaces noted before this method
-     * is called are guaranteed to be included.
-     */
-    public String[] augmentWithStackedInterfaces(@Nullable String[] requiredIfaces) {
-        if (requiredIfaces == NetworkStats.INTERFACES_ALL) {
-            return null;
-        }
-
-        HashSet<String> relatedIfaces = new HashSet<>(Arrays.asList(requiredIfaces));
-        // ConcurrentHashMap's EntrySet iterators are "guaranteed to traverse
-        // elements as they existed upon construction exactly once, and may
-        // (but are not guaranteed to) reflect any modifications subsequent to construction".
-        // This is enough here.
-        for (Map.Entry<String, String> entry : mStackedIfaces.entrySet()) {
-            if (relatedIfaces.contains(entry.getKey())) {
-                relatedIfaces.add(entry.getValue());
-            } else if (relatedIfaces.contains(entry.getValue())) {
-                relatedIfaces.add(entry.getKey());
-            }
-        }
-
-        String[] outArray = new String[relatedIfaces.size()];
-        return relatedIfaces.toArray(outArray);
-    }
-
-    /**
-     * Applies 464xlat adjustments with ifaces noted with {@link #noteStackedIface(String, String)}.
-     * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map)
-     */
-    public void apply464xlatAdjustments(NetworkStats baseTraffic, NetworkStats stackedTraffic) {
-        NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, mStackedIfaces);
-    }
-
-    public NetworkStatsFactory(@NonNull Context ctx) {
-        this(ctx, new File("/proc/"), true);
-    }
-
-    @VisibleForTesting
-    public NetworkStatsFactory(@NonNull Context ctx, File procRoot, boolean useBpfStats) {
-        mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all");
-        mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt");
-        mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
-        mUseBpfStats = useBpfStats;
-        mBpfNetMaps = new BpfNetMaps();
-        synchronized (mPersistentDataLock) {
-            mPersistSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), -1);
-            mTunAnd464xlatAdjustedStats = new NetworkStats(SystemClock.elapsedRealtime(), -1);
-        }
-        mContext = ctx;
-    }
-
-    public NetworkStats readBpfNetworkStatsDev() throws IOException {
-        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
-        if (nativeReadNetworkStatsDev(stats) != 0) {
-            throw new IOException("Failed to parse bpf iface stats");
-        }
-        return stats;
-    }
-
-    /**
-     * Parse and return interface-level summary {@link NetworkStats} measured
-     * using {@code /proc/net/dev} style hooks, which may include non IP layer
-     * traffic. Values monotonically increase since device boot, and may include
-     * details about inactive interfaces.
-     *
-     * @throws IllegalStateException when problem parsing stats.
-     */
-    public NetworkStats readNetworkStatsSummaryDev() throws IOException {
-
-        // Return xt_bpf stats if switched to bpf module.
-        if (mUseBpfStats)
-            return readBpfNetworkStatsDev();
-
-        final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
-
-        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
-        final NetworkStats.Entry entry = new NetworkStats.Entry();
-
-        ProcFileReader reader = null;
-        try {
-            reader = new ProcFileReader(new FileInputStream(mStatsXtIfaceAll));
-
-            while (reader.hasMoreData()) {
-                entry.iface = reader.nextString();
-                entry.uid = UID_ALL;
-                entry.set = SET_ALL;
-                entry.tag = TAG_NONE;
-
-                final boolean active = reader.nextInt() != 0;
-
-                // always include snapshot values
-                entry.rxBytes = reader.nextLong();
-                entry.rxPackets = reader.nextLong();
-                entry.txBytes = reader.nextLong();
-                entry.txPackets = reader.nextLong();
-
-                // fold in active numbers, but only when active
-                if (active) {
-                    entry.rxBytes += reader.nextLong();
-                    entry.rxPackets += reader.nextLong();
-                    entry.txBytes += reader.nextLong();
-                    entry.txPackets += reader.nextLong();
-                }
-
-                stats.insertEntry(entry);
-                reader.finishLine();
-            }
-        } catch (NullPointerException|NumberFormatException e) {
-            throw protocolExceptionWithCause("problem parsing stats", e);
-        } finally {
-            IoUtils.closeQuietly(reader);
-            StrictMode.setThreadPolicy(savedPolicy);
-        }
-        return stats;
-    }
-
-    /**
-     * Parse and return interface-level summary {@link NetworkStats}. Designed
-     * to return only IP layer traffic. Values monotonically increase since
-     * device boot, and may include details about inactive interfaces.
-     *
-     * @throws IllegalStateException when problem parsing stats.
-     */
-    public NetworkStats readNetworkStatsSummaryXt() throws IOException {
-
-        // Return xt_bpf stats if qtaguid  module is replaced.
-        if (mUseBpfStats)
-            return readBpfNetworkStatsDev();
-
-        final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
-
-        // return null when kernel doesn't support
-        if (!mStatsXtIfaceFmt.exists()) return null;
-
-        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
-        final NetworkStats.Entry entry = new NetworkStats.Entry();
-
-        ProcFileReader reader = null;
-        try {
-            // open and consume header line
-            reader = new ProcFileReader(new FileInputStream(mStatsXtIfaceFmt));
-            reader.finishLine();
-
-            while (reader.hasMoreData()) {
-                entry.iface = reader.nextString();
-                entry.uid = UID_ALL;
-                entry.set = SET_ALL;
-                entry.tag = TAG_NONE;
-
-                entry.rxBytes = reader.nextLong();
-                entry.rxPackets = reader.nextLong();
-                entry.txBytes = reader.nextLong();
-                entry.txPackets = reader.nextLong();
-
-                stats.insertEntry(entry);
-                reader.finishLine();
-            }
-        } catch (NullPointerException|NumberFormatException e) {
-            throw protocolExceptionWithCause("problem parsing stats", e);
-        } finally {
-            IoUtils.closeQuietly(reader);
-            StrictMode.setThreadPolicy(savedPolicy);
-        }
-        return stats;
-    }
-
-    public NetworkStats readNetworkStatsDetail() throws IOException {
-        return readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL);
-    }
-
-    @GuardedBy("mPersistentDataLock")
-    private void requestSwapActiveStatsMapLocked() throws IOException {
-        try {
-            // Do a active map stats swap. Once the swap completes, this code
-            // can read and clean the inactive map without races.
-            mBpfNetMaps.swapActiveStatsMap();
-        } catch (ServiceSpecificException e) {
-            throw new IOException(e);
-        }
-    }
-
-    /**
-     * Reads the detailed UID stats based on the provided parameters
-     *
-     * @param limitUid the UID to limit this query to
-     * @param limitIfaces the interfaces to limit this query to. Use {@link
-     *     NetworkStats.INTERFACES_ALL} to select all interfaces
-     * @param limitTag the tags to limit this query to
-     * @return the NetworkStats instance containing network statistics at the present time.
-     */
-    public NetworkStats readNetworkStatsDetail(
-            int limitUid, String[] limitIfaces, int limitTag) throws IOException {
-        // In order to prevent deadlocks, anything protected by this lock MUST NOT call out to other
-        // code that will acquire other locks within the system server. See b/134244752.
-        synchronized (mPersistentDataLock) {
-            // Take a reference. If this gets swapped out, we still have the old reference.
-            final UnderlyingNetworkInfo[] vpnArray = mUnderlyingNetworkInfos;
-            // Take a defensive copy. mPersistSnapshot is mutated in some cases below
-            final NetworkStats prev = mPersistSnapshot.clone();
-
-            if (USE_NATIVE_PARSING) {
-                final NetworkStats stats =
-                        new NetworkStats(SystemClock.elapsedRealtime(), 0 /* initialSize */);
-                if (mUseBpfStats) {
-                    requestSwapActiveStatsMapLocked();
-                    // Stats are always read from the inactive map, so they must be read after the
-                    // swap
-                    if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL,
-                            INTERFACES_ALL, TAG_ALL, mUseBpfStats) != 0) {
-                        throw new IOException("Failed to parse network stats");
-                    }
-
-                    // BPF stats are incremental; fold into mPersistSnapshot.
-                    mPersistSnapshot.setElapsedRealtime(stats.getElapsedRealtime());
-                    mPersistSnapshot.combineAllValues(stats);
-                } else {
-                    if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL,
-                            INTERFACES_ALL, TAG_ALL, mUseBpfStats) != 0) {
-                        throw new IOException("Failed to parse network stats");
-                    }
-                    if (VALIDATE_NATIVE_STATS) {
-                        final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid,
-                                UID_ALL, INTERFACES_ALL, TAG_ALL);
-                        assertEquals(javaStats, stats);
-                    }
-
-                    mPersistSnapshot = stats;
-                }
-            } else {
-                mPersistSnapshot = javaReadNetworkStatsDetail(mStatsXtUid, UID_ALL, INTERFACES_ALL,
-                        TAG_ALL);
-            }
-
-            NetworkStats adjustedStats = adjustForTunAnd464Xlat(mPersistSnapshot, prev, vpnArray);
-
-            // Filter return values
-            adjustedStats.filter(limitUid, limitIfaces, limitTag);
-            return adjustedStats;
-        }
-    }
-
-    @GuardedBy("mPersistentDataLock")
-    private NetworkStats adjustForTunAnd464Xlat(NetworkStats uidDetailStats,
-            NetworkStats previousStats, UnderlyingNetworkInfo[] vpnArray) {
-        // Calculate delta from last snapshot
-        final NetworkStats delta = uidDetailStats.subtract(previousStats);
-
-        // Apply 464xlat adjustments before VPN adjustments. If VPNs are using v4 on a v6 only
-        // network, the overhead is their fault.
-        // No locking here: apply464xlatAdjustments behaves fine with an add-only
-        // ConcurrentHashMap.
-        delta.apply464xlatAdjustments(mStackedIfaces);
-
-        // Migrate data usage over a VPN to the TUN network.
-        for (UnderlyingNetworkInfo info : vpnArray) {
-            delta.migrateTun(info.getOwnerUid(), info.getInterface(),
-                    info.getUnderlyingInterfaces());
-            // Filter out debug entries as that may lead to over counting.
-            delta.filterDebugEntries();
-        }
-
-        // Update mTunAnd464xlatAdjustedStats with migrated delta.
-        mTunAnd464xlatAdjustedStats.combineAllValues(delta);
-        mTunAnd464xlatAdjustedStats.setElapsedRealtime(uidDetailStats.getElapsedRealtime());
-
-        return mTunAnd464xlatAdjustedStats.clone();
-    }
-
-    /**
-     * Parse and return {@link NetworkStats} with UID-level details. Values are
-     * expected to monotonically increase since device boot.
-     */
-    @VisibleForTesting
-    public static NetworkStats javaReadNetworkStatsDetail(File detailPath, int limitUid,
-            String[] limitIfaces, int limitTag)
-            throws IOException {
-        final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
-
-        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24);
-        final NetworkStats.Entry entry = new NetworkStats.Entry();
-
-        int idx = 1;
-        int lastIdx = 1;
-
-        ProcFileReader reader = null;
-        try {
-            // open and consume header line
-            reader = new ProcFileReader(new FileInputStream(detailPath));
-            reader.finishLine();
-
-            while (reader.hasMoreData()) {
-                idx = reader.nextInt();
-                if (idx != lastIdx + 1) {
-                    throw new ProtocolException(
-                            "inconsistent idx=" + idx + " after lastIdx=" + lastIdx);
-                }
-                lastIdx = idx;
-
-                entry.iface = reader.nextString();
-                entry.tag = kernelToTag(reader.nextString());
-                entry.uid = reader.nextInt();
-                entry.set = reader.nextInt();
-                entry.rxBytes = reader.nextLong();
-                entry.rxPackets = reader.nextLong();
-                entry.txBytes = reader.nextLong();
-                entry.txPackets = reader.nextLong();
-
-                if ((limitIfaces == null || CollectionUtils.contains(limitIfaces, entry.iface))
-                        && (limitUid == UID_ALL || limitUid == entry.uid)
-                        && (limitTag == TAG_ALL || limitTag == entry.tag)) {
-                    stats.insertEntry(entry);
-                }
-
-                reader.finishLine();
-            }
-        } catch (NullPointerException|NumberFormatException e) {
-            throw protocolExceptionWithCause("problem parsing idx " + idx, e);
-        } finally {
-            IoUtils.closeQuietly(reader);
-            StrictMode.setThreadPolicy(savedPolicy);
-        }
-
-        return stats;
-    }
-
-    public void assertEquals(NetworkStats expected, NetworkStats actual) {
-        if (expected.size() != actual.size()) {
-            throw new AssertionError(
-                    "Expected size " + expected.size() + ", actual size " + actual.size());
-        }
-
-        NetworkStats.Entry expectedRow = null;
-        NetworkStats.Entry actualRow = null;
-        for (int i = 0; i < expected.size(); i++) {
-            expectedRow = expected.getValues(i, expectedRow);
-            actualRow = actual.getValues(i, actualRow);
-            if (!expectedRow.equals(actualRow)) {
-                throw new AssertionError(
-                        "Expected row " + i + ": " + expectedRow + ", actual row " + actualRow);
-            }
-        }
-    }
-
-    /**
-     * Convert {@code /proc/} tag format to {@link Integer}. Assumes incoming
-     * format like {@code 0x7fffffff00000000}.
-     */
-    public static int kernelToTag(String string) {
-        int length = string.length();
-        if (length > 10) {
-            return Long.decode(string.substring(0, length - 8)).intValue();
-        } else {
-            return 0;
-        }
-    }
-
-    /**
-     * Parse statistics from file into given {@link NetworkStats} object. Values
-     * are expected to monotonically increase since device boot.
-     */
-    @VisibleForTesting
-    public static native int nativeReadNetworkStatsDetail(NetworkStats stats, String path,
-        int limitUid, String[] limitIfaces, int limitTag, boolean useBpfStats);
-
-    @VisibleForTesting
-    public static native int nativeReadNetworkStatsDev(NetworkStats stats);
-
-    private static ProtocolException protocolExceptionWithCause(String message, Throwable cause) {
-        ProtocolException pe = new ProtocolException(message);
-        pe.initCause(cause);
-        return pe;
-    }
-}
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java
deleted file mode 100644
index fdfc893..0000000
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.net;
-
-import static android.app.usage.NetworkStatsManager.MIN_THRESHOLD_BYTES;
-
-import android.app.usage.NetworkStatsManager;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.net.DataUsageRequest;
-import android.net.NetworkIdentitySet;
-import android.net.NetworkStack;
-import android.net.NetworkStats;
-import android.net.NetworkStatsAccess;
-import android.net.NetworkStatsCollection;
-import android.net.NetworkStatsHistory;
-import android.net.NetworkTemplate;
-import android.net.netstats.IUsageCallback;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Process;
-import android.os.RemoteException;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Manages observers of {@link NetworkStats}. Allows observers to be notified when
- * data usage has been reported in {@link NetworkStatsService}. An observer can set
- * a threshold of how much data it cares about to be notified.
- */
-class NetworkStatsObservers {
-    private static final String TAG = "NetworkStatsObservers";
-    private static final boolean LOGV = false;
-
-    private static final int MSG_REGISTER = 1;
-    private static final int MSG_UNREGISTER = 2;
-    private static final int MSG_UPDATE_STATS = 3;
-
-    // All access to this map must be done from the handler thread.
-    // indexed by DataUsageRequest#requestId
-    private final SparseArray<RequestInfo> mDataUsageRequests = new SparseArray<>();
-
-    // Sequence number of DataUsageRequests
-    private final AtomicInteger mNextDataUsageRequestId = new AtomicInteger();
-
-    // Lazily instantiated when an observer is registered.
-    private volatile Handler mHandler;
-
-    /**
-     * Creates a wrapper that contains the caller context and a normalized request.
-     * The request should be returned to the caller app, and the wrapper should be sent to this
-     * object through #addObserver by the service handler.
-     *
-     * <p>It will register the observer asynchronously, so it is safe to call from any thread.
-     *
-     * @return the normalized request wrapped within {@link RequestInfo}.
-     */
-    public DataUsageRequest register(Context context, DataUsageRequest inputRequest,
-            IUsageCallback callback, int callingUid, @NetworkStatsAccess.Level int accessLevel) {
-        DataUsageRequest request = buildRequest(context, inputRequest, callingUid);
-        RequestInfo requestInfo = buildRequestInfo(request, callback, callingUid,
-                accessLevel);
-
-        if (LOGV) Log.v(TAG, "Registering observer for " + request);
-        getHandler().sendMessage(mHandler.obtainMessage(MSG_REGISTER, requestInfo));
-        return request;
-    }
-
-    /**
-     * Unregister a data usage observer.
-     *
-     * <p>It will unregister the observer asynchronously, so it is safe to call from any thread.
-     */
-    public void unregister(DataUsageRequest request, int callingUid) {
-        getHandler().sendMessage(mHandler.obtainMessage(MSG_UNREGISTER, callingUid, 0 /* ignore */,
-                request));
-    }
-
-    /**
-     * Updates data usage statistics of registered observers and notifies if limits are reached.
-     *
-     * <p>It will update stats asynchronously, so it is safe to call from any thread.
-     */
-    public void updateStats(NetworkStats xtSnapshot, NetworkStats uidSnapshot,
-                ArrayMap<String, NetworkIdentitySet> activeIfaces,
-                ArrayMap<String, NetworkIdentitySet> activeUidIfaces,
-                long currentTime) {
-        StatsContext statsContext = new StatsContext(xtSnapshot, uidSnapshot, activeIfaces,
-                activeUidIfaces, currentTime);
-        getHandler().sendMessage(mHandler.obtainMessage(MSG_UPDATE_STATS, statsContext));
-    }
-
-    private Handler getHandler() {
-        if (mHandler == null) {
-            synchronized (this) {
-                if (mHandler == null) {
-                    if (LOGV) Log.v(TAG, "Creating handler");
-                    mHandler = new Handler(getHandlerLooperLocked(), mHandlerCallback);
-                }
-            }
-        }
-        return mHandler;
-    }
-
-    @VisibleForTesting
-    protected Looper getHandlerLooperLocked() {
-        HandlerThread handlerThread = new HandlerThread(TAG);
-        handlerThread.start();
-        return handlerThread.getLooper();
-    }
-
-    private Handler.Callback mHandlerCallback = new Handler.Callback() {
-        @Override
-        public boolean handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_REGISTER: {
-                    handleRegister((RequestInfo) msg.obj);
-                    return true;
-                }
-                case MSG_UNREGISTER: {
-                    handleUnregister((DataUsageRequest) msg.obj, msg.arg1 /* callingUid */);
-                    return true;
-                }
-                case MSG_UPDATE_STATS: {
-                    handleUpdateStats((StatsContext) msg.obj);
-                    return true;
-                }
-                default: {
-                    return false;
-                }
-            }
-        }
-    };
-
-    /**
-     * Adds a {@link RequestInfo} as an observer.
-     * Should only be called from the handler thread otherwise there will be a race condition
-     * on mDataUsageRequests.
-     */
-    private void handleRegister(RequestInfo requestInfo) {
-        mDataUsageRequests.put(requestInfo.mRequest.requestId, requestInfo);
-    }
-
-    /**
-     * Removes a {@link DataUsageRequest} if the calling uid is authorized.
-     * Should only be called from the handler thread otherwise there will be a race condition
-     * on mDataUsageRequests.
-     */
-    private void handleUnregister(DataUsageRequest request, int callingUid) {
-        RequestInfo requestInfo;
-        requestInfo = mDataUsageRequests.get(request.requestId);
-        if (requestInfo == null) {
-            if (LOGV) Log.v(TAG, "Trying to unregister unknown request " + request);
-            return;
-        }
-        if (Process.SYSTEM_UID != callingUid && requestInfo.mCallingUid != callingUid) {
-            Log.w(TAG, "Caller uid " + callingUid + " is not owner of " + request);
-            return;
-        }
-
-        if (LOGV) Log.v(TAG, "Unregistering " + request);
-        mDataUsageRequests.remove(request.requestId);
-        requestInfo.unlinkDeathRecipient();
-        requestInfo.callCallback(NetworkStatsManager.CALLBACK_RELEASED);
-    }
-
-    private void handleUpdateStats(StatsContext statsContext) {
-        if (mDataUsageRequests.size() == 0) {
-            return;
-        }
-
-        for (int i = 0; i < mDataUsageRequests.size(); i++) {
-            RequestInfo requestInfo = mDataUsageRequests.valueAt(i);
-            requestInfo.updateStats(statsContext);
-        }
-    }
-
-    private DataUsageRequest buildRequest(Context context, DataUsageRequest request,
-                int callingUid) {
-        // For non-NETWORK_STACK permission uid, cap the minimum threshold to a safe default to
-        // avoid too many callbacks.
-        final long thresholdInBytes = (context.checkPermission(
-                NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, Process.myPid(), callingUid)
-                == PackageManager.PERMISSION_GRANTED ? request.thresholdInBytes
-                : Math.max(MIN_THRESHOLD_BYTES, request.thresholdInBytes));
-        if (thresholdInBytes > request.thresholdInBytes) {
-            Log.w(TAG, "Threshold was too low for " + request
-                    + ". Overriding to a safer default of " + thresholdInBytes + " bytes");
-        }
-        return new DataUsageRequest(mNextDataUsageRequestId.incrementAndGet(),
-                request.template, thresholdInBytes);
-    }
-
-    private RequestInfo buildRequestInfo(DataUsageRequest request, IUsageCallback callback,
-            int callingUid, @NetworkStatsAccess.Level int accessLevel) {
-        if (accessLevel <= NetworkStatsAccess.Level.USER) {
-            return new UserUsageRequestInfo(this, request, callback, callingUid,
-                    accessLevel);
-        } else {
-            // Safety check in case a new access level is added and we forgot to update this
-            if (accessLevel < NetworkStatsAccess.Level.DEVICESUMMARY) {
-                throw new IllegalArgumentException(
-                        "accessLevel " + accessLevel + " is less than DEVICESUMMARY.");
-            }
-            return new NetworkUsageRequestInfo(this, request, callback, callingUid,
-                    accessLevel);
-        }
-    }
-
-    /**
-     * Tracks information relevant to a data usage observer.
-     * It will notice when the calling process dies so we can self-expire.
-     */
-    private abstract static class RequestInfo implements IBinder.DeathRecipient {
-        private final NetworkStatsObservers mStatsObserver;
-        protected final DataUsageRequest mRequest;
-        private final IUsageCallback mCallback;
-        protected final int mCallingUid;
-        protected final @NetworkStatsAccess.Level int mAccessLevel;
-        protected NetworkStatsRecorder mRecorder;
-        protected NetworkStatsCollection mCollection;
-
-        RequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request,
-                IUsageCallback callback, int callingUid,
-                    @NetworkStatsAccess.Level int accessLevel) {
-            mStatsObserver = statsObserver;
-            mRequest = request;
-            mCallback = callback;
-            mCallingUid = callingUid;
-            mAccessLevel = accessLevel;
-
-            try {
-                mCallback.asBinder().linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                binderDied();
-            }
-        }
-
-        @Override
-        public void binderDied() {
-            if (LOGV) {
-                Log.v(TAG, "RequestInfo binderDied(" + mRequest + ", " + mCallback + ")");
-            }
-            mStatsObserver.unregister(mRequest, Process.SYSTEM_UID);
-            callCallback(NetworkStatsManager.CALLBACK_RELEASED);
-        }
-
-        @Override
-        public String toString() {
-            return "RequestInfo from uid:" + mCallingUid
-                    + " for " + mRequest + " accessLevel:" + mAccessLevel;
-        }
-
-        private void unlinkDeathRecipient() {
-            mCallback.asBinder().unlinkToDeath(this, 0);
-        }
-
-        /**
-         * Update stats given the samples and interface to identity mappings.
-         */
-        private void updateStats(StatsContext statsContext) {
-            if (mRecorder == null) {
-                // First run; establish baseline stats
-                resetRecorder();
-                recordSample(statsContext);
-                return;
-            }
-            recordSample(statsContext);
-
-            if (checkStats()) {
-                resetRecorder();
-                callCallback(NetworkStatsManager.CALLBACK_LIMIT_REACHED);
-            }
-        }
-
-        private void callCallback(int callbackType) {
-            try {
-                if (LOGV) {
-                    Log.v(TAG, "sending notification " + callbackTypeToName(callbackType)
-                            + " for " + mRequest);
-                }
-                switch (callbackType) {
-                    case NetworkStatsManager.CALLBACK_LIMIT_REACHED:
-                        mCallback.onThresholdReached(mRequest);
-                        break;
-                    case NetworkStatsManager.CALLBACK_RELEASED:
-                        mCallback.onCallbackReleased(mRequest);
-                        break;
-                }
-            } catch (RemoteException e) {
-                // May occur naturally in the race of binder death.
-                Log.w(TAG, "RemoteException caught trying to send a callback msg for " + mRequest);
-            }
-        }
-
-        private void resetRecorder() {
-            mRecorder = new NetworkStatsRecorder();
-            mCollection = mRecorder.getSinceBoot();
-        }
-
-        protected abstract boolean checkStats();
-
-        protected abstract void recordSample(StatsContext statsContext);
-
-        private String callbackTypeToName(int callbackType) {
-            switch (callbackType) {
-                case NetworkStatsManager.CALLBACK_LIMIT_REACHED:
-                    return "LIMIT_REACHED";
-                case NetworkStatsManager.CALLBACK_RELEASED:
-                    return "RELEASED";
-                default:
-                    return "UNKNOWN";
-            }
-        }
-    }
-
-    private static class NetworkUsageRequestInfo extends RequestInfo {
-        NetworkUsageRequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request,
-                IUsageCallback callback, int callingUid,
-                    @NetworkStatsAccess.Level int accessLevel) {
-            super(statsObserver, request, callback, callingUid, accessLevel);
-        }
-
-        @Override
-        protected boolean checkStats() {
-            long bytesSoFar = getTotalBytesForNetwork(mRequest.template);
-            if (LOGV) {
-                Log.v(TAG, bytesSoFar + " bytes so far since notification for "
-                        + mRequest.template);
-            }
-            if (bytesSoFar > mRequest.thresholdInBytes) {
-                return true;
-            }
-            return false;
-        }
-
-        @Override
-        protected void recordSample(StatsContext statsContext) {
-            // Recorder does not need to be locked in this context since only the handler
-            // thread will update it. We pass a null VPN array because usage is aggregated by uid
-            // for this snapshot, so VPN traffic can't be reattributed to responsible apps.
-            mRecorder.recordSnapshotLocked(statsContext.mXtSnapshot, statsContext.mActiveIfaces,
-                    statsContext.mCurrentTime);
-        }
-
-        /**
-         * Reads stats matching the given template. {@link NetworkStatsCollection} will aggregate
-         * over all buckets, which in this case should be only one since we built it big enough
-         * that it will outlive the caller. If it doesn't, then there will be multiple buckets.
-         */
-        private long getTotalBytesForNetwork(NetworkTemplate template) {
-            NetworkStats stats = mCollection.getSummary(template,
-                    Long.MIN_VALUE /* start */, Long.MAX_VALUE /* end */,
-                    mAccessLevel, mCallingUid);
-            return stats.getTotalBytes();
-        }
-    }
-
-    private static class UserUsageRequestInfo extends RequestInfo {
-        UserUsageRequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request,
-                    IUsageCallback callback, int callingUid,
-                    @NetworkStatsAccess.Level int accessLevel) {
-            super(statsObserver, request, callback, callingUid, accessLevel);
-        }
-
-        @Override
-        protected boolean checkStats() {
-            int[] uidsToMonitor = mCollection.getRelevantUids(mAccessLevel, mCallingUid);
-
-            for (int i = 0; i < uidsToMonitor.length; i++) {
-                long bytesSoFar = getTotalBytesForNetworkUid(mRequest.template, uidsToMonitor[i]);
-                if (bytesSoFar > mRequest.thresholdInBytes) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        @Override
-        protected void recordSample(StatsContext statsContext) {
-            // Recorder does not need to be locked in this context since only the handler
-            // thread will update it. We pass the VPN info so VPN traffic is reattributed to
-            // responsible apps.
-            mRecorder.recordSnapshotLocked(statsContext.mUidSnapshot, statsContext.mActiveUidIfaces,
-                    statsContext.mCurrentTime);
-        }
-
-        /**
-         * Reads all stats matching the given template and uid. Ther history will likely only
-         * contain one bucket per ident since we build it big enough that it will outlive the
-         * caller lifetime.
-         */
-        private long getTotalBytesForNetworkUid(NetworkTemplate template, int uid) {
-            try {
-                NetworkStatsHistory history = mCollection.getHistory(template, null, uid,
-                        NetworkStats.SET_ALL, NetworkStats.TAG_NONE,
-                        NetworkStatsHistory.FIELD_ALL,
-                        Long.MIN_VALUE /* start */, Long.MAX_VALUE /* end */,
-                        mAccessLevel, mCallingUid);
-                return history.getTotalBytes();
-            } catch (SecurityException e) {
-                if (LOGV) {
-                    Log.w(TAG, "CallerUid " + mCallingUid + " may have lost access to uid "
-                            + uid);
-                }
-                return 0;
-            }
-        }
-    }
-
-    private static class StatsContext {
-        NetworkStats mXtSnapshot;
-        NetworkStats mUidSnapshot;
-        ArrayMap<String, NetworkIdentitySet> mActiveIfaces;
-        ArrayMap<String, NetworkIdentitySet> mActiveUidIfaces;
-        long mCurrentTime;
-
-        StatsContext(NetworkStats xtSnapshot, NetworkStats uidSnapshot,
-                ArrayMap<String, NetworkIdentitySet> activeIfaces,
-                ArrayMap<String, NetworkIdentitySet> activeUidIfaces,
-                long currentTime) {
-            mXtSnapshot = xtSnapshot;
-            mUidSnapshot = uidSnapshot;
-            mActiveIfaces = activeIfaces;
-            mActiveUidIfaces = activeUidIfaces;
-            mCurrentTime = currentTime;
-        }
-    }
-}
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java
deleted file mode 100644
index f62765d..0000000
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.net;
-
-import static android.net.NetworkStats.TAG_NONE;
-import static android.net.TrafficStats.KB_IN_BYTES;
-import static android.net.TrafficStats.MB_IN_BYTES;
-import static android.text.format.DateUtils.YEAR_IN_MILLIS;
-
-import android.net.NetworkIdentitySet;
-import android.net.NetworkStats;
-import android.net.NetworkStats.NonMonotonicObserver;
-import android.net.NetworkStatsAccess;
-import android.net.NetworkStatsCollection;
-import android.net.NetworkStatsHistory;
-import android.net.NetworkTemplate;
-import android.net.TrafficStats;
-import android.os.Binder;
-import android.os.DropBoxManager;
-import android.service.NetworkStatsRecorderProto;
-import android.util.IndentingPrintWriter;
-import android.util.Log;
-import android.util.proto.ProtoOutputStream;
-
-import com.android.internal.util.FileRotator;
-import com.android.net.module.util.NetworkStatsUtils;
-
-import libcore.io.IoUtils;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * Logic to record deltas between periodic {@link NetworkStats} snapshots into
- * {@link NetworkStatsHistory} that belong to {@link NetworkStatsCollection}.
- * Keeps pending changes in memory until they pass a specific threshold, in
- * bytes. Uses {@link FileRotator} for persistence logic if present.
- * <p>
- * Not inherently thread safe.
- */
-public class NetworkStatsRecorder {
-    private static final String TAG = "NetworkStatsRecorder";
-    private static final boolean LOGD = false;
-    private static final boolean LOGV = false;
-
-    private static final String TAG_NETSTATS_DUMP = "netstats_dump";
-
-    /** Dump before deleting in {@link #recoverFromWtf()}. */
-    private static final boolean DUMP_BEFORE_DELETE = true;
-
-    private final FileRotator mRotator;
-    private final NonMonotonicObserver<String> mObserver;
-    private final DropBoxManager mDropBox;
-    private final String mCookie;
-
-    private final long mBucketDuration;
-    private final boolean mOnlyTags;
-
-    private long mPersistThresholdBytes = 2 * MB_IN_BYTES;
-    private NetworkStats mLastSnapshot;
-
-    private final NetworkStatsCollection mPending;
-    private final NetworkStatsCollection mSinceBoot;
-
-    private final CombiningRewriter mPendingRewriter;
-
-    private WeakReference<NetworkStatsCollection> mComplete;
-
-    /**
-     * Non-persisted recorder, with only one bucket. Used by {@link NetworkStatsObservers}.
-     */
-    public NetworkStatsRecorder() {
-        mRotator = null;
-        mObserver = null;
-        mDropBox = null;
-        mCookie = null;
-
-        // set the bucket big enough to have all data in one bucket, but allow some
-        // slack to avoid overflow
-        mBucketDuration = YEAR_IN_MILLIS;
-        mOnlyTags = false;
-
-        mPending = null;
-        mSinceBoot = new NetworkStatsCollection(mBucketDuration);
-
-        mPendingRewriter = null;
-    }
-
-    /**
-     * Persisted recorder.
-     */
-    public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver<String> observer,
-            DropBoxManager dropBox, String cookie, long bucketDuration, boolean onlyTags) {
-        mRotator = Objects.requireNonNull(rotator, "missing FileRotator");
-        mObserver = Objects.requireNonNull(observer, "missing NonMonotonicObserver");
-        mDropBox = Objects.requireNonNull(dropBox, "missing DropBoxManager");
-        mCookie = cookie;
-
-        mBucketDuration = bucketDuration;
-        mOnlyTags = onlyTags;
-
-        mPending = new NetworkStatsCollection(bucketDuration);
-        mSinceBoot = new NetworkStatsCollection(bucketDuration);
-
-        mPendingRewriter = new CombiningRewriter(mPending);
-    }
-
-    public void setPersistThreshold(long thresholdBytes) {
-        if (LOGV) Log.v(TAG, "setPersistThreshold() with " + thresholdBytes);
-        mPersistThresholdBytes = NetworkStatsUtils.constrain(
-                thresholdBytes, 1 * KB_IN_BYTES, 100 * MB_IN_BYTES);
-    }
-
-    public void resetLocked() {
-        mLastSnapshot = null;
-        if (mPending != null) {
-            mPending.reset();
-        }
-        if (mSinceBoot != null) {
-            mSinceBoot.reset();
-        }
-        if (mComplete != null) {
-            mComplete.clear();
-        }
-    }
-
-    public NetworkStats.Entry getTotalSinceBootLocked(NetworkTemplate template) {
-        return mSinceBoot.getSummary(template, Long.MIN_VALUE, Long.MAX_VALUE,
-                NetworkStatsAccess.Level.DEVICE, Binder.getCallingUid()).getTotal(null);
-    }
-
-    public NetworkStatsCollection getSinceBoot() {
-        return mSinceBoot;
-    }
-
-    /**
-     * Load complete history represented by {@link FileRotator}. Caches
-     * internally as a {@link WeakReference}, and updated with future
-     * {@link #recordSnapshotLocked(NetworkStats, Map, long)} snapshots as long
-     * as reference is valid.
-     */
-    public NetworkStatsCollection getOrLoadCompleteLocked() {
-        Objects.requireNonNull(mRotator, "missing FileRotator");
-        NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
-        if (res == null) {
-            res = loadLocked(Long.MIN_VALUE, Long.MAX_VALUE);
-            mComplete = new WeakReference<NetworkStatsCollection>(res);
-        }
-        return res;
-    }
-
-    public NetworkStatsCollection getOrLoadPartialLocked(long start, long end) {
-        Objects.requireNonNull(mRotator, "missing FileRotator");
-        NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
-        if (res == null) {
-            res = loadLocked(start, end);
-        }
-        return res;
-    }
-
-    private NetworkStatsCollection loadLocked(long start, long end) {
-        if (LOGD) Log.d(TAG, "loadLocked() reading from disk for " + mCookie);
-        final NetworkStatsCollection res = new NetworkStatsCollection(mBucketDuration);
-        try {
-            mRotator.readMatching(res, start, end);
-            res.recordCollection(mPending);
-        } catch (IOException e) {
-            Log.wtf(TAG, "problem completely reading network stats", e);
-            recoverFromWtf();
-        } catch (OutOfMemoryError e) {
-            Log.wtf(TAG, "problem completely reading network stats", e);
-            recoverFromWtf();
-        }
-        return res;
-    }
-
-    /**
-     * Record any delta that occurred since last {@link NetworkStats} snapshot, using the given
-     * {@link Map} to identify network interfaces. First snapshot is considered bootstrap, and is
-     * not counted as delta.
-     */
-    public void recordSnapshotLocked(NetworkStats snapshot,
-            Map<String, NetworkIdentitySet> ifaceIdent, long currentTimeMillis) {
-        final HashSet<String> unknownIfaces = new HashSet<>();
-
-        // skip recording when snapshot missing
-        if (snapshot == null) return;
-
-        // assume first snapshot is bootstrap and don't record
-        if (mLastSnapshot == null) {
-            mLastSnapshot = snapshot;
-            return;
-        }
-
-        final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
-
-        final NetworkStats delta = NetworkStats.subtract(
-                snapshot, mLastSnapshot, mObserver, mCookie);
-        final long end = currentTimeMillis;
-        final long start = end - delta.getElapsedRealtime();
-
-        NetworkStats.Entry entry = null;
-        for (int i = 0; i < delta.size(); i++) {
-            entry = delta.getValues(i, entry);
-
-            // As a last-ditch check, report any negative values and
-            // clamp them so recording below doesn't croak.
-            if (entry.isNegative()) {
-                if (mObserver != null) {
-                    mObserver.foundNonMonotonic(delta, i, mCookie);
-                }
-                entry.rxBytes = Math.max(entry.rxBytes, 0);
-                entry.rxPackets = Math.max(entry.rxPackets, 0);
-                entry.txBytes = Math.max(entry.txBytes, 0);
-                entry.txPackets = Math.max(entry.txPackets, 0);
-                entry.operations = Math.max(entry.operations, 0);
-            }
-
-            final NetworkIdentitySet ident = ifaceIdent.get(entry.iface);
-            if (ident == null) {
-                unknownIfaces.add(entry.iface);
-                continue;
-            }
-
-            // skip when no delta occurred
-            if (entry.isEmpty()) continue;
-
-            // only record tag data when requested
-            if ((entry.tag == TAG_NONE) != mOnlyTags) {
-                if (mPending != null) {
-                    mPending.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
-                }
-
-                // also record against boot stats when present
-                if (mSinceBoot != null) {
-                    mSinceBoot.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
-                }
-
-                // also record against complete dataset when present
-                if (complete != null) {
-                    complete.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
-                }
-            }
-        }
-
-        mLastSnapshot = snapshot;
-
-        if (LOGV && unknownIfaces.size() > 0) {
-            Log.w(TAG, "unknown interfaces " + unknownIfaces + ", ignoring those stats");
-        }
-    }
-
-    /**
-     * Consider persisting any pending deltas, if they are beyond
-     * {@link #mPersistThresholdBytes}.
-     */
-    public void maybePersistLocked(long currentTimeMillis) {
-        Objects.requireNonNull(mRotator, "missing FileRotator");
-        final long pendingBytes = mPending.getTotalBytes();
-        if (pendingBytes >= mPersistThresholdBytes) {
-            forcePersistLocked(currentTimeMillis);
-        } else {
-            mRotator.maybeRotate(currentTimeMillis);
-        }
-    }
-
-    /**
-     * Force persisting any pending deltas.
-     */
-    public void forcePersistLocked(long currentTimeMillis) {
-        Objects.requireNonNull(mRotator, "missing FileRotator");
-        if (mPending.isDirty()) {
-            if (LOGD) Log.d(TAG, "forcePersistLocked() writing for " + mCookie);
-            try {
-                mRotator.rewriteActive(mPendingRewriter, currentTimeMillis);
-                mRotator.maybeRotate(currentTimeMillis);
-                mPending.reset();
-            } catch (IOException e) {
-                Log.wtf(TAG, "problem persisting pending stats", e);
-                recoverFromWtf();
-            } catch (OutOfMemoryError e) {
-                Log.wtf(TAG, "problem persisting pending stats", e);
-                recoverFromWtf();
-            }
-        }
-    }
-
-    /**
-     * Remove the given UID from all {@link FileRotator} history, migrating it
-     * to {@link TrafficStats#UID_REMOVED}.
-     */
-    public void removeUidsLocked(int[] uids) {
-        if (mRotator != null) {
-            try {
-                // Rewrite all persisted data to migrate UID stats
-                mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uids));
-            } catch (IOException e) {
-                Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
-                recoverFromWtf();
-            } catch (OutOfMemoryError e) {
-                Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
-                recoverFromWtf();
-            }
-        }
-
-        // Remove any pending stats
-        if (mPending != null) {
-            mPending.removeUids(uids);
-        }
-        if (mSinceBoot != null) {
-            mSinceBoot.removeUids(uids);
-        }
-
-        // Clear UID from current stats snapshot
-        if (mLastSnapshot != null) {
-            mLastSnapshot.removeUids(uids);
-        }
-
-        final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
-        if (complete != null) {
-            complete.removeUids(uids);
-        }
-    }
-
-    /**
-     * Rewriter that will combine current {@link NetworkStatsCollection} values
-     * with anything read from disk, and write combined set to disk. Clears the
-     * original {@link NetworkStatsCollection} when finished writing.
-     */
-    private static class CombiningRewriter implements FileRotator.Rewriter {
-        private final NetworkStatsCollection mCollection;
-
-        public CombiningRewriter(NetworkStatsCollection collection) {
-            mCollection = Objects.requireNonNull(collection, "missing NetworkStatsCollection");
-        }
-
-        @Override
-        public void reset() {
-            // ignored
-        }
-
-        @Override
-        public void read(InputStream in) throws IOException {
-            mCollection.read(in);
-        }
-
-        @Override
-        public boolean shouldWrite() {
-            return true;
-        }
-
-        @Override
-        public void write(OutputStream out) throws IOException {
-            mCollection.write(out);
-            mCollection.reset();
-        }
-    }
-
-    /**
-     * Rewriter that will remove any {@link NetworkStatsHistory} attributed to
-     * the requested UID, only writing data back when modified.
-     */
-    public static class RemoveUidRewriter implements FileRotator.Rewriter {
-        private final NetworkStatsCollection mTemp;
-        private final int[] mUids;
-
-        public RemoveUidRewriter(long bucketDuration, int[] uids) {
-            mTemp = new NetworkStatsCollection(bucketDuration);
-            mUids = uids;
-        }
-
-        @Override
-        public void reset() {
-            mTemp.reset();
-        }
-
-        @Override
-        public void read(InputStream in) throws IOException {
-            mTemp.read(in);
-            mTemp.clearDirty();
-            mTemp.removeUids(mUids);
-        }
-
-        @Override
-        public boolean shouldWrite() {
-            return mTemp.isDirty();
-        }
-
-        @Override
-        public void write(OutputStream out) throws IOException {
-            mTemp.write(out);
-        }
-    }
-
-    public void importLegacyNetworkLocked(File file) throws IOException {
-        Objects.requireNonNull(mRotator, "missing FileRotator");
-
-        // legacy file still exists; start empty to avoid double importing
-        mRotator.deleteAll();
-
-        final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration);
-        collection.readLegacyNetwork(file);
-
-        final long startMillis = collection.getStartMillis();
-        final long endMillis = collection.getEndMillis();
-
-        if (!collection.isEmpty()) {
-            // process legacy data, creating active file at starting time, then
-            // using end time to possibly trigger rotation.
-            mRotator.rewriteActive(new CombiningRewriter(collection), startMillis);
-            mRotator.maybeRotate(endMillis);
-        }
-    }
-
-    public void importLegacyUidLocked(File file) throws IOException {
-        Objects.requireNonNull(mRotator, "missing FileRotator");
-
-        // legacy file still exists; start empty to avoid double importing
-        mRotator.deleteAll();
-
-        final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration);
-        collection.readLegacyUid(file, mOnlyTags);
-
-        final long startMillis = collection.getStartMillis();
-        final long endMillis = collection.getEndMillis();
-
-        if (!collection.isEmpty()) {
-            // process legacy data, creating active file at starting time, then
-            // using end time to possibly trigger rotation.
-            mRotator.rewriteActive(new CombiningRewriter(collection), startMillis);
-            mRotator.maybeRotate(endMillis);
-        }
-    }
-
-    public void dumpLocked(IndentingPrintWriter pw, boolean fullHistory) {
-        if (mPending != null) {
-            pw.print("Pending bytes: "); pw.println(mPending.getTotalBytes());
-        }
-        if (fullHistory) {
-            pw.println("Complete history:");
-            getOrLoadCompleteLocked().dump(pw);
-        } else {
-            pw.println("History since boot:");
-            mSinceBoot.dump(pw);
-        }
-    }
-
-    public void dumpDebugLocked(ProtoOutputStream proto, long tag) {
-        final long start = proto.start(tag);
-        if (mPending != null) {
-            proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES,
-                    mPending.getTotalBytes());
-        }
-        getOrLoadCompleteLocked().dumpDebug(proto,
-                NetworkStatsRecorderProto.COMPLETE_HISTORY);
-        proto.end(start);
-    }
-
-    public void dumpCheckin(PrintWriter pw, long start, long end) {
-        // Only load and dump stats from the requested window
-        getOrLoadPartialLocked(start, end).dumpCheckin(pw, start, end);
-    }
-
-    /**
-     * Recover from {@link FileRotator} failure by dumping state to
-     * {@link DropBoxManager} and deleting contents.
-     */
-    private void recoverFromWtf() {
-        if (DUMP_BEFORE_DELETE) {
-            final ByteArrayOutputStream os = new ByteArrayOutputStream();
-            try {
-                mRotator.dumpAll(os);
-            } catch (IOException e) {
-                // ignore partial contents
-                os.reset();
-            } finally {
-                IoUtils.closeQuietly(os);
-            }
-            mDropBox.addData(TAG_NETSTATS_DUMP, os.toByteArray(), 0);
-        }
-
-        mRotator.deleteAll();
-    }
-}
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
deleted file mode 100644
index 1d22908..0000000
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
+++ /dev/null
@@ -1,2521 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.net;
-
-import static android.Manifest.permission.NETWORK_STATS_PROVIDER;
-import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
-import static android.Manifest.permission.UPDATE_DEVICE_STATS;
-import static android.app.usage.NetworkStatsManager.PREFIX_DEV;
-import static android.content.Intent.ACTION_SHUTDOWN;
-import static android.content.Intent.ACTION_UID_REMOVED;
-import static android.content.Intent.ACTION_USER_REMOVED;
-import static android.content.Intent.EXTRA_UID;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
-import static android.net.NetworkStats.IFACE_ALL;
-import static android.net.NetworkStats.IFACE_VT;
-import static android.net.NetworkStats.INTERFACES_ALL;
-import static android.net.NetworkStats.METERED_ALL;
-import static android.net.NetworkStats.ROAMING_ALL;
-import static android.net.NetworkStats.SET_ALL;
-import static android.net.NetworkStats.SET_DEFAULT;
-import static android.net.NetworkStats.SET_FOREGROUND;
-import static android.net.NetworkStats.STATS_PER_IFACE;
-import static android.net.NetworkStats.STATS_PER_UID;
-import static android.net.NetworkStats.TAG_ALL;
-import static android.net.NetworkStats.TAG_NONE;
-import static android.net.NetworkStats.UID_ALL;
-import static android.net.NetworkStatsHistory.FIELD_ALL;
-import static android.net.NetworkTemplate.buildTemplateMobileWildcard;
-import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
-import static android.net.TrafficStats.KB_IN_BYTES;
-import static android.net.TrafficStats.MB_IN_BYTES;
-import static android.net.TrafficStats.UID_TETHERING;
-import static android.net.TrafficStats.UNSUPPORTED;
-import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_UID;
-import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_UID_TAG;
-import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_XT;
-import static android.os.Trace.TRACE_TAG_NETWORK;
-import static android.system.OsConstants.ENOENT;
-import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-import static android.text.format.DateUtils.DAY_IN_MILLIS;
-import static android.text.format.DateUtils.HOUR_IN_MILLIS;
-import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
-import static android.text.format.DateUtils.SECOND_IN_MILLIS;
-
-import static com.android.net.module.util.NetworkCapabilitiesUtils.getDisplayTransport;
-import static com.android.net.module.util.NetworkStatsUtils.LIMIT_GLOBAL_ALERT;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.TargetApi;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.app.usage.NetworkStatsManager;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.database.ContentObserver;
-import android.net.DataUsageRequest;
-import android.net.INetd;
-import android.net.INetworkStatsService;
-import android.net.INetworkStatsSession;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkIdentity;
-import android.net.NetworkIdentitySet;
-import android.net.NetworkPolicyManager;
-import android.net.NetworkSpecifier;
-import android.net.NetworkStack;
-import android.net.NetworkStateSnapshot;
-import android.net.NetworkStats;
-import android.net.NetworkStats.NonMonotonicObserver;
-import android.net.NetworkStatsAccess;
-import android.net.NetworkStatsCollection;
-import android.net.NetworkStatsHistory;
-import android.net.NetworkTemplate;
-import android.net.TelephonyNetworkSpecifier;
-import android.net.TetherStatsParcel;
-import android.net.TetheringManager;
-import android.net.TrafficStats;
-import android.net.UnderlyingNetworkInfo;
-import android.net.Uri;
-import android.net.netstats.IUsageCallback;
-import android.net.netstats.provider.INetworkStatsProvider;
-import android.net.netstats.provider.INetworkStatsProviderCallback;
-import android.net.netstats.provider.NetworkStatsProvider;
-import android.os.Binder;
-import android.os.Build;
-import android.os.DropBoxManager;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.ServiceSpecificException;
-import android.os.SystemClock;
-import android.os.Trace;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.provider.Settings.Global;
-import android.service.NetworkInterfaceProto;
-import android.service.NetworkStatsServiceDumpProto;
-import android.system.ErrnoException;
-import android.telephony.PhoneStateListener;
-import android.telephony.SubscriptionPlan;
-import android.text.TextUtils;
-import android.text.format.DateUtils;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.EventLog;
-import android.util.IndentingPrintWriter;
-import android.util.Log;
-import android.util.SparseIntArray;
-import android.util.proto.ProtoOutputStream;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FileRotator;
-import com.android.net.module.util.BaseNetdUnsolicitedEventListener;
-import com.android.net.module.util.BestClock;
-import com.android.net.module.util.BinderUtils;
-import com.android.net.module.util.BpfMap;
-import com.android.net.module.util.CollectionUtils;
-import com.android.net.module.util.IBpfMap;
-import com.android.net.module.util.LocationPermissionChecker;
-import com.android.net.module.util.NetworkStatsUtils;
-import com.android.net.module.util.PermissionUtils;
-import com.android.net.module.util.Struct.U32;
-import com.android.net.module.util.Struct.U8;
-
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.time.Clock;
-import java.time.ZoneOffset;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Collect and persist detailed network statistics, and provide this data to
- * other system services.
- */
-@TargetApi(Build.VERSION_CODES.TIRAMISU)
-public class NetworkStatsService extends INetworkStatsService.Stub {
-    static {
-        System.loadLibrary("service-connectivity");
-    }
-
-    static final String TAG = "NetworkStats";
-    static final boolean LOGD = Log.isLoggable(TAG, Log.DEBUG);
-    static final boolean LOGV = Log.isLoggable(TAG, Log.VERBOSE);
-
-    // Perform polling and persist all (FLAG_PERSIST_ALL).
-    private static final int MSG_PERFORM_POLL = 1;
-    // Perform polling, persist network, and register the global alert again.
-    private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 2;
-    private static final int MSG_NOTIFY_NETWORK_STATUS = 3;
-    // A message for broadcasting ACTION_NETWORK_STATS_UPDATED in handler thread to prevent
-    // deadlock.
-    private static final int MSG_BROADCAST_NETWORK_STATS_UPDATED = 4;
-
-    /** Flags to control detail level of poll event. */
-    private static final int FLAG_PERSIST_NETWORK = 0x1;
-    private static final int FLAG_PERSIST_UID = 0x2;
-    private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID;
-    private static final int FLAG_PERSIST_FORCE = 0x100;
-
-    /**
-     * When global alert quota is high, wait for this delay before processing each polling,
-     * and do not schedule further polls once there is already one queued.
-     * This avoids firing the global alert too often on devices with high transfer speeds and
-     * high quota.
-     */
-    private static final int DEFAULT_PERFORM_POLL_DELAY_MS = 1000;
-
-    private static final String TAG_NETSTATS_ERROR = "netstats_error";
-
-    /**
-     * EventLog tags used when logging into the event log. Note the values must be sync with
-     * frameworks/base/services/core/java/com/android/server/EventLogTags.logtags to get correct
-     * name translation.
-      */
-    private static final int LOG_TAG_NETSTATS_MOBILE_SAMPLE = 51100;
-    private static final int LOG_TAG_NETSTATS_WIFI_SAMPLE = 51101;
-
-    // TODO: Replace the hardcoded string and move it into ConnectivitySettingsManager.
-    private static final String NETSTATS_COMBINE_SUBTYPE_ENABLED =
-            "netstats_combine_subtype_enabled";
-
-    // This is current path but may be changed soon.
-    private static final String UID_COUNTERSET_MAP_PATH =
-            "/sys/fs/bpf/map_netd_uid_counterset_map";
-    private static final String COOKIE_TAG_MAP_PATH =
-            "/sys/fs/bpf/map_netd_cookie_tag_map";
-    private static final String APP_UID_STATS_MAP_PATH =
-            "/sys/fs/bpf/map_netd_app_uid_stats_map";
-    private static final String STATS_MAP_A_PATH =
-            "/sys/fs/bpf/map_netd_stats_map_A";
-    private static final String STATS_MAP_B_PATH =
-            "/sys/fs/bpf/map_netd_stats_map_B";
-
-    private final Context mContext;
-    private final NetworkStatsFactory mStatsFactory;
-    private final AlarmManager mAlarmManager;
-    private final Clock mClock;
-    private final NetworkStatsSettings mSettings;
-    private final NetworkStatsObservers mStatsObservers;
-
-    private final File mSystemDir;
-    private final File mBaseDir;
-
-    private final PowerManager.WakeLock mWakeLock;
-
-    private final ContentObserver mContentObserver;
-    private final ContentResolver mContentResolver;
-
-    protected INetd mNetd;
-    private final AlertObserver mAlertObserver = new AlertObserver();
-
-    @VisibleForTesting
-    public static final String ACTION_NETWORK_STATS_POLL =
-            "com.android.server.action.NETWORK_STATS_POLL";
-    public static final String ACTION_NETWORK_STATS_UPDATED =
-            "com.android.server.action.NETWORK_STATS_UPDATED";
-
-    private PendingIntent mPollIntent;
-
-    /**
-     * Settings that can be changed externally.
-     */
-    public interface NetworkStatsSettings {
-        long getPollInterval();
-        long getPollDelay();
-        boolean getSampleEnabled();
-        boolean getAugmentEnabled();
-        /**
-         * When enabled, all mobile data is reported under {@link NetworkTemplate#NETWORK_TYPE_ALL}.
-         * When disabled, mobile data is broken down by a granular ratType representative of the
-         * actual ratType. {@see android.app.usage.NetworkStatsManager#getCollapsedRatType}.
-         * Enabling this decreases the level of detail but saves performance, disk space and
-         * amount of data logged.
-         */
-        boolean getCombineSubtypeEnabled();
-
-        class Config {
-            public final long bucketDuration;
-            public final long rotateAgeMillis;
-            public final long deleteAgeMillis;
-
-            public Config(long bucketDuration, long rotateAgeMillis, long deleteAgeMillis) {
-                this.bucketDuration = bucketDuration;
-                this.rotateAgeMillis = rotateAgeMillis;
-                this.deleteAgeMillis = deleteAgeMillis;
-            }
-        }
-
-        Config getDevConfig();
-        Config getXtConfig();
-        Config getUidConfig();
-        Config getUidTagConfig();
-
-        long getGlobalAlertBytes(long def);
-        long getDevPersistBytes(long def);
-        long getXtPersistBytes(long def);
-        long getUidPersistBytes(long def);
-        long getUidTagPersistBytes(long def);
-    }
-
-    private final Object mStatsLock = new Object();
-
-    /** Set of currently active ifaces. */
-    @GuardedBy("mStatsLock")
-    private final ArrayMap<String, NetworkIdentitySet> mActiveIfaces = new ArrayMap<>();
-
-    /** Set of currently active ifaces for UID stats. */
-    @GuardedBy("mStatsLock")
-    private final ArrayMap<String, NetworkIdentitySet> mActiveUidIfaces = new ArrayMap<>();
-
-    /** Current default active iface. */
-    @GuardedBy("mStatsLock")
-    private String mActiveIface;
-
-    /** Set of any ifaces associated with mobile networks since boot. */
-    private volatile String[] mMobileIfaces = new String[0];
-
-    /** Set of any ifaces associated with wifi networks since boot. */
-    private volatile String[] mWifiIfaces = new String[0];
-
-    /** Set of all ifaces currently used by traffic that does not explicitly specify a Network. */
-    @GuardedBy("mStatsLock")
-    private Network[] mDefaultNetworks = new Network[0];
-
-    /** Last states of all networks sent from ConnectivityService. */
-    @GuardedBy("mStatsLock")
-    @Nullable
-    private NetworkStateSnapshot[] mLastNetworkStateSnapshots = null;
-
-    private final DropBoxNonMonotonicObserver mNonMonotonicObserver =
-            new DropBoxNonMonotonicObserver();
-
-    private static final int MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS = 100;
-    private final CopyOnWriteArrayList<NetworkStatsProviderCallbackImpl> mStatsProviderCbList =
-            new CopyOnWriteArrayList<>();
-    /** Semaphore used to wait for stats provider to respond to request stats update. */
-    private final Semaphore mStatsProviderSem = new Semaphore(0, true);
-
-    @GuardedBy("mStatsLock")
-    private NetworkStatsRecorder mDevRecorder;
-    @GuardedBy("mStatsLock")
-    private NetworkStatsRecorder mXtRecorder;
-    @GuardedBy("mStatsLock")
-    private NetworkStatsRecorder mUidRecorder;
-    @GuardedBy("mStatsLock")
-    private NetworkStatsRecorder mUidTagRecorder;
-
-    /** Cached {@link #mXtRecorder} stats. */
-    @GuardedBy("mStatsLock")
-    private NetworkStatsCollection mXtStatsCached;
-
-    /**
-     * Current counter sets for each UID.
-     * TODO: maybe remove mActiveUidCounterSet and read UidCouneterSet value from mUidCounterSetMap
-     * directly ? But if mActiveUidCounterSet would be accessed very frequently, maybe keep
-     * mActiveUidCounterSet to avoid accessing kernel too frequently.
-     */
-    private SparseIntArray mActiveUidCounterSet = new SparseIntArray();
-    private final IBpfMap<U32, U8> mUidCounterSetMap;
-    private final IBpfMap<CookieTagMapKey, CookieTagMapValue> mCookieTagMap;
-    private final IBpfMap<StatsMapKey, StatsMapValue> mStatsMapA;
-    private final IBpfMap<StatsMapKey, StatsMapValue> mStatsMapB;
-    private final IBpfMap<UidStatsMapKey, StatsMapValue> mAppUidStatsMap;
-
-    /** Data layer operation counters for splicing into other structures. */
-    private NetworkStats mUidOperations = new NetworkStats(0L, 10);
-
-    @NonNull
-    private final Handler mHandler;
-
-    private volatile boolean mSystemReady;
-    private long mPersistThreshold = 2 * MB_IN_BYTES;
-    private long mGlobalAlertBytes;
-
-    private static final long POLL_RATE_LIMIT_MS = 15_000;
-
-    private long mLastStatsSessionPoll;
-
-    /** Map from UID to number of opened sessions */
-    @GuardedBy("mOpenSessionCallsPerUid")
-    private final SparseIntArray mOpenSessionCallsPerUid = new SparseIntArray();
-
-    private final static int DUMP_STATS_SESSION_COUNT = 20;
-
-    @NonNull
-    private final Dependencies mDeps;
-
-    @NonNull
-    private final NetworkStatsSubscriptionsMonitor mNetworkStatsSubscriptionsMonitor;
-
-    @NonNull
-    private final LocationPermissionChecker mLocationPermissionChecker;
-
-    @NonNull
-    private final BpfInterfaceMapUpdater mInterfaceMapUpdater;
-
-    private static @NonNull File getDefaultSystemDir() {
-        return new File(Environment.getDataDirectory(), "system");
-    }
-
-    private static @NonNull File getDefaultBaseDir() {
-        File baseDir = new File(getDefaultSystemDir(), "netstats");
-        baseDir.mkdirs();
-        return baseDir;
-    }
-
-    private static @NonNull Clock getDefaultClock() {
-        return new BestClock(ZoneOffset.UTC, SystemClock.currentNetworkTimeClock(),
-                Clock.systemUTC());
-    }
-
-    private final class NetworkStatsHandler extends Handler {
-        NetworkStatsHandler(@NonNull Looper looper) {
-            super(looper);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_PERFORM_POLL: {
-                    performPoll(FLAG_PERSIST_ALL);
-                    break;
-                }
-                case MSG_NOTIFY_NETWORK_STATUS: {
-                    // If no cached states, ignore.
-                    if (mLastNetworkStateSnapshots == null) break;
-                    // TODO (b/181642673): Protect mDefaultNetworks from concurrent accessing.
-                    handleNotifyNetworkStatus(
-                            mDefaultNetworks, mLastNetworkStateSnapshots, mActiveIface);
-                    break;
-                }
-                case MSG_PERFORM_POLL_REGISTER_ALERT: {
-                    performPoll(FLAG_PERSIST_NETWORK);
-                    registerGlobalAlert();
-                    break;
-                }
-                case MSG_BROADCAST_NETWORK_STATS_UPDATED: {
-                    final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED);
-                    updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-                    mContext.sendBroadcastAsUser(updatedIntent, UserHandle.ALL,
-                            READ_NETWORK_USAGE_HISTORY);
-                    break;
-                }
-            }
-        }
-    }
-
-    /** Creates a new NetworkStatsService */
-    public static NetworkStatsService create(Context context) {
-        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
-        PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-        PowerManager.WakeLock wakeLock =
-                powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
-        final INetd netd = INetd.Stub.asInterface(
-                (IBinder) context.getSystemService(Context.NETD_SERVICE));
-        final NetworkStatsService service = new NetworkStatsService(context,
-                INetd.Stub.asInterface((IBinder) context.getSystemService(Context.NETD_SERVICE)),
-                alarmManager, wakeLock, getDefaultClock(),
-                new DefaultNetworkStatsSettings(), new NetworkStatsFactory(context),
-                new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir(),
-                new Dependencies());
-
-        return service;
-    }
-
-    // This must not be called outside of tests, even within the same package, as this constructor
-    // does not register the local service. Use the create() helper above.
-    @VisibleForTesting
-    NetworkStatsService(Context context, INetd netd, AlarmManager alarmManager,
-            PowerManager.WakeLock wakeLock, Clock clock, NetworkStatsSettings settings,
-            NetworkStatsFactory factory, NetworkStatsObservers statsObservers, File systemDir,
-            File baseDir, @NonNull Dependencies deps) {
-        mContext = Objects.requireNonNull(context, "missing Context");
-        mNetd = Objects.requireNonNull(netd, "missing Netd");
-        mAlarmManager = Objects.requireNonNull(alarmManager, "missing AlarmManager");
-        mClock = Objects.requireNonNull(clock, "missing Clock");
-        mSettings = Objects.requireNonNull(settings, "missing NetworkStatsSettings");
-        mWakeLock = Objects.requireNonNull(wakeLock, "missing WakeLock");
-        mStatsFactory = Objects.requireNonNull(factory, "missing factory");
-        mStatsObservers = Objects.requireNonNull(statsObservers, "missing NetworkStatsObservers");
-        mSystemDir = Objects.requireNonNull(systemDir, "missing systemDir");
-        mBaseDir = Objects.requireNonNull(baseDir, "missing baseDir");
-        mDeps = Objects.requireNonNull(deps, "missing Dependencies");
-
-        final HandlerThread handlerThread = mDeps.makeHandlerThread();
-        handlerThread.start();
-        mHandler = new NetworkStatsHandler(handlerThread.getLooper());
-        mNetworkStatsSubscriptionsMonitor = deps.makeSubscriptionsMonitor(mContext,
-                (command) -> mHandler.post(command) , this);
-        mContentResolver = mContext.getContentResolver();
-        mContentObserver = mDeps.makeContentObserver(mHandler, mSettings,
-                mNetworkStatsSubscriptionsMonitor);
-        mLocationPermissionChecker = mDeps.makeLocationPermissionChecker(mContext);
-        mInterfaceMapUpdater = mDeps.makeBpfInterfaceMapUpdater(mContext, mHandler);
-        mInterfaceMapUpdater.start();
-        mUidCounterSetMap = mDeps.getUidCounterSetMap();
-        mCookieTagMap = mDeps.getCookieTagMap();
-        mStatsMapA = mDeps.getStatsMapA();
-        mStatsMapB = mDeps.getStatsMapB();
-        mAppUidStatsMap = mDeps.getAppUidStatsMap();
-    }
-
-    /**
-     * Dependencies of NetworkStatsService, for injection in tests.
-     */
-    // TODO: Move more stuff into dependencies object.
-    @VisibleForTesting
-    public static class Dependencies {
-        /**
-         * Create a HandlerThread to use in NetworkStatsService.
-         */
-        @NonNull
-        public HandlerThread makeHandlerThread() {
-            return new HandlerThread(TAG);
-        }
-
-        /**
-         * Create a {@link NetworkStatsSubscriptionsMonitor}, can be used to monitor RAT change
-         * event in NetworkStatsService.
-         */
-        @NonNull
-        public NetworkStatsSubscriptionsMonitor makeSubscriptionsMonitor(@NonNull Context context,
-                @NonNull Executor executor, @NonNull NetworkStatsService service) {
-            // TODO: Update RatType passively in NSS, instead of querying into the monitor
-            //  when notifyNetworkStatus.
-            return new NetworkStatsSubscriptionsMonitor(context, executor,
-                    (subscriberId, type) -> service.handleOnCollapsedRatTypeChanged());
-        }
-
-        /**
-         * Create a ContentObserver instance which is used to observe settings changes,
-         * and dispatch onChange events on handler thread.
-         */
-        public @NonNull ContentObserver makeContentObserver(@NonNull Handler handler,
-                @NonNull NetworkStatsSettings settings,
-                @NonNull NetworkStatsSubscriptionsMonitor monitor) {
-            return new ContentObserver(handler) {
-                @Override
-                public void onChange(boolean selfChange, @NonNull Uri uri) {
-                    if (!settings.getCombineSubtypeEnabled()) {
-                        monitor.start();
-                    } else {
-                        monitor.stop();
-                    }
-                }
-            };
-        }
-
-        /**
-         * @see LocationPermissionChecker
-         */
-        public LocationPermissionChecker makeLocationPermissionChecker(final Context context) {
-            return new LocationPermissionChecker(context);
-        }
-
-        /** Create BpfInterfaceMapUpdater to update bpf interface map. */
-        @NonNull
-        public BpfInterfaceMapUpdater makeBpfInterfaceMapUpdater(
-                @NonNull Context ctx, @NonNull Handler handler) {
-            return new BpfInterfaceMapUpdater(ctx, handler);
-        }
-
-        /** Get counter sets map for each UID. */
-        public IBpfMap<U32, U8> getUidCounterSetMap() {
-            try {
-                return new BpfMap<U32, U8>(UID_COUNTERSET_MAP_PATH, BpfMap.BPF_F_RDWR,
-                        U32.class, U8.class);
-            } catch (ErrnoException e) {
-                Log.wtf(TAG, "Cannot open uid counter set map: " + e);
-                return null;
-            }
-        }
-
-        /** Gets the cookie tag map */
-        public IBpfMap<CookieTagMapKey, CookieTagMapValue> getCookieTagMap() {
-            try {
-                return new BpfMap<CookieTagMapKey, CookieTagMapValue>(COOKIE_TAG_MAP_PATH,
-                        BpfMap.BPF_F_RDWR, CookieTagMapKey.class, CookieTagMapValue.class);
-            } catch (ErrnoException e) {
-                Log.wtf(TAG, "Cannot open cookie tag map: " + e);
-                return null;
-            }
-        }
-
-        /** Gets stats map A */
-        public IBpfMap<StatsMapKey, StatsMapValue> getStatsMapA() {
-            try {
-                return new BpfMap<StatsMapKey, StatsMapValue>(STATS_MAP_A_PATH,
-                        BpfMap.BPF_F_RDWR, StatsMapKey.class, StatsMapValue.class);
-            } catch (ErrnoException e) {
-                Log.wtf(TAG, "Cannot open stats map A: " + e);
-                return null;
-            }
-        }
-
-        /** Gets stats map B */
-        public IBpfMap<StatsMapKey, StatsMapValue> getStatsMapB() {
-            try {
-                return new BpfMap<StatsMapKey, StatsMapValue>(STATS_MAP_B_PATH,
-                        BpfMap.BPF_F_RDWR, StatsMapKey.class, StatsMapValue.class);
-            } catch (ErrnoException e) {
-                Log.wtf(TAG, "Cannot open stats map B: " + e);
-                return null;
-            }
-        }
-
-        /** Gets the uid stats map */
-        public IBpfMap<UidStatsMapKey, StatsMapValue> getAppUidStatsMap() {
-            try {
-                return new BpfMap<UidStatsMapKey, StatsMapValue>(APP_UID_STATS_MAP_PATH,
-                        BpfMap.BPF_F_RDWR, UidStatsMapKey.class, StatsMapValue.class);
-            } catch (ErrnoException e) {
-                Log.wtf(TAG, "Cannot open app uid stats map: " + e);
-                return null;
-            }
-        }
-    }
-
-    /**
-     * Observer that watches for {@link INetdUnsolicitedEventListener} alerts.
-     */
-    @VisibleForTesting
-    public class AlertObserver extends BaseNetdUnsolicitedEventListener {
-        @Override
-        public void onQuotaLimitReached(@NonNull String alertName, @NonNull String ifName) {
-            PermissionUtils.enforceNetworkStackPermission(mContext);
-
-            if (LIMIT_GLOBAL_ALERT.equals(alertName)) {
-                // kick off background poll to collect network stats unless there is already
-                // such a call pending; UID stats are handled during normal polling interval.
-                if (!mHandler.hasMessages(MSG_PERFORM_POLL_REGISTER_ALERT)) {
-                    mHandler.sendEmptyMessageDelayed(MSG_PERFORM_POLL_REGISTER_ALERT,
-                            mSettings.getPollDelay());
-                }
-            }
-        }
-    }
-
-    public void systemReady() {
-        synchronized (mStatsLock) {
-            mSystemReady = true;
-
-            // create data recorders along with historical rotators
-            mDevRecorder = buildRecorder(PREFIX_DEV, mSettings.getDevConfig(), false);
-            mXtRecorder = buildRecorder(PREFIX_XT, mSettings.getXtConfig(), false);
-            mUidRecorder = buildRecorder(PREFIX_UID, mSettings.getUidConfig(), false);
-            mUidTagRecorder = buildRecorder(PREFIX_UID_TAG, mSettings.getUidTagConfig(), true);
-
-            updatePersistThresholdsLocked();
-
-            // upgrade any legacy stats, migrating them to rotated files
-            maybeUpgradeLegacyStatsLocked();
-
-            // read historical network stats from disk, since policy service
-            // might need them right away.
-            mXtStatsCached = mXtRecorder.getOrLoadCompleteLocked();
-
-            // bootstrap initial stats to prevent double-counting later
-            bootstrapStatsLocked();
-        }
-
-        // watch for tethering changes
-        final TetheringManager tetheringManager = mContext.getSystemService(TetheringManager.class);
-        tetheringManager.registerTetheringEventCallback(
-                (command) -> mHandler.post(command), mTetherListener);
-
-        // listen for periodic polling events
-        final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL);
-        mContext.registerReceiver(mPollReceiver, pollFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
-
-        // listen for uid removal to clean stats
-        final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED);
-        mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler);
-
-        // listen for user changes to clean stats
-        final IntentFilter userFilter = new IntentFilter(ACTION_USER_REMOVED);
-        mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
-
-        // persist stats during clean shutdown
-        final IntentFilter shutdownFilter = new IntentFilter(ACTION_SHUTDOWN);
-        mContext.registerReceiver(mShutdownReceiver, shutdownFilter);
-
-        try {
-            mNetd.registerUnsolicitedEventListener(mAlertObserver);
-        } catch (RemoteException | ServiceSpecificException e) {
-            Log.wtf(TAG, "Error registering event listener :", e);
-        }
-
-        //  schedule periodic pall alarm based on {@link NetworkStatsSettings#getPollInterval()}.
-        final PendingIntent pollIntent =
-                PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL),
-                        PendingIntent.FLAG_IMMUTABLE);
-
-        final long currentRealtime = SystemClock.elapsedRealtime();
-        mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime,
-                mSettings.getPollInterval(), pollIntent);
-
-        mContentResolver.registerContentObserver(Settings.Global
-                .getUriFor(NETSTATS_COMBINE_SUBTYPE_ENABLED),
-                        false /* notifyForDescendants */, mContentObserver);
-
-        // Post a runnable on handler thread to call onChange(). It's for getting current value of
-        // NETSTATS_COMBINE_SUBTYPE_ENABLED to decide start or stop monitoring RAT type changes.
-        mHandler.post(() -> mContentObserver.onChange(false, Settings.Global
-                .getUriFor(NETSTATS_COMBINE_SUBTYPE_ENABLED)));
-
-        registerGlobalAlert();
-    }
-
-    private NetworkStatsRecorder buildRecorder(
-            String prefix, NetworkStatsSettings.Config config, boolean includeTags) {
-        final DropBoxManager dropBox = (DropBoxManager) mContext.getSystemService(
-                Context.DROPBOX_SERVICE);
-        return new NetworkStatsRecorder(new FileRotator(
-                mBaseDir, prefix, config.rotateAgeMillis, config.deleteAgeMillis),
-                mNonMonotonicObserver, dropBox, prefix, config.bucketDuration, includeTags);
-    }
-
-    @GuardedBy("mStatsLock")
-    private void shutdownLocked() {
-        final TetheringManager tetheringManager = mContext.getSystemService(TetheringManager.class);
-        tetheringManager.unregisterTetheringEventCallback(mTetherListener);
-        mContext.unregisterReceiver(mPollReceiver);
-        mContext.unregisterReceiver(mRemovedReceiver);
-        mContext.unregisterReceiver(mUserReceiver);
-        mContext.unregisterReceiver(mShutdownReceiver);
-
-        if (!mSettings.getCombineSubtypeEnabled()) {
-            mNetworkStatsSubscriptionsMonitor.stop();
-        }
-
-        mContentResolver.unregisterContentObserver(mContentObserver);
-
-        final long currentTime = mClock.millis();
-
-        // persist any pending stats
-        mDevRecorder.forcePersistLocked(currentTime);
-        mXtRecorder.forcePersistLocked(currentTime);
-        mUidRecorder.forcePersistLocked(currentTime);
-        mUidTagRecorder.forcePersistLocked(currentTime);
-
-        mSystemReady = false;
-    }
-
-    @GuardedBy("mStatsLock")
-    private void maybeUpgradeLegacyStatsLocked() {
-        File file;
-        try {
-            file = new File(mSystemDir, "netstats.bin");
-            if (file.exists()) {
-                mDevRecorder.importLegacyNetworkLocked(file);
-                file.delete();
-            }
-
-            file = new File(mSystemDir, "netstats_xt.bin");
-            if (file.exists()) {
-                file.delete();
-            }
-
-            file = new File(mSystemDir, "netstats_uid.bin");
-            if (file.exists()) {
-                mUidRecorder.importLegacyUidLocked(file);
-                mUidTagRecorder.importLegacyUidLocked(file);
-                file.delete();
-            }
-        } catch (IOException e) {
-            Log.wtf(TAG, "problem during legacy upgrade", e);
-        } catch (OutOfMemoryError e) {
-            Log.wtf(TAG, "problem during legacy upgrade", e);
-        }
-    }
-
-    /**
-     * Register for a global alert that is delivered through {@link AlertObserver}
-     * or {@link NetworkStatsProviderCallback#onAlertReached()} once a threshold amount of data has
-     * been transferred.
-     */
-    private void registerGlobalAlert() {
-        try {
-            mNetd.bandwidthSetGlobalAlert(mGlobalAlertBytes);
-        } catch (IllegalStateException e) {
-            Log.w(TAG, "problem registering for global alert: " + e);
-        } catch (RemoteException e) {
-            // ignored; service lives in system_server
-        }
-        invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetAlert(mGlobalAlertBytes));
-    }
-
-    @Override
-    public INetworkStatsSession openSession() {
-        return openSessionInternal(NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN, null);
-    }
-
-    @Override
-    public INetworkStatsSession openSessionForUsageStats(int flags, String callingPackage) {
-        return openSessionInternal(flags, callingPackage);
-    }
-
-    private boolean isRateLimitedForPoll(int callingUid) {
-        if (callingUid == android.os.Process.SYSTEM_UID) {
-            return false;
-        }
-
-        final long lastCallTime;
-        final long now = SystemClock.elapsedRealtime();
-        synchronized (mOpenSessionCallsPerUid) {
-            int calls = mOpenSessionCallsPerUid.get(callingUid, 0);
-            mOpenSessionCallsPerUid.put(callingUid, calls + 1);
-            lastCallTime = mLastStatsSessionPoll;
-            mLastStatsSessionPoll = now;
-        }
-
-        return now - lastCallTime < POLL_RATE_LIMIT_MS;
-    }
-
-    private int restrictFlagsForCaller(int flags) {
-        // All non-privileged callers are not allowed to turn off POLL_ON_OPEN.
-        final boolean isPrivileged = PermissionUtils.checkAnyPermissionOf(mContext,
-                NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
-                android.Manifest.permission.NETWORK_STACK);
-        if (!isPrivileged) {
-            flags |= NetworkStatsManager.FLAG_POLL_ON_OPEN;
-        }
-        // Non-system uids are rate limited for POLL_ON_OPEN.
-        final int callingUid = Binder.getCallingUid();
-        flags = isRateLimitedForPoll(callingUid)
-                ? flags & (~NetworkStatsManager.FLAG_POLL_ON_OPEN)
-                : flags;
-        return flags;
-    }
-
-    private INetworkStatsSession openSessionInternal(final int flags, final String callingPackage) {
-        final int restrictedFlags = restrictFlagsForCaller(flags);
-        if ((restrictedFlags & (NetworkStatsManager.FLAG_POLL_ON_OPEN
-                | NetworkStatsManager.FLAG_POLL_FORCE)) != 0) {
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                performPoll(FLAG_PERSIST_ALL);
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
-        }
-
-        // return an IBinder which holds strong references to any loaded stats
-        // for its lifetime; when caller closes only weak references remain.
-
-        return new INetworkStatsSession.Stub() {
-            private final int mCallingUid = Binder.getCallingUid();
-            private final String mCallingPackage = callingPackage;
-            private final @NetworkStatsAccess.Level int mAccessLevel = checkAccessLevel(
-                    callingPackage);
-
-            private NetworkStatsCollection mUidComplete;
-            private NetworkStatsCollection mUidTagComplete;
-
-            private NetworkStatsCollection getUidComplete() {
-                synchronized (mStatsLock) {
-                    if (mUidComplete == null) {
-                        mUidComplete = mUidRecorder.getOrLoadCompleteLocked();
-                    }
-                    return mUidComplete;
-                }
-            }
-
-            private NetworkStatsCollection getUidTagComplete() {
-                synchronized (mStatsLock) {
-                    if (mUidTagComplete == null) {
-                        mUidTagComplete = mUidTagRecorder.getOrLoadCompleteLocked();
-                    }
-                    return mUidTagComplete;
-                }
-            }
-
-            @Override
-            public int[] getRelevantUids() {
-                return getUidComplete().getRelevantUids(mAccessLevel);
-            }
-
-            @Override
-            public NetworkStats getDeviceSummaryForNetwork(
-                    NetworkTemplate template, long start, long end) {
-                enforceTemplatePermissions(template, callingPackage);
-                return internalGetSummaryForNetwork(template, restrictedFlags, start, end,
-                        mAccessLevel, mCallingUid);
-            }
-
-            @Override
-            public NetworkStats getSummaryForNetwork(
-                    NetworkTemplate template, long start, long end) {
-                enforceTemplatePermissions(template, callingPackage);
-                return internalGetSummaryForNetwork(template, restrictedFlags, start, end,
-                        mAccessLevel, mCallingUid);
-            }
-
-            // TODO: Remove this after all callers are removed.
-            @Override
-            public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) {
-                enforceTemplatePermissions(template, callingPackage);
-                return internalGetHistoryForNetwork(template, restrictedFlags, fields,
-                        mAccessLevel, mCallingUid, Long.MIN_VALUE, Long.MAX_VALUE);
-            }
-
-            @Override
-            public NetworkStatsHistory getHistoryIntervalForNetwork(NetworkTemplate template,
-                    int fields, long start, long end) {
-                enforceTemplatePermissions(template, callingPackage);
-                // TODO(b/200768422): Redact returned history if the template is location
-                //  sensitive but the caller is not privileged.
-                return internalGetHistoryForNetwork(template, restrictedFlags, fields,
-                        mAccessLevel, mCallingUid, start, end);
-            }
-
-            @Override
-            public NetworkStats getSummaryForAllUid(
-                    NetworkTemplate template, long start, long end, boolean includeTags) {
-                enforceTemplatePermissions(template, callingPackage);
-                try {
-                    final NetworkStats stats = getUidComplete()
-                            .getSummary(template, start, end, mAccessLevel, mCallingUid);
-                    if (includeTags) {
-                        final NetworkStats tagStats = getUidTagComplete()
-                                .getSummary(template, start, end, mAccessLevel, mCallingUid);
-                        stats.combineAllValues(tagStats);
-                    }
-                    return stats;
-                } catch (NullPointerException e) {
-                    throw e;
-                }
-            }
-
-            @Override
-            public NetworkStats getTaggedSummaryForAllUid(
-                    NetworkTemplate template, long start, long end) {
-                enforceTemplatePermissions(template, callingPackage);
-                try {
-                    final NetworkStats tagStats = getUidTagComplete()
-                            .getSummary(template, start, end, mAccessLevel, mCallingUid);
-                    return tagStats;
-                } catch (NullPointerException e) {
-                    throw e;
-                }
-            }
-
-            @Override
-            public NetworkStatsHistory getHistoryForUid(
-                    NetworkTemplate template, int uid, int set, int tag, int fields) {
-                enforceTemplatePermissions(template, callingPackage);
-                // NOTE: We don't augment UID-level statistics
-                if (tag == TAG_NONE) {
-                    return getUidComplete().getHistory(template, null, uid, set, tag, fields,
-                            Long.MIN_VALUE, Long.MAX_VALUE, mAccessLevel, mCallingUid);
-                } else {
-                    return getUidTagComplete().getHistory(template, null, uid, set, tag, fields,
-                            Long.MIN_VALUE, Long.MAX_VALUE, mAccessLevel, mCallingUid);
-                }
-            }
-
-            @Override
-            public NetworkStatsHistory getHistoryIntervalForUid(
-                    NetworkTemplate template, int uid, int set, int tag, int fields,
-                    long start, long end) {
-                enforceTemplatePermissions(template, callingPackage);
-                // TODO(b/200768422): Redact returned history if the template is location
-                //  sensitive but the caller is not privileged.
-                // NOTE: We don't augment UID-level statistics
-                if (tag == TAG_NONE) {
-                    return getUidComplete().getHistory(template, null, uid, set, tag, fields,
-                            start, end, mAccessLevel, mCallingUid);
-                } else if (uid == Binder.getCallingUid()) {
-                    return getUidTagComplete().getHistory(template, null, uid, set, tag, fields,
-                            start, end, mAccessLevel, mCallingUid);
-                } else {
-                    throw new SecurityException("Calling package " + mCallingPackage
-                            + " cannot access tag information from a different uid");
-                }
-            }
-
-            @Override
-            public void close() {
-                mUidComplete = null;
-                mUidTagComplete = null;
-            }
-        };
-    }
-
-    private void enforceTemplatePermissions(@NonNull NetworkTemplate template,
-            @NonNull String callingPackage) {
-        // For a template with wifi network keys, it is possible for a malicious
-        // client to track the user locations via querying data usage. Thus, enforce
-        // fine location permission check.
-        if (!template.getWifiNetworkKeys().isEmpty()) {
-            final boolean canAccessFineLocation = mLocationPermissionChecker
-                    .checkCallersLocationPermission(callingPackage,
-                    null /* featureId */,
-                            Binder.getCallingUid(),
-                            false /* coarseForTargetSdkLessThanQ */,
-                            null /* message */);
-            if (!canAccessFineLocation) {
-                throw new SecurityException("Access fine location is required when querying"
-                        + " with wifi network keys, make sure the app has the necessary"
-                        + "permissions and the location toggle is on.");
-            }
-        }
-    }
-
-    private @NetworkStatsAccess.Level int checkAccessLevel(String callingPackage) {
-        return NetworkStatsAccess.checkAccessLevel(
-                mContext, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage);
-    }
-
-    /**
-     * Find the most relevant {@link SubscriptionPlan} for the given
-     * {@link NetworkTemplate} and flags. This is typically used to augment
-     * local measurement results to match a known anchor from the carrier.
-     */
-    private SubscriptionPlan resolveSubscriptionPlan(NetworkTemplate template, int flags) {
-        SubscriptionPlan plan = null;
-        if ((flags & NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN) != 0
-                && mSettings.getAugmentEnabled()) {
-            if (LOGD) Log.d(TAG, "Resolving plan for " + template);
-            final long token = Binder.clearCallingIdentity();
-            try {
-                plan = mContext.getSystemService(NetworkPolicyManager.class)
-                        .getSubscriptionPlan(template);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-            if (LOGD) Log.d(TAG, "Resolved to plan " + plan);
-        }
-        return plan;
-    }
-
-    /**
-     * Return network summary, splicing between DEV and XT stats when
-     * appropriate.
-     */
-    private NetworkStats internalGetSummaryForNetwork(NetworkTemplate template, int flags,
-            long start, long end, @NetworkStatsAccess.Level int accessLevel, int callingUid) {
-        // We've been using pure XT stats long enough that we no longer need to
-        // splice DEV and XT together.
-        final NetworkStatsHistory history = internalGetHistoryForNetwork(template, flags, FIELD_ALL,
-                accessLevel, callingUid, start, end);
-
-        final long now = System.currentTimeMillis();
-        final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null);
-
-        final NetworkStats stats = new NetworkStats(end - start, 1);
-        stats.insertEntry(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE,
-                METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, entry.rxBytes, entry.rxPackets,
-                entry.txBytes, entry.txPackets, entry.operations));
-        return stats;
-    }
-
-    /**
-     * Return network history, splicing between DEV and XT stats when
-     * appropriate.
-     */
-    private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate template,
-            int flags, int fields, @NetworkStatsAccess.Level int accessLevel, int callingUid,
-            long start, long end) {
-        // We've been using pure XT stats long enough that we no longer need to
-        // splice DEV and XT together.
-        final SubscriptionPlan augmentPlan = resolveSubscriptionPlan(template, flags);
-        synchronized (mStatsLock) {
-            return mXtStatsCached.getHistory(template, augmentPlan,
-                    UID_ALL, SET_ALL, TAG_NONE, fields, start, end, accessLevel, callingUid);
-        }
-    }
-
-    private long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
-        assertSystemReady();
-
-        return internalGetSummaryForNetwork(template,
-                NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN, start, end,
-                NetworkStatsAccess.Level.DEVICE, Binder.getCallingUid()).getTotalBytes();
-    }
-
-    private NetworkStats getNetworkUidBytes(NetworkTemplate template, long start, long end) {
-        assertSystemReady();
-
-        final NetworkStatsCollection uidComplete;
-        synchronized (mStatsLock) {
-            uidComplete = mUidRecorder.getOrLoadCompleteLocked();
-        }
-        return uidComplete.getSummary(template, start, end, NetworkStatsAccess.Level.DEVICE,
-                android.os.Process.SYSTEM_UID);
-    }
-
-    @Override
-    public NetworkStats getDataLayerSnapshotForUid(int uid) throws RemoteException {
-        if (Binder.getCallingUid() != uid) {
-            Log.w(TAG, "Snapshots only available for calling UID");
-            return new NetworkStats(SystemClock.elapsedRealtime(), 0);
-        }
-
-        // TODO: switch to data layer stats once kernel exports
-        // for now, read network layer stats and flatten across all ifaces.
-        // This function is used to query NeworkStats for calle's uid. The only caller method
-        // TrafficStats#getDataLayerSnapshotForUid alrady claim no special permission to query
-        // its own NetworkStats.
-        final long ident = Binder.clearCallingIdentity();
-        final NetworkStats networkLayer;
-        try {
-            networkLayer = readNetworkStatsUidDetail(uid, INTERFACES_ALL, TAG_ALL);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-
-        // splice in operation counts
-        networkLayer.spliceOperationsFrom(mUidOperations);
-
-        final NetworkStats dataLayer = new NetworkStats(
-                networkLayer.getElapsedRealtime(), networkLayer.size());
-
-        NetworkStats.Entry entry = null;
-        for (int i = 0; i < networkLayer.size(); i++) {
-            entry = networkLayer.getValues(i, entry);
-            entry.iface = IFACE_ALL;
-            dataLayer.combineValues(entry);
-        }
-
-        return dataLayer;
-    }
-
-    @Override
-    public NetworkStats getUidStatsForTransport(int transport) {
-        PermissionUtils.enforceNetworkStackPermission(mContext);
-        try {
-            final String[] relevantIfaces =
-                    transport == TRANSPORT_WIFI ? mWifiIfaces : mMobileIfaces;
-            // TODO(b/215633405) : mMobileIfaces and mWifiIfaces already contain the stacked
-            // interfaces, so this is not useful, remove it.
-            final String[] ifacesToQuery =
-                    mStatsFactory.augmentWithStackedInterfaces(relevantIfaces);
-            return getNetworkStatsUidDetail(ifacesToQuery);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error compiling UID stats", e);
-            return new NetworkStats(0L, 0);
-        }
-    }
-
-    @Override
-    public String[] getMobileIfaces() {
-        // TODO (b/192758557): Remove debug log.
-        if (CollectionUtils.contains(mMobileIfaces, null)) {
-            throw new NullPointerException(
-                    "null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces));
-        }
-        return mMobileIfaces.clone();
-    }
-
-    @Override
-    public void incrementOperationCount(int uid, int tag, int operationCount) {
-        if (Binder.getCallingUid() != uid) {
-            mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG);
-        }
-
-        if (operationCount < 0) {
-            throw new IllegalArgumentException("operation count can only be incremented");
-        }
-        if (tag == TAG_NONE) {
-            throw new IllegalArgumentException("operation count must have specific tag");
-        }
-
-        synchronized (mStatsLock) {
-            final int set = mActiveUidCounterSet.get(uid, SET_DEFAULT);
-            mUidOperations.combineValues(
-                    mActiveIface, uid, set, tag, 0L, 0L, 0L, 0L, operationCount);
-            mUidOperations.combineValues(
-                    mActiveIface, uid, set, TAG_NONE, 0L, 0L, 0L, 0L, operationCount);
-        }
-    }
-
-    private void setKernelCounterSet(int uid, int set) {
-        if (mUidCounterSetMap == null) {
-            Log.wtf(TAG, "Fail to set UidCounterSet: Null bpf map");
-            return;
-        }
-
-        if (set == SET_DEFAULT) {
-            try {
-                mUidCounterSetMap.deleteEntry(new U32(uid));
-            } catch (ErrnoException e) {
-                Log.w(TAG, "UidCounterSetMap.deleteEntry(" + uid + ") failed with errno: " + e);
-            }
-            return;
-        }
-
-        try {
-            mUidCounterSetMap.updateEntry(new U32(uid), new U8((short) set));
-        } catch (ErrnoException e) {
-            Log.w(TAG, "UidCounterSetMap.updateEntry(" + uid + ", " + set
-                    + ") failed with errno: " + e);
-        }
-    }
-
-    @VisibleForTesting
-    public void setUidForeground(int uid, boolean uidForeground) {
-        PermissionUtils.enforceNetworkStackPermission(mContext);
-        synchronized (mStatsLock) {
-            final int set = uidForeground ? SET_FOREGROUND : SET_DEFAULT;
-            final int oldSet = mActiveUidCounterSet.get(uid, SET_DEFAULT);
-            if (oldSet != set) {
-                mActiveUidCounterSet.put(uid, set);
-                setKernelCounterSet(uid, set);
-            }
-        }
-    }
-
-    /**
-     * Notify {@code NetworkStatsService} about network status changed.
-     */
-    public void notifyNetworkStatus(
-            @NonNull Network[] defaultNetworks,
-            @NonNull NetworkStateSnapshot[] networkStates,
-            @Nullable String activeIface,
-            @NonNull UnderlyingNetworkInfo[] underlyingNetworkInfos) {
-        PermissionUtils.enforceNetworkStackPermission(mContext);
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            handleNotifyNetworkStatus(defaultNetworks, networkStates, activeIface);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-
-        // Update the VPN underlying interfaces only after the poll is made and tun data has been
-        // migrated. Otherwise the migration would use the new interfaces instead of the ones that
-        // were current when the polled data was transferred.
-        mStatsFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
-    }
-
-    @Override
-    public void forceUpdate() {
-        PermissionUtils.enforceNetworkStackPermission(mContext);
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            performPoll(FLAG_PERSIST_ALL);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    /** Advise persistence threshold; may be overridden internally. */
-    public void advisePersistThreshold(long thresholdBytes) {
-        PermissionUtils.enforceNetworkStackPermission(mContext);
-        // clamp threshold into safe range
-        mPersistThreshold = NetworkStatsUtils.constrain(thresholdBytes,
-                128 * KB_IN_BYTES, 2 * MB_IN_BYTES);
-        if (LOGV) {
-            Log.v(TAG, "advisePersistThreshold() given " + thresholdBytes + ", clamped to "
-                    + mPersistThreshold);
-        }
-
-        final long oldGlobalAlertBytes = mGlobalAlertBytes;
-
-        // update and persist if beyond new thresholds
-        final long currentTime = mClock.millis();
-        synchronized (mStatsLock) {
-            if (!mSystemReady) return;
-
-            updatePersistThresholdsLocked();
-
-            mDevRecorder.maybePersistLocked(currentTime);
-            mXtRecorder.maybePersistLocked(currentTime);
-            mUidRecorder.maybePersistLocked(currentTime);
-            mUidTagRecorder.maybePersistLocked(currentTime);
-        }
-
-        if (oldGlobalAlertBytes != mGlobalAlertBytes) {
-            registerGlobalAlert();
-        }
-    }
-
-    @Override
-    public DataUsageRequest registerUsageCallback(@NonNull String callingPackage,
-                @NonNull DataUsageRequest request, @NonNull IUsageCallback callback) {
-        Objects.requireNonNull(callingPackage, "calling package is null");
-        Objects.requireNonNull(request, "DataUsageRequest is null");
-        Objects.requireNonNull(request.template, "NetworkTemplate is null");
-        Objects.requireNonNull(callback, "callback is null");
-
-        int callingUid = Binder.getCallingUid();
-        @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(callingPackage);
-        DataUsageRequest normalizedRequest;
-        final long token = Binder.clearCallingIdentity();
-        try {
-            normalizedRequest = mStatsObservers.register(mContext,
-                    request, callback, callingUid, accessLevel);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-
-        // Create baseline stats
-        mHandler.sendMessage(mHandler.obtainMessage(MSG_PERFORM_POLL));
-
-        return normalizedRequest;
-   }
-
-    @Override
-    public void unregisterUsageRequest(DataUsageRequest request) {
-        Objects.requireNonNull(request, "DataUsageRequest is null");
-
-        int callingUid = Binder.getCallingUid();
-        final long token = Binder.clearCallingIdentity();
-        try {
-            mStatsObservers.unregister(request, callingUid);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    @Override
-    public long getUidStats(int uid, int type) {
-        final int callingUid = Binder.getCallingUid();
-        if (callingUid != android.os.Process.SYSTEM_UID && callingUid != uid) {
-            return UNSUPPORTED;
-        }
-        return nativeGetUidStat(uid, type);
-    }
-
-    @Override
-    public long getIfaceStats(@NonNull String iface, int type) {
-        Objects.requireNonNull(iface);
-        long nativeIfaceStats = nativeGetIfaceStat(iface, type);
-        if (nativeIfaceStats == -1) {
-            return nativeIfaceStats;
-        } else {
-            // When tethering offload is in use, nativeIfaceStats does not contain usage from
-            // offload, add it back here. Note that the included statistics might be stale
-            // since polling newest stats from hardware might impact system health and not
-            // suitable for TrafficStats API use cases.
-            return nativeIfaceStats + getProviderIfaceStats(iface, type);
-        }
-    }
-
-    @Override
-    public long getTotalStats(int type) {
-        long nativeTotalStats = nativeGetTotalStat(type);
-        if (nativeTotalStats == -1) {
-            return nativeTotalStats;
-        } else {
-            // Refer to comment in getIfaceStats
-            return nativeTotalStats + getProviderIfaceStats(IFACE_ALL, type);
-        }
-    }
-
-    private long getProviderIfaceStats(@Nullable String iface, int type) {
-        final NetworkStats providerSnapshot = getNetworkStatsFromProviders(STATS_PER_IFACE);
-        final HashSet<String> limitIfaces;
-        if (iface == IFACE_ALL) {
-            limitIfaces = null;
-        } else {
-            limitIfaces = new HashSet<>();
-            limitIfaces.add(iface);
-        }
-        final NetworkStats.Entry entry = providerSnapshot.getTotal(null, limitIfaces);
-        switch (type) {
-            case TrafficStats.TYPE_RX_BYTES:
-                return entry.rxBytes;
-            case TrafficStats.TYPE_RX_PACKETS:
-                return entry.rxPackets;
-            case TrafficStats.TYPE_TX_BYTES:
-                return entry.txBytes;
-            case TrafficStats.TYPE_TX_PACKETS:
-                return entry.txPackets;
-            default:
-                return 0;
-        }
-    }
-
-    /**
-     * Update {@link NetworkStatsRecorder} and {@link #mGlobalAlertBytes} to
-     * reflect current {@link #mPersistThreshold} value. Always defers to
-     * {@link Global} values when defined.
-     */
-    @GuardedBy("mStatsLock")
-    private void updatePersistThresholdsLocked() {
-        mDevRecorder.setPersistThreshold(mSettings.getDevPersistBytes(mPersistThreshold));
-        mXtRecorder.setPersistThreshold(mSettings.getXtPersistBytes(mPersistThreshold));
-        mUidRecorder.setPersistThreshold(mSettings.getUidPersistBytes(mPersistThreshold));
-        mUidTagRecorder.setPersistThreshold(mSettings.getUidTagPersistBytes(mPersistThreshold));
-        mGlobalAlertBytes = mSettings.getGlobalAlertBytes(mPersistThreshold);
-    }
-
-    /**
-     * Listener that watches for {@link TetheringManager} to claim interface pairs.
-     */
-    private final TetheringManager.TetheringEventCallback mTetherListener =
-            new TetheringManager.TetheringEventCallback() {
-                @Override
-                public void onUpstreamChanged(@Nullable Network network) {
-                    performPoll(FLAG_PERSIST_NETWORK);
-                }
-            };
-
-    private BroadcastReceiver mPollReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            // on background handler thread, and verified UPDATE_DEVICE_STATS
-            // permission above.
-            performPoll(FLAG_PERSIST_ALL);
-
-            // verify that we're watching global alert
-            registerGlobalAlert();
-        }
-    };
-
-    private BroadcastReceiver mRemovedReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            // on background handler thread, and UID_REMOVED is protected
-            // broadcast.
-
-            final int uid = intent.getIntExtra(EXTRA_UID, -1);
-            if (uid == -1) return;
-
-            synchronized (mStatsLock) {
-                mWakeLock.acquire();
-                try {
-                    removeUidsLocked(uid);
-                } finally {
-                    mWakeLock.release();
-                }
-            }
-        }
-    };
-
-    private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            // On background handler thread, and USER_REMOVED is protected
-            // broadcast.
-
-            final UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER);
-            if (userHandle == null) return;
-
-            synchronized (mStatsLock) {
-                mWakeLock.acquire();
-                try {
-                    removeUserLocked(userHandle);
-                } finally {
-                    mWakeLock.release();
-                }
-            }
-        }
-    };
-
-    private BroadcastReceiver mShutdownReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            // SHUTDOWN is protected broadcast.
-            synchronized (mStatsLock) {
-                shutdownLocked();
-            }
-        }
-    };
-
-    /**
-     * Handle collapsed RAT type changed event.
-     */
-    @VisibleForTesting
-    public void handleOnCollapsedRatTypeChanged() {
-        // Protect service from frequently updating. Remove pending messages if any.
-        mHandler.removeMessages(MSG_NOTIFY_NETWORK_STATUS);
-        mHandler.sendMessageDelayed(
-                mHandler.obtainMessage(MSG_NOTIFY_NETWORK_STATUS), mSettings.getPollDelay());
-    }
-
-    private void handleNotifyNetworkStatus(
-            Network[] defaultNetworks,
-            NetworkStateSnapshot[] snapshots,
-            String activeIface) {
-        synchronized (mStatsLock) {
-            mWakeLock.acquire();
-            try {
-                mActiveIface = activeIface;
-                handleNotifyNetworkStatusLocked(defaultNetworks, snapshots);
-            } finally {
-                mWakeLock.release();
-            }
-        }
-    }
-
-    /**
-     * Inspect all current {@link NetworkStateSnapshot}s to derive mapping from {@code iface} to
-     * {@link NetworkStatsHistory}. When multiple networks are active on a single {@code iface},
-     * they are combined under a single {@link NetworkIdentitySet}.
-     */
-    @GuardedBy("mStatsLock")
-    private void handleNotifyNetworkStatusLocked(@NonNull Network[] defaultNetworks,
-            @NonNull NetworkStateSnapshot[] snapshots) {
-        if (!mSystemReady) return;
-        if (LOGV) Log.v(TAG, "handleNotifyNetworkStatusLocked()");
-
-        // take one last stats snapshot before updating iface mapping. this
-        // isn't perfect, since the kernel may already be counting traffic from
-        // the updated network.
-
-        // poll, but only persist network stats to keep codepath fast. UID stats
-        // will be persisted during next alarm poll event.
-        performPollLocked(FLAG_PERSIST_NETWORK);
-
-        // Rebuild active interfaces based on connected networks
-        mActiveIfaces.clear();
-        mActiveUidIfaces.clear();
-        // Update the list of default networks.
-        mDefaultNetworks = defaultNetworks;
-
-        mLastNetworkStateSnapshots = snapshots;
-
-        final boolean combineSubtypeEnabled = mSettings.getCombineSubtypeEnabled();
-        final ArraySet<String> mobileIfaces = new ArraySet<>();
-        final ArraySet<String> wifiIfaces = new ArraySet<>();
-        for (NetworkStateSnapshot snapshot : snapshots) {
-            final int displayTransport =
-                    getDisplayTransport(snapshot.getNetworkCapabilities().getTransportTypes());
-            final boolean isMobile = (NetworkCapabilities.TRANSPORT_CELLULAR == displayTransport);
-            final boolean isWifi = (NetworkCapabilities.TRANSPORT_WIFI == displayTransport);
-            final boolean isDefault = CollectionUtils.contains(
-                    mDefaultNetworks, snapshot.getNetwork());
-            final int ratType = combineSubtypeEnabled ? NetworkTemplate.NETWORK_TYPE_ALL
-                    : getRatTypeForStateSnapshot(snapshot);
-            final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot,
-                    isDefault, ratType);
-
-            // Traffic occurring on the base interface is always counted for
-            // both total usage and UID details.
-            final String baseIface = snapshot.getLinkProperties().getInterfaceName();
-            if (baseIface != null) {
-                findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident);
-                findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident);
-
-                // Build a separate virtual interface for VT (Video Telephony) data usage.
-                // Only do this when IMS is not metered, but VT is metered.
-                // If IMS is metered, then the IMS network usage has already included VT usage.
-                // VT is considered always metered in framework's layer. If VT is not metered
-                // per carrier's policy, modem will report 0 usage for VT calls.
-                if (snapshot.getNetworkCapabilities().hasCapability(
-                        NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.isMetered()) {
-
-                    // Copy the identify from IMS one but mark it as metered.
-                    NetworkIdentity vtIdent = new NetworkIdentity.Builder()
-                            .setType(ident.getType())
-                            .setRatType(ident.getRatType())
-                            .setSubscriberId(ident.getSubscriberId())
-                            .setWifiNetworkKey(ident.getWifiNetworkKey())
-                            .setRoaming(ident.isRoaming()).setMetered(true)
-                            .setDefaultNetwork(true)
-                            .setOemManaged(ident.getOemManaged())
-                            .setSubId(ident.getSubId()).build();
-                    final String ifaceVt = IFACE_VT + getSubIdForMobile(snapshot);
-                    findOrCreateNetworkIdentitySet(mActiveIfaces, ifaceVt).add(vtIdent);
-                    findOrCreateNetworkIdentitySet(mActiveUidIfaces, ifaceVt).add(vtIdent);
-                }
-
-                if (isMobile) {
-                    mobileIfaces.add(baseIface);
-                }
-                if (isWifi) {
-                    wifiIfaces.add(baseIface);
-                }
-            }
-
-            // Traffic occurring on stacked interfaces is usually clatd.
-            //
-            // UID stats are always counted on the stacked interface and never on the base
-            // interface, because the packets on the base interface do not actually match
-            // application sockets (they're not IPv4) and thus the app uid is not known.
-            // For receive this is obvious: packets must be translated from IPv6 to IPv4
-            // before the application socket can be found.
-            // For transmit: either they go through the clat daemon which by virtue of going
-            // through userspace strips the original socket association during the IPv4 to
-            // IPv6 translation process, or they are offloaded by eBPF, which doesn't:
-            // However, on an ebpf device the accounting is done in cgroup ebpf hooks,
-            // which don't trigger again post ebpf translation.
-            // (as such stats accounted to the clat uid are ignored)
-            //
-            // Interface stats are more complicated.
-            //
-            // eBPF offloaded 464xlat'ed packets never hit base interface ip6tables, and thus
-            // *all* statistics are collected by iptables on the stacked v4-* interface.
-            //
-            // Additionally for ingress all packets bound for the clat IPv6 address are dropped
-            // in ip6tables raw prerouting and thus even non-offloaded packets are only
-            // accounted for on the stacked interface.
-            //
-            // For egress, packets subject to eBPF offload never appear on the base interface
-            // and only appear on the stacked interface. Thus to ensure packets increment
-            // interface stats, we must collate data from stacked interfaces. For xt_qtaguid
-            // (or non eBPF offloaded) TX they would appear on both, however egress interface
-            // accounting is explicitly bypassed for traffic from the clat uid.
-            //
-            // TODO: This code might be combined to above code.
-            for (String iface : snapshot.getLinkProperties().getAllInterfaceNames()) {
-                // baseIface has been handled, so ignore it.
-                if (TextUtils.equals(baseIface, iface)) continue;
-                if (iface != null) {
-                    findOrCreateNetworkIdentitySet(mActiveIfaces, iface).add(ident);
-                    findOrCreateNetworkIdentitySet(mActiveUidIfaces, iface).add(ident);
-                    if (isMobile) {
-                        mobileIfaces.add(iface);
-                    }
-                    if (isWifi) {
-                        wifiIfaces.add(iface);
-                    }
-
-                    mStatsFactory.noteStackedIface(iface, baseIface);
-                }
-            }
-        }
-
-        mMobileIfaces = mobileIfaces.toArray(new String[0]);
-        mWifiIfaces = wifiIfaces.toArray(new String[0]);
-        // TODO (b/192758557): Remove debug log.
-        if (CollectionUtils.contains(mMobileIfaces, null)) {
-            throw new NullPointerException(
-                    "null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces));
-        }
-        if (CollectionUtils.contains(mWifiIfaces, null)) {
-            throw new NullPointerException(
-                    "null element in mWifiIfaces: " + Arrays.toString(mWifiIfaces));
-        }
-    }
-
-    private static int getSubIdForMobile(@NonNull NetworkStateSnapshot state) {
-        if (!state.getNetworkCapabilities().hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
-            throw new IllegalArgumentException("Mobile state need capability TRANSPORT_CELLULAR");
-        }
-
-        final NetworkSpecifier spec = state.getNetworkCapabilities().getNetworkSpecifier();
-        if (spec instanceof TelephonyNetworkSpecifier) {
-             return ((TelephonyNetworkSpecifier) spec).getSubscriptionId();
-        } else {
-            Log.wtf(TAG, "getSubIdForState invalid NetworkSpecifier");
-            return INVALID_SUBSCRIPTION_ID;
-        }
-    }
-
-    /**
-     * For networks with {@code TRANSPORT_CELLULAR}, get ratType that was obtained through
-     * {@link PhoneStateListener}. Otherwise, return 0 given that other networks with different
-     * transport types do not actually fill this value.
-     */
-    private int getRatTypeForStateSnapshot(@NonNull NetworkStateSnapshot state) {
-        if (!state.getNetworkCapabilities().hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
-            return 0;
-        }
-
-        return mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(state.getSubscriberId());
-    }
-
-    private static <K> NetworkIdentitySet findOrCreateNetworkIdentitySet(
-            ArrayMap<K, NetworkIdentitySet> map, K key) {
-        NetworkIdentitySet ident = map.get(key);
-        if (ident == null) {
-            ident = new NetworkIdentitySet();
-            map.put(key, ident);
-        }
-        return ident;
-    }
-
-    @GuardedBy("mStatsLock")
-    private void recordSnapshotLocked(long currentTime) throws RemoteException {
-        // snapshot and record current counters; read UID stats first to
-        // avoid over counting dev stats.
-        Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotUid");
-        final NetworkStats uidSnapshot = getNetworkStatsUidDetail(INTERFACES_ALL);
-        Trace.traceEnd(TRACE_TAG_NETWORK);
-        Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotXt");
-        final NetworkStats xtSnapshot = readNetworkStatsSummaryXt();
-        Trace.traceEnd(TRACE_TAG_NETWORK);
-        Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotDev");
-        final NetworkStats devSnapshot = readNetworkStatsSummaryDev();
-        Trace.traceEnd(TRACE_TAG_NETWORK);
-
-        // Snapshot for dev/xt stats from all custom stats providers. Counts per-interface data
-        // from stats providers that isn't already counted by dev and XT stats.
-        Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotStatsProvider");
-        final NetworkStats providersnapshot = getNetworkStatsFromProviders(STATS_PER_IFACE);
-        Trace.traceEnd(TRACE_TAG_NETWORK);
-        xtSnapshot.combineAllValues(providersnapshot);
-        devSnapshot.combineAllValues(providersnapshot);
-
-        // For xt/dev, we pass a null VPN array because usage is aggregated by UID, so VPN traffic
-        // can't be reattributed to responsible apps.
-        Trace.traceBegin(TRACE_TAG_NETWORK, "recordDev");
-        mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime);
-        Trace.traceEnd(TRACE_TAG_NETWORK);
-        Trace.traceBegin(TRACE_TAG_NETWORK, "recordXt");
-        mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, currentTime);
-        Trace.traceEnd(TRACE_TAG_NETWORK);
-
-        // For per-UID stats, pass the VPN info so VPN traffic is reattributed to responsible apps.
-        Trace.traceBegin(TRACE_TAG_NETWORK, "recordUid");
-        mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime);
-        Trace.traceEnd(TRACE_TAG_NETWORK);
-        Trace.traceBegin(TRACE_TAG_NETWORK, "recordUidTag");
-        mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime);
-        Trace.traceEnd(TRACE_TAG_NETWORK);
-
-        // We need to make copies of member fields that are sent to the observer to avoid
-        // a race condition between the service handler thread and the observer's
-        mStatsObservers.updateStats(xtSnapshot, uidSnapshot, new ArrayMap<>(mActiveIfaces),
-                new ArrayMap<>(mActiveUidIfaces), currentTime);
-    }
-
-    /**
-     * Bootstrap initial stats snapshot, usually during {@link #systemReady()}
-     * so we have baseline values without double-counting.
-     */
-    @GuardedBy("mStatsLock")
-    private void bootstrapStatsLocked() {
-        final long currentTime = mClock.millis();
-
-        try {
-            recordSnapshotLocked(currentTime);
-        } catch (IllegalStateException e) {
-            Log.w(TAG, "problem reading network stats: " + e);
-        } catch (RemoteException e) {
-            // ignored; service lives in system_server
-        }
-    }
-
-    private void performPoll(int flags) {
-        synchronized (mStatsLock) {
-            mWakeLock.acquire();
-
-            try {
-                performPollLocked(flags);
-            } finally {
-                mWakeLock.release();
-            }
-        }
-    }
-
-    /**
-     * Periodic poll operation, reading current statistics and recording into
-     * {@link NetworkStatsHistory}.
-     */
-    @GuardedBy("mStatsLock")
-    private void performPollLocked(int flags) {
-        if (!mSystemReady) return;
-        if (LOGV) Log.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")");
-        Trace.traceBegin(TRACE_TAG_NETWORK, "performPollLocked");
-
-        final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0;
-        final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0;
-        final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0;
-
-        performPollFromProvidersLocked();
-
-        // TODO: consider marking "untrusted" times in historical stats
-        final long currentTime = mClock.millis();
-
-        try {
-            recordSnapshotLocked(currentTime);
-        } catch (IllegalStateException e) {
-            Log.wtf(TAG, "problem reading network stats", e);
-            return;
-        } catch (RemoteException e) {
-            // ignored; service lives in system_server
-            return;
-        }
-
-        // persist any pending data depending on requested flags
-        Trace.traceBegin(TRACE_TAG_NETWORK, "[persisting]");
-        if (persistForce) {
-            mDevRecorder.forcePersistLocked(currentTime);
-            mXtRecorder.forcePersistLocked(currentTime);
-            mUidRecorder.forcePersistLocked(currentTime);
-            mUidTagRecorder.forcePersistLocked(currentTime);
-        } else {
-            if (persistNetwork) {
-                mDevRecorder.maybePersistLocked(currentTime);
-                mXtRecorder.maybePersistLocked(currentTime);
-            }
-            if (persistUid) {
-                mUidRecorder.maybePersistLocked(currentTime);
-                mUidTagRecorder.maybePersistLocked(currentTime);
-            }
-        }
-        Trace.traceEnd(TRACE_TAG_NETWORK);
-
-        if (mSettings.getSampleEnabled()) {
-            // sample stats after each full poll
-            performSampleLocked();
-        }
-
-        // finally, dispatch updated event to any listeners
-        mHandler.sendMessage(mHandler.obtainMessage(MSG_BROADCAST_NETWORK_STATS_UPDATED));
-
-        Trace.traceEnd(TRACE_TAG_NETWORK);
-    }
-
-    @GuardedBy("mStatsLock")
-    private void performPollFromProvidersLocked() {
-        // Request asynchronous stats update from all providers for next poll. And wait a bit of
-        // time to allow providers report-in given that normally binder call should be fast. Note
-        // that size of list might be changed because addition/removing at the same time. For
-        // addition, the stats of the missed provider can only be collected in next poll;
-        // for removal, wait might take up to MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS
-        // once that happened.
-        // TODO: request with a valid token.
-        Trace.traceBegin(TRACE_TAG_NETWORK, "provider.requestStatsUpdate");
-        final int registeredCallbackCount = mStatsProviderCbList.size();
-        mStatsProviderSem.drainPermits();
-        invokeForAllStatsProviderCallbacks(
-                (cb) -> cb.mProvider.onRequestStatsUpdate(0 /* unused */));
-        try {
-            mStatsProviderSem.tryAcquire(registeredCallbackCount,
-                    MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS, TimeUnit.MILLISECONDS);
-        } catch (InterruptedException e) {
-            // Strictly speaking it's possible a provider happened to deliver between the timeout
-            // and the log, and that doesn't matter too much as this is just a debug log.
-            Log.d(TAG, "requestStatsUpdate - providers responded "
-                    + mStatsProviderSem.availablePermits()
-                    + "/" + registeredCallbackCount + " : " + e);
-        }
-        Trace.traceEnd(TRACE_TAG_NETWORK);
-    }
-
-    /**
-     * Sample recent statistics summary into {@link EventLog}.
-     */
-    @GuardedBy("mStatsLock")
-    private void performSampleLocked() {
-        // TODO: migrate trustedtime fixes to separate binary log events
-        final long currentTime = mClock.millis();
-
-        NetworkTemplate template;
-        NetworkStats.Entry devTotal;
-        NetworkStats.Entry xtTotal;
-        NetworkStats.Entry uidTotal;
-
-        // collect mobile sample
-        template = buildTemplateMobileWildcard();
-        devTotal = mDevRecorder.getTotalSinceBootLocked(template);
-        xtTotal = mXtRecorder.getTotalSinceBootLocked(template);
-        uidTotal = mUidRecorder.getTotalSinceBootLocked(template);
-
-        EventLog.writeEvent(LOG_TAG_NETSTATS_MOBILE_SAMPLE,
-                devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets,
-                xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
-                uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
-                currentTime);
-
-        // collect wifi sample
-        template = buildTemplateWifiWildcard();
-        devTotal = mDevRecorder.getTotalSinceBootLocked(template);
-        xtTotal = mXtRecorder.getTotalSinceBootLocked(template);
-        uidTotal = mUidRecorder.getTotalSinceBootLocked(template);
-
-        EventLog.writeEvent(LOG_TAG_NETSTATS_WIFI_SAMPLE,
-                devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets,
-                xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
-                uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
-                currentTime);
-    }
-
-    // deleteKernelTagData can ignore ENOENT; otherwise we should log an error
-    private void logErrorIfNotErrNoent(final ErrnoException e, final String msg) {
-        if (e.errno != ENOENT) Log.e(TAG, msg, e);
-    }
-
-    private <K extends StatsMapKey, V extends StatsMapValue> void deleteStatsMapTagData(
-            IBpfMap<K, V> statsMap, int uid) {
-        try {
-            statsMap.forEach((key, value) -> {
-                if (key.uid == uid) {
-                    try {
-                        statsMap.deleteEntry(key);
-                    } catch (ErrnoException e) {
-                        logErrorIfNotErrNoent(e, "Failed to delete data(uid = " + key.uid + ")");
-                    }
-                }
-            });
-        } catch (ErrnoException e) {
-            Log.e(TAG, "FAILED to delete tag data from stats map", e);
-        }
-    }
-
-    /**
-     * Deletes uid tag data from CookieTagMap, StatsMapA, StatsMapB, and UidStatsMap
-     * @param uid
-     */
-    private void deleteKernelTagData(int uid) {
-        try {
-            mCookieTagMap.forEach((key, value) -> {
-                // If SkDestroyListener deletes the socket tag while this code is running,
-                // forEach will either restart iteration from the beginning or return null,
-                // depending on when the deletion happens.
-                // If it returns null, continue iteration to delete the data and in fact it would
-                // just iterate from first key because BpfMap#getNextKey would return first key
-                // if the current key is not exist.
-                if (value != null && value.uid == uid) {
-                    try {
-                        mCookieTagMap.deleteEntry(key);
-                    } catch (ErrnoException e) {
-                        logErrorIfNotErrNoent(e, "Failed to delete data(cookie = " + key + ")");
-                    }
-                }
-            });
-        } catch (ErrnoException e) {
-            Log.e(TAG, "Failed to delete tag data from cookie tag map", e);
-        }
-
-        deleteStatsMapTagData(mStatsMapA, uid);
-        deleteStatsMapTagData(mStatsMapB, uid);
-
-        try {
-            mUidCounterSetMap.deleteEntry(new U32(uid));
-        } catch (ErrnoException e) {
-            logErrorIfNotErrNoent(e, "Failed to delete tag data from uid counter set map");
-        }
-
-        try {
-            mAppUidStatsMap.deleteEntry(new UidStatsMapKey(uid));
-        } catch (ErrnoException e) {
-            logErrorIfNotErrNoent(e, "Failed to delete tag data from app uid stats map");
-        }
-    }
-
-    /**
-     * Clean up {@link #mUidRecorder} after UID is removed.
-     */
-    @GuardedBy("mStatsLock")
-    private void removeUidsLocked(int... uids) {
-        if (LOGV) Log.v(TAG, "removeUidsLocked() for UIDs " + Arrays.toString(uids));
-
-        // Perform one last poll before removing
-        performPollLocked(FLAG_PERSIST_ALL);
-
-        mUidRecorder.removeUidsLocked(uids);
-        mUidTagRecorder.removeUidsLocked(uids);
-
-        // Clear kernel stats associated with UID
-        for (int uid : uids) {
-            deleteKernelTagData(uid);
-        }
-    }
-
-    /**
-     * Clean up {@link #mUidRecorder} after user is removed.
-     */
-    @GuardedBy("mStatsLock")
-    private void removeUserLocked(@NonNull UserHandle userHandle) {
-        if (LOGV) Log.v(TAG, "removeUserLocked() for UserHandle=" + userHandle);
-
-        // Build list of UIDs that we should clean up
-        final ArrayList<Integer> uids = new ArrayList<>();
-        final List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(
-                PackageManager.MATCH_ANY_USER
-                | PackageManager.MATCH_DISABLED_COMPONENTS);
-        for (ApplicationInfo app : apps) {
-            final int uid = userHandle.getUid(app.uid);
-            uids.add(uid);
-        }
-
-        removeUidsLocked(CollectionUtils.toIntArray(uids));
-    }
-
-    /**
-     * Set the warning and limit to all registered custom network stats providers.
-     * Note that invocation of any interface will be sent to all providers.
-     */
-    public void setStatsProviderWarningAndLimitAsync(
-            @NonNull String iface, long warning, long limit) {
-        PermissionUtils.enforceNetworkStackPermission(mContext);
-        if (LOGV) {
-            Log.v(TAG, "setStatsProviderWarningAndLimitAsync("
-                    + iface + "," + warning + "," + limit + ")");
-        }
-        invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetWarningAndLimit(iface,
-                warning, limit));
-    }
-
-    @Override
-    protected void dump(FileDescriptor fd, PrintWriter rawWriter, String[] args) {
-        if (!PermissionUtils.checkDumpPermission(mContext, TAG, rawWriter)) return;
-
-        long duration = DateUtils.DAY_IN_MILLIS;
-        final HashSet<String> argSet = new HashSet<String>();
-        for (String arg : args) {
-            argSet.add(arg);
-
-            if (arg.startsWith("--duration=")) {
-                try {
-                    duration = Long.parseLong(arg.substring(11));
-                } catch (NumberFormatException ignored) {
-                }
-            }
-        }
-
-        // usage: dumpsys netstats --full --uid --tag --poll --checkin
-        final boolean poll = argSet.contains("--poll") || argSet.contains("poll");
-        final boolean checkin = argSet.contains("--checkin");
-        final boolean fullHistory = argSet.contains("--full") || argSet.contains("full");
-        final boolean includeUid = argSet.contains("--uid") || argSet.contains("detail");
-        final boolean includeTag = argSet.contains("--tag") || argSet.contains("detail");
-
-        final IndentingPrintWriter pw = new IndentingPrintWriter(rawWriter, "  ");
-
-        synchronized (mStatsLock) {
-            if (args.length > 0 && "--proto".equals(args[0])) {
-                // In this case ignore all other arguments.
-                dumpProtoLocked(fd);
-                return;
-            }
-
-            if (poll) {
-                performPollLocked(FLAG_PERSIST_ALL | FLAG_PERSIST_FORCE);
-                pw.println("Forced poll");
-                return;
-            }
-
-            if (checkin) {
-                final long end = System.currentTimeMillis();
-                final long start = end - duration;
-
-                pw.print("v1,");
-                pw.print(start / SECOND_IN_MILLIS); pw.print(',');
-                pw.print(end / SECOND_IN_MILLIS); pw.println();
-
-                pw.println("xt");
-                mXtRecorder.dumpCheckin(rawWriter, start, end);
-
-                if (includeUid) {
-                    pw.println("uid");
-                    mUidRecorder.dumpCheckin(rawWriter, start, end);
-                }
-                if (includeTag) {
-                    pw.println("tag");
-                    mUidTagRecorder.dumpCheckin(rawWriter, start, end);
-                }
-                return;
-            }
-
-            pw.println("Configs:");
-            pw.increaseIndent();
-            pw.print(NETSTATS_COMBINE_SUBTYPE_ENABLED, mSettings.getCombineSubtypeEnabled());
-            pw.println();
-            pw.decreaseIndent();
-
-            pw.println("Active interfaces:");
-            pw.increaseIndent();
-            for (int i = 0; i < mActiveIfaces.size(); i++) {
-                pw.print("iface", mActiveIfaces.keyAt(i));
-                pw.print("ident", mActiveIfaces.valueAt(i));
-                pw.println();
-            }
-            pw.decreaseIndent();
-
-            pw.println("Active UID interfaces:");
-            pw.increaseIndent();
-            for (int i = 0; i < mActiveUidIfaces.size(); i++) {
-                pw.print("iface", mActiveUidIfaces.keyAt(i));
-                pw.print("ident", mActiveUidIfaces.valueAt(i));
-                pw.println();
-            }
-            pw.decreaseIndent();
-
-            // Get the top openSession callers
-            final SparseIntArray calls;
-            synchronized (mOpenSessionCallsPerUid) {
-                calls = mOpenSessionCallsPerUid.clone();
-            }
-
-            final int N = calls.size();
-            final long[] values = new long[N];
-            for (int j = 0; j < N; j++) {
-                values[j] = ((long) calls.valueAt(j) << 32) | calls.keyAt(j);
-            }
-            Arrays.sort(values);
-
-            pw.println("Top openSession callers (uid=count):");
-            pw.increaseIndent();
-            final int end = Math.max(0, N - DUMP_STATS_SESSION_COUNT);
-            for (int j = N - 1; j >= end; j--) {
-                final int uid = (int) (values[j] & 0xffffffff);
-                final int count = (int) (values[j] >> 32);
-                pw.print(uid); pw.print("="); pw.println(count);
-            }
-            pw.decreaseIndent();
-            pw.println();
-
-            pw.println("Stats Providers:");
-            pw.increaseIndent();
-            invokeForAllStatsProviderCallbacks((cb) -> {
-                pw.println(cb.mTag + " Xt:");
-                pw.increaseIndent();
-                pw.print(cb.getCachedStats(STATS_PER_IFACE).toString());
-                pw.decreaseIndent();
-                if (includeUid) {
-                    pw.println(cb.mTag + " Uid:");
-                    pw.increaseIndent();
-                    pw.print(cb.getCachedStats(STATS_PER_UID).toString());
-                    pw.decreaseIndent();
-                }
-            });
-            pw.decreaseIndent();
-
-            pw.println("Dev stats:");
-            pw.increaseIndent();
-            mDevRecorder.dumpLocked(pw, fullHistory);
-            pw.decreaseIndent();
-
-            pw.println("Xt stats:");
-            pw.increaseIndent();
-            mXtRecorder.dumpLocked(pw, fullHistory);
-            pw.decreaseIndent();
-
-            if (includeUid) {
-                pw.println("UID stats:");
-                pw.increaseIndent();
-                mUidRecorder.dumpLocked(pw, fullHistory);
-                pw.decreaseIndent();
-            }
-
-            if (includeTag) {
-                pw.println("UID tag stats:");
-                pw.increaseIndent();
-                mUidTagRecorder.dumpLocked(pw, fullHistory);
-                pw.decreaseIndent();
-            }
-        }
-    }
-
-    @GuardedBy("mStatsLock")
-    private void dumpProtoLocked(FileDescriptor fd) {
-        final ProtoOutputStream proto = new ProtoOutputStream(new FileOutputStream(fd));
-
-        // TODO Right now it writes all history.  Should it limit to the "since-boot" log?
-
-        dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES,
-                mActiveIfaces);
-        dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES,
-                mActiveUidIfaces);
-        mDevRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS);
-        mXtRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.XT_STATS);
-        mUidRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_STATS);
-        mUidTagRecorder.dumpDebugLocked(proto,
-                NetworkStatsServiceDumpProto.UID_TAG_STATS);
-
-        proto.flush();
-    }
-
-    private static void dumpInterfaces(ProtoOutputStream proto, long tag,
-            ArrayMap<String, NetworkIdentitySet> ifaces) {
-        for (int i = 0; i < ifaces.size(); i++) {
-            final long start = proto.start(tag);
-
-            proto.write(NetworkInterfaceProto.INTERFACE, ifaces.keyAt(i));
-            ifaces.valueAt(i).dumpDebug(proto, NetworkInterfaceProto.IDENTITIES);
-
-            proto.end(start);
-        }
-    }
-
-    private NetworkStats readNetworkStatsSummaryDev() {
-        try {
-            return mStatsFactory.readNetworkStatsSummaryDev();
-        } catch (IOException e) {
-            throw new IllegalStateException(e);
-        }
-    }
-
-    private NetworkStats readNetworkStatsSummaryXt() {
-        try {
-            return mStatsFactory.readNetworkStatsSummaryXt();
-        } catch (IOException e) {
-            throw new IllegalStateException(e);
-        }
-    }
-
-    private NetworkStats readNetworkStatsUidDetail(int uid, String[] ifaces, int tag) {
-        try {
-            return mStatsFactory.readNetworkStatsDetail(uid, ifaces, tag);
-        } catch (IOException e) {
-            throw new IllegalStateException(e);
-        }
-    }
-
-    /**
-     * Return snapshot of current UID statistics, including any
-     * {@link TrafficStats#UID_TETHERING}, video calling data usage, and {@link #mUidOperations}
-     * values.
-     *
-     * @param ifaces A list of interfaces the stats should be restricted to, or
-     *               {@link NetworkStats#INTERFACES_ALL}.
-     */
-    private NetworkStats getNetworkStatsUidDetail(String[] ifaces)
-            throws RemoteException {
-        final NetworkStats uidSnapshot = readNetworkStatsUidDetail(UID_ALL,  ifaces, TAG_ALL);
-
-        // fold tethering stats and operations into uid snapshot
-        final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID);
-        tetherSnapshot.filter(UID_ALL, ifaces, TAG_ALL);
-        mStatsFactory.apply464xlatAdjustments(uidSnapshot, tetherSnapshot);
-        uidSnapshot.combineAllValues(tetherSnapshot);
-
-        // get a stale copy of uid stats snapshot provided by providers.
-        final NetworkStats providerStats = getNetworkStatsFromProviders(STATS_PER_UID);
-        providerStats.filter(UID_ALL, ifaces, TAG_ALL);
-        mStatsFactory.apply464xlatAdjustments(uidSnapshot, providerStats);
-        uidSnapshot.combineAllValues(providerStats);
-
-        uidSnapshot.combineAllValues(mUidOperations);
-
-        return uidSnapshot;
-    }
-
-    /**
-     * Return snapshot of current non-offloaded tethering statistics. Will return empty
-     * {@link NetworkStats} if any problems are encountered, or queried by {@code STATS_PER_IFACE}
-     * since it is already included by {@link #nativeGetIfaceStat}.
-     * See {@code OffloadTetheringStatsProvider} for offloaded tethering stats.
-     */
-    // TODO: Remove this by implementing {@link NetworkStatsProvider} for non-offloaded
-    //  tethering stats.
-    private @NonNull NetworkStats getNetworkStatsTethering(int how) throws RemoteException {
-         // We only need to return per-UID stats. Per-device stats are already counted by
-        // interface counters.
-        if (how != STATS_PER_UID) {
-            return new NetworkStats(SystemClock.elapsedRealtime(), 0);
-        }
-
-        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
-        try {
-            final TetherStatsParcel[] tetherStatsParcels = mNetd.tetherGetStats();
-            for (TetherStatsParcel tetherStats : tetherStatsParcels) {
-                try {
-                    stats.combineValues(new NetworkStats.Entry(tetherStats.iface, UID_TETHERING,
-                            SET_DEFAULT, TAG_NONE, tetherStats.rxBytes, tetherStats.rxPackets,
-                            tetherStats.txBytes, tetherStats.txPackets, 0L));
-                } catch (ArrayIndexOutOfBoundsException e) {
-                    throw new IllegalStateException("invalid tethering stats " + e);
-                }
-            }
-        } catch (IllegalStateException e) {
-            Log.wtf(TAG, "problem reading network stats", e);
-        }
-        return stats;
-    }
-
-    // TODO: It is copied from ConnectivityService, consider refactor these check permission
-    //  functions to a proper util.
-    private boolean checkAnyPermissionOf(String... permissions) {
-        for (String permission : permissions) {
-            if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private void enforceAnyPermissionOf(String... permissions) {
-        if (!checkAnyPermissionOf(permissions)) {
-            throw new SecurityException("Requires one of the following permissions: "
-                    + String.join(", ", permissions) + ".");
-        }
-    }
-
-    /**
-     * Registers a custom provider of {@link android.net.NetworkStats} to combine the network
-     * statistics that cannot be seen by the kernel to system. To unregister, invoke the
-     * {@code unregister()} of the returned callback.
-     *
-     * @param tag a human readable identifier of the custom network stats provider.
-     * @param provider the {@link INetworkStatsProvider} binder corresponding to the
-     *                 {@link NetworkStatsProvider} to be registered.
-     *
-     * @return a {@link INetworkStatsProviderCallback} binder
-     *         interface, which can be used to report events to the system.
-     */
-    public @NonNull INetworkStatsProviderCallback registerNetworkStatsProvider(
-            @NonNull String tag, @NonNull INetworkStatsProvider provider) {
-        enforceAnyPermissionOf(NETWORK_STATS_PROVIDER,
-                NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
-        Objects.requireNonNull(provider, "provider is null");
-        Objects.requireNonNull(tag, "tag is null");
-        final NetworkPolicyManager netPolicyManager = mContext
-                .getSystemService(NetworkPolicyManager.class);
-        try {
-            NetworkStatsProviderCallbackImpl callback = new NetworkStatsProviderCallbackImpl(
-                    tag, provider, mStatsProviderSem, mAlertObserver,
-                    mStatsProviderCbList, netPolicyManager);
-            mStatsProviderCbList.add(callback);
-            Log.d(TAG, "registerNetworkStatsProvider from " + callback.mTag + " uid/pid="
-                    + getCallingUid() + "/" + getCallingPid());
-            return callback;
-        } catch (RemoteException e) {
-            Log.e(TAG, "registerNetworkStatsProvider failed", e);
-        }
-        return null;
-    }
-
-    // Collect stats from local cache of providers.
-    private @NonNull NetworkStats getNetworkStatsFromProviders(int how) {
-        final NetworkStats ret = new NetworkStats(0L, 0);
-        invokeForAllStatsProviderCallbacks((cb) -> ret.combineAllValues(cb.getCachedStats(how)));
-        return ret;
-    }
-
-    @FunctionalInterface
-    private interface ThrowingConsumer<S, T extends Throwable> {
-        void accept(S s) throws T;
-    }
-
-    private void invokeForAllStatsProviderCallbacks(
-            @NonNull ThrowingConsumer<NetworkStatsProviderCallbackImpl, RemoteException> task) {
-        for (final NetworkStatsProviderCallbackImpl cb : mStatsProviderCbList) {
-            try {
-                task.accept(cb);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Fail to broadcast to provider: " + cb.mTag, e);
-            }
-        }
-    }
-
-    private static class NetworkStatsProviderCallbackImpl extends INetworkStatsProviderCallback.Stub
-            implements IBinder.DeathRecipient {
-        @NonNull final String mTag;
-
-        @NonNull final INetworkStatsProvider mProvider;
-        @NonNull private final Semaphore mSemaphore;
-        @NonNull final AlertObserver mAlertObserver;
-        @NonNull final CopyOnWriteArrayList<NetworkStatsProviderCallbackImpl> mStatsProviderCbList;
-        @NonNull final NetworkPolicyManager mNetworkPolicyManager;
-
-        @NonNull private final Object mProviderStatsLock = new Object();
-
-        @GuardedBy("mProviderStatsLock")
-        // Track STATS_PER_IFACE and STATS_PER_UID separately.
-        private final NetworkStats mIfaceStats = new NetworkStats(0L, 0);
-        @GuardedBy("mProviderStatsLock")
-        private final NetworkStats mUidStats = new NetworkStats(0L, 0);
-
-        NetworkStatsProviderCallbackImpl(
-                @NonNull String tag, @NonNull INetworkStatsProvider provider,
-                @NonNull Semaphore semaphore,
-                @NonNull AlertObserver alertObserver,
-                @NonNull CopyOnWriteArrayList<NetworkStatsProviderCallbackImpl> cbList,
-                @NonNull NetworkPolicyManager networkPolicyManager)
-                throws RemoteException {
-            mTag = tag;
-            mProvider = provider;
-            mProvider.asBinder().linkToDeath(this, 0);
-            mSemaphore = semaphore;
-            mAlertObserver = alertObserver;
-            mStatsProviderCbList = cbList;
-            mNetworkPolicyManager = networkPolicyManager;
-        }
-
-        @NonNull
-        public NetworkStats getCachedStats(int how) {
-            synchronized (mProviderStatsLock) {
-                NetworkStats stats;
-                switch (how) {
-                    case STATS_PER_IFACE:
-                        stats = mIfaceStats;
-                        break;
-                    case STATS_PER_UID:
-                        stats = mUidStats;
-                        break;
-                    default:
-                        throw new IllegalArgumentException("Invalid type: " + how);
-                }
-                // Callers might be able to mutate the returned object. Return a defensive copy
-                // instead of local reference.
-                return stats.clone();
-            }
-        }
-
-        @Override
-        public void notifyStatsUpdated(int token, @Nullable NetworkStats ifaceStats,
-                @Nullable NetworkStats uidStats) {
-            // TODO: 1. Use token to map ifaces to correct NetworkIdentity.
-            //       2. Store the difference and store it directly to the recorder.
-            synchronized (mProviderStatsLock) {
-                if (ifaceStats != null) mIfaceStats.combineAllValues(ifaceStats);
-                if (uidStats != null) mUidStats.combineAllValues(uidStats);
-            }
-            mSemaphore.release();
-        }
-
-        @Override
-        public void notifyAlertReached() throws RemoteException {
-            // This binder object can only have been obtained by a process that holds
-            // NETWORK_STATS_PROVIDER. Thus, no additional permission check is required.
-            BinderUtils.withCleanCallingIdentity(() ->
-                    mAlertObserver.onQuotaLimitReached(LIMIT_GLOBAL_ALERT, null /* unused */));
-        }
-
-        @Override
-        public void notifyWarningOrLimitReached() {
-            Log.d(TAG, mTag + ": notifyWarningOrLimitReached");
-            BinderUtils.withCleanCallingIdentity(() ->
-                    mNetworkPolicyManager.notifyStatsProviderWarningOrLimitReached());
-        }
-
-        @Override
-        public void binderDied() {
-            Log.d(TAG, mTag + ": binderDied");
-            mStatsProviderCbList.remove(this);
-        }
-
-        @Override
-        public void unregister() {
-            Log.d(TAG, mTag + ": unregister");
-            mStatsProviderCbList.remove(this);
-        }
-
-    }
-
-    private void assertSystemReady() {
-        if (!mSystemReady) {
-            throw new IllegalStateException("System not ready");
-        }
-    }
-
-    private class DropBoxNonMonotonicObserver implements NonMonotonicObserver<String> {
-        @Override
-        public void foundNonMonotonic(NetworkStats left, int leftIndex, NetworkStats right,
-                int rightIndex, String cookie) {
-            Log.w(TAG, "Found non-monotonic values; saving to dropbox");
-
-            // record error for debugging
-            final StringBuilder builder = new StringBuilder();
-            builder.append("found non-monotonic " + cookie + " values at left[" + leftIndex
-                    + "] - right[" + rightIndex + "]\n");
-            builder.append("left=").append(left).append('\n');
-            builder.append("right=").append(right).append('\n');
-
-            mContext.getSystemService(DropBoxManager.class).addText(TAG_NETSTATS_ERROR,
-                    builder.toString());
-        }
-
-        @Override
-        public void foundNonMonotonic(
-                NetworkStats stats, int statsIndex, String cookie) {
-            Log.w(TAG, "Found non-monotonic values; saving to dropbox");
-
-            final StringBuilder builder = new StringBuilder();
-            builder.append("Found non-monotonic " + cookie + " values at [" + statsIndex + "]\n");
-            builder.append("stats=").append(stats).append('\n');
-
-            mContext.getSystemService(DropBoxManager.class).addText(TAG_NETSTATS_ERROR,
-                    builder.toString());
-        }
-    }
-
-    /**
-     * Default external settings that read from
-     * {@link android.provider.Settings.Global}.
-     */
-    private static class DefaultNetworkStatsSettings implements NetworkStatsSettings {
-        DefaultNetworkStatsSettings() {}
-
-        @Override
-        public long getPollInterval() {
-            return 30 * MINUTE_IN_MILLIS;
-        }
-        @Override
-        public long getPollDelay() {
-            return DEFAULT_PERFORM_POLL_DELAY_MS;
-        }
-        @Override
-        public long getGlobalAlertBytes(long def) {
-            return def;
-        }
-        @Override
-        public boolean getSampleEnabled() {
-            return true;
-        }
-        @Override
-        public boolean getAugmentEnabled() {
-            return true;
-        }
-        @Override
-        public boolean getCombineSubtypeEnabled() {
-            return false;
-        }
-        @Override
-        public Config getDevConfig() {
-            return new Config(HOUR_IN_MILLIS, 15 * DAY_IN_MILLIS, 90 * DAY_IN_MILLIS);
-        }
-        @Override
-        public Config getXtConfig() {
-            return getDevConfig();
-        }
-        @Override
-        public Config getUidConfig() {
-            return new Config(2 * HOUR_IN_MILLIS, 15 * DAY_IN_MILLIS, 90 * DAY_IN_MILLIS);
-        }
-        @Override
-        public Config getUidTagConfig() {
-            return new Config(2 * HOUR_IN_MILLIS, 5 * DAY_IN_MILLIS, 15 * DAY_IN_MILLIS);
-        }
-        @Override
-        public long getDevPersistBytes(long def) {
-            return def;
-        }
-        @Override
-        public long getXtPersistBytes(long def) {
-            return def;
-        }
-        @Override
-        public long getUidPersistBytes(long def) {
-            return def;
-        }
-        @Override
-        public long getUidTagPersistBytes(long def) {
-            return def;
-        }
-    }
-
-    private static native long nativeGetTotalStat(int type);
-    private static native long nativeGetIfaceStat(String iface, int type);
-    private static native long nativeGetUidStat(int uid, int type);
-}
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
deleted file mode 100644
index 65ccd20..0000000
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.net;
-
-import static android.app.usage.NetworkStatsManager.NETWORK_TYPE_5G_NSA;
-import static android.app.usage.NetworkStatsManager.getCollapsedRatType;
-import static android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED;
-import static android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA;
-import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE;
-
-import android.annotation.NonNull;
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.os.Build;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyCallback;
-import android.telephony.TelephonyDisplayInfo;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Pair;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.net.module.util.CollectionUtils;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.Executor;
-
-/**
- * Helper class that watches for events that are triggered per subscription.
- */
-@TargetApi(Build.VERSION_CODES.TIRAMISU)
-public class NetworkStatsSubscriptionsMonitor extends
-        SubscriptionManager.OnSubscriptionsChangedListener {
-
-    /**
-     * Interface that this monitor uses to delegate event handling to NetworkStatsService.
-     */
-    public interface Delegate {
-        /**
-         * Notify that the collapsed RAT type has been changed for any subscription. The method
-         * will also be triggered for any existing sub when start and stop monitoring.
-         *
-         * @param subscriberId IMSI of the subscription.
-         * @param collapsedRatType collapsed RAT type.
-         *                     @see android.app.usage.NetworkStatsManager#getCollapsedRatType(int).
-         */
-        void onCollapsedRatTypeChanged(@NonNull String subscriberId, int collapsedRatType);
-    }
-    private final Delegate mDelegate;
-
-    /**
-     * Receivers that watches for {@link TelephonyDisplayInfo} changes for each subscription, to
-     * monitor the transitioning between Radio Access Technology(RAT) types for each sub.
-     */
-    @NonNull
-    private final CopyOnWriteArrayList<RatTypeListener> mRatListeners =
-            new CopyOnWriteArrayList<>();
-
-    @NonNull
-    private final SubscriptionManager mSubscriptionManager;
-    @NonNull
-    private final TelephonyManager mTeleManager;
-
-    @NonNull
-    private final Executor mExecutor;
-
-    NetworkStatsSubscriptionsMonitor(@NonNull Context context,
-            @NonNull Executor executor, @NonNull Delegate delegate) {
-        super();
-        mSubscriptionManager = (SubscriptionManager) context.getSystemService(
-                Context.TELEPHONY_SUBSCRIPTION_SERVICE);
-        mTeleManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
-        mExecutor = executor;
-        mDelegate = delegate;
-    }
-
-    @Override
-    public void onSubscriptionsChanged() {
-        // Collect active subId list, hidden subId such as opportunistic subscriptions are
-        // also needed to track CBRS.
-        final List<Integer> newSubs = getActiveSubIdList(mSubscriptionManager);
-
-        // IMSI is needed for every newly added sub. Listener stores subscriberId into it to
-        // prevent binder call to telephony when querying RAT. Keep listener registration with empty
-        // IMSI is meaningless since the RAT type changed is ambiguous for multi-SIM if reported
-        // with empty IMSI. So filter the subs w/o a valid IMSI to prevent such registration.
-        final List<Pair<Integer, String>> filteredNewSubs = new ArrayList<>();
-        for (final int subId : newSubs) {
-            final String subscriberId =
-                    mTeleManager.createForSubscriptionId(subId).getSubscriberId();
-            if (!TextUtils.isEmpty(subscriberId)) {
-                filteredNewSubs.add(new Pair(subId, subscriberId));
-            }
-        }
-
-        for (final Pair<Integer, String> sub : filteredNewSubs) {
-            // Fully match listener with subId and IMSI, since in some rare cases, IMSI might be
-            // suddenly change regardless of subId, such as switch IMSI feature in modem side.
-            // If that happens, register new listener with new IMSI and remove old one later.
-            if (CollectionUtils.any(mRatListeners, it -> it.equalsKey(sub.first, sub.second))) {
-                continue;
-            }
-
-            final RatTypeListener listener = new RatTypeListener(this, sub.first, sub.second);
-            mRatListeners.add(listener);
-
-            // Register listener to the telephony manager that associated with specific sub.
-            mTeleManager.createForSubscriptionId(sub.first)
-                    .registerTelephonyCallback(mExecutor, listener);
-            Log.d(NetworkStatsService.TAG, "RAT type listener registered for sub " + sub.first);
-        }
-
-        for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) {
-            // If there is no subId and IMSI matched the listener, removes it.
-            if (!CollectionUtils.any(filteredNewSubs,
-                    it -> listener.equalsKey(it.first, it.second))) {
-                handleRemoveRatTypeListener(listener);
-            }
-        }
-    }
-
-    @NonNull
-    private List<Integer> getActiveSubIdList(@NonNull SubscriptionManager subscriptionManager) {
-        final ArrayList<Integer> ret = new ArrayList<>();
-        final int[] ids = subscriptionManager.getCompleteActiveSubscriptionIdList();
-        for (int id : ids) ret.add(id);
-        return ret;
-    }
-
-    /**
-     * Get a collapsed RatType for the given subscriberId.
-     *
-     * @param subscriberId the target subscriberId
-     * @return collapsed RatType for the given subscriberId
-     */
-    public int getRatTypeForSubscriberId(@NonNull String subscriberId) {
-        final int index = CollectionUtils.indexOf(mRatListeners,
-                it -> TextUtils.equals(subscriberId, it.mSubscriberId));
-        return index != -1 ? mRatListeners.get(index).mLastCollapsedRatType
-                : TelephonyManager.NETWORK_TYPE_UNKNOWN;
-    }
-
-    /**
-     * Start monitoring events that triggered per subscription.
-     */
-    public void start() {
-        mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor, this);
-    }
-
-    /**
-     * Unregister subscription changes and all listeners for each subscription.
-     */
-    public void stop() {
-        mSubscriptionManager.removeOnSubscriptionsChangedListener(this);
-
-        for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) {
-            handleRemoveRatTypeListener(listener);
-        }
-    }
-
-    private void handleRemoveRatTypeListener(@NonNull RatTypeListener listener) {
-        mTeleManager.createForSubscriptionId(listener.mSubId)
-                .unregisterTelephonyCallback(listener);
-        Log.d(NetworkStatsService.TAG, "RAT type listener unregistered for sub " + listener.mSubId);
-        mRatListeners.remove(listener);
-
-        // Removal of subscriptions doesn't generate RAT changed event, fire it for every
-        // RatTypeListener.
-        mDelegate.onCollapsedRatTypeChanged(
-                listener.mSubscriberId, TelephonyManager.NETWORK_TYPE_UNKNOWN);
-    }
-
-    static class RatTypeListener extends TelephonyCallback
-            implements TelephonyCallback.DisplayInfoListener {
-        // Unique id for the subscription. See {@link SubscriptionInfo#getSubscriptionId}.
-        @NonNull
-        private final int mSubId;
-
-        // IMSI to identifying the corresponding network from {@link NetworkState}.
-        // See {@link TelephonyManager#getSubscriberId}.
-        @NonNull
-        private final String mSubscriberId;
-
-        private volatile int mLastCollapsedRatType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
-        @NonNull
-        private final NetworkStatsSubscriptionsMonitor mMonitor;
-
-        RatTypeListener(@NonNull NetworkStatsSubscriptionsMonitor monitor, int subId,
-                @NonNull String subscriberId) {
-            mSubId = subId;
-            mSubscriberId = subscriberId;
-            mMonitor = monitor;
-        }
-
-        @Override
-        public void onDisplayInfoChanged(TelephonyDisplayInfo displayInfo) {
-            // In 5G SA (Stand Alone) mode, the primary cell itself will be 5G hence telephony
-            // would report RAT = 5G_NR.
-            // However, in 5G NSA (Non Stand Alone) mode, the primary cell is still LTE and
-            // network allocates a secondary 5G cell so telephony reports RAT = LTE along with
-            // NR state as connected. In such case, attributes the data usage to NR.
-            // See b/160727498.
-            final boolean is5GNsa = displayInfo.getNetworkType() == NETWORK_TYPE_LTE
-                    && (displayInfo.getOverrideNetworkType() == OVERRIDE_NETWORK_TYPE_NR_NSA
-                    || displayInfo.getOverrideNetworkType() == OVERRIDE_NETWORK_TYPE_NR_ADVANCED);
-
-            final int networkType =
-                    (is5GNsa ? NETWORK_TYPE_5G_NSA : displayInfo.getNetworkType());
-            final int collapsedRatType = getCollapsedRatType(networkType);
-            if (collapsedRatType == mLastCollapsedRatType) return;
-
-            if (NetworkStatsService.LOGD) {
-                Log.d(NetworkStatsService.TAG, "subtype changed for sub(" + mSubId + "): "
-                        + mLastCollapsedRatType + " -> " + collapsedRatType);
-            }
-            mLastCollapsedRatType = collapsedRatType;
-            mMonitor.mDelegate.onCollapsedRatTypeChanged(mSubscriberId, mLastCollapsedRatType);
-        }
-
-        @VisibleForTesting
-        public int getSubId() {
-            return mSubId;
-        }
-
-        boolean equalsKey(int subId, @NonNull String subscriberId) {
-            return mSubId == subId && TextUtils.equals(mSubscriberId, subscriberId);
-        }
-    }
-}
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/StatsMapKey.java b/packages/ConnectivityT/service/src/com/android/server/net/StatsMapKey.java
deleted file mode 100644
index ea8d836..0000000
--- a/packages/ConnectivityT/service/src/com/android/server/net/StatsMapKey.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.server.net;
-
-import com.android.net.module.util.Struct;
-import com.android.net.module.util.Struct.Field;
-import com.android.net.module.util.Struct.Type;
-
-/**
- * Key for both stats maps.
- */
-public class StatsMapKey extends Struct {
-    @Field(order = 0, type = Type.U32)
-    public final long uid;
-
-    @Field(order = 1, type = Type.U32)
-    public final long tag;
-
-    @Field(order = 2, type = Type.U32)
-    public final long counterSet;
-
-    @Field(order = 3, type = Type.U32)
-    public final long ifaceIndex;
-
-    public StatsMapKey(final long uid, final long tag, final long counterSet,
-            final long ifaceIndex) {
-        this.uid = uid;
-        this.tag = tag;
-        this.counterSet = counterSet;
-        this.ifaceIndex = ifaceIndex;
-    }
-}
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/StatsMapValue.java b/packages/ConnectivityT/service/src/com/android/server/net/StatsMapValue.java
deleted file mode 100644
index 48f26ce..0000000
--- a/packages/ConnectivityT/service/src/com/android/server/net/StatsMapValue.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.server.net;
-
-import com.android.net.module.util.Struct;
-import com.android.net.module.util.Struct.Field;
-import com.android.net.module.util.Struct.Type;
-
-/**
- * Value used for both stats maps and uid stats map.
- */
-public class StatsMapValue extends Struct {
-    @Field(order = 0, type = Type.U63)
-    public final long rxPackets;
-
-    @Field(order = 1, type = Type.U63)
-    public final long rxBytes;
-
-    @Field(order = 2, type = Type.U63)
-    public final long txPackets;
-
-    @Field(order = 3, type = Type.U63)
-    public final long txBytes;
-
-    public StatsMapValue(final long rxPackets, final long rxBytes, final long txPackets,
-            final long txBytes) {
-        this.rxPackets = rxPackets;
-        this.rxBytes = rxBytes;
-        this.txPackets = txPackets;
-        this.txBytes = txBytes;
-    }
-}
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/UidStatsMapKey.java b/packages/ConnectivityT/service/src/com/android/server/net/UidStatsMapKey.java
deleted file mode 100644
index 2849f94..0000000
--- a/packages/ConnectivityT/service/src/com/android/server/net/UidStatsMapKey.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.server.net;
-
-import com.android.net.module.util.Struct;
-import com.android.net.module.util.Struct.Field;
-import com.android.net.module.util.Struct.Type;
-
-/**
- * Key for uid stats map.
- */
-public class UidStatsMapKey extends Struct {
-    @Field(order = 0, type = Type.U32)
-    public final long uid;
-
-    public UidStatsMapKey(final long uid) {
-        this.uid = uid;
-    }
-}
diff --git a/packages/ConnectivityT/tests/unit/java/com/android/server/NativeDaemonConnectorTest.java b/packages/ConnectivityT/tests/unit/java/com/android/server/NativeDaemonConnectorTest.java
deleted file mode 100644
index e2253a2..0000000
--- a/packages/ConnectivityT/tests/unit/java/com/android/server/NativeDaemonConnectorTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static com.android.server.NativeDaemonConnector.appendEscaped;
-import static com.android.server.NativeDaemonConnector.makeCommand;
-
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-
-import com.android.server.NativeDaemonConnector.SensitiveArg;
-
-/**
- * Tests for {@link NativeDaemonConnector}.
- */
-@MediumTest
-public class NativeDaemonConnectorTest extends AndroidTestCase {
-    private static final String TAG = "NativeDaemonConnectorTest";
-
-    public void testArgumentNormal() throws Exception {
-        final StringBuilder builder = new StringBuilder();
-
-        builder.setLength(0);
-        appendEscaped(builder, "");
-        assertEquals("", builder.toString());
-
-        builder.setLength(0);
-        appendEscaped(builder, "foo");
-        assertEquals("foo", builder.toString());
-
-        builder.setLength(0);
-        appendEscaped(builder, "foo\"bar");
-        assertEquals("foo\\\"bar", builder.toString());
-
-        builder.setLength(0);
-        appendEscaped(builder, "foo\\bar\\\"baz");
-        assertEquals("foo\\\\bar\\\\\\\"baz", builder.toString());
-    }
-
-    public void testArgumentWithSpaces() throws Exception {
-        final StringBuilder builder = new StringBuilder();
-
-        builder.setLength(0);
-        appendEscaped(builder, "foo bar");
-        assertEquals("\"foo bar\"", builder.toString());
-
-        builder.setLength(0);
-        appendEscaped(builder, "foo\"bar\\baz foo");
-        assertEquals("\"foo\\\"bar\\\\baz foo\"", builder.toString());
-    }
-
-    public void testArgumentWithUtf() throws Exception {
-        final StringBuilder builder = new StringBuilder();
-
-        builder.setLength(0);
-        appendEscaped(builder, "caf\u00E9 c\u00F6ffee");
-        assertEquals("\"caf\u00E9 c\u00F6ffee\"", builder.toString());
-    }
-
-    public void testSensitiveArgs() throws Exception {
-        final StringBuilder rawBuilder = new StringBuilder();
-        final StringBuilder logBuilder = new StringBuilder();
-
-        rawBuilder.setLength(0);
-        logBuilder.setLength(0);
-        makeCommand(rawBuilder, logBuilder, 1, "foo", "bar", "baz");
-        assertEquals("1 foo bar baz\0", rawBuilder.toString());
-        assertEquals("1 foo bar baz", logBuilder.toString());
-
-        rawBuilder.setLength(0);
-        logBuilder.setLength(0);
-        makeCommand(rawBuilder, logBuilder, 1, "foo", new SensitiveArg("bar"), "baz");
-        assertEquals("1 foo bar baz\0", rawBuilder.toString());
-        assertEquals("1 foo [scrubbed] baz", logBuilder.toString());
-
-        rawBuilder.setLength(0);
-        logBuilder.setLength(0);
-        makeCommand(rawBuilder, logBuilder, 1, "foo", new SensitiveArg("foo bar"), "baz baz",
-                new SensitiveArg("wat"));
-        assertEquals("1 foo \"foo bar\" \"baz baz\" wat\0", rawBuilder.toString());
-        assertEquals("1 foo [scrubbed] \"baz baz\" [scrubbed]", logBuilder.toString());
-    }
-}
diff --git a/packages/DynamicSystemInstallationService/Android.bp b/packages/DynamicSystemInstallationService/Android.bp
index ad86f46..b8f54b3 100644
--- a/packages/DynamicSystemInstallationService/Android.bp
+++ b/packages/DynamicSystemInstallationService/Android.bp
@@ -22,6 +22,9 @@
     defaults: ["platform_app_defaults"],
 
     srcs: ["src/**/*.java"],
+    static_libs: [
+        "DynamicSystemInstallationService-logtags",
+    ],
     resource_dirs: ["res"],
 
     certificate: "platform",
@@ -32,3 +35,8 @@
         enabled: false,
     },
 }
+
+java_library {
+    name: "DynamicSystemInstallationService-logtags",
+    srcs: ["src/**/*.logtags"],
+}
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index f8cb5d3..02128d4 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -58,6 +58,7 @@
 import android.os.image.DynamicSystemClient;
 import android.os.image.DynamicSystemManager;
 import android.text.TextUtils;
+import android.util.EventLog;
 import android.util.Log;
 import android.widget.Toast;
 
@@ -104,6 +105,36 @@
     private static final int NOTIFICATION_ID = 1;
 
     /*
+     * Event log tags
+     */
+    private static final int EVENT_DSU_PROGRESS_UPDATE = 120000;
+    private static final int EVENT_DSU_INSTALL_COMPLETE = 120001;
+    private static final int EVENT_DSU_INSTALL_FAILED = 120002;
+
+    protected static void logEventProgressUpdate(
+            String partition,
+            long installedSize,
+            long partitionSize,
+            int partitionNumber,
+            int totalPartitionNumber) {
+        EventLog.writeEvent(
+                EVENT_DSU_PROGRESS_UPDATE,
+                partition,
+                installedSize,
+                partitionSize,
+                partitionNumber,
+                totalPartitionNumber);
+    }
+
+    protected static void logEventComplete() {
+        EventLog.writeEvent(EVENT_DSU_INSTALL_COMPLETE);
+    }
+
+    protected static void logEventFailed(String cause) {
+        EventLog.writeEvent(EVENT_DSU_INSTALL_FAILED, cause);
+    }
+
+    /*
      * IPC
      */
     /** Keeps track of all current registered clients. */
@@ -132,15 +163,10 @@
     private DynamicSystemManager mDynSystem;
     private NotificationManager mNM;
 
-    private int mNumInstalledPartitions;
-
-    private String mCurrentPartitionName;
-    private long mCurrentPartitionSize;
-    private long mCurrentPartitionInstalledSize;
-
     // This is for testing only now
     private boolean mEnableWhenCompleted;
 
+    private InstallationAsyncTask.Progress mInstallTaskProgress;
     private InstallationAsyncTask mInstallTask;
 
 
@@ -203,17 +229,21 @@
 
     @Override
     public void onProgressUpdate(InstallationAsyncTask.Progress progress) {
-        mCurrentPartitionName = progress.partitionName;
-        mCurrentPartitionSize = progress.partitionSize;
-        mCurrentPartitionInstalledSize = progress.installedSize;
-        mNumInstalledPartitions = progress.numInstalledPartitions;
+        logEventProgressUpdate(
+                progress.partitionName,
+                progress.installedSize,
+                progress.partitionSize,
+                progress.partitionNumber,
+                progress.totalPartitionNumber);
 
+        mInstallTaskProgress = progress;
         postStatus(STATUS_IN_PROGRESS, CAUSE_NOT_SPECIFIED, null);
     }
 
     @Override
     public void onResult(int result, Throwable detail) {
         if (result == RESULT_OK) {
+            logEventComplete();
             postStatus(STATUS_READY, CAUSE_INSTALL_COMPLETED, null);
 
             // For testing: enable DSU and restart the device when install completed
@@ -223,6 +253,12 @@
             return;
         }
 
+        if (result == RESULT_CANCELLED) {
+            logEventFailed("Dynamic System installation task is canceled by the user.");
+        } else {
+            logEventFailed("error: " + detail);
+        }
+
         boolean removeNotification = false;
         switch (result) {
             case RESULT_CANCELLED:
@@ -251,16 +287,20 @@
     private void executeInstallCommand(Intent intent) {
         if (!verifyRequest(intent)) {
             Log.e(TAG, "Verification failed. Did you use VerificationActivity?");
+            logEventFailed("VerificationActivity");
             return;
         }
 
         if (mInstallTask != null) {
             Log.e(TAG, "There is already an installation task running");
+            logEventFailed("There is already an ongoing installation task.");
             return;
         }
 
         if (isInDynamicSystem()) {
             Log.e(TAG, "We are already running in DynamicSystem");
+            logEventFailed(
+                    "Cannot start a Dynamic System installation task within a Dynamic System.");
             return;
         }
 
@@ -445,19 +485,22 @@
             case STATUS_IN_PROGRESS:
                 builder.setContentText(getString(R.string.notification_install_inprogress));
 
-                int max = 1024;
-                int progress = 0;
+                if (mInstallTaskProgress != null) {
+                    int max = 1024;
+                    int progress = 0;
 
-                int currentMax = max >> (mNumInstalledPartitions + 1);
-                progress = max - currentMax * 2;
+                    int currentMax = max >> mInstallTaskProgress.partitionNumber;
+                    progress = max - currentMax * 2;
 
-                long currentProgress = (mCurrentPartitionInstalledSize >> 20) * currentMax
-                        / Math.max(mCurrentPartitionSize >> 20, 1);
+                    long currentProgress =
+                            (mInstallTaskProgress.installedSize >> 20)
+                                    * currentMax
+                                    / Math.max(mInstallTaskProgress.partitionSize >> 20, 1);
 
-                progress += (int) currentProgress;
+                    progress += (int) currentProgress;
 
-                builder.setProgress(max, progress, false);
-
+                    builder.setProgress(max, progress, false);
+                }
                 builder.addAction(new Notification.Action.Builder(
                         null, getString(R.string.notification_action_cancel),
                         createPendingIntent(ACTION_CANCEL_INSTALL)).build());
@@ -563,13 +606,13 @@
 
         StringBuilder msg = new StringBuilder();
         msg.append("status: " + statusString + ", cause: " + causeString);
-        if (status == STATUS_IN_PROGRESS) {
+        if (status == STATUS_IN_PROGRESS && mInstallTaskProgress != null) {
             msg.append(
                     String.format(
                             ", partition name: %s, progress: %d/%d",
-                            mCurrentPartitionName,
-                            mCurrentPartitionInstalledSize,
-                            mCurrentPartitionSize));
+                            mInstallTaskProgress.partitionName,
+                            mInstallTaskProgress.installedSize,
+                            mInstallTaskProgress.partitionSize));
         }
         if (detail != null) {
             msg.append(", detail: " + detail);
@@ -594,7 +637,10 @@
         Bundle bundle = new Bundle();
 
         // TODO: send more info to the clients
-        bundle.putLong(DynamicSystemClient.KEY_INSTALLED_SIZE, mCurrentPartitionInstalledSize);
+        if (mInstallTaskProgress != null) {
+            bundle.putLong(
+                    DynamicSystemClient.KEY_INSTALLED_SIZE, mInstallTaskProgress.installedSize);
+        }
 
         if (detail != null) {
             bundle.putSerializable(DynamicSystemClient.KEY_EXCEPTION_DETAIL,
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/EventLogTags.logtags b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/EventLogTags.logtags
new file mode 100644
index 0000000..eae9de9
--- /dev/null
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/EventLogTags.logtags
@@ -0,0 +1,7 @@
+# See system/logging/logcat/event.logtags for a description of the format of this file.
+
+option java_package com.android.dynsystem
+
+120000 dsu_progress_update (partition|3),(installed_size|2|5),(partition_size|2|5),(partition_number|1|5),(total_partition_number|1|5)
+120001 dsu_install_complete
+120002 dsu_install_failed (cause|3)
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
index f18d426..998aeeab 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
@@ -23,9 +23,11 @@
 import android.os.Build;
 import android.os.MemoryFile;
 import android.os.ParcelFileDescriptor;
+import android.os.SystemProperties;
 import android.os.image.DynamicSystemManager;
 import android.service.persistentdata.PersistentDataBlockManager;
 import android.util.Log;
+import android.util.Range;
 import android.webkit.URLUtil;
 
 import org.json.JSONException;
@@ -44,11 +46,16 @@
 import java.util.zip.ZipFile;
 import java.util.zip.ZipInputStream;
 
-class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Progress, Throwable> {
+class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
 
     private static final String TAG = "InstallationAsyncTask";
 
-    private static final int READ_BUFFER_SIZE = 1 << 13;
+    private static final int MIN_SHARED_MEMORY_SIZE = 8 << 10; // 8KiB
+    private static final int MAX_SHARED_MEMORY_SIZE = 1024 << 10; // 1MiB
+    private static final int DEFAULT_SHARED_MEMORY_SIZE = 64 << 10; // 64KiB
+    private static final String SHARED_MEMORY_SIZE_PROP =
+            "dynamic_system.data_transfer.shared_memory.size";
+
     private static final long MIN_PROGRESS_TO_PUBLISH = 1 << 27;
 
     private static final List<String> UNSUPPORTED_PARTITIONS =
@@ -106,14 +113,22 @@
 
     static class Progress {
         public final String partitionName;
+        public final long installedSize;
         public final long partitionSize;
-        public final int numInstalledPartitions;
-        public long installedSize;
+        public final int partitionNumber;
+        public final int totalPartitionNumber;
 
-        Progress(String partitionName, long partitionSize, int numInstalledPartitions) {
+        Progress(
+                String partitionName,
+                long installedSize,
+                long partitionSize,
+                int partitionNumber,
+                int totalPartitionNumber) {
             this.partitionName = partitionName;
+            this.installedSize = installedSize;
             this.partitionSize = partitionSize;
-            this.numInstalledPartitions = numInstalledPartitions;
+            this.partitionNumber = partitionNumber;
+            this.totalPartitionNumber = totalPartitionNumber;
         }
     }
 
@@ -123,6 +138,7 @@
         void onResult(int resultCode, Throwable detail);
     }
 
+    private final int mSharedMemorySize;
     private final String mUrl;
     private final String mDsuSlot;
     private final String mPublicKey;
@@ -139,7 +155,10 @@
     private boolean mIsZip;
     private boolean mIsCompleted;
 
-    private int mNumInstalledPartitions;
+    private String mPartitionName;
+    private long mPartitionSize;
+    private int mPartitionNumber;
+    private int mTotalPartitionNumber;
 
     private InputStream mStream;
     private ZipFile mZipFile;
@@ -153,6 +172,11 @@
             Context context,
             DynamicSystemManager dynSystem,
             ProgressListener listener) {
+        mSharedMemorySize =
+                Range.create(MIN_SHARED_MEMORY_SIZE, MAX_SHARED_MEMORY_SIZE)
+                        .clamp(
+                                SystemProperties.getInt(
+                                        SHARED_MEMORY_SIZE_PROP, DEFAULT_SHARED_MEMORY_SIZE));
         mUrl = url;
         mDsuSlot = dsuSlot;
         mPublicKey = publicKey;
@@ -175,11 +199,15 @@
     protected Throwable doInBackground(String... voids) {
         Log.d(TAG, "Start doInBackground(), URL: " + mUrl);
 
+        final boolean wantScratchPartition = Build.IS_DEBUGGABLE;
         try {
             // call DynamicSystemManager to cleanup stuff
             mDynSystem.remove();
 
             verifyAndPrepare();
+            if (wantScratchPartition) {
+                ++mTotalPartitionNumber;
+            }
 
             mDynSystem.startInstallation(mDsuSlot);
 
@@ -198,7 +226,7 @@
                 return null;
             }
 
-            if (Build.IS_DEBUGGABLE) {
+            if (wantScratchPartition) {
                 // If host is debuggable, then install a scratch partition so that we can do
                 // adb remount in the guest system.
                 try {
@@ -262,9 +290,14 @@
     }
 
     @Override
-    protected void onProgressUpdate(Progress... values) {
-        Progress progress = values[0];
-        mListener.onProgressUpdate(progress);
+    protected void onProgressUpdate(Long... installedSize) {
+        mListener.onProgressUpdate(
+                new Progress(
+                        mPartitionName,
+                        installedSize[0],
+                        mPartitionSize,
+                        mPartitionNumber,
+                        mTotalPartitionNumber));
     }
 
     private void verifyAndPrepare() throws Exception {
@@ -281,12 +314,16 @@
             throw new UnsupportedFormatException(
                 String.format(Locale.US, "Unsupported file format: %s", mUrl));
         }
+        // At least two partitions, {system, userdata}
+        mTotalPartitionNumber = 2;
 
         if (mIsNetworkUrl) {
             mStream = new URL(mUrl).openStream();
         } else if (URLUtil.isFileUrl(mUrl)) {
             if (mIsZip) {
                 mZipFile = new ZipFile(new File(new URL(mUrl).toURI()));
+                // {*.img in zip} + {userdata}
+                mTotalPartitionNumber = calculateNumberOfImagesInLocalZip(mZipFile) + 1;
             } else {
                 mStream = new URL(mUrl).openStream();
             }
@@ -333,9 +370,13 @@
             }
         };
 
-        thread.start();
-        Progress progress = new Progress(partitionName, partitionSize, mNumInstalledPartitions++);
+        mPartitionName = partitionName;
+        mPartitionSize = partitionSize;
+        ++mPartitionNumber;
+        publishProgress(/* installedSize = */ 0L);
 
+        long prevInstalledSize = 0;
+        thread.start();
         while (thread.isAlive()) {
             if (isCancelled()) {
                 return;
@@ -343,9 +384,9 @@
 
             final long installedSize = mDynSystem.getInstallationProgress().bytes_processed;
 
-            if (installedSize > progress.installedSize + MIN_PROGRESS_TO_PUBLISH) {
-                progress.installedSize = installedSize;
-                publishProgress(progress);
+            if (installedSize > prevInstalledSize + MIN_PROGRESS_TO_PUBLISH) {
+                publishProgress(installedSize);
+                prevInstalledSize = installedSize;
             }
 
             try {
@@ -392,14 +433,42 @@
         installImage("system", mSystemSize, new GZIPInputStream(mStream));
     }
 
+    private boolean shouldInstallEntry(String name) {
+        if (!name.endsWith(".img")) {
+            return false;
+        }
+        String partitionName = name.substring(0, name.length() - 4);
+        if (UNSUPPORTED_PARTITIONS.contains(partitionName)) {
+            return false;
+        }
+        return true;
+    }
+
+    private int calculateNumberOfImagesInLocalZip(ZipFile zipFile) {
+        int total = 0;
+        Enumeration<? extends ZipEntry> entries = zipFile.entries();
+        while (entries.hasMoreElements()) {
+            ZipEntry entry = entries.nextElement();
+            if (shouldInstallEntry(entry.getName())) {
+                ++total;
+            }
+        }
+        return total;
+    }
+
     private void installStreamingZipUpdate() throws IOException, ImageValidationException {
         Log.d(TAG, "To install a streaming ZIP update");
 
         ZipInputStream zis = new ZipInputStream(mStream);
-        ZipEntry zipEntry = null;
+        ZipEntry entry = null;
 
-        while ((zipEntry = zis.getNextEntry()) != null) {
-            installImageFromAnEntry(zipEntry, zis);
+        while ((entry = zis.getNextEntry()) != null) {
+            String name = entry.getName();
+            if (shouldInstallEntry(name)) {
+                installImageFromAnEntry(entry, zis);
+            } else {
+                Log.d(TAG, name + " installation is not supported, skip it.");
+            }
 
             if (isCancelled()) {
                 break;
@@ -414,7 +483,12 @@
 
         while (entries.hasMoreElements()) {
             ZipEntry entry = entries.nextElement();
-            installImageFromAnEntry(entry, mZipFile.getInputStream(entry));
+            String name = entry.getName();
+            if (shouldInstallEntry(name)) {
+                installImageFromAnEntry(entry, mZipFile.getInputStream(entry));
+            } else {
+                Log.d(TAG, name + " installation is not supported, skip it.");
+            }
 
             if (isCancelled()) {
                 break;
@@ -422,28 +496,16 @@
         }
     }
 
-    private boolean installImageFromAnEntry(ZipEntry entry, InputStream is)
+    private void installImageFromAnEntry(ZipEntry entry, InputStream is)
             throws IOException, ImageValidationException {
         String name = entry.getName();
 
         Log.d(TAG, "ZipEntry: " + name);
 
-        if (!name.endsWith(".img")) {
-            return false;
-        }
-
         String partitionName = name.substring(0, name.length() - 4);
-
-        if (UNSUPPORTED_PARTITIONS.contains(partitionName)) {
-            Log.d(TAG, name + " installation is not supported, skip it.");
-            return false;
-        }
-
         long uncompressedSize = entry.getSize();
 
         installImage(partitionName, uncompressedSize, is);
-
-        return true;
     }
 
     private void installImage(String partitionName, long uncompressedSize, InputStream is)
@@ -492,18 +554,22 @@
 
         Log.d(TAG, "Start installing: " + partitionName);
 
-        MemoryFile memoryFile = new MemoryFile("dsu_" + partitionName, READ_BUFFER_SIZE);
+        MemoryFile memoryFile = new MemoryFile("dsu_" + partitionName, mSharedMemorySize);
         ParcelFileDescriptor pfd = new ParcelFileDescriptor(memoryFile.getFileDescriptor());
 
-        mInstallationSession.setAshmem(pfd, READ_BUFFER_SIZE);
+        mInstallationSession.setAshmem(pfd, memoryFile.length());
 
-        Progress progress = new Progress(partitionName, partitionSize, mNumInstalledPartitions++);
+        mPartitionName = partitionName;
+        mPartitionSize = partitionSize;
+        ++mPartitionNumber;
+        publishProgress(/* installedSize = */ 0L);
 
+        long prevInstalledSize = 0;
         long installedSize = 0;
-        byte[] bytes = new byte[READ_BUFFER_SIZE];
+        byte[] bytes = new byte[memoryFile.length()];
         int numBytesRead;
 
-        while ((numBytesRead = sis.read(bytes, 0, READ_BUFFER_SIZE)) != -1) {
+        while ((numBytesRead = sis.read(bytes, 0, bytes.length)) != -1) {
             if (isCancelled()) {
                 return;
             }
@@ -516,9 +582,9 @@
 
             installedSize += numBytesRead;
 
-            if (installedSize > progress.installedSize + MIN_PROGRESS_TO_PUBLISH) {
-                progress.installedSize = installedSize;
-                publishProgress(progress);
+            if (installedSize > prevInstalledSize + MIN_PROGRESS_TO_PUBLISH) {
+                publishProgress(installedSize);
+                prevInstalledSize = installedSize;
             }
         }
 
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/SparseInputStream.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/SparseInputStream.java
index 4117d0f..7d23266 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/SparseInputStream.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/SparseInputStream.java
@@ -133,36 +133,32 @@
         return mLeft == 0;
     }
 
-    /**
-     * It overrides the InputStream.read(byte[] buf)
-     */
-    public int read(byte[] buf) throws IOException {
+    @Override
+    public int read(byte[] buf, int off, int len) throws IOException {
         if (!mIsSparse) {
-            return mIn.read(buf);
+            return mIn.read(buf, off, len);
         }
         if (prepareChunk()) return -1;
         int n = -1;
         switch (mCur.mChunkType) {
             case SparseChunk.RAW:
-                n = mIn.read(buf, 0, (int) min(mLeft, buf.length));
+                n = mIn.read(buf, off, (int) min(mLeft, len));
                 mLeft -= n;
                 return n;
             case SparseChunk.DONTCARE:
-                n = (int) min(mLeft, buf.length);
-                Arrays.fill(buf, 0, n - 1, (byte) 0);
+                n = (int) min(mLeft, len);
+                Arrays.fill(buf, off, off + n, (byte) 0);
                 mLeft -= n;
                 return n;
             case SparseChunk.FILL:
                 // The FILL type is rarely used, so use a simple implmentation.
-                return super.read(buf);
+                return super.read(buf, off, len);
             default:
                 throw new IOException("Unsupported Chunk:" + mCur.toString());
         }
     }
 
-    /**
-     * It overrides the InputStream.read()
-     */
+    @Override
     public int read() throws IOException {
         if (!mIsSparse) {
             return mIn.read();
diff --git a/packages/PackageInstaller/res/values-ar/strings.xml b/packages/PackageInstaller/res/values-ar/strings.xml
index 2d6fca6..51b18d3 100644
--- a/packages/PackageInstaller/res/values-ar/strings.xml
+++ b/packages/PackageInstaller/res/values-ar/strings.xml
@@ -59,7 +59,7 @@
     <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"هل تريد إزالة تثبيت هذا التطبيق من ملفك الشخصي للعمل؟"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"هل تريد استبدال هذا التطبيق بإصدار المصنع؟ ستتم إزالة جميع البيانات."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"هل تريد إعادة ضبط هذا التطبيق على الإعدادات الأصلية؟ سؤدي ذلك إلى إزالة جميع البيانات، كما سيؤثر على جميع مستخدمي هذا الجهاز، بما في ذلك من لديهم ملفات شخصية للعمل."</string>
-    <string name="uninstall_keep_data" msgid="7002379587465487550">"الاحتفاظ بالحجم <xliff:g id="SIZE">%1$s</xliff:g> من بيانات التطبيق."</string>
+    <string name="uninstall_keep_data" msgid="7002379587465487550">"الاحتفاظ بـ <xliff:g id="SIZE">%1$s</xliff:g> من بيانات التطبيق."</string>
     <string name="uninstalling_notification_channel" msgid="840153394325714653">"عمليات إلغاء التثبيت الجارية"</string>
     <string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"عمليات إلغاء التثبيت غير الناجحة"</string>
     <string name="uninstalling" msgid="8709566347688966845">"جارٍ إلغاء التثبيت…"</string>
diff --git a/packages/PackageInstaller/res/values-or/strings.xml b/packages/PackageInstaller/res/values-or/strings.xml
index 20a3480..ca01d7f 100644
--- a/packages/PackageInstaller/res/values-or/strings.xml
+++ b/packages/PackageInstaller/res/values-or/strings.xml
@@ -88,7 +88,7 @@
     <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"ଅଜଣା ଆପ୍‌ ଦ୍ୱାରା ଆପଣଙ୍କ ଟାବଲେଟ୍‍ ଏବଂ ବ୍ୟକ୍ତିଗତ ଡାଟାକୁ ନଷ୍ଟ କରାଯାଇପାରିବାର ସମ୍ଭାବନା ବହୁତ ଅଧିକ। ଏହି ଆପ୍‌କୁ ଇନଷ୍ଟଲ୍‌ କରିବାର ଅର୍ଥ ହେଉଛି ଆପଣଙ୍କ ଟାବ୍‌ଲେଟ୍‌ରେ ଘଟିବା କୌଣସି ପ୍ରକାର କ୍ଷତି କିମ୍ବା ସେଗୁଡ଼ିକର ବ୍ୟବହାରରୁ ହେବା କୌଣସି ପ୍ରକାର ଡାଟାର ହାନୀ ପାଇଁ ଆପଣ ଦାୟୀ ରହିବାକୁ ରାଜି ହୁଅନ୍ତି।"</string>
     <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"ଅଜଣା ଆପ୍‌ ଦ୍ୱାରା ଆପଣଙ୍କ ଟିଭି ଏବଂ ବ୍ୟକ୍ତିଗତ ଡାଟାକୁ ନଷ୍ଟ କରାଯାଇପାରିବାର ସମ୍ଭାବନା ବହୁତ ଅଧିକ। ଏହି ଆପ୍‌କୁ ଇନଷ୍ଟଲ୍‌ କରିବାର ଅର୍ଥ ହେଉଛି ଆପଣଙ୍କ ଟିଭିରେ ଘଟିବା କୌଣସି ପ୍ରକାର କ୍ଷତି କିମ୍ବା ସେଗୁଡ଼ିକର ବ୍ୟବହାରରୁ ହେବା କୌଣସି ପ୍ରକାର ଡାଟାର ହାନୀ ପାଇଁ ଆପଣ ଦାୟୀ ରହିବାକୁ ରାଜି ହୁଅନ୍ତି।"</string>
     <string name="anonymous_source_continue" msgid="4375745439457209366">"ଜାରି ରଖନ୍ତୁ"</string>
-    <string name="external_sources_settings" msgid="4046964413071713807">"ସେଟିଂସ୍"</string>
+    <string name="external_sources_settings" msgid="4046964413071713807">"ସେଟିଂସ"</string>
     <string name="wear_app_channel" msgid="1960809674709107850">"ୱିଅର୍‍ ଆପ୍‍ ଇନଷ୍ଟଲ୍‌/ଅନଇନଷ୍ଟଲ୍‍ କରାଯାଉଛି"</string>
     <string name="app_installed_notification_channel_description" msgid="2695385797601574123">"ଆପ୍ ଇନ୍‌ଷ୍ଟଲ୍‌ କରାଯାଇଥିବା ବିଜ୍ଞପ୍ତି"</string>
     <string name="notification_installation_success_message" msgid="6450467996056038442">"ସଫଳତାପୂର୍ବକ ଇନ୍‌ଷ୍ଟଲ୍‌ କରାଗଲା"</string>
diff --git a/packages/PrintSpooler/res/values-it/strings.xml b/packages/PrintSpooler/res/values-it/strings.xml
index 40b621c..d898b1e 100644
--- a/packages/PrintSpooler/res/values-it/strings.xml
+++ b/packages/PrintSpooler/res/values-it/strings.xml
@@ -56,8 +56,8 @@
     <string name="print_select_printer" msgid="7388760939873368698">"Seleziona stampante"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Elimina stampante"</string>
     <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
-      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> stampanti trovate</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> stampante trovata</item>
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Ulteriori informazioni su questa stampante"</string>
@@ -76,8 +76,8 @@
     <string name="disabled_services_title" msgid="7313253167968363211">"Servizi disattivati"</string>
     <string name="all_services_title" msgid="5578662754874906455">"Tutti i servizi"</string>
     <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
-      <item quantity="one">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
       <item quantity="other">Installa per rilevare <xliff:g id="COUNT_1">%1$s</xliff:g> stampanti</item>
+      <item quantity="one">Installa per rilevare <xliff:g id="COUNT_0">%1$s</xliff:g> stampante</item>
     </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Stampa di <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Annullamento di <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-pt-rPT/strings.xml b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
index 56001d8..4517efe 100644
--- a/packages/PrintSpooler/res/values-pt-rPT/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
@@ -56,8 +56,8 @@
     <string name="print_select_printer" msgid="7388760939873368698">"Selecionar impressora"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Esquecer impressora"</string>
     <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
-      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> impressora encontrada</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> impressora encontrada</item>
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Mais informações acerca desta impressora"</string>
@@ -76,8 +76,8 @@
     <string name="disabled_services_title" msgid="7313253167968363211">"Serviços desativados"</string>
     <string name="all_services_title" msgid="5578662754874906455">"Todos os serviços"</string>
     <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
-      <item quantity="one">Instale para detetar <xliff:g id="COUNT_0">%1$s</xliff:g> impressora</item>
       <item quantity="other">Instale para detetar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
+      <item quantity="one">Instale para detetar <xliff:g id="COUNT_0">%1$s</xliff:g> impressora</item>
     </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"A imprimir <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"A cancelar <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 1b7298a..9a80b02 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -51,6 +51,7 @@
         "SettingsLibSettingsTransition",
         "SettingsLibButtonPreference",
         "setupdesign",
+        "zxing-core-1.7",
     ],
 
     // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
index 543a5a0..77d6583 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
@@ -63,8 +63,7 @@
             return;
         }
 
-        mToolbardelegate = new CollapsingToolbarDelegate(new DelegateCallback());
-        View view = mToolbardelegate.onCreateView(getLayoutInflater(), null);
+        View view = getToolbarDelegate().onCreateView(getLayoutInflater(), null);
         super.setContentView(view);
     }
 
@@ -107,7 +106,7 @@
 
     @Override
     public void setTitle(CharSequence title) {
-        mToolbardelegate.setTitle(title);
+        getToolbarDelegate().setTitle(title);
     }
 
     @Override
@@ -128,7 +127,7 @@
      */
     @Nullable
     public CollapsingToolbarLayout getCollapsingToolbarLayout() {
-        return mToolbardelegate.getCollapsingToolbarLayout();
+        return getToolbarDelegate().getCollapsingToolbarLayout();
     }
 
     /**
@@ -136,6 +135,13 @@
      */
     @Nullable
     public AppBarLayout getAppBarLayout() {
-        return mToolbardelegate.getAppBarLayout();
+        return getToolbarDelegate().getAppBarLayout();
+    }
+
+    private CollapsingToolbarDelegate getToolbarDelegate() {
+        if (mToolbardelegate == null) {
+            mToolbardelegate = new CollapsingToolbarDelegate(new DelegateCallback());
+        }
+        return mToolbardelegate;
     }
 }
diff --git a/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml b/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml
index b127630..212ae52 100644
--- a/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml
+++ b/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml
@@ -46,7 +46,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:orientation="vertical">
-        <com.android.settingslib.widget.LinkTextView
+        <TextView
             android:id="@android:id/title"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
diff --git a/packages/SettingsLib/FooterPreference/res/layout/preference_footer.xml b/packages/SettingsLib/FooterPreference/res/layout/preference_footer.xml
index 23192b6..d403f9e 100644
--- a/packages/SettingsLib/FooterPreference/res/layout/preference_footer.xml
+++ b/packages/SettingsLib/FooterPreference/res/layout/preference_footer.xml
@@ -45,7 +45,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:orientation="vertical">
-        <com.android.settingslib.widget.LinkTextView
+        <TextView
             android:id="@android:id/title"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
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 3eb6ea9..ac30636 100644
--- a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
+++ b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.text.SpannableString;
 import android.text.TextUtils;
-import android.text.method.LinkMovementMethod;
 import android.text.style.URLSpan;
 import android.util.AttributeSet;
 import android.view.View;
@@ -59,10 +58,6 @@
     public void onBindViewHolder(PreferenceViewHolder holder) {
         super.onBindViewHolder(holder);
         TextView title = holder.itemView.findViewById(android.R.id.title);
-        title.setMovementMethod(new LinkMovementMethod());
-        title.setClickable(false);
-        title.setLongClickable(false);
-        title.setFocusable(false);
         if (!TextUtils.isEmpty(mContentDescription)) {
             title.setContentDescription(mContentDescription);
         }
@@ -86,7 +81,6 @@
             if (!TextUtils.isEmpty(mLearnMoreContentDescription)) {
                 learnMore.setContentDescription(mLearnMoreContentDescription);
             }
-            learnMore.setFocusable(false);
         } else {
             learnMore.setVisibility(View.GONE);
         }
@@ -180,6 +174,7 @@
         if (TextUtils.isEmpty(getKey())) {
             setKey(KEY_FOOTER);
         }
+        setSelectable(false);
     }
 
     /**
diff --git a/packages/SettingsLib/SearchWidget/res/values-or/strings.xml b/packages/SettingsLib/SearchWidget/res/values-or/strings.xml
index cf824de..322571ad 100644
--- a/packages/SettingsLib/SearchWidget/res/values-or/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-or/strings.xml
@@ -17,5 +17,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="search_menu" msgid="1914043873178389845">"ସେଟିଂସ୍ ସନ୍ଧାନ କରନ୍ତୁ"</string>
+    <string name="search_menu" msgid="1914043873178389845">"ସେଟିଂସ ସନ୍ଧାନ କରନ୍ତୁ"</string>
 </resources>
diff --git a/packages/SettingsLib/SettingsSpinner/Android.bp b/packages/SettingsLib/SettingsSpinner/Android.bp
index c5b2fe6..d3cc4d1 100644
--- a/packages/SettingsLib/SettingsSpinner/Android.bp
+++ b/packages/SettingsLib/SettingsSpinner/Android.bp
@@ -15,6 +15,7 @@
 
     static_libs: [
         "androidx.preference_preference",
+        "SettingsLibSettingsTheme",
     ],
 
     sdk_version: "system_current",
diff --git a/packages/SettingsLib/SettingsSpinner/res/values-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_text_color_primary.xml
similarity index 66%
copy from packages/SettingsLib/SettingsSpinner/res/values-v31/colors.xml
copy to packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_text_color_primary.xml
index 8fda876..221d2db 100644
--- a/packages/SettingsLib/SettingsSpinner/res/values-v31/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_text_color_primary.xml
@@ -14,7 +14,9 @@
      limitations under the License.
 -->
 
-<resources>
-    <color name="settingslib_spinner_title_color">@android:color/system_neutral1_900</color>
-    <color name="settingslib_spinner_dropdown_color">@android:color/system_neutral2_700</color>
-</resources>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+        android:alpha="?android:attr/disabledAlpha"
+        android:color="@color/settingslib_text_color_primary_device_default"/>
+    <item android:color="@color/settingslib_text_color_primary_device_default"/>
+</selector>
diff --git a/packages/SettingsLib/SettingsSpinner/res/values-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_text_color_secondary.xml
similarity index 66%
rename from packages/SettingsLib/SettingsSpinner/res/values-v31/colors.xml
rename to packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_text_color_secondary.xml
index 8fda876..98ea3ea 100644
--- a/packages/SettingsLib/SettingsSpinner/res/values-v31/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_text_color_secondary.xml
@@ -14,7 +14,9 @@
      limitations under the License.
 -->
 
-<resources>
-    <color name="settingslib_spinner_title_color">@android:color/system_neutral1_900</color>
-    <color name="settingslib_spinner_dropdown_color">@android:color/system_neutral2_700</color>
-</resources>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+        android:alpha="?android:attr/disabledAlpha"
+        android:color="@color/settingslib_text_color_secondary_device_default"/>
+    <item android:color="@color/settingslib_text_color_secondary_device_default"/>
+</selector>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
index c4dbc5e..fe47e85 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
@@ -79,4 +79,7 @@
     <color name="settingslib_colorAccentSecondary">@color/settingslib_accent_secondary_device_default</color>
 
     <color name="settingslib_colorSurface">@color/settingslib_surface_light</color>
+
+    <color name="settingslib_spinner_title_color">@android:color/system_neutral1_900</color>
+    <color name="settingslib_spinner_dropdown_color">@android:color/system_neutral2_700</color>
 </resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
index 9d39911..b12c6d2 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
@@ -17,14 +17,14 @@
 <resources>
     <style name="TextAppearance.PreferenceTitle.SettingsLib"
            parent="@android:style/TextAppearance.Material.Subhead">
-        <item name="android:textColor">@color/settingslib_text_color_primary_device_default</item>
+        <item name="android:textColor">@color/settingslib_text_color_primary</item>
         <item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
         <item name="android:textSize">20sp</item>
     </style>
 
     <style name="TextAppearance.PreferenceSummary.SettingsLib"
            parent="@android:style/TextAppearance.DeviceDefault.Small">
-        <item name="android:textColor">@color/settingslib_text_color_secondary_device_default</item>
+        <item name="android:textColor">@color/settingslib_text_color_secondary</item>
     </style>
 
     <style name="TextAppearance.CategoryTitle.SettingsLib"
@@ -54,4 +54,15 @@
         <item name="android:layout_marginTop">16dp</item>
         <item name="android:layout_marginBottom">8dp</item>
     </style>
+
+    <style name="SpinnerItem.SettingsLib"
+           parent="@android:style/Widget.DeviceDefault.TextView.SpinnerItem">
+        <item name="android:textColor">@color/settingslib_spinner_dropdown_color</item>
+    </style>
+
+    <style name="SpinnerDropDownItem.SettingsLib"
+           parent="@android:style/Widget.Material.DropDownItem.Spinner">
+        <item name="android:textColor">@color/settingslib_spinner_dropdown_color</item>
+    </style>
+
 </resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
index e9bbcc78..4f426a3 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
@@ -27,6 +27,8 @@
         <item name="android:switchStyle">@style/Switch.SettingsLib</item>
         <item name="android:progressBarStyleHorizontal">@style/HorizontalProgressBar.SettingsLib</item>
         <item name="android:spinnerStyle">@style/Spinner.SettingsLib</item>
+        <item name="android:spinnerItemStyle">@style/SpinnerItem.SettingsLib</item>
+        <item name="android:spinnerDropDownItemStyle">@style/SpinnerDropDownItem.SettingsLib</item>
     </style>
 
     <!-- Using in SubSettings page including injected settings page -->
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 24d1171..23f9a13 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Minder tyd."</string>
     <string name="cancel" msgid="5665114069455378395">"Kanselleer"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Wekkers en onthounotas"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Laat toe dat wekkers en onthounotas gestel word"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Wekkers en onthounotas"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Vra elke keer"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Totdat jy dit afskakel"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Sopas"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Hierdie foon"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Hierdie foon"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Hierdie foon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Kan nie koppel nie. Skakel toestel af en weer aan"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Bedrade oudiotoestel"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Stel slot op"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Skakel oor na <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Skep tans nuwe gebruiker …"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Skep tans nuwe gas …"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Kon nie \'n nuwe gebruiker skep nie"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Kon nie ’n nuwe gas skep nie"</string>
     <string name="user_nickname" msgid="262624187455825083">"Bynaam"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Voeg gas by"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Verwyder gas"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Uitsaai-inligting"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Kies \'n profielprent"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Verstekgebruikerikoon"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Fisieke sleutelbord"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Kies sleutelborduitleg"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Verstek"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index e620141..c32e94f 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"ያነሰ ጊዜ።"</string>
     <string name="cancel" msgid="5665114069455378395">"ይቅር"</string>
     <string name="okay" msgid="949938843324579502">"እሺ"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"ማንቂያዎች እና አስታዋሾች"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"ማንቂያዎች እና አስታዋሾች እንዲዋቀሩ ይፍቀዱ"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"ማንቂያዎች እና አስታዋሾች"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"ሁልጊዜ ጠይቅ"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"እስኪያጠፉት ድረስ"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"ልክ አሁን"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ይህ ስልክ"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ይህ ስልክ"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"ይህ ስልክ"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"መገናኘት ላይ ችግር። መሳሪያውን ያጥፉት እና እንደገና ያብሩት"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ባለገመድ የኦዲዮ መሣሪያ"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"ቁልፍ አዘጋጅ"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"ወደ <xliff:g id="USER_NAME">%s</xliff:g> ቀይር"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"አዲስ ተጠቃሚ በመፍጠር ላይ…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"አዲስ እንግዳ በመፍጠር ላይ…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"አዲስ ተጠቃሚን መፍጠር አልተሳካም"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"አዲስ እንግዳ መፍጠር አልተሳካም"</string>
     <string name="user_nickname" msgid="262624187455825083">"ቅጽል ስም"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"እንግዳን አክል"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"እንግዳን አስወግድ"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"የCast መረጃ"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"የመገለጫ ሥዕል ይምረጡ"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"ነባሪ የተጠቃሚ አዶ"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"አካላዊ ቁልፍ ሰሌዳ"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"የቁልፍ ሰሌዳ አቀማመጥን ይምረጡ"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ነባሪ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 65e37e8..894bc3f 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"وقت أقل."</string>
     <string name="cancel" msgid="5665114069455378395">"إلغاء"</string>
     <string name="okay" msgid="949938843324579502">"حسنًا"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"المنبّهات والتذكيرات"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"السماح بضبط المنبّهات والتذكيرات"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"المنبّهات والتذكيرات"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"السؤال في كل مرة"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"إلى أن يتم إيقاف الوضع"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"للتو"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"هذا الهاتف"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"هذا الهاتف"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"هذا الهاتف"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"حدثت مشكلة أثناء الاتصال. يُرجى إيقاف الجهاز ثم إعادة تشغيله."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"جهاز سماعي سلكي"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"تعيين التأمين"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"التبديل إلى <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"جارٍ إنشاء مستخدم جديد…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"جارٍ إنشاء جلسة ضيف جديدة…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"تعذّر إنشاء مستخدم جديد."</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"تعذّر إنشاء جلسة ضيف جديدة."</string>
     <string name="user_nickname" msgid="262624187455825083">"اللقب"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"إضافة ضيف"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"إزالة جلسة الضيف"</string>
@@ -644,4 +650,10 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"معلومات البث"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"اختيار صورة الملف الشخصي"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"رمز المستخدم التلقائي"</string>
+    <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index f965a34..4ed2e38 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"কম সময়।"</string>
     <string name="cancel" msgid="5665114069455378395">"বাতিল কৰক"</string>
     <string name="okay" msgid="949938843324579502">"ঠিক"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"এলাৰ্ম আৰু ৰিমাইণ্ডাৰ"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"এলাৰ্ম আৰু ৰিমাইণ্ডাৰ ছেট কৰাৰ অনুমতি দিয়ক"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"এলাৰ্ম আৰু ৰিমাইণ্ডাৰ"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"প্ৰতিবাৰতে সোধক"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"আপুনি অফ নকৰা পর্যন্ত"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"এই মাত্ৰ"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"এই ফ’নটো"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"এই ফ’নটো"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"এই ফ’নটো"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"সংযোগ হোৱাত সমস্যা হৈছে। ডিভাইচটো অফ কৰি পুনৰ অন কৰক"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"তাঁৰযুক্ত অডিঅ’ ডিভাইচ"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"লক ছেট কৰক"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>লৈ সলনি কৰক"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"নতুন ব্যৱহাৰকাৰী সৃষ্টি কৰি থকা হৈছে…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"নতুন অতিথি সৃষ্টি কৰি থকা হৈছে…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"নতুন ব্যৱহাৰকাৰী সৃষ্টি কৰিব পৰা নগ’ল"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"নতুন অতিথি সৃষ্টি কৰিব পৰা নগ’ল"</string>
     <string name="user_nickname" msgid="262624187455825083">"উপনাম"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"অতিথি যোগ কৰক"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"অতিথি আঁতৰাওক"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"কাষ্টৰ তথ্য"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"এখন প্ৰ’ফাইল চিত্ৰ বাছনি কৰক"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"ডিফ’ল্ট ব্যৱহাৰকাৰীৰ চিহ্ন"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"কায়িক কীব’ৰ্ড"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"কীব\'ৰ্ডৰ চানেকি বাছক"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ডিফ’ল্ট"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 3fb3f2c..4b2fa6c 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Daha az vaxt."</string>
     <string name="cancel" msgid="5665114069455378395">"Ləğv edin"</string>
     <string name="okay" msgid="949938843324579502">"Ok"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Siqnallar və xatırladıcılar"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Siqnallar və xatırlatmaları ayarlamağa icazə verin"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Siqnallar və xatırlatmalar"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Həmişə soruşulsun"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Deaktiv edilənə qədər"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"İndicə"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Bu telefon"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Bu telefon"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Bu telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Qoşulmaqla bağlı problem. Cihazı deaktiv edin, sonra yenidən aktiv edin"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Simli audio cihaz"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Kilid ayarlayın"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> adlı istifadəçiyə keçin"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Yeni istifadəçi yaradılır…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Yeni qonaq yaradılır…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Yeni istifadəçi yaratmaq alınmadı"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Yeni qonaq yaratmaq alınmadı"</string>
     <string name="user_nickname" msgid="262624187455825083">"Ləqəb"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Qonaq əlavə edin"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Qonağı silin"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Yayım məlumatı"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Profil şəkli seçin"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Defolt istifadəçi ikonası"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Fiziki klaviatura"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Klaviatura düzənini seçin"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Defolt"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index a267b46..ffc38bf 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Manje vremena."</string>
     <string name="cancel" msgid="5665114069455378395">"Otkaži"</string>
     <string name="okay" msgid="949938843324579502">"Potvrdi"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmi i podsetnici"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Omogući podešavanje alarma i podsetnika"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmi i podsetnici"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Pitaj svaki put"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Dok ne isključite"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Upravo"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ovaj telefon"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ovaj telefon"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Ovaj telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem pri povezivanju. Isključite uređaj, pa ga ponovo uključite"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audio uređaj"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Podesi zaključavanje"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Pređi na korisnika <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Pravi se novi korisnik…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Pravi se novi gost…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Pravljenje novog korisnika nije uspelo"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Pravljenje novog gosta nije uspelo"</string>
     <string name="user_nickname" msgid="262624187455825083">"Nadimak"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gosta"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Podaci o prebacivanju"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Odaberite sliku profila"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Podrazumevana ikona korisnika"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Fizička tastatura"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Odaberite raspored tastature"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Podrazumevano"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 4a1f387..ddadbea 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Менш часу."</string>
     <string name="cancel" msgid="5665114069455378395">"Скасаваць"</string>
     <string name="okay" msgid="949938843324579502">"ОК"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Будзільнікі і напаміны"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Дазволіць усталёўваць будзільнікі і напаміны"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Будзільнікі і напаміны"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Заўсёды пытацца"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Пакуль не выключыце"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Толькі што"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Гэты тэлефон"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Гэты тэлефон"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Гэты тэлефон"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Праблема з падключэннем. Выключыце і зноў уключыце прыладу"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Правадная аўдыяпрылада"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Усталёўка блакiроўкi"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Пераключыцца на карыстальніка <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Ствараецца новы карыстальнік…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Ствараецца новы госць…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Не ўдалося стварыць новага карыстальніка"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Не ўдалося стварыць новага госця"</string>
     <string name="user_nickname" msgid="262624187455825083">"Псеўданім"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Дадаць госця"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Выдаліць госця"</string>
@@ -644,4 +650,10 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Даныя пра трансляцыю"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Выберыце відарыс профілю"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Стандартны карыстальніцкі значок"</string>
+    <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index c3fd060..42f8782 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"По-малко време."</string>
     <string name="cancel" msgid="5665114069455378395">"Отказ"</string>
     <string name="okay" msgid="949938843324579502">"ОK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Будилници и напомняния"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Разреш. на задаването на будилници и напомняния"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Будилници и напомняния"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Да се пита винаги"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"До изключване"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Току-що"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Този телефон"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Този телефон"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Този телефон"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"При свързването възникна проблем. Изключете устройството и го включете отново"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Аудиоустройство с кабел"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Задаване на заключване"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Превключване към: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Създава се нов потребител…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Новият гост се създава…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Неуспешно създаване на нов потребител"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Създаването на нов гост не бе успешно"</string>
     <string name="user_nickname" msgid="262624187455825083">"Псевдоним"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Добавяне на гост"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Премахване на госта"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Предаване: Инф."</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Изберете снимка на потребителския профил"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Икона за основния потребител"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Физическа клавиатура"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Избор на клавиатурна подредба"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"По подразбиране"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 2e9360e..d21cfad 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"আরও কম।"</string>
     <string name="cancel" msgid="5665114069455378395">"বাতিল"</string>
     <string name="okay" msgid="949938843324579502">"ঠিক আছে"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"অ্যালার্ম এবং রিমাইন্ডার"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"অ্যালার্ম এবং রিমাইন্ডার সেট করার অনুমতি দিন"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"অ্যালার্ম এবং রিমাইন্ডার"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"প্রতিবার জিজ্ঞেস করা হবে"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"যতক্ষণ না আপনি বন্ধ করছেন"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"এখনই"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"এই ফোন"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"এই ফোন"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"এই ফোনটি"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"কানেক্ট করতে সমস্যা হচ্ছে। ডিভাইস বন্ধ করে আবার চালু করুন"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ওয়্যার অডিও ডিভাইস"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"লক সেট করুন"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>-এ পাল্টান"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"নতুন ব্যবহারকারী তৈরি করা হচ্ছে…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"নতুন অতিথি তৈরি করা হচ্ছে…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"নতুন ব্যবহারকারী যোগ করা যায়নি"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"নতুন অতিথি তৈরি করা যায়নি"</string>
     <string name="user_nickname" msgid="262624187455825083">"বিশেষ নাম"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"অতিথি যোগ করুন"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"অতিথি সরান"</string>
@@ -644,4 +650,10 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"কাস্ট সম্পর্কিত তথ্য"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"একটি প্রোফাইল ছবি বেছে নিন"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"ডিফল্ট ব্যবহারকারীর আইকন"</string>
+    <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 77711cc..c17532b 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Manje vremena."</string>
     <string name="cancel" msgid="5665114069455378395">"Otkaži"</string>
     <string name="okay" msgid="949938843324579502">"Uredu"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmi i podsjetnici"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Dozvoli postavljanje alarma i podsjetnika"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmi i podsjetnici"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Pitaj svaki put"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Dok ne isključite"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Upravo"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ovaj telefon"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ovaj telefon"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Ovaj telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Došlo je do problema prilikom povezivanja. Isključite, pa ponovo uključite uređaj"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audio uređaj"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Postaviti zaključavanje"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Prebaci na korisnika <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Kreiranje novog korisnika…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Kreiranje novog gosta…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Kreiranje novog korisnika nije uspjelo"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Kreiranje novog gosta nije uspjelo"</string>
     <string name="user_nickname" msgid="262624187455825083">"Nadimak"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gosta"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Podaci o emitiranju"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Odaberite sliku profila"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Zadana ikona korisnika"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Fizička tastatura"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Odaberite raspored tastature"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Zadano"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 92e7c1a..c7f9ce6 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Menys temps"</string>
     <string name="cancel" msgid="5665114069455378395">"Cancel·la"</string>
     <string name="okay" msgid="949938843324579502">"D\'acord"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes i recordatoris"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permet la configuració d\'alarmes i recordatoris"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes i recordatoris"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Pregunta sempre"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Fins que no el desactivis"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Ara mateix"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Aquest telèfon"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Aquest telèfon"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Aquest telèfon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Hi ha hagut un problema amb la connexió. Apaga el dispositiu i torna\'l a encendre."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositiu d\'àudio amb cable"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Defineix un bloqueig"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Canvia a <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"S\'està creant l\'usuari…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"S\'està creant un convidat…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"No s\'ha pogut crear l\'usuari"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"No s\'ha pogut crear un convidat"</string>
     <string name="user_nickname" msgid="262624187455825083">"Àlies"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Afegeix un convidat"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Suprimeix el convidat"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Informació d\'emissió"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Tria una foto de perfil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Icona d\'usuari predeterminat"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Teclat físic"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Tria una disposició de teclat"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Predeterminat"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 014eda9..d7c8ed2 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Kratší doba"</string>
     <string name="cancel" msgid="5665114069455378395">"Zrušit"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Budíky a připomenutí"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Povolit nastavování budíků a připomenutí"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Budíky a připomenutí"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Pokaždé se zeptat"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Dokud funkci nevypnete"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Právě teď"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Tento telefon"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Tento telefon"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Tento telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problém s připojením. Vypněte zařízení a znovu jej zapněte"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kabelové audiozařízení"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Nastavit zámek"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Přepnout na uživatele <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Vytváření nového uživatele…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Vytváření nového hosta…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Nového uživatele se nepodařilo vytvořit"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Vytvoření nového hosta se nezdařilo"</string>
     <string name="user_nickname" msgid="262624187455825083">"Přezdívka"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Přidat hosta"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Odstranit hosta"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info o odesílání"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Vyberte profilový obrázek"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Výchozí uživatelská ikona"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Fyzická klávesnice"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Zvolte rozložení klávesnice"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Výchozí"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index d10975d..19caaa5 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Mindre tid."</string>
     <string name="cancel" msgid="5665114069455378395">"Annuller"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmer og påmindelser"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Tillad indstilling af alarmer og påmindelser"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmer og påmindelser"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Spørg hver gang"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Indtil du deaktiverer"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Lige nu"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Denne telefon"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Denne telefon"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Denne telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Der kunne ikke oprettes forbindelse. Sluk og tænd enheden"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Lydenhed med ledning"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Konfigurer låseskærmen"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Skift til <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Opretter ny bruger…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Opretter ny gæst…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Der kunne ikke oprettes en ny bruger"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Der kunne ikke oprettes en ny gæst"</string>
     <string name="user_nickname" msgid="262624187455825083">"Kaldenavn"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Tilføj gæst"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Fjern gæsten"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Cast-oplysninger"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Vælg et profilbillede"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Ikon for standardbruger"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Fysisk tastatur"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Vælg tastaturlayout"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Standard"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 9b8b3b5..594129b 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -95,7 +95,7 @@
     <string name="bluetooth_disconnecting" msgid="7638892134401574338">"Verbindung wird getrennt..."</string>
     <string name="bluetooth_connecting" msgid="5871702668260192755">"Verbindung wird hergestellt..."</string>
     <string name="bluetooth_connected" msgid="8065345572198502293">"Mit <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> verbunden"</string>
-    <string name="bluetooth_pairing" msgid="4269046942588193600">"Verbindung wird hergestellt…"</string>
+    <string name="bluetooth_pairing" msgid="4269046942588193600">"Wird gekoppelt…"</string>
     <string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"Mit <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> verbunden (kein Telefon-Audio)"</string>
     <string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"Mit <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> verbunden (kein Medien-Audio)"</string>
     <string name="bluetooth_connected_no_map" msgid="3381860077002724689">"Mit <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> verbunden (kein Nachrichtenzugriff)"</string>
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Weniger Zeit."</string>
     <string name="cancel" msgid="5665114069455378395">"Abbrechen"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Wecker und Erinnerungen"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Erlauben, Wecker und Erinnerungen einzurichten"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Wecker und Erinnerungen"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Jedes Mal fragen"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Bis zur Deaktivierung"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Gerade eben"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Dieses Smartphone"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Dieses Smartphone"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Dieses Smartphone"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Verbindung kann nicht hergestellt werden. Schalte das Gerät aus &amp; und wieder ein."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Netzbetriebenes Audiogerät"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Sperre einrichten"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Zu <xliff:g id="USER_NAME">%s</xliff:g> wechseln"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Neuer Nutzer wird erstellt…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Neuer Gast wird erstellt…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Nutzer konnte nicht erstellt werden"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Fehler beim Erstellen eines neuen Gasts"</string>
     <string name="user_nickname" msgid="262624187455825083">"Alias"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Gast hinzufügen"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Gast entfernen"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Streaming-Info"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Profilbild auswählen"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Standardmäßiges Nutzersymbol"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Physische Tastatur"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Tastaturlayout wählen"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Standard"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index cb6ec17..b913da7 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Λιγότερη ώρα."</string>
     <string name="cancel" msgid="5665114069455378395">"Ακύρωση"</string>
     <string name="okay" msgid="949938843324579502">"ΟΚ"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Ξυπνητήρια και ειδοποιήσεις"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Να επιτρέπεται ο ορισμός ξυπνητ. και υπενθυμίσεων"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Ξυπνητήρια και υπενθυμίσεις"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Να ερωτώμαι κάθε φορά"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Μέχρι την απενεργοποίηση"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Μόλις τώρα"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Αυτό το τηλέφωνο"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Αυτό το τηλέφωνο"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Αυτό το τηλέφωνο"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Πρόβλημα κατά τη σύνδεση. Απενεργοποιήστε τη συσκευή και ενεργοποιήστε την ξανά"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Ενσύρματη συσκευή ήχου"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Ορισμός κλειδώματος"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Εναλλαγή σε <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Δημιουργία νέου χρήστη…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Δημιουργία νέου προσκεκλημένου…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Η δημιουργία νέου χρήστη απέτυχε"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Αποτυχία δημιουργίας νέου προσκεκλημένου"</string>
     <string name="user_nickname" msgid="262624187455825083">"Ψευδώνυμο"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Προσθήκη επισκέπτη"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Κατάργηση επισκέπτη"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Πληροφορίες ηθοποιών"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Επιλογή φωτογραφίας προφίλ"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Προεπιλεγμένο εικονίδιο χρήστη"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Φυσικό πληκτρολόγιο"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Επιλέξτε διάταξη πληκτρολογίου"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Προεπιλογή"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index c2c14b4..d6dce99 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -533,6 +533,7 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Less time."</string>
     <string name="cancel" msgid="5665114069455378395">"Cancel"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <string name="done" msgid="381184316122520313">"Done"</string>
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarms and reminders"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Allow setting alarms and reminders"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarms &amp; reminders"</string>
@@ -551,7 +552,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Ask every time"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Until you turn off"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"This phone"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"This phone"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"This phone"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string>
@@ -591,7 +594,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Set lock"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Switch to <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creating new user…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Creating new guest…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Failed to create a new user"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Failed to create a new guest"</string>
     <string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
@@ -644,4 +649,10 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Cast info"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Choose a profile picture"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Default user icon"</string>
+    <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 91d4a31..76d1a94 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -533,6 +533,7 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Less time."</string>
     <string name="cancel" msgid="5665114069455378395">"Cancel"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <string name="done" msgid="381184316122520313">"Done"</string>
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarms and reminders"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Allow setting alarms and reminders"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarms &amp; reminders"</string>
@@ -551,7 +552,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Ask every time"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Until you turn off"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"This phone"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"This phone"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"This phone"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string>
@@ -591,7 +594,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Set lock"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Switch to <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creating new user…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Creating new guest…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Failed to create a new user"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Failed to create a new guest"</string>
     <string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
@@ -644,4 +649,10 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Cast info"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Choose a profile picture"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Default user icon"</string>
+    <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index c2c14b4..d6dce99 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -533,6 +533,7 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Less time."</string>
     <string name="cancel" msgid="5665114069455378395">"Cancel"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <string name="done" msgid="381184316122520313">"Done"</string>
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarms and reminders"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Allow setting alarms and reminders"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarms &amp; reminders"</string>
@@ -551,7 +552,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Ask every time"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Until you turn off"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"This phone"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"This phone"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"This phone"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string>
@@ -591,7 +594,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Set lock"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Switch to <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creating new user…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Creating new guest…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Failed to create a new user"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Failed to create a new guest"</string>
     <string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
@@ -644,4 +649,10 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Cast info"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Choose a profile picture"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Default user icon"</string>
+    <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index c2c14b4..d6dce99 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -533,6 +533,7 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Less time."</string>
     <string name="cancel" msgid="5665114069455378395">"Cancel"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <string name="done" msgid="381184316122520313">"Done"</string>
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarms and reminders"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Allow setting alarms and reminders"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarms &amp; reminders"</string>
@@ -551,7 +552,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Ask every time"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Until you turn off"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"This phone"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"This phone"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"This phone"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string>
@@ -591,7 +594,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Set lock"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Switch to <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creating new user…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Creating new guest…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Failed to create a new user"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Failed to create a new guest"</string>
     <string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
@@ -644,4 +649,10 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Cast info"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Choose a profile picture"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Default user icon"</string>
+    <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index ebb1d0e..f02d0c5 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -533,6 +533,7 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‎‏‎‏‎‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‏‎‎‏‎‏‎‎‎‎‏‎‎‎‏‎‎‎‏‎‎‏‏‎‏‎Less time.‎‏‎‎‏‎"</string>
     <string name="cancel" msgid="5665114069455378395">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‎‏‏‏‏‎‏‎‎‎‎‏‏‏‎‎‏‏‏‎‏‏‎‎‏‎‏‎‎‏‏‏‏‏‎‏‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‎Cancel‎‏‎‎‏‎"</string>
     <string name="okay" msgid="949938843324579502">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‎‏‎‎‏‎‏‏‏‎‏‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‎‏‎‏‎‎‏‎‏‎‏‏‎‏‎‎‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‎OK‎‏‎‎‏‎"</string>
+    <string name="done" msgid="381184316122520313">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‏‏‎‏‎‏‎‎‏‎‏‎‎‎‏‏‏‏‎‏‎‎‎‏‏‏‎‏‏‎‏‎‏‏‎‎‎‏‏‎‏‏‏‎‏‏‎‏‏‎‏‎‏‏‏‏‏‎‎‏‎Done‎‏‎‎‏‎"</string>
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‎‎‎‏‏‎‎‎‏‎‏‎‎‎‎‏‏‎‎‎‎‎‎‏‎‏‏‎‏‏‏‎‏‏‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‏‎‎Alarms and reminders‎‏‎‎‏‎"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‏‎‎‏‎‎‎‏‏‎‎‎‏‎‎‎‎‎‎‏‎‎‏‎‏‏‏‏‎‏‎‏‏‏‎‏‎‎‏‎‏‎‎‏‏‏‎‏‏‎‎‎‎‏‎‏‏‏‎‎Allow setting alarms and reminders‎‏‎‎‏‎"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‎‏‎‏‏‎‎‏‎‏‎‎‏‎‎‏‎‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‏‎‎‎‎‎Alarms &amp; reminders‎‏‎‎‏‎"</string>
@@ -551,7 +552,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‎‎‏‎‎‏‎‏‏‎‏‏‎‏‏‎‏‏‏‎‎‏‏‏‏‏‎‎‎‏‎‏‏‎‎‏‏‎‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‎‎‎‏‏‎Ask every time‎‏‎‎‏‎"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‏‎‏‎‏‏‏‎‏‎‎‏‏‏‎‏‏‏‏‏‏‎‏‎‎‎‏‎‏‎‏‎‎‎‎‏‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‏‎‏‏‎Until you turn off‎‏‎‎‏‎"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎‎‎‎‏‎‏‏‏‎‏‎‎‎‏‏‏‎‎‏‎‏‏‏‎‏‏‎‎‏‎‎‎‏‏‎Just now‎‏‎‎‏‎"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‏‏‎‏‎‏‎‎‏‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎‎‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‏‎‏‎‎‎‏‎This phone‎‏‎‎‏‎"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‏‏‎‏‎‏‎‎‏‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎‎‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‏‎‏‎‎‎‏‎This phone‎‏‎‎‏‎"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‎‏‎‏‏‏‎‏‏‎‏‏‏‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‏‏‏‎‎‎‎‏‎‎‏‎‏‏‏‎‎‏‏‏‎‏‎‏‏‎This phone‎‏‎‎‏‎"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‏‏‏‎‏‎‎‎‏‎‎‏‎‎‏‎‏‎‏‎‎‎‎‏‎‎‎‏‎‎‎‎‎‎‏‎‎‏‎‎‏‎‏‎‎‎‏‏‏‎‎‎‏‎Problem connecting. Turn device off &amp; back on‎‏‎‎‏‎"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‏‏‏‎‏‎‎‎‎‎‏‏‎‎‎‎‎‏‏‏‎‎‏‏‎‏‎‏‎‏‏‎‎‏‏‎‏‎‎‎‏‏‎‎‎‏‏‏‎‎‎‏‏‏‎Wired audio device‎‏‎‎‏‎"</string>
@@ -591,7 +594,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‏‏‏‏‎‎‏‏‏‎‎‎‏‎‏‏‎‏‏‎‎‎‎‏‎‏‏‏‏‎‎‎‏‎‏‏‎‏‎‏‎‏‏‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‎Set lock‎‏‎‎‏‎"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‏‏‎‏‏‎‏‏‎‎‏‏‎‎‎‏‎‏‎‎‎‎‏‏‎‎‎‎‎‎‏‎‎‎‎‏‎‎‏‏‏‎‏‏‏‏‎‏‏‏‏‏‎Switch to ‎‏‎‎‏‏‎<xliff:g id="USER_NAME">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‎‎‎‎‎‎‏‎‏‏‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‎‏‎‏‏‎‎‎‏‎‏‏‏‏‎‏‎‎‏‏‎‎‎‎‎‏‏‏‎Creating new user…‎‏‎‎‏‎"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‏‏‎‏‏‏‏‎‎‎‏‏‏‏‎‎‎‎‏‎‏‏‏‏‎‎‏‏‏‏‏‎‎‎‎‎‎‏‏‏‎‎‏‏‎‎‎‏‎‏‎‎‏‎‎‎‏‎‎Creating new guest…‎‏‎‎‏‎"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‏‎‏‏‎‎‎‎‎‎‎‎‏‎‎‏‏‏‎‏‏‏‎‏‏‏‎‎‎‎‏‏‎‏‏‎‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‎‏‎‏‎‎‎‎Failed to create a new user‎‏‎‎‏‎"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‏‎‎‎‎‎‏‎‏‎‎‏‏‎‏‏‎‎‏‎‎‎‎‏‎‏‏‏‏‎‎‎‏‏‏‏‏‎‎‏‏‎Failed to create a new guest‎‏‎‎‏‎"</string>
     <string name="user_nickname" msgid="262624187455825083">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‎‏‏‏‎‏‎‎‏‎‏‎‎‎‎‎‏‏‏‎‏‎‎‏‏‏‎‏‎‎‏‏‎‏‎‏‎‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‎‏‏‏‎‏‏‎Nickname‎‏‎‎‏‎"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‏‎‎‏‎‏‎‏‎‎‏‎‎‎‏‎‎‏‏‏‏‎‏‏‎‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‎‎‏‏‎‏‏‏‎‎‏‎‏‎Add guest‎‏‎‎‏‎"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎‎‎‎‎‎‏‏‎‎‏‎‎‏‏‏‎‎‎‎Remove guest‎‏‎‎‏‎"</string>
@@ -644,4 +649,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‎‏‏‎‎‏‎‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‏‎‎‏‏‏‏‏‎‎‏‎‎‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎Cast Info‎‏‎‎‏‎"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‎‎‏‏‎‎‏‎‎‏‎‎‏‎‏‎‎‎‎‏‏‎‏‎‎‏‎‎‎‏‏‎‏‏‎‎‎‏‎‏‏‎‏‏‎‏‏‏‎‎‎Choose a profile picture‎‏‎‎‏‎"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‎‏‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‏‏‎‏‎‏‎‎‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎Default user icon‎‏‎‎‏‎"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‏‎‏‏‎‎‎‏‏‏‎‏‏‎‏‏‎‏‏‏‎‎‏‎‎‎‏‎‏‎‎‎‎‎‎‎‎‏‏‏‎‏‎‏‏‏‎‎‎‏‎‏‎‏‎‏‎‎‎Physical keyboard‎‏‎‎‏‎"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‎‎‎‎‎‎‎‏‎‎‏‎‏‏‎‎‎‏‎‎‏‎‏‎‏‏‏‏‏‎‎‏‏‏‏‎‎‎‏‏‏‎‎‎‎‏‎‏‎‎‎‏‎‎Choose keyboard layout‎‏‎‎‏‎"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‏‏‏‎‏‏‎‏‏‏‏‏‎‎‏‏‏‎‏‎‏‏‎‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‎‏‎‎‎‎‏‏‎‏‎Default‎‏‎‎‏‎"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 254d41e..49b4b51 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Menos tiempo"</string>
     <string name="cancel" msgid="5665114069455378395">"Cancelar"</string>
     <string name="okay" msgid="949938843324579502">"Aceptar"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmas y recordatorios"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permitir configuración de alarmas y recordatorios"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmas y recordatorios"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Preguntar siempre"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Hasta que lo desactives"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Recién"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Este teléfono"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este teléfono"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Este teléfono"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Error al establecer la conexión. Apaga el dispositivo y vuelve a encenderlo."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Configurar bloqueo"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Cambiar a <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creando usuario nuevo…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Creando nuevo invitado…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"No se pudo crear el usuario nuevo"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"No se pudo crear un nuevo invitado"</string>
     <string name="user_nickname" msgid="262624187455825083">"Sobrenombre"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Agregar invitado"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Quitar invitado"</string>
@@ -644,4 +650,10 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info de reparto"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Elige una foto de perfil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Ícono de usuario predeterminado"</string>
+    <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 447475f..d34beed 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Menos tiempo."</string>
     <string name="cancel" msgid="5665114069455378395">"Cancelar"</string>
     <string name="okay" msgid="949938843324579502">"Aceptar"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmas y recordatorios"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permitir la programación de alarmas y recordatorios"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmas y recordatorios"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Preguntar siempre"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Hasta que lo desactives"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"justo ahora"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Este teléfono"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este teléfono"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Este teléfono"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"No se ha podido conectar; reinicia el dispositivo"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Establecer bloqueo"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Cambiar a <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creando usuario…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Creando nuevo invitado…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"No se ha podido crear el usuario"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"No se ha podido crear un nuevo invitado"</string>
     <string name="user_nickname" msgid="262624187455825083">"Apodo"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Añadir invitado"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Quitar invitado"</string>
@@ -639,9 +645,12 @@
     <string name="accessibility_no_calling" msgid="3540827068323895748">"Sin llamadas."</string>
     <string name="dream_complication_title_time" msgid="701747800712893499">"Hora"</string>
     <string name="dream_complication_title_date" msgid="8661176085446135789">"Fecha"</string>
-    <string name="dream_complication_title_weather" msgid="598609151677172783">"Info. meteorológica"</string>
+    <string name="dream_complication_title_weather" msgid="598609151677172783">"Tiempo"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Calidad del aire"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info. de emisión"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Elige una imagen de perfil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Icono de usuario predeterminado"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Teclado físico"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Elige el diseño del teclado"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Predeterminado"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 2c8a943..a5fa201 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Lühem aeg."</string>
     <string name="cancel" msgid="5665114069455378395">"Tühista"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmid ja meeldetuletused"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Luba alarmide ja meeldetuletuste määramine"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmid ja meeldetuletused"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Küsi iga kord"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Kuni välja lülitate"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Äsja"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"See telefon"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"See telefon"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"See telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Probleem ühendamisel. Lülitage seade välja ja uuesti sisse"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Juhtmega heliseade"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Määra lukk"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Lülita kasutajale <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Uue kasutaja loomine …"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Uue külalise loomine …"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Uue kasutaja loomine ebaõnnestus"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Uue külalise loomine ei õnnestunud"</string>
     <string name="user_nickname" msgid="262624187455825083">"Hüüdnimi"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Lisa külaline"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Eemalda külaline"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Osatäitjate teave"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Valige profiilipilt"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Vaikekasutajaikoon"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Füüsiline klaviatuur"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Klaviatuuri paigutuse valimine"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Vaikimisi"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 019119e..13ffee7 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Denbora gutxiago."</string>
     <string name="cancel" msgid="5665114069455378395">"Utzi"</string>
     <string name="okay" msgid="949938843324579502">"Ados"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmak eta abisuak"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Eman alarmak eta abisuak ezartzeko baimena"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmak eta abisuak"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Galdetu beti"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Zuk desaktibatu arte"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Oraintxe"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Telefono hau"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Telefono hau"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Telefono hau"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Arazo bat izan da konektatzean. Itzali gailua eta pitz ezazu berriro."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Audio-gailu kableduna"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Ezarri blokeoa"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Aldatu <xliff:g id="USER_NAME">%s</xliff:g> erabiltzailera"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Beste erabiltzaile bat sortzen…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Beste gonbidatu bat sortzen…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Ezin izan da sortu erabiltzailea"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Ezin izan da sortu beste gonbidatu bat"</string>
     <string name="user_nickname" msgid="262624187455825083">"Goitizena"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Gehitu gonbidatua"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Kendu gonbidatua"</string>
@@ -644,4 +650,10 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Igorpenari buruzko informazioa"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Aukeratu profileko argazki bat"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Erabiltzaile lehenetsiaren ikonoa"</string>
+    <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 5e7ee60..c50d247 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"زمان کمتر."</string>
     <string name="cancel" msgid="5665114069455378395">"لغو"</string>
     <string name="okay" msgid="949938843324579502">"تأیید"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"زنگ‌های هشدار و یادآوری‌ها"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"مجاز کردن تنظیم زنگ ساعت و یادآوری"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"زنگ‌های ساعت و یادآوری‌ها"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"هربار پرسیده شود"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"تا زمانی‌که آن را خاموش کنید"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"هم‌اکنون"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"این تلفن"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"این تلفن"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"این تلفن"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"مشکل در اتصال. دستگاه را خاموش و دوباره روشن کنید"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"دستگاه صوتی سیمی"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"تنظیم قفل"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"رفتن به <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"درحال ایجاد کاربر جدید…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"درحال ایجاد مهمان جدید…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"کاربر جدید ایجاد نشد"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"مهمان جدید ایجاد نشد"</string>
     <string name="user_nickname" msgid="262624187455825083">"نام مستعار"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"افزودن مهمان"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"حذف مهمان"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"اطلاعات ارسال محتوا"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"انتخاب عکس نمایه"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"نماد کاربر پیش‌فرض"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"صفحه‌کلید فیزیکی"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"انتخاب طرح‌بندی صفحه‌کلید"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"پیش‌فرض"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 04df99f..d958b81 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Vähemmän aikaa"</string>
     <string name="cancel" msgid="5665114069455378395">"Peru"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Herätykset ja muistutukset"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Salli herätysten ja muistutusten lisääminen"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Herätykset ja muistutukset"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Kysy aina"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Kunnes laitat pois päältä"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Äsken"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Tämä puhelin"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Tämä puhelin"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Tämä puhelin"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Yhteysvirhe. Sammuta laite ja käynnistä se uudelleen."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Langallinen äänilaite"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Aseta lukitus"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Vaihda tähän käyttäjään: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Luodaan uutta käyttäjää…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Luodaan uutta vierasta…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Uuden käyttäjän luominen epäonnistui"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Uutta vierasta ei voitu luoda"</string>
     <string name="user_nickname" msgid="262624187455825083">"Lempinimi"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Lisää vieras"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Poista vieras"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Striimaustiedot"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Valitse profiilikuva"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Oletuskäyttäjäkuvake"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Fyysinen näppäimistö"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Valitse näppäimistöasettelu"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Oletus"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 88ddd28d..4999bda 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Moins longtemps."</string>
     <string name="cancel" msgid="5665114069455378395">"Annuler"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes et rappels"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Autoriser la création d\'alarmes et de rappels"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes et rappels"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Toujours demander"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Jusqu\'à la désactivation"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"À l\'instant"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ce téléphone"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ce téléphone"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Ce téléphone"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problème de connexion. Éteingez et rallumez l\'appareil"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Appareil audio à câble"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Définir verrouillage écran"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Passer à <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Création d\'un utilisateur en cours…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Création d\'un nouvel invité en cours…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Impossible de créer un utilisateur"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Impossible de créer un nouvel invité"</string>
     <string name="user_nickname" msgid="262624187455825083">"Pseudo"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Ajouter un invité"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Supprimer l\'invité"</string>
@@ -644,4 +650,10 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info diffusion"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Choisir une photo de profil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Icône d\'utilisateur par défaut"</string>
+    <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index c703484..5257534 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Moins longtemps."</string>
     <string name="cancel" msgid="5665114069455378395">"Annuler"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes et rappels"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Autoriser à définir des alarmes et des rappels"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes et rappels"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Toujours demander"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Jusqu\'à la désactivation"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"À l\'instant"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ce téléphone"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ce téléphone"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Ce téléphone"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problème de connexion. Éteignez l\'appareil, puis rallumez-le"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Appareil audio filaire"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Définir verrouillage écran"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Passer à <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Création d\'un nouvel utilisateur…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Création du profil invité…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Échec de la création d\'un utilisateur"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Impossible de créer un profil invité"</string>
     <string name="user_nickname" msgid="262624187455825083">"Pseudo"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Ajouter un invité"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Supprimer l\'invité"</string>
@@ -644,4 +650,10 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Infos distribution"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Choisissez une photo de profil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Icône de l\'utilisateur par défaut"</string>
+    <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 02fa931f..f45c60d 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Menos tempo."</string>
     <string name="cancel" msgid="5665114069455378395">"Cancelar"</string>
     <string name="okay" msgid="949938843324579502">"Aceptar"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmas e recordatorios"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permitir axuste de alarmas e recordatorios"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmas e recordatorios"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Preguntar sempre"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Ata a desactivación"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Agora mesmo"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Este teléfono"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este teléfono"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Este teléfono"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Produciuse un problema coa conexión. Apaga e acende o dispositivo."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Establecer bloqueo"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Cambiar a <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creando usuario novo…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Creando novo convidado…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Non se puido crear un novo usuario"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Produciuse un erro ao crear o convidado"</string>
     <string name="user_nickname" msgid="262624187455825083">"Alcume"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Engadir convidado"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Quitar convidado"</string>
@@ -644,4 +650,10 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Datos da emisión"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Escolle unha imaxe do perfil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Icona do usuario predeterminado"</string>
+    <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index b2a9ff3..672bd77 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"ઓછો સમય."</string>
     <string name="cancel" msgid="5665114069455378395">"રદ કરો"</string>
     <string name="okay" msgid="949938843324579502">"ઓકે"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"અલાર્મ અને રિમાઇન્ડર"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"અલાર્મ અને રિમાન્ડરના સેટિંગની મંજૂરી આપો"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"અલાર્મ અને રિમાઇન્ડર"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"દર વખતે પૂછો"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"તમે બંધ ન કરો ત્યાં સુધી"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"હમણાં જ"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"આ ફોન"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"આ ફોન"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"આ ફોન"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"કનેક્ટ કરવામાં સમસ્યા આવી રહી છે. ડિવાઇસને બંધ કરીને ફરી ચાલુ કરો"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"વાયરવાળો ઑડિયો ડિવાઇસ"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"લૉક સેટ કરો"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> પર સ્વિચ કરો"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"નવા વપરાશકર્તા બનાવી રહ્યાં છીએ…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"નવા અતિથિની પ્રોફાઇલ બનાવી રહ્યાં છીએ…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"નવો વપરાશકર્તા બનાવવામાં નિષ્ફળ"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"નવી અતિથિ બનાવવામાં નિષ્ફળ રહ્યાં"</string>
     <string name="user_nickname" msgid="262624187455825083">"ઉપનામ"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"અતિથિ ઉમેરો"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"અતિથિને કાઢી નાખો"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"કાસ્ટ વિશેની માહિતી"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"પ્રોફાઇલ ફોટો પસંદ કરો"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"ડિફૉલ્ટ વપરાશકર્તાનું આઇકન"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"ભૌતિક કીબોર્ડ"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"કીબોર્ડ લેઆઉટ પસંદ કરો"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ડિફૉલ્ટ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index fa51dd2..55e3eaf 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"कम समय."</string>
     <string name="cancel" msgid="5665114069455378395">"रद्द करें"</string>
     <string name="okay" msgid="949938843324579502">"ठीक है"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"अलार्म और रिमाइंडर"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"अलार्म और रिमाइंडर सेट करने की अनुमति दें"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"अलार्म और रिमाइंडर"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"हर बार पूछें"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"जब तक आप इसे बंद नहीं करते"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"अभी-अभी"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"यह फ़ोन"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"यह फ़ोन"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"यह फ़ोन"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"कनेक्ट करने में समस्या हो रही है. डिवाइस को बंद करके चालू करें"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"वायर वाला ऑडियो डिवाइस"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"लॉक सेट करें"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> पर जाएं"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"नया उपयोगकर्ता बनाया जा रहा है…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"नया मेहमान खाता बनाया जा रहा है…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"नया उपयोगकर्ता जोड़ा नहीं जा सका"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"नया मेहमान खाता नहीं बनाया जा सका"</string>
     <string name="user_nickname" msgid="262624187455825083">"प्रचलित नाम"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"मेहमान जोड़ें"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"मेहमान हटाएं"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"कास्टिंग की जानकारी"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"प्रोफ़ाइल फ़ोटो चुनें"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"उपयोगकर्ता के लिए डिफ़ॉल्ट आइकॉन"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"फ़िज़िकल कीबोर्ड"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"कीबोर्ड का लेआउट चुनें"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"डिफ़ॉल्ट"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 12d9745..fd29bb5 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Manje vremena."</string>
     <string name="cancel" msgid="5665114069455378395">"Odustani"</string>
     <string name="okay" msgid="949938843324579502">"U redu"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmi i podsjetnici"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Dopusti postavljanje alarma i podsjetnika"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmi i podsjetnici"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Pitaj svaki put"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Dok ne isključite"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Upravo sad"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ovaj telefon"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ovaj telefon"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Ovaj telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem s povezivanjem. Isključite i ponovo uključite uređaj"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audiouređaj"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Postavi zaključavanje"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Prelazak na korisnika <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Izrada novog korisnika…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Izrada novog gosta…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Izrada novog korisnika nije uspjela"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Izrada novog gosta nije uspjela"</string>
     <string name="user_nickname" msgid="262624187455825083">"Nadimak"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Dodavanje gosta"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Uklanjanje gosta"</string>
@@ -644,4 +650,10 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Inform. o emitiranju"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Odabir profilne slike"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Ikona zadanog korisnika"</string>
+    <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 984df4a..dae5854 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Kevesebb idő."</string>
     <string name="cancel" msgid="5665114069455378395">"Mégse"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Ébresztések és emlékeztetők"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Beállíthat ébresztéseket és emlékeztetőket"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Ébresztések és emlékeztetők"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Mindig kérdezzen rá"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Kikapcsolásig"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Az imént"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ez a telefon"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ez a telefon"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Ez a telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Sikertelen csatlakozás. Kapcsolja ki az eszközt, majd kapcsolja be újra."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Vezetékes audioeszköz"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Képernyőzár beállítása"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Váltás erre: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Új felhasználó létrehozása…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Új vendég létrehozása…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Az új felhasználó létrehozása sikertelen"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Az új vendég létrehozása nem sikerült"</string>
     <string name="user_nickname" msgid="262624187455825083">"Becenév"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Vendég hozzáadása"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Vendég munkamenet eltávolítása"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Átküldési információ"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Profilkép választása"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Alapértelmezett felhasználó ikonja"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Fizikai billentyűzet"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Billentyűzetkiosztás kiválasztása"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Alapértelmezett"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 1488aea..61d9093 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Պակասեցնել ժամանակը:"</string>
     <string name="cancel" msgid="5665114069455378395">"Չեղարկել"</string>
     <string name="okay" msgid="949938843324579502">"Եղավ"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Զարթուցիչներ և հիշեցումներ"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Թույլատրել զարթուցիչների և հիշեցումների սահմանումը"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Զարթուցիչներ և հիշեցումներ"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Ամեն անգամ հարցնել"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Մինչև անջատեք"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Հենց նոր"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Այս հեռախոսը"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Այս հեռախոսը"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Այս հեռախոսը"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Կապի խնդիր կա: Սարքն անջատեք և նորից միացրեք:"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Լարով աուդիո սարք"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Կարգավորել կողպումը"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Անցնել <xliff:g id="USER_NAME">%s</xliff:g> պրոֆիլին"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Ստեղծվում է օգտատիրոջ նոր պրոֆիլ…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Նոր հյուրի ստեղծում…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Չհաջողվեց ստեղծել նոր օգտատեր"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Չհաջողվեց նոր հյուր ստեղծել"</string>
     <string name="user_nickname" msgid="262624187455825083">"Կեղծանուն"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Ավելացնել հյուր"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Հեռացնել հյուրին"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Հեռարձակման տվյալներ"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Պրոֆիլի նկար ընտրեք"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Օգտատիրոջ կանխադրված պատկերակ"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Ֆիզիկական ստեղնաշար"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Ընտրեք ստեղնաշարի դասավորությունը"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Կանխադրված"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index ffa4d4a..b60e0b7 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Lebih cepat."</string>
     <string name="cancel" msgid="5665114069455378395">"Batal"</string>
     <string name="okay" msgid="949938843324579502">"Oke"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarm dan pengingat"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Izinkan menyetel alarm dan pengingat"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarm &amp; pengingat"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Selalu tanya"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Sampai Anda menonaktifkannya"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Baru saja"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ponsel ini"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ponsel ini"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Ponsel ini"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ada masalah saat menghubungkan. Nonaktifkan perangkat &amp; aktifkan kembali"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Perangkat audio berkabel"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Setel kunci"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Beralih ke <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Membuat pengguna baru …"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Membuat tamu baru …"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Gagal membuat pengguna baru"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Gagal membuat tamu baru"</string>
     <string name="user_nickname" msgid="262624187455825083">"Nama panggilan"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Tambahkan tamu"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Hapus tamu"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info Transmisi"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Pilih foto profil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Ikon pengguna default"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Keyboard fisik"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Pilih tata letak keyboard"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Default"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index b8a75047..40724fd 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Minni tími."</string>
     <string name="cancel" msgid="5665114069455378395">"Hætta við"</string>
     <string name="okay" msgid="949938843324579502">"Í lagi"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Vekjarar og áminningar"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Leyfa stillingu vekjara og áminninga"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Vekjarar og áminningar"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Spyrja í hvert skipti"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Þar til þú slekkur"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Rétt í þessu"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Þessi sími"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Þessi sími"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Þessi sími"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Vandamál í tengingu. Slökktu og kveiktu á tækinu"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Snúrutengt hljómtæki"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Velja lás"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Skipta yfir í <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Stofnar nýjan notanda…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Býr til nýjan gest…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Ekki tókst að stofna nýjan notanda"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Ekki tókst að búa til nýjan gest"</string>
     <string name="user_nickname" msgid="262624187455825083">"Gælunafn"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Bæta gesti við"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Fjarlægja gest"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Útsendingaruppl."</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Veldu prófílmynd"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Tákn sjálfgefins notanda"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Vélbúnaðarlyklaborð"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Veldu lyklaskipan"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Sjálfgefið"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 1552006..703a0b3 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -528,11 +528,13 @@
     <string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Non registrato"</string>
     <string name="status_unavailable" msgid="5279036186589861608">"Non disponibile"</string>
     <string name="wifi_status_mac_randomized" msgid="466382542497832189">"Selezione casuale dell\'indirizzo MAC"</string>
-    <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 dispositivi connessi}=1{1 dispositivo connesso}one{# dispositivo connesso}other{# dispositivi connessi}}"</string>
+    <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 dispositivi connessi}=1{1 dispositivo connesso}other{# dispositivi connessi}}"</string>
     <string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Più tempo."</string>
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Meno tempo."</string>
     <string name="cancel" msgid="5665114069455378395">"Annulla"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Sveglie e promemoria"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Consenti l\'impostazione di sveglie e promemoria"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Sveglie e promemoria"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Chiedi ogni volta"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Fino alla disattivazione"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Adesso"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Questo telefono"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Questo telefono"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Questo telefono"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problema di connessione. Spegni e riaccendi il dispositivo"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo audio cablato"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Imposta blocco"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Passa a <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creazione nuovo utente…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Creazione di un nuovo ospite in corso…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Creazione nuovo utente non riuscita"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Impossibile creare un nuovo ospite"</string>
     <string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Aggiungi ospite"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Rimuovi ospite"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info sul cast"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Scegli un\'immagine del profilo"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Icona dell\'utente predefinito"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Tastiera fisica"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Scegli layout tastiera"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Predefinito"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 22810e9..987af9c 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"פחות זמן."</string>
     <string name="cancel" msgid="5665114069455378395">"ביטול"</string>
     <string name="okay" msgid="949938843324579502">"אישור"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"שעונים מעוררים ותזכורות"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"אישור להגדיר שעונים מעוררים ותזכורות"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"שעונים מעוררים ותזכורות"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"יש לשאול בכל פעם"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"עד הכיבוי"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"הרגע"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"הטלפון הזה"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"הטלפון הזה"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"הטלפון הזה"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"יש בעיה בחיבור. עליך לכבות את המכשיר ולהפעיל אותו מחדש"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"התקן אודיו חוטי"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"הגדרת נעילה"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"מעבר אל <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"בתהליך יצירה של משתמש חדש…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"מיד ייווצר אורח חדש…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"לא ניתן היה ליצור משתמש חדש"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"יצירת אורח חדש נכשלה"</string>
     <string name="user_nickname" msgid="262624187455825083">"כינוי"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"הוספת אורח"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"הסרת אורח/ת"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"פרטי ההעברה"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"בחירה של תמונת פרופיל"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"סמל המשתמש שמוגדר כברירת מחדל"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"מקלדת פיזית"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"בחירה של פריסת המקלדת"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ברירת מחדל"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index be98ee4..07b04a8 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"短くします。"</string>
     <string name="cancel" msgid="5665114069455378395">"キャンセル"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"アラームとリマインダー"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"アラームとリマインダーの設定を許可する"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"アラームとリマインダー"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"毎回確認"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"OFF にするまで"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"たった今"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"このスマートフォン"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"このスマートフォン"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"このスマートフォン"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"接続エラーです。デバイスを OFF にしてから ON に戻してください"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線オーディオ デバイス"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"ロックを設定"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> に切り替え"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"新しいユーザーを作成しています…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"新しいゲストを作成中…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"新しいユーザーを作成できませんでした"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"新しいゲストを作成できませんでした"</string>
     <string name="user_nickname" msgid="262624187455825083">"ニックネーム"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"ゲストを追加"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"ゲストを削除"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"キャスト情報"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"プロフィール写真の選択"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"デフォルト ユーザー アイコン"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"物理キーボード"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"キーボード レイアウトの選択"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"デフォルト"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index f0006d3..a396600 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"ნაკლები დრო."</string>
     <string name="cancel" msgid="5665114069455378395">"გაუქმება"</string>
     <string name="okay" msgid="949938843324579502">"კარგი"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"მაღვიძარები და შეხსენებები"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"დაუშვით მაღვიძარების და შეხსენებების დაყენება"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"მაღვიძარები და შეხსენებები"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"ყოველთვის მკითხეთ"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"გამორთვამდე"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"ახლახან"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ეს ტელეფონი"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ეს ტელეფონი"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"ეს ტელეფონი"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"დაკავშირებისას წარმოიქმნა პრობლემა. გამორთეთ და კვლავ ჩართეთ მოწყობილობა"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"სადენიანი აუდიო მოწყობილობა"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"საკეტის დაყენება"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>-ზე გადართვა"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"მიმდინარეობს ახალი მომხმარებლის შექმნა…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"ახალი სტუმრის შექმნა…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"ახალი მომხმარებლის შექმნა ვერ მოხერხდა"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"ახალი სტუმრის შექმნა ვერ მოხერხდა"</string>
     <string name="user_nickname" msgid="262624187455825083">"მეტსახელი"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"სტუმრის დამატება"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"სტუმრის ამოშლა"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ტრანსლირების ინფო"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"აირჩიეთ პროფილის სურათი"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"მომხმარებლის ნაგულისხმევი ხატულა"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"ფიზიკური კლავიატურა"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"აირჩიე კლავიატურის განლაგება"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ნაგულისხმევი"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 3724ca5..ccaf1c4 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Азырақ уақыт."</string>
     <string name="cancel" msgid="5665114069455378395">"Бас тарту"</string>
     <string name="okay" msgid="949938843324579502">"Жарайды"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Оятқыш және еске салғыш"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Оятқыштар мен еске салғыштарды орнатуға рұқсат беру"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Оятқыштар мен еске салғыштар"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Әрдайым сұрау"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Өшірілгенге дейін"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Дәл қазір"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Осы телефон"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Осы телефон"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Осы телефон"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Байланыс орнату қатесі шығуып жатыр. Құрылғыны өшіріп, қайта қосыңыз."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Сымды аудио құрылғысы"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Бекітпе тағайындау"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> пайдаланушысына ауысу"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Жаңа пайдаланушы профилі жасалуда…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Жаңа қонақ профилі жасалуда…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Жаңа пайдаланушы жасалмады."</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Жаңа қонақ профилі жасалмады."</string>
     <string name="user_nickname" msgid="262624187455825083">"Лақап ат"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Қонақ қосу"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Қонақты жою"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Трансляция ақпараты"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Профиль суретін таңдау"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Әдепкі пайдаланушы белгішесі"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Пернетақта"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Пернетақтаның орналасу ретін таңдау"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Әдепкі"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 28211f0..370fc4b 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"រយៈពេល​តិច​ជាង។"</string>
     <string name="cancel" msgid="5665114069455378395">"បោះ​បង់​"</string>
     <string name="okay" msgid="949938843324579502">"យល់ព្រម"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"ម៉ោងរោទ៍ និងការរំលឹក"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"អនុញ្ញាតឱ្យ​កំណត់​ម៉ោងរោទ៍ និង​ការរំលឹក"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"ម៉ោងរោទ៍ និង​ការរំលឹក"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"សួរគ្រប់ពេល"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"រហូតទាល់តែ​អ្នកបិទ"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"អម្បាញ់មិញ"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ទូរសព្ទនេះ"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ទូរសព្ទនេះ"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"ទូរសព្ទនេះ"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"មាន​បញ្ហា​ក្នុងការ​ភ្ជាប់។ បិទ រួច​បើក​ឧបករណ៍​វិញ"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ឧបករណ៍​សំឡេងប្រើខ្សែ"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"កំណត់​ការ​ចាក់​សោ"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"ប្ដូរទៅ <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"កំពុងបង្កើត​អ្នកប្រើប្រាស់ថ្មី…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"កំពុងបង្កើតភ្ញៀវថ្មី…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"មិន​អាច​បង្កើត​អ្នកប្រើប្រាស់ថ្មី​បានទេ"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"មិនអាចបង្កើតភ្ញៀវថ្មីបានទេ"</string>
     <string name="user_nickname" msgid="262624187455825083">"ឈ្មោះ​ហៅក្រៅ"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"បញ្ចូល​ភ្ញៀវ"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"ដកភ្ញៀវចេញ"</string>
@@ -644,4 +650,10 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ព័ត៌មានអំពីការបញ្ជូន"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"ជ្រើសរើស​រូបភាព​កម្រង​ព័ត៌មាន"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"រូបអ្នកប្រើប្រាស់លំនាំដើម"</string>
+    <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 635c687..a070ad2 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"ಕಡಿಮೆ ಸಮಯ."</string>
     <string name="cancel" msgid="5665114069455378395">"ರದ್ದುಮಾಡಿ"</string>
     <string name="okay" msgid="949938843324579502">"ಸರಿ"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"ಅಲಾರಾಮ್‌ಗಳು ಮತ್ತು ರಿಮೈಂಡರ್‌ಗಳು"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"ಅಲಾರಂಗಳು ಮತ್ತು ರಿಮೈಂಡರ್‌ಗಳನ್ನು ಹೊಂದಿಸಲು ಅನುಮತಿಸಿ"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"ಅಲಾರಂಗಳು ಮತ್ತು ರಿಮೈಂಡರ್‌ಗಳು"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"ಪ್ರತಿ ಬಾರಿ ಕೇಳಿ"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"ನೀವು ಆಫ್ ಮಾಡುವವರೆಗೆ"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"ಇದೀಗ"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ಈ ಫೋನ್"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ಈ ಫೋನ್"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"ಈ ಫೋನ್"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ಕನೆಕ್ಟ್ ಮಾಡುವಾಗ ಸಮಸ್ಯೆ ಎದುರಾಗಿದೆ ಸಾಧನವನ್ನು ಆಫ್ ಮಾಡಿ ಹಾಗೂ ನಂತರ ಪುನಃ ಆನ್ ಮಾಡಿ"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ವೈರ್ ಹೊಂದಿರುವ ಆಡಿಯೋ ಸಾಧನ"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"ಲಾಕ್ ಹೊಂದಿಸಿ"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> ಗೆ ಬದಲಿಸಿ"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"ಹೊಸ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಲಾಗುತ್ತಿದೆ…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"ಹೊಸ ಅತಿಥಿಯನ್ನು ರಚಿಸಲಾಗುತ್ತಿದೆ…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"ಹೊಸ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಲು ವಿಫಲವಾಗಿದೆ"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"ಹೊಸ ಅತಿಥಿಯನ್ನು ರಚಿಸಲು ವಿಫಲವಾಗಿದೆ"</string>
     <string name="user_nickname" msgid="262624187455825083">"ಅಡ್ಡ ಹೆಸರು"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"ಅತಿಥಿಯನ್ನು ಸೇರಿಸಿ"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"ಅತಿಥಿಯನ್ನು ತೆಗೆದುಹಾಕಿ"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ಬಿತ್ತರಿಸಿದ ಮಾಹಿತಿ"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"ಪ್ರೊಫೈಲ್ ಚಿತ್ರವನ್ನು ಆಯ್ಕೆ ಮಾಡಿ"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"ಡೀಫಾಲ್ಟ್ ಬಳಕೆದಾರರ ಐಕಾನ್"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"ಭೌತಿಕ ಕೀಬೋರ್ಡ್"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"ಕೀಬೋರ್ಡ್ ಲೇಔಟ್ ಆರಿಸಿ"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ಡೀಫಾಲ್ಟ್"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 40acb1a..3cd8583 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"시간 줄이기"</string>
     <string name="cancel" msgid="5665114069455378395">"취소"</string>
     <string name="okay" msgid="949938843324579502">"확인"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"알람 및 리마인더"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"알람 및 리마인더 설정 허용"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"알람 및 리마인더"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"항상 확인"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"사용 중지할 때까지"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"조금 전"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"이 휴대전화"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"이 휴대전화"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"이 휴대전화"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"연결 중에 문제가 발생했습니다. 기기를 껐다가 다시 켜 보세요."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"유선 오디오 기기"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"잠금 설정"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>(으)로 전환"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"새로운 사용자를 만드는 중…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"새 게스트 생성 중…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"새 사용자를 만들지 못함"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"새 게스트 생성 실패"</string>
     <string name="user_nickname" msgid="262624187455825083">"닉네임"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"게스트 추가"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"게스트 삭제"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"전송 정보"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"프로필 사진 선택하기"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"기본 사용자 아이콘"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"물리적 키보드"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"키보드 레이아웃 선택"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"기본"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 7a50ece..93c4321 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Азыраак убакыт."</string>
     <string name="cancel" msgid="5665114069455378395">"Жок"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Ойготкучтар жана эстеткичтер"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Ойготкуч жана эстеткичтерди коюуга уруксат берүү"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Ойготкучтар жана эстеткичтер"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Ар дайым суралсын"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Бул функция өчүрүлгөнгө чейин"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Жаңы эле"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ушул телефон"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ушул телефон"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Ушул телефон"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Туташууда маселе келип чыкты. Түзмөктү өчүрүп, кайра күйгүзүп көрүңүз"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Зымдуу аудио түзмөк"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Бөгөт коюу"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> аккаунтуна которулуу"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Жаңы колдонуучу түзүлүүдө…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Жаңы конок түзүлүүдө…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Жаңы колдонуучу түзүлбөй калды"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Жаңы конок түзүлгөн жок"</string>
     <string name="user_nickname" msgid="262624187455825083">"Ылакап аты"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Конок кошуу"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Конокту өчүрүү"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Тышкы экранга чыгаруу маалыматы"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Профилдин сүрөтүн тандоо"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Демейки колдонуучунун сүрөтчөсү"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Аппараттык баскычтоп"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Тергичтин жайылмасын тандоо"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Демейки"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 2aced9d..e4d677d 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"ຫຼຸດເວລາ."</string>
     <string name="cancel" msgid="5665114069455378395">"ຍົກເລີກ"</string>
     <string name="okay" msgid="949938843324579502">"ຕົກລົງ"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"ໂມງປຸກ ແລະ ການແຈ້ງເຕືອນ"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"ອະນຸຍາດໃຫ້ຕັ້ງໂມງປຸກ ແລະ ການແຈ້ງເຕືອນ"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"ໂມງປຸກ ແລະ ການແຈ້ງເຕືອນ"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"ຖາມທຸກເທື່ອ"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"ຈົນກວ່າທ່ານຈະປິດ"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"ຕອນນີ້"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ໂທລະສັບນີ້"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ໂທລະສັບນີ້"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"ໂທລະສັບນີ້"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ເກີດບັນຫາໃນການເຊື່ອມຕໍ່. ປິດອຸປະກອນແລ້ວເປີດກັບຄືນມາໃໝ່"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ອຸປະກອນສຽງແບບມີສາຍ"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"ຕັ້ງການລັອກ"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"ສະຫຼັບໄປ <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"ກຳລັງສ້າງຜູ້ໃຊ້ໃໝ່…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"ກຳລັງສ້າງແຂກໃໝ່…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"ສ້າງຜູ້ໃຊ້ໃໝ່ບໍ່ສຳເລັດ"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"ສ້າງແຂກໃໝ່ບໍ່ສຳເລັດ"</string>
     <string name="user_nickname" msgid="262624187455825083">"ຊື່ຫຼິ້ນ"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"ເພີ່ມແຂກ"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"ລຶບແຂກອອກ"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ຂໍ້ມູນການສົ່ງສັນຍານ"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"ເລືອກຮູບໂປຣໄຟລ໌"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"ໄອຄອນຜູ້ໃຊ້ເລີ່ມຕົ້ນ"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"ແປ້ນພິມພາຍນອກ"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"ເລືອກຮູບແບບແປ້ນພິມ"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ຄ່າເລີ່ມຕົ້ນ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 6e7daa7..fbd800c 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Mažiau laiko."</string>
     <string name="cancel" msgid="5665114069455378395">"Atšaukti"</string>
     <string name="okay" msgid="949938843324579502">"Gerai"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Signalai ir priminimai"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Leisti nustatyti signalus ir priminimus"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Signalai ir priminimai"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Klausti kaskart"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Kol išjungsite"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Ką tik"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Šis telefonas"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Šis telefonas"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Šis telefonas"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Prisijungiant kilo problema. Išjunkite įrenginį ir vėl jį įjunkite"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Laidinis garso įrenginys"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Nustatyti užraktą"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Perjungti į <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Kuriamas naujas naudotojas…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Kuriamas naujas gestas…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Nepavyko sukurti naujo naudotojo"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Nepavyko sukurti naujo gesto"</string>
     <string name="user_nickname" msgid="262624187455825083">"Slapyvardis"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Pridėti svečią"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Pašalinti svečią"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Perdav. informacija"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Pasirinkite profilio nuotrauką"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Numatytojo naudotojo piktograma"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Fizinė klaviatūra"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Klaviatūros išdėstymo pasirinkimas"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Numatytasis"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 0d6651a..5ef979e 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Mazāk laika."</string>
     <string name="cancel" msgid="5665114069455378395">"Atcelt"</string>
     <string name="okay" msgid="949938843324579502">"LABI"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Signāli un atgādinājumi"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Atļaut iestatīt signālus un atgādinājumus"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Signāli un atgādinājumi"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Vaicāt katru reizi"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Līdz brīdim, kad izslēgsiet"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Tikko"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Šis tālrunis"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Šis tālrunis"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Šis tālrunis"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Radās problēma ar savienojuma izveidi. Izslēdziet un atkal ieslēdziet ierīci."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Vadu audioierīce"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Iestatīt bloķēšanu"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Pārslēgties uz: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Notiek jauna lietotāja izveide…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Notiek jauna viesa profila izveide…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Neizdevās izveidot jaunu lietotāju"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Neizdevās izveidot jaunu viesa profilu"</string>
     <string name="user_nickname" msgid="262624187455825083">"Segvārds"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Pievienot viesi"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Noņemt viesi"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Apraides informācija"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Profila attēla izvēle"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Noklusējuma lietotāja ikona"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Fiziskā tastatūra"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Tastatūras izkārtojuma izvēle"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Noklusējums"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 8111ec0..85788103 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Помалку време."</string>
     <string name="cancel" msgid="5665114069455378395">"Откажи"</string>
     <string name="okay" msgid="949938843324579502">"Во ред"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Аларми и потсетници"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Дозволи поставување аларми и потсетници"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Аларми и потсетници"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Прашувај секогаш"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Додека не го исклучите"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Пред малку"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Овој телефон"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Овој телефон"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Овој телефон"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Проблем со поврзување. Исклучете го уредот и повторно вклучете го"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Жичен аудиоуред"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Постави заклучување"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Префрли на <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Се создава нов корисник…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Се создава нов гостин…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Не успеа да создаде нов корисник"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Не успеа создавањето нов гостин"</string>
     <string name="user_nickname" msgid="262624187455825083">"Прекар"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Додајте гостин"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Отстрани гостин"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Инфо за улогите"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Изберете профилна слика"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Икона за стандарден корисник"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Физичка тастатура"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Избери распоред на тастатура"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Стандардно"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 0ae164b..5abb782 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"കുറഞ്ഞ സമയം."</string>
     <string name="cancel" msgid="5665114069455378395">"റദ്ദാക്കുക"</string>
     <string name="okay" msgid="949938843324579502">"ശരി"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"അലാറങ്ങളും റിമെെൻഡറുകളും"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"അലാറവും റിമെെൻഡറും സജ്ജീകരിക്കാൻ അനുവദിക്കുക"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"അലാറങ്ങളും റിമെെൻഡറുകളും"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"എപ്പോഴും ചോദിക്കുക"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"നിങ്ങൾ ഓഫാക്കുന്നത് വരെ"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"ഇപ്പോൾ"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ഈ ഫോൺ"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ഈ ഫോൺ"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"ഈ ഫോൺ"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"കണക്‌റ്റ് ചെയ്യുന്നതിൽ പ്രശ്‌നമുണ്ടായി. ഉപകരണം ഓഫാക്കി വീണ്ടും ഓണാക്കുക"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"വയർ മുഖേന ബന്ധിപ്പിച്ച ഓഡിയോ ഉപകരണം"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"ലോക്ക് സജ്ജീകരിക്കുക"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> എന്നതിലേക്ക് മാറുക"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"പുതിയ ഉപയോക്താവിനെ സൃഷ്‌ടിക്കുന്നു…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"പുതിയ അതിഥിയെ സൃഷ്‌ടിക്കുന്നു…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"പുതിയ ഉപയോക്താവിനെ സൃഷ്‌ടിക്കാനായില്ല"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"പുതിയ അതിഥിയെ സൃഷ്‌ടിക്കാനായില്ല"</string>
     <string name="user_nickname" msgid="262624187455825083">"വിളിപ്പേര്"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"അതിഥിയെ ചേർക്കുക"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"അതിഥിയെ നീക്കം ചെയ്യുക"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"കാസ്റ്റ് വിവരങ്ങൾ"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"പ്രൊഫൈൽ ചിത്രം തിരഞ്ഞെടുക്കുക"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"ഡിഫോൾട്ട് ഉപയോക്തൃ ഐക്കൺ"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"ഫിസിക്കൽ കീബോർഡ്"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"കീബോർഡ് ലേഔട്ട് തിരഞ്ഞെടുക്കുക"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ഡിഫോൾട്ട്"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 7b74da2..fb11d04 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Бага хугацаа."</string>
     <string name="cancel" msgid="5665114069455378395">"Цуцлах"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Сэрүүлэг болон сануулагч"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Сэрүүлэг болон сануулагч тохируулахыг зөвшөөрөх"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Сэрүүлэг, сануулагч"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Тухай бүрд асуух"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Таныг унтраах хүртэл"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Дөнгөж сая"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Энэ утас"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Энэ утас"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Энэ утас"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Холбогдоход асуудал гарлаа. Төхөөрөмжийг унтраагаад дахин асаана уу"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Утастай аудио төхөөрөмж"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Түгжээг тохируулах"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> руу сэлгэх"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Шинэ хэрэглэгч үүсгэж байна…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Шинэ зочин үүсгэж байна…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Шинэ хэрэглэгч үүсгэж чадсангүй"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Шинэ зочин үүсгэж чадсангүй"</string>
     <string name="user_nickname" msgid="262624187455825083">"Хоч"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Зочин нэмэх"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Зочин хасах"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Дамжуулах мэдээлэл"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Профайл зураг сонгох"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Өгөгдмөл хэрэглэгчийн дүрс тэмдэг"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Биет гар"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Гарын бүдүүвчийг сонгох"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Өгөгдмөл"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 451d834..52aa9c6 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"कमी वेळ."</string>
     <string name="cancel" msgid="5665114069455378395">"रद्द करा"</string>
     <string name="okay" msgid="949938843324579502">"ठीक आहे"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"अलार्म आणि रिमाइंडर"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"अलार्म आणि रिमाइंडर सेट करण्याची अनुमती द्या"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"अलार्म आणि रिमाइंडर"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"प्रत्येक वेळी विचारा"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"तुम्ही बंद करेपर्यंत"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"आत्ताच"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"हा फोन"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"हा फोन"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"हा फोन"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"कनेक्‍ट करण्‍यात समस्‍या आली. डिव्हाइस बंद करा आणि नंतर सुरू करा"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"वायर असलेले ऑडिओ डिव्हाइस"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"लॉक सेट करा"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> वर स्विच करा"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"नवीन वापरकर्ता तयार करत आहे…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"नवीन अतिथी तयार करत आहे…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"नवीन वापरकर्ता तयार करता आला नाही"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"नवीन अतिथी तयार करता आला नाही"</string>
     <string name="user_nickname" msgid="262624187455825083">"टोपणनाव"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"अतिथी जोडा"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"अतिथी काढून टाका"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"कास्टसंबंधित माहिती"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"प्रोफाइल फोटो निवडा"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"डीफॉल्ट वापरकर्ता आयकन"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"वास्तविक कीबोर्ड"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"किबोर्ड लेआउट निवडा"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"डीफॉल्ट"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index d3dfb62..7c96e99 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Kurang masa."</string>
     <string name="cancel" msgid="5665114069455378395">"Batal"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Penggera dan peringatan"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Benarkan penetapan penggera dan peringatan"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Penggera &amp; peringatan"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Tanya setiap kali"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Sehingga anda matikan"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Sebentar tadi"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Telefon ini"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Telefon ini"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Telefon ini"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Masalah penyambungan. Matikan &amp; hidupkan kembali peranti"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Peranti audio berwayar"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Tetapkan kunci"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Tukar kepada <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Mencipta pengguna baharu…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Membuat tetamu baharu…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Gagal membuat pengguna baharu"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Gagal membuat tetamu baharu"</string>
     <string name="user_nickname" msgid="262624187455825083">"Nama panggilan"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Tambah tetamu"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Alih keluar tetamu"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Maklumat Pelakon"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Pilih gambar profil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Ikon pengguna lalai"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Papan kekunci fizikal"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Pilih susun atur papan kekunci"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Lalai"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index cc6269f..6fd1d8ba 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"အချိန်လျှော့ရန်။"</string>
     <string name="cancel" msgid="5665114069455378395">"မလုပ်တော့"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"နှိုးစက်နှင့် သတိပေးချက်များ"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"နှိုးစက်နှင့် သတိပေးချက်များ သတ်မှတ်ခွင့်ပြုရန်"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"နှိုးစက်နှင့် သတိပေးချက်များ"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"အမြဲမေးရန်"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"သင်ပိတ်လိုက်သည် အထိ"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"ယခုလေးတင်"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ဤဖုန်း"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ဤဖုန်း"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"ဤဖုန်း"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ချိတ်ဆက်ရာတွင် ပြဿနာရှိပါသည်။ စက်ကိုပိတ်ပြီး ပြန်ဖွင့်ပါ"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ကြိုးတပ် အသံစက်ပစ္စည်း"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"သော့ချရန် သတ်မှတ်ပါ"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> သို့ ပြောင်းရန်"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"အသုံးပြုသူအသစ် ပြုလုပ်နေသည်…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"ဧည့်သည်သစ် ပြုလုပ်နေသည်…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"အသုံးပြုသူအသစ် ပြုလုပ်၍မရပါ"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"ဧည့်သည်သစ် ပြုလုပ်၍မရပါ"</string>
     <string name="user_nickname" msgid="262624187455825083">"နာမည်ပြောင်"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"ဧည့်သည့် ထည့်ရန်"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"ဧည့်သည်ကို ဖယ်ထုတ်ရန်"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ကာစ် အချက်အလက်"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"ပရိုဖိုင်ပုံ ရွေးပါ"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"မူရင်းအသုံးပြုသူ သင်္ကေတ"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"ပကတိ ကီးဘုတ်"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"လက်ကွက်အပြင်အဆင်ရွေးချယ်ခြင်း"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"မူရင်း"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 8900fe7..e965d60 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Mindre tid."</string>
     <string name="cancel" msgid="5665114069455378395">"Avbryt"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmer og påminnelser"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Tillat innstilling av alarmer og påminnelser"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmer og påminnelser"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Spør hver gang"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Til du slår av"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Nå nettopp"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Denne telefonen"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Denne telefonen"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Denne telefonen"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Tilkoblingsproblemer. Slå enheten av og på igjen"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Lydenhet med kabel"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Angi lås"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Bytt til <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Oppretter en ny bruker …"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Oppretter en ny gjest …"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Kunne ikke opprette noen ny bruker"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Kunne ikke opprette en ny gjest"</string>
     <string name="user_nickname" msgid="262624187455825083">"Kallenavn"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Legg til en gjest"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Fjern gjesten"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Castinformasjon"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Velg et profilbilde"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Standard brukerikon"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Fysisk tastatur"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Velg et tastaturoppsett"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Standard"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index d0270a9..3bcc65a 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"कम समय।"</string>
     <string name="cancel" msgid="5665114069455378395">"रद्द गर्नुहोस्"</string>
     <string name="okay" msgid="949938843324579502">"ठिक छ"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"अलार्म र रिमाइन्डरहरू"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"अलार्म तथा रिमाइन्डर सेट गर्न दिइयोस्"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"घडी तथा रिमाइन्डरहरू"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"प्रत्येक पटक सोधियोस्"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"तपाईंले अफ नगरेसम्म"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"अहिले भर्खरै"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"यो फोन"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"यो फोन"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"यो फोन"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"जोड्ने क्रममा समस्या भयो। यन्त्रलाई निष्क्रिय पारेर फेरि सक्रिय गर्नुहोस्"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"तारयुक्त अडियो यन्त्र"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"लक सेट गर्नुहोस्"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"प्रयोगकर्ता बदलेर <xliff:g id="USER_NAME">%s</xliff:g> पार्नुहोस्"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"नयाँ प्रयोगकर्ता बनाउँदै…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"नयाँ अतिथि बनाइँदै छ…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"नयाँ प्रयोगकर्ता सिर्जना गर्न सकिएन"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"नयाँ अतिथि बनाउन सकिएन"</string>
     <string name="user_nickname" msgid="262624187455825083">"उपनाम"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"अतिथि थप्नुहोस्"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"अतिथि हटाउनुहोस्"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"कास्टसम्बन्धी जानकारी"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"प्रोफाइल फोटो छान्नुहोस्"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"प्रयोगकर्ताको डिफल्ट आइकन"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"भौतिक किबोर्ड"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"किबोर्ड लेआउट छान्नुहोस्"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"डिफल्ट"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 5c19a72..3d14776 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Minder tijd."</string>
     <string name="cancel" msgid="5665114069455378395">"Annuleren"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Wekkers en herinneringen"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Wekkers en herinneringen laten instellen"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Wekkers en herinneringen"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Vraag altijd"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Totdat je uitzet"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Zojuist"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Deze telefoon"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Deze telefoon"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Deze telefoon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Probleem bij verbinding maken. Zet het apparaat uit en weer aan."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Bedraad audioapparaat"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Vergrendeling instellen"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Overschakelen naar <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Nieuwe gebruiker maken…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Nieuwe gast maken…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Kan geen nieuwe gebruiker maken"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Kan geen nieuwe gast maken"</string>
     <string name="user_nickname" msgid="262624187455825083">"Bijnaam"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Gast toevoegen"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Gast verwijderen"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Castinformatie"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Kies een profielfoto"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Standaard gebruikersicoon"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Fysiek toetsenbord"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Toetsenbordindeling kiezen"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Standaard"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 14abf05..f9ee66c 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -207,8 +207,8 @@
     <string name="tts_status_requires_network" msgid="8327617638884678896">"<xliff:g id="LOCALE">%1$s</xliff:g> ନେଟ୍‌ୱର୍କ ସଂଯୋଜନା ଆବଶ୍ୟକ କରେ"</string>
     <string name="tts_status_not_supported" msgid="2702997696245523743">"<xliff:g id="LOCALE">%1$s</xliff:g> ସପୋର୍ଟ କରୁ ନାହିଁ"</string>
     <string name="tts_status_checking" msgid="8026559918948285013">"ଯାଞ୍ଚ କରାଯାଉଛି…"</string>
-    <string name="tts_engine_settings_title" msgid="7849477533103566291">"<xliff:g id="TTS_ENGINE_NAME">%s</xliff:g> ପାଇଁ ସେଟିଙ୍ଗ"</string>
-    <string name="tts_engine_settings_button" msgid="477155276199968948">"ଇଞ୍ଜିନ୍‌ ସେଟିଙ୍ଗ ଆରମ୍ଭ କରନ୍ତୁ"</string>
+    <string name="tts_engine_settings_title" msgid="7849477533103566291">"<xliff:g id="TTS_ENGINE_NAME">%s</xliff:g> ପାଇଁ ସେଟିଂସ"</string>
+    <string name="tts_engine_settings_button" msgid="477155276199968948">"ଇଞ୍ଜିନ୍‌ ସେଟିଂସ ଲଞ୍ଚ କରନ୍ତୁ"</string>
     <string name="tts_engine_preference_section_title" msgid="3861562305498624904">"ନିଜ ପସନ୍ଦର ଇଞ୍ଜିନ୍‌"</string>
     <string name="tts_general_section_title" msgid="8919671529502364567">"ସାଧାରଣ"</string>
     <string name="tts_reset_speech_pitch_title" msgid="7149398585468413246">"ସ୍ପୀଚ୍‌ର ପିଚ୍‌ ରିସେଟ୍‌ କରନ୍ତୁ"</string>
@@ -231,9 +231,9 @@
     <string name="development_settings_enable" msgid="4285094651288242183">"ଡେଭଲପର୍‌ ବିକଳ୍ପଗୁଡ଼ିକ ସକ୍ଷମ କରନ୍ତୁ"</string>
     <string name="development_settings_summary" msgid="8718917813868735095">"ଆପ୍‌ର ବିକାଶ ପାଇଁ ବିକଳ୍ପମାନ ସେଟ୍‌ କରନ୍ତୁ"</string>
     <string name="development_settings_not_available" msgid="355070198089140951">"ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଡେଭଲପରଙ୍କ ବିକଳ୍ପସମୂହ ଉପଲବ୍ଧ ନୁହେଁ"</string>
-    <string name="vpn_settings_not_available" msgid="2894137119965668920">"VPN ସେଟିଙ୍ଗ ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଉପଲବ୍ଧ ନୁହେଁ"</string>
-    <string name="tethering_settings_not_available" msgid="266821736434699780">"ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଟିଥରିଙ୍ଗ ସେଟିଙ୍ଗ ଉପଲବ୍ଧ ନାହିଁ"</string>
-    <string name="apn_settings_not_available" msgid="1147111671403342300">"ଆକ୍ସେସ୍‌ ପଏଣ୍ଟ ନାମର ସେଟିଙ୍ଗ ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଉପଲବ୍ଧ ନାହିଁ"</string>
+    <string name="vpn_settings_not_available" msgid="2894137119965668920">"VPN ସେଟିଂସ ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଉପଲବ୍ଧ ନାହିଁ"</string>
+    <string name="tethering_settings_not_available" msgid="266821736434699780">"ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଟିଥରିଂ ସେଟିଂସ ଉପଲବ୍ଧ ନାହିଁ"</string>
+    <string name="apn_settings_not_available" msgid="1147111671403342300">"ଆକ୍ସେସ ପଏଣ୍ଟ ନାମର ସେଟିଂସ ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଉପଲବ୍ଧ ନାହିଁ"</string>
     <string name="enable_adb" msgid="8072776357237289039">"USB ଡିବଗିଂ"</string>
     <string name="enable_adb_summary" msgid="3711526030096574316">"USB ସଂଯୁକ୍ତ ହେବାବେଳେ ଡିବଗ୍‌ ମୋଡ୍‌"</string>
     <string name="clear_adb_keys" msgid="3010148733140369917">"USB ଡିବଗିଂ ଅଧିକାରକୁ ବାତିଲ୍ କରନ୍ତୁ"</string>
@@ -335,8 +335,8 @@
     <string name="adbwifi_warning_title" msgid="727104571653031865">"ୱାୟାରଲେସ୍ ଡିବଗିଂ ପାଇଁ ଅନୁମତି ଦେବେ?"</string>
     <string name="adbwifi_warning_message" msgid="8005936574322702388">"ୱାୟାରଲେସ୍ ଡିବଗିଂ କେବଳ ଉନ୍ନତି ପାଇଁ ଉଦ୍ଦିଷ୍ଟ ଅଟେ। ଆପଣଙ୍କ କମ୍ପ୍ୟୁଟର ଏବଂ ଡିଭାଇସ୍ ମଧ୍ୟରେ ଡାଟା କପି କରିବାକୁ, ବିନା ବିଜ୍ଞପ୍ତିରେ ଆପଣଙ୍କ ଡିଭାଇସରେ ଆପ୍ସ ଇନଷ୍ଟଲ୍ କରିବାକୁ ଏବଂ ଲଗ୍ ଡାଟା ପଢ଼ିବା ପାଇଁ ଏହାକୁ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
     <string name="adb_keys_warning_message" msgid="2968555274488101220">"ଅଧିକୃତ ସମସ୍ତ କମ୍ପ୍ୟୁଟରରୁ USB ଡିବଗ୍‌ କରିବା ଆକ୍ସେସ୍‌ ପ୍ରତ୍ୟାହାର କରିବେ କି?"</string>
-    <string name="dev_settings_warning_title" msgid="8251234890169074553">"ଡେଭଲପମେଣ୍ଟ ସେଟିଙ୍ଗ ଅନୁମତି ଦେବେ?"</string>
-    <string name="dev_settings_warning_message" msgid="37741686486073668">"ଏହି ସେଟିଙ୍ଗଗୁଡ଼ିକ କେବଳ ବିକାଶ ବ୍ୟବହାର ପାଇଁ ଉଦ୍ଦିଷ୍ଟ। ସେଗୁଡ଼ିକ କାରଣରୁ ଆପଣଙ୍କ ଡିଭାଇସ୍‌ ଓ ଆପ୍ଲିକେଶନ୍‍‍ଗୁଡ଼ିକ ଠିକ୍‌ ଭାବେ କାମ ନକରିପାରେ।"</string>
+    <string name="dev_settings_warning_title" msgid="8251234890169074553">"ଡେଭଲପମେଣ୍ଟ ସେଟିଂସକୁ ଅନୁମତି ଦେବେ?"</string>
+    <string name="dev_settings_warning_message" msgid="37741686486073668">"ଏହି ସେଟିଂସ କେବଳ ବିକାଶର ବ୍ୟବହାର ପାଇଁ ଉଦ୍ଦିଷ୍ଟ। ସେଗୁଡ଼ିକ କାରଣରୁ ଆପଣଙ୍କ ଡିଭାଇସ ଓ ଆପ୍ଲିକେସନଗୁଡ଼ିକ ଖରାପ ହୋଇଯାଇପାରେ କିମ୍ବା ଠିକ୍‌ ଭାବେ କାମ ନକରିପାରେ।"</string>
     <string name="verify_apps_over_usb_title" msgid="6031809675604442636">"USB ଜରିଆରେ ଆପ୍‌ଗୁଡ଼ିକୁ ଯାଞ୍ଚ କରନ୍ତୁ"</string>
     <string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"ADB/ADT ମାଧ୍ୟମରେ ଇନଷ୍ଟଲ ହୋଇଥିବା ଆପ୍‌ଗୁଡ଼ିକ କ୍ଷତିକାରକ କି ନୁହେଁ ଯାଞ୍ଚ କରନ୍ତୁ।"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"(କେବଳ MAC ଠିକଣା ଥାଇ) ନାମ ବିନା ବ୍ଲୁଟୂଥ ଡିଭାଇସଗୁଡ଼ିକ ପ୍ରଦର୍ଶିତ ହେବ"</string>
@@ -500,7 +500,7 @@
     <string name="external_source_trusted" msgid="1146522036773132905">"ଅନୁମତି ଦିଆଯାଇଛି"</string>
     <string name="external_source_untrusted" msgid="5037891688911672227">"ଅନୁମତି ନାହିଁ"</string>
     <string name="install_other_apps" msgid="3232595082023199454">"ଅଜଣା ଆପ୍‌ ଇନଷ୍ଟଲ୍‌ କରନ୍ତୁ"</string>
-    <string name="home" msgid="973834627243661438">"ସେଟିଂସ୍ ହୋମ୍‌"</string>
+    <string name="home" msgid="973834627243661438">"ସେଟିଂସ ହୋମ"</string>
   <string-array name="battery_labels">
     <item msgid="7878690469765357158">"0%"</item>
     <item msgid="8894873528875953317">"50%"</item>
@@ -520,7 +520,7 @@
     <string name="retail_demo_reset_title" msgid="1866911701095959800">"ପାସ୍‌ୱର୍ଡ ଆବଶ୍ୟକ"</string>
     <string name="active_input_method_subtypes" msgid="4232680535471633046">"ସକ୍ରିୟ ଇନପୁଟ୍‌-ପଦ୍ଧତିଗୁଡ଼ିକ"</string>
     <string name="use_system_language_to_select_input_method_subtypes" msgid="4865195835541387040">"ସିଷ୍ଟମ୍‌ ଭାଷା ବ୍ୟବହାର କରନ୍ତୁ"</string>
-    <string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> ପାଇଁ ସେଟିଙ୍ଗ ଖୋଲିବାରେ ବିଫଳ"</string>
+    <string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> ପାଇଁ ସେଟିଂସ ଖୋଲିବାରେ ବିଫଳ"</string>
     <string name="ime_security_warning" msgid="6547562217880551450">"ଏହି ଇନ୍‌ପୁଟ୍‌ ପଦ୍ଧତି, ପାସ୍‌ୱର୍ଡ ଓ କ୍ରେଡିଟ୍‌ କାର୍ଡ ନମ୍ୱର୍‌ ଭଳି ବ୍ୟକ୍ତିଗତ ଡାଟା ସମେତ ଆପଣ ଟାଇପ୍‌ କରିଥିବା ସମସ୍ତ ଅକ୍ଷର ସଂଗହ କରିପାରେ।ଏହା, <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> ଆପ୍‌ରୁ ଆସିଛି| ଏହି ଇନ୍‌ପୁଟ୍‌ ପଦ୍ଧତି ବ୍ୟବହାର କରିବେ?"</string>
     <string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"ଧ୍ୟାନଦିଅନ୍ତୁ: ରିବୁଟ୍‌ କରିବା ପରେ, ଆପଣଙ୍କ ଫୋନ୍‌ ଅନଲକ୍‌ ନହେବା ପର୍ଯ୍ୟନ୍ତ ଏହି ଆପ୍‌ ଆରମ୍ଭ ହୋଇପାରିବ ନାହିଁ"</string>
     <string name="ims_reg_title" msgid="8197592958123671062">"IMS ପଞ୍ଜିକରଣ ସ୍ଥିତି"</string>
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"କମ୍ ସମୟ।"</string>
     <string name="cancel" msgid="5665114069455378395">"ବାତିଲ୍"</string>
     <string name="okay" msgid="949938843324579502">"ଠିକ୍‌ ଅଛି"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"ଆଲାରାମ୍ ଏବଂ ରିମାଇଣ୍ଡରଗୁଡ଼ିକ"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"ଆଲାରାମ ଓ ରିମାଇଣ୍ଡରଗୁଡ଼ିକ ସେଟ କରିବାକୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"ଆଲାରାମ୍ ଏବଂ ରିମାଇଣ୍ଡରଗୁଡ଼ିକ"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"ପ୍ରତ୍ୟେକ ଥର ପଚାରନ୍ତୁ"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"ଆପଣ ବନ୍ଦ ନକରିବା ପର୍ଯ୍ୟନ୍ତ"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"ଏହିକ୍ଷଣି"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ଏହି ଫୋନ"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ଏହି ଫୋନ"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"ଏହି ଫୋନ୍"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ସଂଯୋଗ କରିବାରେ ସମସ୍ୟା ହେଉଛି। ଡିଭାଇସ୍ ବନ୍ଦ କରି ପୁଣି ଚାଲୁ କରନ୍ତୁ"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ତାରଯୁକ୍ତ ଅଡିଓ ଡିଭାଇସ୍"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"ଲକ୍‌ ସେଟ୍‌ କରନ୍ତୁ"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>କୁ ସ୍ୱିଚ୍ କରନ୍ତୁ"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"ନୂଆ ଉପଯୋଗକର୍ତ୍ତା ତିଆରି କରାଯାଉଛି…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"ନୂଆ ଅତିଥି ତିଆରି କରାଯାଉଛି…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"ନୂଆ ଉପଯୋଗକର୍ତ୍ତା ତିଆରି କରିବାକୁ ବିଫଳ ହେଲା"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"ଜଣେ ନୂଆ ଅତିଥି ତିଆରି କରିବାରେ ବିଫଳ ହୋଇଛି"</string>
     <string name="user_nickname" msgid="262624187455825083">"ଡାକନାମ"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"ଅତିଥି ଯୋଗ କରନ୍ତୁ"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"ଅତିଥିଙ୍କୁ କାଢ଼ି ଦିଅନ୍ତୁ"</string>
@@ -644,4 +650,10 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"କାଷ୍ଟ ସୂଚନା"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"ଏକ ପ୍ରୋଫାଇଲ ଛବି ବାଛନ୍ତୁ"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"ଡିଫଲ୍ଟ ଉପଯୋଗକର୍ତ୍ତା ଆଇକନ"</string>
+    <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 4671454..f1a24e4 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"ਘੱਟ ਸਮਾਂ।"</string>
     <string name="cancel" msgid="5665114069455378395">"ਰੱਦ ਕਰੋ"</string>
     <string name="okay" msgid="949938843324579502">"ਠੀਕ ਹੈ"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"ਅਲਾਰਮ ਅਤੇ ਰਿਮਾਈਂਡਰ"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"ਅਲਾਰਮ ਅਤੇ ਰਿਮਾਈਂਡਰ ਸੈੱਟ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"ਅਲਾਰਮ ਅਤੇ ਰਿਮਾਈਂਡਰ"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"ਹਰ ਵਾਰ ਪੁੱਛੋ"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਬੰਦ ਨਹੀਂ ਕਰਦੇ"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"ਹੁਣੇ ਹੀ"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ਇਹ ਫ਼ੋਨ"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ਇਹ ਫ਼ੋਨ"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"ਇਹ ਫ਼ੋਨ"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ਕਨੈਕਟ ਕਰਨ ਵਿੱਚ ਸਮੱਸਿਆ ਆਈ। ਡੀਵਾਈਸ ਨੂੰ ਬੰਦ ਕਰਕੇ ਵਾਪਸ ਚਾਲੂ ਕਰੋ"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ਤਾਰ ਵਾਲਾ ਆਡੀਓ ਡੀਵਾਈਸ"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">" ਲਾਕ  ਸੈੱਟ ਕਰੋ"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> \'ਤੇ ਜਾਓ"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਬਣਾਇਆ ਜਾ ਰਿਹਾ ਹੈ…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"ਨਵਾਂ ਮਹਿਮਾਨ ਪ੍ਰੋਫਾਈਲ ਬਣਾਇਆ ਜਾ ਰਿਹਾ ਹੈ…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਬਣਾਉਣਾ ਅਸਫਲ ਰਿਹਾ"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"ਨਵਾਂ ਮਹਿਮਾਨ ਪ੍ਰੋਫਾਈਲ ਬਣਾਉਣਾ ਅਸਫਲ ਰਿਹਾ"</string>
     <string name="user_nickname" msgid="262624187455825083">"ਉਪਨਾਮ"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"ਮਹਿਮਾਨ ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"ਮਹਿਮਾਨ ਹਟਾਓ"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ਕਾਸਟ ਸੰਬੰਧੀ ਜਾਣਕਾਰੀ"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"ਕੋਈ ਪ੍ਰੋਫਾਈਲ ਤਸਵੀਰ ਚੁਣੋ"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਵਰਤੋਂਕਾਰ ਪ੍ਰਤੀਕ"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"ਭੌਤਿਕ ਕੀ-ਬੋਰਡ"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"ਕੀ-ਬੋਰਡ ਖਾਕਾ ਚੁਣੋ"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ਪੂਰਵ-ਨਿਰਧਾਰਿਤ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 073ffbd..852ed6f 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Mniej czasu."</string>
     <string name="cancel" msgid="5665114069455378395">"Anuluj"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmy i przypomnienia"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Zezwalaj na ustawianie alarmów i przypomnień"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmy i przypomnienia"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Zawsze pytaj"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Dopóki nie wyłączysz"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Przed chwilą"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ten telefon"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ten telefon"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Ten telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem z połączeniem. Wyłącz i ponownie włącz urządzenie"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Przewodowe urządzenie audio"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Ustaw blokadę"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Przełącz na: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Tworzę nowego użytkownika…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Tworzę nowego gościa…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Nie udało się utworzyć nowego użytkownika"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Nie udało się utworzyć nowego gościa"</string>
     <string name="user_nickname" msgid="262624187455825083">"Pseudonim"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gościa"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Usuń gościa"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Obsada"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Wybierz zdjęcie profilowe"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Ikona domyślnego użytkownika"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Klawiatura fizyczna"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Wybierz układ klawiatury"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Domyślny"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 8d93b31..cdb364a 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Menos tempo."</string>
     <string name="cancel" msgid="5665114069455378395">"Cancelar"</string>
     <string name="okay" msgid="949938843324579502">"Ok"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes e lembretes"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Autorizar a definição de alarmes e lembretes"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes e lembretes"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Perguntar sempre"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Até você desativar"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Agora"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Este smartphone"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este smartphone"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Este smartphone"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ocorreu um problema na conexão. Desligue o dispositivo e ligue-o novamente"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fio"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Definir bloqueio"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Mudar para <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Criando novo usuário…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Criando novo convidado…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Falha ao criar um novo usuário"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Falha ao criar um novo convidado"</string>
     <string name="user_nickname" msgid="262624187455825083">"Apelido"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info. de transmissão"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Escolher a foto do perfil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Ícone de usuário padrão"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Teclado físico"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Escolha o layout do teclado"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Padrão"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 47a49e7..c647a213 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -528,11 +528,13 @@
     <string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Não registado"</string>
     <string name="status_unavailable" msgid="5279036186589861608">"Indisponível"</string>
     <string name="wifi_status_mac_randomized" msgid="466382542497832189">"O MAC é aleatório."</string>
-    <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 dispositivo ligados}=1{1 dispositivo ligado}one{# dispositivo(s) ligado(s)}other{# dispositivos ligados}}"</string>
+    <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 dispositivo ligados}=1{1 dispositivo ligado}other{# dispositivos ligados}}"</string>
     <string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Mais tempo."</string>
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Menos tempo."</string>
     <string name="cancel" msgid="5665114069455378395">"Cancelar"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes e lembretes"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permitir a definição de alarmes e lembretes"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes e lembretes"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Perguntar sempre"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Até desativar"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Agora mesmo"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Este telemóvel"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este telemóvel"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Este telemóvel"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problema ao ligar. Desligue e volte a ligar o dispositivo."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fios"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Definir bloqueio"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Mudar para <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"A criar novo utilizador…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"A criar novo convidado…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Falha ao criar um novo utilizador"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Falha ao criar um novo convidado"</string>
     <string name="user_nickname" msgid="262624187455825083">"Alcunha"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info. de transmissão"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Escolha uma imagem do perfil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Ícone do utilizador predefinido"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Teclado físico"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Escolha um esquema de teclado"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Predefinição"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 8d93b31..cdb364a 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Menos tempo."</string>
     <string name="cancel" msgid="5665114069455378395">"Cancelar"</string>
     <string name="okay" msgid="949938843324579502">"Ok"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes e lembretes"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Autorizar a definição de alarmes e lembretes"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes e lembretes"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Perguntar sempre"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Até você desativar"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Agora"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Este smartphone"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este smartphone"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Este smartphone"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ocorreu um problema na conexão. Desligue o dispositivo e ligue-o novamente"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fio"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Definir bloqueio"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Mudar para <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Criando novo usuário…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Criando novo convidado…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Falha ao criar um novo usuário"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Falha ao criar um novo convidado"</string>
     <string name="user_nickname" msgid="262624187455825083">"Apelido"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info. de transmissão"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Escolher a foto do perfil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Ícone de usuário padrão"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Teclado físico"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Escolha o layout do teclado"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Padrão"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index b110c9c..778351e 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Mai puțin timp."</string>
     <string name="cancel" msgid="5665114069455378395">"Anulați"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarme și mementouri"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permiteți setarea pentru alarme și mementouri"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarme și mementouri"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Întreabă de fiecare dată"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Până când dezactivați"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Chiar acum"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Acest telefon"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Acest telefon"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Acest telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problemă la conectare. Opriți și reporniți dispozitivul."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispozitiv audio cu fir"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Configurați blocarea"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Treceți la <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Se creează un utilizator nou…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Se creează un invitat nou…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Nu s-a creat noul utilizator"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Nu s-a putut crea un invitat nou"</string>
     <string name="user_nickname" msgid="262624187455825083">"Pseudonim"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Adăugați un invitat"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Ștergeți invitatul"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Informații artiști"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Alegeți o fotografie de profil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Pictograma prestabilită a utilizatorului"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Tastatură fizică"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Alegeți aspectul tastaturii"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Prestabilit"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 6a2da7f..d07e12b 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Уменьшить продолжительность"</string>
     <string name="cancel" msgid="5665114069455378395">"Отмена"</string>
     <string name="okay" msgid="949938843324579502">"ОК"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Будильники и напоминания"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Разрешить установку будильников и напоминаний"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Будильники и напоминания"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Всегда спрашивать"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Пока вы не отключите"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Только что"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Этот смартфон"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Этот смартфон"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Этот смартфон"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ошибка подключения. Выключите и снова включите устройство."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Проводное аудиоустройство"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Включить блокировку"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Сменить пользователя на <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Создаем нового пользователя…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Создание гостя…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Не удалось создать пользователя"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Не удалось создать гостя."</string>
     <string name="user_nickname" msgid="262624187455825083">"Псевдоним"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Добавить гостя"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Удалить аккаунт гостя"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Данные о трансляции"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Выберите фото профиля"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Значок пользователя по умолчанию"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Физическая клавиатура"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Выберите раскладку клавиатуры"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"По умолчанию"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index b75f548..5140e89 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"වේලාව අඩුවෙන්."</string>
     <string name="cancel" msgid="5665114069455378395">"අවලංගු කරන්න"</string>
     <string name="okay" msgid="949938843324579502">"හරි"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"එලාම සහ සිහිකැඳවීම්"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"එලාම සහ සිහිකැඳවීම් සැකසීමට ඉඩ දෙන්න"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"එලාම සහ සිහිකැඳවීම්"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"සෑම විටම ඉල්ලන්න"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"ඔබ ක්‍රියාවිරහිත කරන තුරු"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"මේ දැන්"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"මෙම දුරකථනය"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"මෙම දුරකථනය"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"මෙම දුරකථනය"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"සම්බන්ධ කිරීමේ ගැටලුවකි උපාංගය ක්‍රියාවිරහිත කර &amp; ආපසු ක්‍රියාත්මක කරන්න"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"රැහැන්ගත කළ ඕඩියෝ උපාංගය"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"අගුල සකසන්න"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> වෙත මාරු වන්න"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"නව පරිශීලක තනමින්…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"නව අමුත්තකු තනමින්…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"නව පරිශීලකයෙකු තැනීමට අසමත් විය"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"නව අමුත්තකු තැනීම අසාර්ථක විය"</string>
     <string name="user_nickname" msgid="262624187455825083">"අපනාමය"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"අමුත්තා එක් කරන්න"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"අමුත්තා ඉවත් කරන්න"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"විකාශ තතු"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"පැතිකඩ පින්තූරයක් තේරීම"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"පෙරනිමි පරිශීලක නිරූපකය"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"භෞතික යතුරු පුවරුව"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"යතුරු පුවරු පිරිසැලසුම තෝරන්න"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"පෙරනිමි"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 83f880d..b53a799 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Kratší čas."</string>
     <string name="cancel" msgid="5665114069455378395">"Zrušiť"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Budíky a pripomenutia"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Povoliť nastavovanie budíkov a pripomenutí"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Budíky a pripomenutia"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Vždy sa opýtať"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Dokým funkciu nevypnete"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Teraz"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Tento telefón"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Tento telefón"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Tento telefón"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Pri pripájaní sa vyskytol problém. Zariadenie vypnite a znova zapnite."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Audio zariadenie s káblom"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Nastaviť uzamknutie"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Prepnúť na používateľa <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Vytvára sa nový používateľ…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Vytvára sa nový hosť…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Nového použív. sa nepodarilo vytvoriť"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Nového hosťa sa nepodarilo vytvoriť"</string>
     <string name="user_nickname" msgid="262624187455825083">"Prezývka"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Pridať hosťa"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Odobrať hosťa"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Informácie o prenose"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Výber profilovej fotky"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Predvolená ikona používateľa"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Fyzická klávesnica"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Vyberte rozloženie klávesnice"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Predvolené"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 6d4078d..67e20b1 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Krajši čas."</string>
     <string name="cancel" msgid="5665114069455378395">"Prekliči"</string>
     <string name="okay" msgid="949938843324579502">"V redu"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmi in opomniki"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Dovoli nastavljanje alarmov in opomnikov"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmi in opomniki"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Vedno vprašaj"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Dokler ne izklopite"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Pravkar"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ta telefon"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ta telefon"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Ta telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Težava pri povezovanju. Napravo izklopite in znova vklopite."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žična zvočna naprava"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Nastavi zaklepanje"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Preklopi na račun <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Ustvarjanje novega uporabnika …"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Ustvarjanje novega gosta …"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Ustvarjanje novega uporabnika ni uspelo."</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Ustvarjanje novega gosta ni uspelo."</string>
     <string name="user_nickname" msgid="262624187455825083">"Vzdevek"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Dodajanje gosta"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Odstranitev gosta"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"O zasedbi"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Izbira profilne slike"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Privzeta ikona uporabnika"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Fizična tipkovnica"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Izbira razporeditve tipkovnice"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Privzeto"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index ef1e59d..fc2639e 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Më pak kohë."</string>
     <string name="cancel" msgid="5665114069455378395">"Anulo"</string>
     <string name="okay" msgid="949938843324579502">"Në rregull"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmet dhe alarmet rikujtuese"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Lejo caktimin e alarmeve dhe alarmeve rikujtuese"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmet dhe alarmet rikujtuese"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Pyet çdo herë"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Derisa ta çaktivizosh"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Pikërisht tani"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ky telefon"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ky telefon"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Ky telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem me lidhjen. Fike dhe ndize përsëri pajisjen"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Pajisja audio me tel"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Cakto kyçjen"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Kalo te <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Po krijohet një përdorues i ri…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Po krijohet një vizitor i ri…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Krijimi i një përdoruesi të ri dështoi"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Profili i vizitorit të ri nuk u krijua"</string>
     <string name="user_nickname" msgid="262624187455825083">"Pseudonimi"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Shto të ftuar"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Hiq të ftuarin"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Të dhënat e aktorëve"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Zgjidh një fotografi profili"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Ikona e parazgjedhur e përdoruesit"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Tastiera fizike"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Zgjidh strukturën e tastierës"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Parazgjedhja"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 333720e..44080fa 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Мање времена."</string>
     <string name="cancel" msgid="5665114069455378395">"Откажи"</string>
     <string name="okay" msgid="949938843324579502">"Потврди"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Аларми и подсетници"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Омогући подешавање аларма и подсетника"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Аларми и подсетници"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Питај сваки пут"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Док не искључите"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Управо"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Овај телефон"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Овај телефон"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Овај телефон"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Проблем при повезивању. Искључите уређај, па га поново укључите"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Жичани аудио уређај"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Подеси закључавање"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Пређи на корисника <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Прави се нови корисник…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Прави се нови гост…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Прављење новог корисника није успело"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Прављење новог госта није успело"</string>
     <string name="user_nickname" msgid="262624187455825083">"Надимак"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Додај госта"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Уклони госта"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Подаци о пребацивању"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Одаберите слику профила"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Подразумевана икона корисника"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Физичка тастатура"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Одаберите распоред тастатуре"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Подразумевано"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 2522d7d..fbcc2ba 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Kortare tid."</string>
     <string name="cancel" msgid="5665114069455378395">"Avbryt"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarm och påminnelser"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Tillåt att alarm och påminnelser ställs in"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarm och påminnelser"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Fråga varje gång"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Tills du inaktiverar funktionen"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Nyss"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Den här telefonen"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Den här telefonen"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Den här telefonen"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Det gick inte att ansluta. Stäng av enheten och slå på den igen"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Ljudenhet med kabelanslutning"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Konfigurera lås"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Byt till <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Skapar ny användare …"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Skapar ny gäst …"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Det gick inte att skapa en ny användare"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Det gick inte att skapa en ny gäst"</string>
     <string name="user_nickname" msgid="262624187455825083">"Smeknamn"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Lägg till gäst"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Ta bort gäst"</string>
@@ -644,4 +650,10 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info om rollistan"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Välj en profilbild"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Ikon för standardanvändare"</string>
+    <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index d6deb2b..8000841 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Muda kidogo."</string>
     <string name="cancel" msgid="5665114069455378395">"Ghairi"</string>
     <string name="okay" msgid="949938843324579502">"Sawa"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Ving\'ora na vikumbusho"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Ruhusu iweke kengele na vikumbusho"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Kengele na vikumbusho"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Uliza kila wakati"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Hadi utakapoizima"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Sasa hivi"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Simu hii"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Simu hii"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Simu hii"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Kuna tatizo la kuunganisha kwenye Intaneti. Zima kisha uwashe kifaa"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kifaa cha sauti kinachotumia waya"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Weka ufunguo"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Badili utumie <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Inaweka mtumiaji mpya…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Inaunda wasifu mpya wa mgeni…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Imeshindwa kuweka mtumiaji mpya"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Imeshindwa kuunda wasifu mpya wa mgeni"</string>
     <string name="user_nickname" msgid="262624187455825083">"Jina wakilishi"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Ongeza mgeni"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Ondoa mgeni"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Maelezo ya Wahusika"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Chagua picha ya wasifu"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Aikoni chaguomsingi ya mtumiaji"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Kibodi halisi"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Chagua mpangilio wa kibodi"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Chaguomsingi"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 8d5b876..30da814 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"நேரத்தைக் குறைக்கும்."</string>
     <string name="cancel" msgid="5665114069455378395">"ரத்துசெய்"</string>
     <string name="okay" msgid="949938843324579502">"சரி"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"அலாரங்களும் நினைவூட்டல்களும்"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"அலாரங்கள் &amp; நினைவூட்டல்களை அமைக்க அனுமதித்தல்"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"அலாரங்கள் &amp; நினைவூட்டல்கள்"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"ஒவ்வொரு முறையும் கேள்"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"ஆஃப் செய்யும் வரை"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"சற்றுமுன்"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"இந்த மொபைல்"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"இந்த மொபைல்"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"இந்த மொபைல்"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"இணைப்பதில் சிக்கல். சாதனத்தை ஆஃப் செய்து மீண்டும் ஆன் செய்யவும்"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"வயருடன்கூடிய ஆடியோ சாதனம்"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"பூட்டை அமை"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>க்கு மாறு"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"புதிய பயனரை உருவாக்குகிறது…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"புதிய விருந்தினரை உருவாக்குகிறது…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"புதிய பயனரை உருவாக்க முடியவில்லை"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"புதிய விருந்தினரை உருவாக்க முடியவில்லை"</string>
     <string name="user_nickname" msgid="262624187455825083">"புனைப்பெயர்"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"கெஸ்ட்டைச் சேர்"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"கெஸ்ட்டை அகற்று"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"அலைபரப்புத் தகவல்"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"சுயவிவரப் படத்தைத் தேர்வுசெய்யுங்கள்"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"இயல்புநிலைப் பயனர் ஐகான்"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"கீபோர்டு"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"கீபோர்டு தளவமைப்பைத் தேர்வுசெய்தல்"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"இயல்பு"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 1744832..34a324e 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -442,11 +442,11 @@
     <string name="select_webview_provider_title" msgid="3917815648099445503">"వెబ్ వీక్షణ అమలు"</string>
     <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"వెబ్ వీక్షణ అమలుని సెట్ చేయండి"</string>
     <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"ఈ ఎంపిక ఇప్పుడు లేదు. మళ్లీ ప్రయత్నించండి."</string>
-    <string name="convert_to_file_encryption" msgid="2828976934129751818">"ఫైల్ గుప్తీకరణకు మార్చు"</string>
+    <string name="convert_to_file_encryption" msgid="2828976934129751818">"ఫైల్ ఎన్‌క్రిప్షన్‌కు మార్చు"</string>
     <string name="convert_to_file_encryption_enabled" msgid="840757431284311754">"మార్చండి…"</string>
-    <string name="convert_to_file_encryption_done" msgid="8965831011811180627">"ఫైల్ ఇప్పటికే గుప్తీకరించబడింది"</string>
-    <string name="title_convert_fbe" msgid="5780013350366495149">"ఫైల్ ఆధారిత గుప్తీకరణకు మార్చడం"</string>
-    <string name="convert_to_fbe_warning" msgid="34294381569282109">"డేటా భాగాన్ని ఫైల్ ఆధారిత గుప్తీకరణకు మార్చండి.\n !!హెచ్చరిక!! దీని వలన మీ డేటా మొత్తం తీసివేయబడుతుంది.\n ఈ లక్షణం ఆల్ఫా, కనుక సరిగ్గా పని చేయకపోవచ్చు.\n కొనసాగించడానికి \'తొలగించి, మార్చు...\' నొక్కండి."</string>
+    <string name="convert_to_file_encryption_done" msgid="8965831011811180627">"ఫైల్ ఇప్పటికే ఎన్‌క్రిప్ట్ చేయబడింది"</string>
+    <string name="title_convert_fbe" msgid="5780013350366495149">"ఫైల్ ఆధారిత ఎన్‌క్రిప్షన్‌కు మార్చడం"</string>
+    <string name="convert_to_fbe_warning" msgid="34294381569282109">"డేటా భాగాన్ని ఫైల్ ఆధారిత ఎన్‌క్రిప్షన్‌కు మార్చండి.\n !!హెచ్చరిక!! దీని వలన మీ డేటా మొత్తం తీసివేయబడుతుంది.\n ఈ లక్షణం ఆల్ఫా, కనుక సరిగ్గా పని చేయకపోవచ్చు.\n కొనసాగించడానికి \'తొలగించి, మార్చు...\' నొక్కండి."</string>
     <string name="button_convert_fbe" msgid="1159861795137727671">"తొలగించి, మార్చు…"</string>
     <string name="picture_color_mode" msgid="1013807330552931903">"చిత్రం రంగు మోడ్"</string>
     <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB ఉపయోగిస్తుంది"</string>
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"తక్కువ సమయం."</string>
     <string name="cancel" msgid="5665114069455378395">"రద్దు చేయి"</string>
     <string name="okay" msgid="949938843324579502">"సరే"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"అలారాలు, రిమైండర్‌లు"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"అలారాలు, రిమైండర్‌లను సెట్ చేయడానికి అనుమతించండి"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"అలారాలు &amp; రిమైండర్‌లు"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"ప్రతిసారి అడుగు"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"మీరు ఆఫ్‌ చేసే వరకు"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"ఇప్పుడే"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ఈ ఫోన్"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ఈ ఫోన్"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"ఈ ఫోన్"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"కనెక్ట్ చేయడంలో సమస్య ఉంది. పరికరాన్ని ఆఫ్ చేసి, ఆపై తిరిగి ఆన్ చేయండి"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"వైర్ గల ఆడియో పరికరం"</string>
@@ -575,7 +579,7 @@
     <string name="user_add_user_item_title" msgid="2394272381086965029">"యూజర్"</string>
     <string name="user_add_profile_item_title" msgid="3111051717414643029">"పరిమితం చేయబడిన ప్రొఫైల్"</string>
     <string name="user_add_user_title" msgid="5457079143694924885">"కొత్త వినియోగదారుని జోడించాలా?"</string>
-    <string name="user_add_user_message_long" msgid="1527434966294733380">"అదనపు యూజర్‌లను సృష్టించడం ద్వారా మీరు ఈ దేవైజ్‌ను ఇతరులతో షేర్ చేయవచ్చు. ప్రతి యూజర్‌కు‌ వారికంటూ ప్రత్యేక స్థలం ఉంటుంది, వారు ఆ స్థలాన్ని యాప్‌లు, వాల్‌పేపర్ మొదలైనవాటితో అనుకూలీకరించవచ్చు. యూజర్‌లు ప్రతి ఒక్కరిపై ప్రభావం చూపే Wi‑Fi వంటి పరికర సెట్టింగ్‌లను కూడా సర్దుబాటు చేయవచ్చు.\n\nమీరు కొత్త యూజర్ ను జోడించినప్పుడు, ఆ వ్యక్తి వారికంటూ స్వంత స్థలం సెట్ చేసుకోవాలి.\n\nఏ వినియోగదారు అయినా మిగిలిన అందరు యూజర్‌ల కోసం యాప్‌లను అప్‌డేట్ చేయవచ్చు. యాక్సెస్ సామర్ధ్యం సెట్టింగ్‌లు మరియు సేవలు కొత్త యూజర్‌కి బదిలీ కాకపోవచ్చు."</string>
+    <string name="user_add_user_message_long" msgid="1527434966294733380">"అదనపు యూజర్‌లను క్రియేట్ చేయడం ద్వారా మీరు ఈ దేవైజ్‌ను ఇతరులతో షేర్ చేయవచ్చు. ప్రతి యూజర్‌కు‌ వారికంటూ ప్రత్యేక స్థలం ఉంటుంది, వారు ఆ స్థలాన్ని యాప్‌లు, వాల్‌పేపర్ మొదలైనవాటితో అనుకూలీకరించవచ్చు. యూజర్‌లు ప్రతి ఒక్కరిపై ప్రభావం చూపే Wi‑Fi వంటి పరికర సెట్టింగ్‌లను కూడా సర్దుబాటు చేయవచ్చు.\n\nమీరు కొత్త యూజర్ ను జోడించినప్పుడు, ఆ వ్యక్తి వారికంటూ స్వంత స్థలం సెట్ చేసుకోవాలి.\n\nఏ వినియోగదారు అయినా మిగిలిన అందరు యూజర్‌ల కోసం యాప్‌లను అప్‌డేట్ చేయవచ్చు. యాక్సెస్ సామర్ధ్యం సెట్టింగ్‌లు మరియు సేవలు కొత్త యూజర్‌కి బదిలీ కాకపోవచ్చు."</string>
     <string name="user_add_user_message_short" msgid="3295959985795716166">"మీరు కొత్త వినియోగదారుని జోడించినప్పుడు, ఆ వ్యక్తి తన స్థలాన్ని సెటప్ చేసుకోవాలి.\n\nఏ వినియోగదారు అయినా మిగతా అందరు వినియోగదారుల కోసం యాప్‌లను అప్‌డేట్‌ చేయగలరు."</string>
     <string name="user_setup_dialog_title" msgid="8037342066381939995">"యూజర్‌ను ఇప్పుడే సెటప్ చేయాలా?"</string>
     <string name="user_setup_dialog_message" msgid="269931619868102841">"పరికరాన్ని తీసుకోవడానికి వ్యక్తి అందుబాటులో ఉన్నారని నిర్ధారించుకొని, ఆపై వారికి నిల్వ స్థలాన్ని సెటప్ చేయండి"</string>
@@ -587,11 +591,13 @@
     <string name="user_new_profile_name" msgid="2405500423304678841">"కొత్త ప్రొఫైల్"</string>
     <string name="user_info_settings_title" msgid="6351390762733279907">"వినియోగదారు సమాచారం"</string>
     <string name="profile_info_settings_title" msgid="105699672534365099">"ప్రొఫైల్ సమాచారం"</string>
-    <string name="user_need_lock_message" msgid="4311424336209509301">"మీరు పరిమితం చేయబడిన ప్రొఫైల్‌ను సృష్టించడానికి ముందు, మీ యాప్‌లు మరియు వ్యక్తిగత డేటాను రక్షించడానికి స్క్రీన్ లాక్‌ను సెటప్ చేయాల్సి ఉంటుంది."</string>
+    <string name="user_need_lock_message" msgid="4311424336209509301">"మీరు పరిమితం చేయబడిన ప్రొఫైల్‌ను క్రియేట్ చేయడానికి ముందు, మీ యాప్‌లు మరియు వ్యక్తిగత డేటాను రక్షించడానికి స్క్రీన్ లాక్‌ను సెటప్ చేయాల్సి ఉంటుంది."</string>
     <string name="user_set_lock_button" msgid="1427128184982594856">"లాక్‌ను సెట్ చేయి"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>కు స్విచ్ చేయి"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"కొత్త యూజర్‌ను క్రియేట్ చేస్తోంది…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"కొత్త అతిథిని క్రియేట్ చేస్తోంది…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"కొత్త యూజర్‌ను క్రియేట్ చేయడం విఫలమైంది"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"కొత్త అతిథిని క్రియేట్ చేయడం విఫలమైంది"</string>
     <string name="user_nickname" msgid="262624187455825083">"మారుపేరు"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"గెస్ట్‌ను జోడించండి"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"గెస్ట్‌ను తీసివేయండి"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"కాస్ట్ సమాచారం"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"ప్రొఫైల్ ఫోటోను ఎంచుకోండి"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"ఆటోమేటిక్ సెట్టింగ్ యూజర్ చిహ్నం"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"భౌతిక కీబోర్డ్"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"కీబోర్డ్ లేఅవుట్‌ను ఎంచుకోండి"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ఆటోమేటిక్ సెట్టింగ్"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index c2c34ed..900ac51 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"เวลาน้อยลง"</string>
     <string name="cancel" msgid="5665114069455378395">"ยกเลิก"</string>
     <string name="okay" msgid="949938843324579502">"ตกลง"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"การปลุกและการช่วยเตือน"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"อนุญาตให้ตั้งปลุกและการช่วยเตือน"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"การปลุกและการช่วยเตือน"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"ถามทุกครั้ง"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"จนกว่าคุณจะปิด"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"เมื่อสักครู่"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"โทรศัพท์เครื่องนี้"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"โทรศัพท์เครื่องนี้"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"โทรศัพท์เครื่องนี้"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"เกิดปัญหาในการเชื่อมต่อ ปิดอุปกรณ์แล้วเปิดใหม่อีกครั้ง"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"อุปกรณ์เสียงแบบมีสาย"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"ตั้งค่าล็อก"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"เปลี่ยนเป็น <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"กำลังสร้างผู้ใช้ใหม่…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"กำลังสร้างผู้เข้าร่วมใหม่…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"สร้างผู้ใช้ใหม่ไม่ได้"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"สร้างผู้เข้าร่วมใหม่ไม่สำเร็จ"</string>
     <string name="user_nickname" msgid="262624187455825083">"ชื่อเล่น"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"เพิ่มผู้ใช้ชั่วคราว"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"นำผู้ใช้ชั่วคราวออก"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ข้อมูลแคสต์"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"เลือกรูปโปรไฟล์"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"ไอคอนผู้ใช้เริ่มต้น"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"แป้นพิมพ์จริง"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"เลือกรูปแบบแป้นพิมพ์"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ค่าเริ่มต้น"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index a8dcb02..5bfb3ef 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Bawasan ang oras."</string>
     <string name="cancel" msgid="5665114069455378395">"Kanselahin"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Mga alarm at paalala"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Payagan ang pagtakda ng mga alarm at paalala"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Mga alarm at paalala"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Magtanong palagi"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Hanggang sa i-off mo"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Ngayon lang"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ang teleponong ito"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ang teleponong ito"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Ang teleponong ito"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Nagkaproblema sa pagkonekta. I-off at pagkatapos ay i-on ang device"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired na audio device"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Itakda ang lock"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Lumipat sa <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Gumagawa ng bagong user…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Gumagawa ng bagong guest…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Hindi nakagawa ng bagong user"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Hindi nakagawa ng bagong guest"</string>
     <string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Magdagdag ng bisita"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Alisin ang bisita"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Impormasyon ng Cast"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Pumili ng larawan sa profile"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Icon ng default na user"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Pisikal na keyboard"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Pumili ng layout ng keyboard"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Default"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 592bbae..98ed832 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Daha kısa süre."</string>
     <string name="cancel" msgid="5665114069455378395">"İptal"</string>
     <string name="okay" msgid="949938843324579502">"Tamam"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmlar ve hatırlatıcılar"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Alarm ve hatırlatıcı ayarlanmasına izin ver"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmlar ve hatırlatıcılar"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Her zaman sor"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Siz kapatana kadar"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Az önce"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Bu telefon"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Bu telefon"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Bu telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Bağlanırken sorun oluştu. Cihazı kapatıp tekrar açın"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kablolu ses cihazı"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Kilidi ayarla"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> hesabına geç"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Yeni kullanıcı oluşturuluyor…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Yeni misafir oluşturuluyor…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Yeni kullanıcı oluşturulamadı"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Yeni misafir oluşturulamadı"</string>
     <string name="user_nickname" msgid="262624187455825083">"Takma ad"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Misafir ekle"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Misafir oturumunu kaldır"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Yayın Bilgisi"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Profil fotoğrafı seç"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Varsayılan kullanıcı simgesi"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Fiziksel klavye"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Klavye düzenini seçin"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Varsayılan"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index a219f98..a09dc11f 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Менше часу."</string>
     <string name="cancel" msgid="5665114069455378395">"Скасувати"</string>
     <string name="okay" msgid="949938843324579502">"ОК"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Будильники й нагадування"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Дозволити встановлювати будильники й нагадування"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Будильники й нагадування"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Запитувати щоразу"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Доки не вимкнути"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Щойно"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Цей телефон"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Цей телефон"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Цей телефон"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Не вдається підключитися. Перезавантажте пристрій."</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Дротовий аудіопристрій"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Налаштувати блокування"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Перейти до користувача <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Створення нового користувача…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Створення гостя…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Не вдалося створити користувача"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Не вдалося створити гостя"</string>
     <string name="user_nickname" msgid="262624187455825083">"Псевдонім"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Додати гостя"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Видалити гостя"</string>
@@ -644,4 +650,10 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Акторський склад"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Вибрати зображення профілю"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Значок користувача за умовчанням"</string>
+    <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 3a2d2efb..ab7c517 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"کم وقت۔"</string>
     <string name="cancel" msgid="5665114069455378395">"منسوخ کریں"</string>
     <string name="okay" msgid="949938843324579502">"ٹھیک ہے"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"الارمز اور یاد دہانیاں"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"الارمز اور یاد دہانیاں سیٹ کرنے کی اجازت دیں"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"الارمز اور یاد دہانیاں"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"ہر بار پوچھیں"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"یہاں تک کہ آپ آف کر دیں"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"ابھی ابھی"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"یہ فون"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"یہ فون"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"یہ فون"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"منسلک کرنے میں مسئلہ پیش آ گیا۔ آلہ کو آف اور بیک آن کریں"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"وائرڈ آڈیو آلہ"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"لاک سیٹ کریں"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"‫<xliff:g id="USER_NAME">%s</xliff:g> پر سوئچ کریں"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"نیا صارف تخلیق ہو رہا ہے…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"نیا مہمان تخلیق کیا جا رہا ہے…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"نیا صارف بنانے میں ناکام"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"نیا مہمان بنانے میں ناکام"</string>
     <string name="user_nickname" msgid="262624187455825083">"عرفی نام"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"مہمان کو شامل کریں"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"مہمان کو ہٹائیں"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"کاسٹ کرنے کی معلومات"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"پروفائل کی تصویر منتخب کریں"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"ڈیفالٹ صارف کا آئیکن"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"فزیکل کی بورڈ"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"کی بورڈ لے آؤٹ منتخب کریں"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ڈیفالٹ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 3e3db69..c1748a3 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Kamroq vaqt."</string>
     <string name="cancel" msgid="5665114069455378395">"Bekor qilish"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Signal va eslatmalar"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Signal va eslatmalarni sozlashga ruxsat berish"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Signal va eslatmalar"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Har safar so‘ralsin"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Rejimdan chiqilgunicha"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Hozir"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Shu telefon"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Shu telefon"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Shu telefon"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ulanishda muammo yuz berdi. Qurilmani oʻchiring va yoqing"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Simli audio qurilma"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Qulf o‘rnatish"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Bunga almashish: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Yangi foydalanuvchi yaratilmoqda…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Yangi mehmon yaratilmoqda…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Yangi foydalanuvchi yaratilmadi"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Yangi mehmon yaratilmadi"</string>
     <string name="user_nickname" msgid="262624187455825083">"Nik"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Mehmon kiritish"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Mehmonni olib tashlash"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Translatsiya axboroti"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Profil rasmini tanlash"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Foydalanuvchining standart belgisi"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Tashqi klaviatura"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Klaviatura sxemasini tanlang"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Asosiy"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 2094400..419f1da 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Ít thời gian hơn."</string>
     <string name="cancel" msgid="5665114069455378395">"Hủy"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Chuông báo và lời nhắc"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Cho phép đặt chuông báo và lời nhắc"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Chuông báo và lời nhắc"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Luôn hỏi"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Cho đến khi bạn tắt"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Vừa xong"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Điện thoại này"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Điện thoại này"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Điện thoại này"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Sự cố kết nối. Hãy tắt thiết bị rồi bật lại"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Thiết bị âm thanh có dây"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Thiết lập khóa"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Chuyển sang <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Đang tạo người dùng mới…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Đang tạo khách mới…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Không tạo được người dùng mới"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Không tạo được khách mới"</string>
     <string name="user_nickname" msgid="262624187455825083">"Biệt hiệu"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Thêm khách"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Xóa phiên khách"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Thông tin về dàn nghệ sĩ"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Chọn một ảnh hồ sơ"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Biểu tượng người dùng mặc định"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Bàn phím thực"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Chọn bố cục bàn phím"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Mặc định"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 6d5b8e1..592e69c 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"减少时间。"</string>
     <string name="cancel" msgid="5665114069455378395">"取消"</string>
     <string name="okay" msgid="949938843324579502">"确定"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"闹钟和提醒"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"允许设置闹钟和提醒"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"闹钟和提醒"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"每次都询问"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"直到您将其关闭"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"刚刚"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"这部手机"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"这部手机"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"这部手机"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"连接时遇到问题。请关闭并重新开启设备"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有线音频设备"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"设置屏幕锁定方式"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"切换到<xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"正在创建新用户…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"正在创建新的访客…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"无法创建新用户"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"未能创建新的访客"</string>
     <string name="user_nickname" msgid="262624187455825083">"昵称"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"添加访客"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"移除访客"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"投射信息"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"选择个人资料照片"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"默认用户图标"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"实体键盘"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"选择键盘布局"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"默认"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index d18c0c9..41f3994 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"減少時間。"</string>
     <string name="cancel" msgid="5665114069455378395">"取消"</string>
     <string name="okay" msgid="949938843324579502">"確定"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"鬧鐘和提醒"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"允許設定鬧鐘和提醒"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"鬧鐘和提醒"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"每次都詢問"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"直至您關閉為止"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"剛剛"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"此手機"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"此手機"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"這部手機"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"無法連接,請關閉裝置然後重新開機"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線音響裝置"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"設定上鎖畫面"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"切換至<xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"正在建立新使用者…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"正在建立新訪客…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"無法建立新使用者"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"無法建立新訪客"</string>
     <string name="user_nickname" msgid="262624187455825083">"暱稱"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"新增訪客"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"移除訪客"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"投放資料"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"選擇個人檔案相片"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"預設使用者圖示"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"實體鍵盤"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"選擇鍵盤配置"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"預設"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index bec3c93..975e650 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"減少時間。"</string>
     <string name="cancel" msgid="5665114069455378395">"取消"</string>
     <string name="okay" msgid="949938843324579502">"確定"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"鬧鐘與提醒"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"允許設定鬧鐘和提醒"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"鬧鐘和提醒"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"每次都詢問"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"直到你關閉為止"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"剛剛"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"這支手機"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"這支手機"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"這支手機"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"無法連線,請關閉裝置後再重新開啟"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線音訊裝置"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"設定鎖定"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"切換至<xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"正在建立新使用者…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"正在建立新訪客…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"無法建立新的使用者"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"無法建立新訪客"</string>
     <string name="user_nickname" msgid="262624187455825083">"暱稱"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"新增訪客"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"移除訪客"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"演出者資訊"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"選擇個人資料相片"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"預設使用者圖示"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"實體鍵盤"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"選擇鍵盤配置"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"預設"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 16b601c..119c91b 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -533,6 +533,8 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Isikhathi esincane."</string>
     <string name="cancel" msgid="5665114069455378395">"Khansela"</string>
     <string name="okay" msgid="949938843324579502">"KULUNGILE"</string>
+    <!-- no translation found for done (381184316122520313) -->
+    <skip />
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Ama-alamu nezikhumbuzi"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Vumela ukusetha ama-alamu nezikhumbuzi"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Ama-alamu nezikhumbuzi"</string>
@@ -551,7 +553,9 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Buza njalo"</string>
     <string name="zen_mode_forever" msgid="3339224497605461291">"Uze uvale isikrini"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Khona manje"</string>
-    <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Le foni"</string>
+    <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Le foni"</string>
+    <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+    <skip />
     <string name="media_transfer_this_phone" msgid="7194341457812151531">"Le foni"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Inkinga yokuxhumeka. Vala idivayisi futhi uphinde uyivule"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Idivayisi yomsindo enentambo"</string>
@@ -591,7 +595,9 @@
     <string name="user_set_lock_button" msgid="1427128184982594856">"Setha ukukhiya"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Shintshela ku-<xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Idala umsebenzisi omusha…"</string>
+    <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Isungula isimenywa esisha…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Yehlulekile ukudala umsebenzisi omusha"</string>
+    <string name="add_guest_failed" msgid="8074548434469843443">"Yehlulekile ukusungula isimenywa esisha"</string>
     <string name="user_nickname" msgid="262624187455825083">"Isiteketiso"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Engeza isivakashi"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Susa isihambeli"</string>
@@ -644,4 +650,7 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Ulwazi Lokusakaza"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Khetha isithombe sephrofayela"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Isithonjana somsebenzisi sokuzenzakalelayo"</string>
+    <string name="physical_keyboard_title" msgid="4811935435315835220">"Ikhibhodi ephathekayo"</string>
+    <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Khetha isendlalelo sekhibhodi"</string>
+    <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Zenzekela"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 042fef2..1c1e1ba3 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -228,6 +228,13 @@
     <!-- Connected devices settings. Message when Bluetooth is connected and active but no battery information, showing remote device status. [CHAR LIMIT=NONE] -->
     <string name="bluetooth_active_no_battery_level">Active</string>
 
+    <!-- Connected device settings. Message when the left-side hearing aid device is active. [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_hearing_aid_left_active">Active, left only</string>
+    <!-- Connected device settings. Message when the right-side hearing aid device is active. [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_hearing_aid_right_active">Active, right only</string>
+    <!-- Connected device settings. Message when the left-side and right-side hearing aids device are active. [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_hearing_aid_left_and_right_active">Active, left and right</string>
+
     <!-- Bluetooth settings.  The user-visible string that is used whenever referring to the A2DP profile. -->
     <string name="bluetooth_profile_a2dp">Media audio</string>
     <!-- Bluetooth settings.  The user-visible string that is used whenever referring to the headset or handsfree profile. -->
@@ -347,15 +354,6 @@
     <!-- Message for telling the user the kind of BT device being displayed in list. [CHAR LIMIT=30 BACKUP_MESSAGE_ID=5615463912185280812] -->
     <string name="bluetooth_talkback_bluetooth">Bluetooth</string>
 
-    <!-- Message for telling the user the left-side hearing aid device is doing its pairing operation [CHAR LIMIT=NONE] -->
-    <string name="bluetooth_hearingaid_left_pairing_message">Pairing left hearing aid\u2026</string>
-    <!-- Message for telling the user the right-side hearing aid device is doing its pairing operation [CHAR LIMIT=NONE] -->
-    <string name="bluetooth_hearingaid_right_pairing_message">Pairing right hearing aid\u2026</string>
-    <!-- Bluetooth settings.  Message when connected to a left-side Hearing Aid device, showing remote device battery level. [CHAR LIMIT=NONE] -->
-    <string name="bluetooth_hearingaid_left_battery_level">Left - <xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery</string>
-    <!-- Bluetooth settings.  Message when connected to a right-side Hearing Aid device, showing remote device battery level. [CHAR LIMIT=NONE] -->
-    <string name="bluetooth_hearingaid_right_battery_level">Right - <xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery</string>
-
     <!-- Content description of the WIFI signal when WIFI is disabled for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_wifi_off">Wifi off.</string>
     <!-- Content description of the WIFI signal when no signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -400,9 +398,6 @@
     <!-- Title for a work profile. [CHAR LIMIT=25] -->
     <string name="managed_user_title">All work apps</string>
 
-    <!-- Title for Guest user [CHAR LIMIT=35] -->
-    <string name="user_guest">Guest</string>
-
     <!-- Manage apps, individual app screen, substituted for the application's label when the app's label CAN NOT be determined.-->
     <string name="unknown">Unknown</string>
 
@@ -1038,23 +1033,6 @@
     <!-- Developer settings: text for the WebView provider selection toast shown if an invalid provider was chosen (i.e. the setting list was stale). [CHAR LIMIT=NONE] -->
     <string name="select_webview_provider_toast_text">This choice is no longer valid. Try again.</string>
 
-    <!-- Developer settings screen, convert userdata to file encryption option name -->
-    <string name="convert_to_file_encryption">Convert to file encryption</string>
-    <!-- Developer settings screen, convert userdata to file encryption summary when option is available -->
-    <string name="convert_to_file_encryption_enabled">Convert\u2026</string>
-    <!-- Developer settings screen, convert userdata to file encryption summary when option is already done -->
-    <string name="convert_to_file_encryption_done">Already file encrypted</string>
-    <!-- Title used on dialog with final prompt for converting to file encryption -->
-    <string name="title_convert_fbe">Converting to file based encryption</string>
-    <!-- Warning displayed on dialog with final prompt for converting to file encryption -->
-    <string name="convert_to_fbe_warning">
-        Convert data partition to file based encryption.\n
-        !!Warning!! This will erase all your data.\n
-        This feature is alpha, and may not work correctly.\n
-        Press \'Wipe and convert\u2026\' to continue.</string>
-    <!-- Button on dialog that triggers convertion to file encryption -->
-    <string name="button_convert_fbe">Wipe and convert\u2026</string>
-
     <!-- Name of feature to change color setting for the display [CHAR LIMIT=60] -->
     <string name="picture_color_mode">Picture color mode</string>
 
@@ -1293,6 +1271,8 @@
     <string name="cancel">Cancel</string>
     <!-- Button label for generic OK action [CHAR LIMIT=20] -->
     <string name="okay">OK</string>
+    <!-- Button label for generic Done action, to be pressed when an action has been completed [CHAR LIMIT=20] -->
+    <string name="done">Done</string>
 
     <!-- Label for the settings activity for controlling apps that can schedule alarms [CHAR LIMIT=30] -->
     <string name="alarms_and_reminders_label">Alarms and reminders</string>
@@ -1342,7 +1322,9 @@
     <string name="notice_header" translatable="false"></string>
 
     <!-- Name of the phone device. [CHAR LIMIT=30] -->
-    <string name="media_transfer_this_device_name">This phone</string>
+    <string name="media_transfer_this_device_name" product="default">This phone</string>
+    <!-- Name of the tablet device. [CHAR LIMIT=30] -->
+    <string name="media_transfer_this_device_name" product="tablet">This tablet</string>
     <!-- Name of the phone device with an active remote session. [CHAR LIMIT=30] -->
     <string name="media_transfer_this_phone">This phone</string>
 
@@ -1436,16 +1418,18 @@
     <!-- Title for the preference to enter the nickname of the user to display in the user switcher [CHAR LIMIT=25]-->
     <string name="user_nickname">Nickname</string>
 
+    <!-- Label for adding a new user in the user switcher [CHAR LIMIT=35] -->
+    <string name="user_add_user">Add user</string>
     <!-- Label for adding a new guest in the user switcher [CHAR LIMIT=35] -->
     <string name="guest_new_guest">Add guest</string>
     <!-- Label for exiting and removing the guest session in the user switcher [CHAR LIMIT=35] -->
     <string name="guest_exit_guest">Remove guest</string>
     <!-- Label for resetting guest session in the user switcher, which will remove all data from the current guest session [CHAR LIMIT=35] -->
     <string name="guest_reset_guest">Reset guest</string>
-    <!-- Name for the guest user [CHAR LIMIT=35] -->
-    <string name="guest_nickname">Guest</string>
     <!-- Title of the confirmation dialog to confirm resetting guest. [CHAR LIMIT=NONE] -->
     <string name="guest_reset_guest_dialog_title">Reset guest?</string>
+    <!-- Title of the confirmation dialog to confirm removing guest. [CHAR LIMIT=NONE] -->
+    <string name="guest_remove_guest_dialog_title">Remove guest?</string>
     <!-- Label for button in confirmation dialog when resetting guest user [CHAR LIMIT=35] -->
     <string name="guest_reset_guest_confirm_button">Reset</string>
     <!-- Status message indicating the device is in the process of resetting the guest user. [CHAR_LIMIT=NONE] -->
@@ -1457,6 +1441,15 @@
     <!-- Accessibility message for the photo selector which is a button/popup with the current photo [CHAR LIMIT=50] -->
     <string name="user_image_photo_selector">Select photo</string>
 
+    <!-- Content of the dialog shown when the user has failed to provide the device lock too many times and the device is wiped. [CHAR LIMIT=NONE] -->
+    <string name="failed_attempts_now_wiping_device">Too many incorrect attempts. This device\'s data will be deleted.</string>
+    <!-- Content of the dialog shown when the user has failed to provide the user lock too many times and the user is removed. [CHAR LIMIT=NONE] -->
+    <string name="failed_attempts_now_wiping_user">Too many incorrect attempts. This user will be deleted.</string>
+    <!-- Content of the dialog shown when the user has failed to provide the work lock too many times and the work profile is removed. [CHAR LIMIT=NONE] -->
+    <string name="failed_attempts_now_wiping_profile">Too many incorrect attempts. This work profile and its data will be deleted.</string>
+    <!-- Button label to dismiss the dialog telling the user the work profile has been wiped. [CHAR LIMIT=40] -->
+    <string name="failed_attempts_now_wiping_dialog_dismiss">Dismiss</string>
+
     <!-- List entry in developer settings to choose default device/system behavior for the app freezer [CHAR LIMIT=30]-->
     <string name="cached_apps_freezer_device_default">Device default</string>
     <!-- List entry in developer settings to disable the app freezer in developer settings [CHAR LIMIT=30]-->
@@ -1578,4 +1571,11 @@
     <string name="keyboard_layout_dialog_title">Choose keyboard layout</string>
     <!-- Label of the default keyboard layout.  [CHAR LIMIT=35] -->
     <string name="keyboard_layout_default_label">Default</string>
+
+    <!-- Special access > Title for managing turn screen on settings. [CHAR LIMIT=50] -->
+    <string name="turn_screen_on_title">Turn screen on</string>
+    <!-- Label for a setting which controls whether an app can turn the screen on [CHAR LIMIT=45] -->
+    <string name="allow_turn_screen_on">Allow turning the screen on</string>
+    <!-- Description for a setting which controls whether an app can turn the screen on [CHAR LIMIT=NONE] -->
+    <string name="allow_turn_screen_on_description">Allow an app to turn the screen on. If granted, the app may turn on the screen at any time without your explicit intent.</string>
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
index 17db45d..3a4a8d2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
@@ -30,11 +30,11 @@
 import android.util.TypedValue;
 import android.widget.TextView;
 
+import androidx.annotation.RequiresApi;
+import androidx.core.os.BuildCompat;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceViewHolder;
 
-import com.android.internal.util.Preconditions;
-
 /**
  * Helper class for managing settings preferences that can be disabled
  * by device admins via user restrictions.
@@ -42,8 +42,8 @@
 public class RestrictedPreferenceHelper {
     private final Context mContext;
     private final Preference mPreference;
-    final String packageName;
-    final int uid;
+    String packageName;
+    int uid;
 
     private boolean mDisabledByAdmin;
     private EnforcedAdmin mEnforcedAdmin;
@@ -105,11 +105,9 @@
         if (mDisabledSummary) {
             final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
             if (summaryView != null) {
-                final CharSequence disabledText = mContext
-                        .getSystemService(DevicePolicyManager.class)
-                        .getString(CONTROLLED_BY_ADMIN_SUMMARY,
-                                () -> summaryView.getContext().getString(
-                                        R.string.disabled_by_admin_summary_text));
+                final CharSequence disabledText = BuildCompat.isAtLeastT()
+                        ? getDisabledByAdminUpdatableString()
+                        : mContext.getString(R.string.disabled_by_admin_summary_text);
                 if (mDisabledByAdmin) {
                     summaryView.setText(disabledText);
                 } else if (mDisabledByAppOps) {
@@ -122,6 +120,13 @@
         }
     }
 
+    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+    private String getDisabledByAdminUpdatableString() {
+        return mContext.getSystemService(DevicePolicyManager.class).getResources().getString(
+                CONTROLLED_BY_ADMIN_SUMMARY,
+                () -> mContext.getString(R.string.disabled_by_admin_summary_text));
+    }
+
     public void useAdminDisabledSummary(boolean useSummary) {
         mDisabledSummary = useSummary;
     }
@@ -219,6 +224,11 @@
         return mDisabledByAppOps;
     }
 
+    public void updatePackageDetails(String packageName, int uid) {
+        this.packageName = packageName;
+        this.uid = uid;
+    }
+
     private void updateDisabledState() {
         if (!(mPreference instanceof RestrictedTopLevelPreference)) {
             mPreference.setEnabled(!(mDisabledByAdmin || mDisabledByAppOps));
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
index c607d74..091e322 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
@@ -18,8 +18,11 @@
 
 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 
+import android.annotation.NonNull;
+import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.os.Process;
 import android.os.UserHandle;
 import android.util.AttributeSet;
 import android.util.TypedValue;
@@ -28,6 +31,7 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import androidx.annotation.VisibleForTesting;
 import androidx.core.content.res.TypedArrayUtils;
 import androidx.preference.PreferenceManager;
 import androidx.preference.PreferenceViewHolder;
@@ -39,6 +43,7 @@
  */
 public class RestrictedSwitchPreference extends SwitchPreference {
     RestrictedPreferenceHelper mHelper;
+    AppOpsManager mAppOpsManager;
     boolean mUseAdditionalSummary = false;
     CharSequence mRestrictedSwitchSummary;
     private int mIconSize;
@@ -90,6 +95,11 @@
         this(context, null);
     }
 
+    @VisibleForTesting
+    public void setAppOps(AppOpsManager appOps) {
+        mAppOpsManager = appOps;
+    }
+
     public void setIconSize(int iconSize) {
         mIconSize = iconSize;
     }
@@ -97,6 +107,12 @@
     @Override
     public void onBindViewHolder(PreferenceViewHolder holder) {
         super.onBindViewHolder(holder);
+        final View switchView = holder.findViewById(android.R.id.switch_widget);
+        if (switchView != null) {
+            final View rootView = switchView.getRootView();
+            rootView.setFilterTouchesWhenObscured(true);
+        }
+
         mHelper.onBindViewHolder(holder);
 
         CharSequence switchSummary;
@@ -164,11 +180,18 @@
 
     @Override
     public void setEnabled(boolean enabled) {
+        boolean changed = false;
         if (enabled && isDisabledByAdmin()) {
             mHelper.setDisabledByAdmin(null);
-            return;
+            changed = true;
         }
-        super.setEnabled(enabled);
+        if (enabled && isDisabledByAppOps()) {
+            mHelper.setDisabledByAppOps(false);
+            changed = true;
+        }
+        if (!changed) {
+            super.setEnabled(enabled);
+        }
     }
 
     public void setDisabledByAdmin(EnforcedAdmin admin) {
@@ -180,4 +203,38 @@
     public boolean isDisabledByAdmin() {
         return mHelper.isDisabledByAdmin();
     }
+
+    private void setDisabledByAppOps(boolean disabled) {
+        if (mHelper.setDisabledByAppOps(disabled)) {
+            notifyChanged();
+        }
+    }
+
+    public boolean isDisabledByAppOps() {
+        return mHelper.isDisabledByAppOps();
+    }
+
+    public int getUid() {
+        return mHelper != null ? mHelper.uid : Process.INVALID_UID;
+    }
+
+    public String getPackageName() {
+        return mHelper != null ? mHelper.packageName : null;
+    }
+
+    public void updateState(@NonNull String packageName, int uid, boolean isEnabled) {
+        mHelper.updatePackageDetails(packageName, uid);
+        if (mAppOpsManager == null) {
+            mAppOpsManager = getContext().getSystemService(AppOpsManager.class);
+        }
+        final int mode = mAppOpsManager.noteOpNoThrow(
+                AppOpsManager.OP_ACCESS_RESTRICTED_SETTINGS,
+                uid, packageName);
+        final boolean appOpsAllowed = mode == AppOpsManager.MODE_ALLOWED;
+        if (appOpsAllowed || isEnabled) {
+            setEnabled(true);
+        } else {
+            setDisabledByAppOps(true);
+        }
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 19114cf..aaa0114 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -30,6 +30,7 @@
 import android.net.vcn.VcnTransportInfo;
 import android.net.wifi.WifiInfo;
 import android.os.BatteryManager;
+import android.os.Build;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -41,8 +42,10 @@
 import android.telephony.TelephonyManager;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
 import androidx.core.graphics.drawable.RoundedBitmapDrawable;
 import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+import androidx.core.os.BuildCompat;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.UserIcons;
@@ -127,10 +130,11 @@
         String name = info != null ? info.name : null;
         if (info.isManagedProfile()) {
             // We use predefined values for managed profiles
-            return context.getSystemService(DevicePolicyManager.class).getString(
-                    WORK_PROFILE_USER_LABEL, () -> context.getString(R.string.managed_user_title));
+            return  BuildCompat.isAtLeastT()
+                    ? getUpdatableManagedUserTitle(context)
+                    : context.getString(R.string.managed_user_title);
         } else if (info.isGuest()) {
-            name = context.getString(R.string.user_guest);
+            name = context.getString(com.android.internal.R.string.guest_name);
         }
         if (name == null && info != null) {
             name = Integer.toString(info.id);
@@ -140,6 +144,13 @@
         return context.getResources().getString(R.string.running_process_item_user_label, name);
     }
 
+    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+    private static String getUpdatableManagedUserTitle(Context context) {
+        return context.getSystemService(DevicePolicyManager.class).getResources().getString(
+                WORK_PROFILE_USER_LABEL,
+                () -> context.getString(R.string.managed_user_title));
+    }
+
     /**
      * Returns a circular icon for a user.
      */
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothBroadcastUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothBroadcastUtils.java
new file mode 100644
index 0000000..3ce7a0e
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothBroadcastUtils.java
@@ -0,0 +1,56 @@
+/*
+ * 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.bluetooth;
+
+public final class BluetoothBroadcastUtils {
+
+    static final String SCHEME_BT_BROADCAST_METADATA = "BT:";
+
+    // BluetoothLeBroadcastMetadata
+    static final String PREFIX_BT_ADDRESS_TYPE = "T:";
+    static final String PREFIX_BT_DEVICE = "D:";
+    static final String PREFIX_BT_ADVERTISING_SID = "AS:";
+    static final String PREFIX_BT_BROADCAST_ID = "B:";
+    static final String PREFIX_BT_SYNC_INTERVAL = "SI:";
+    static final String PREFIX_BT_IS_ENCRYPTED = "E:";
+    static final String PREFIX_BT_BROADCAST_CODE = "C:";
+    static final String PREFIX_BT_PRESENTATION_DELAY = "D:";
+    static final String PREFIX_BT_SUBGROUPS = "G:";
+    static final String PREFIX_BT_ANDROID_VERSION = "V:";
+
+    // BluetoothLeBroadcastSubgroup
+    static final String PREFIX_BTSG_CODEC_ID = "CID:";
+    static final String PREFIX_BTSG_CODEC_CONFIG = "CC:";
+    static final String PREFIX_BTSG_AUDIO_CONTENT = "AC:";
+    static final String PREFIX_BTSG_CHANNEL_PREF = "CP:";
+    static final String PREFIX_BTSG_BROADCAST_CHANNEL = "BC:";
+
+    // BluetoothLeAudioCodecConfigMetadata
+    static final String PREFIX_BTCC_AUDIO_LOCATION = "AL:";
+    static final String PREFIX_BTCC_RAW_METADATA = "CCRM:";
+
+    // BluetoothLeAudioContentMetadata
+    static final String PREFIX_BTAC_PROGRAM_INFO = "PI:";
+    static final String PREFIX_BTAC_LANGUAGE = "L:";
+    static final String PREFIX_BTAC_RAW_METADATA = "ACRM:";
+
+    // BluetoothLeBroadcastChannel
+    static final String PREFIX_BTBC_CHANNEL_INDEX = "CI:";
+    static final String PREFIX_BTBC_CODEC_CONFIG = "BCCM:";
+
+    static final String DELIMITER_QR_CODE = ";";
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 389892e..62c83cf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -371,7 +371,7 @@
                         || cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID) {
                     mDeviceManager.onDeviceUnpaired(cachedDevice);
                 }
-                int reason = intent.getIntExtra(BluetoothDevice.EXTRA_REASON,
+                int reason = intent.getIntExtra(BluetoothDevice.EXTRA_UNBOND_REASON,
                         BluetoothDevice.ERROR);
 
                 showUnbondMessage(context, cachedDevice.getName(), reason);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 1c9d9cf..2a28891 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -285,6 +285,12 @@
 
     public void disconnect() {
         synchronized (mProfileLock) {
+            if (getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
+                for (CachedBluetoothDevice member : getMemberDevice()) {
+                    Log.d(TAG, "Disconnect the member(" + member.getAddress() + ")");
+                    member.disconnect();
+                }
+            }
             mDevice.disconnect();
         }
         // Disconnect  PBAP server in case its connected
@@ -399,6 +405,12 @@
             }
 
             mDevice.connect();
+            if (getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
+                for (CachedBluetoothDevice member : getMemberDevice()) {
+                    Log.d(TAG, "connect the member(" + member.getAddress() + ")");
+                    member.connect();
+                }
+            }
         }
     }
 
@@ -741,7 +753,10 @@
         ParcelUuid[] uuids = mDevice.getUuids();
         if (uuids == null) return false;
 
-        ParcelUuid[] localUuids = mLocalAdapter.getUuids();
+        List<ParcelUuid> uuidsList = mLocalAdapter.getUuidsList();
+        ParcelUuid[] localUuids = new ParcelUuid[uuidsList.size()];
+        uuidsList.toArray(localUuids);
+
         if (localUuids == null) return false;
 
         /*
@@ -1105,7 +1120,8 @@
                 final boolean isOnCall = Utils.isAudioModeOngoingCall(mContext);
                 if ((mIsActiveDeviceHearingAid)
                         || (mIsActiveDeviceHeadset && isOnCall)
-                        || (mIsActiveDeviceA2dp && !isOnCall)) {
+                        || (mIsActiveDeviceA2dp && !isOnCall)
+                        || mIsActiveDeviceLeAudio) {
                     if (isTwsBatteryAvailable(leftBattery, rightBattery) && !shortSummary) {
                         stringRes = R.string.bluetooth_active_battery_level_untethered;
                     } else if (batteryLevelPercentageString != null && !shortSummary) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
index e203cba..19df1e9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
@@ -246,6 +246,13 @@
         return R.drawable.ic_bt_le_audio;
     }
 
+    public int getAudioLocation(BluetoothDevice device) {
+        if (mService == null || device == null) {
+            return BluetoothLeAudio.AUDIO_LOCATION_INVALID;
+        }
+        return mService.getAudioLocation(device);
+    }
+
     @RequiresApi(Build.VERSION_CODES.S)
     protected void finalize() {
         if (DEBUG) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
index e7a6b32..31cc6a4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
@@ -126,7 +126,10 @@
     }
 
     public ParcelUuid[] getUuids() {
-        return mAdapter.getUuids();
+        List<ParcelUuid> uuidsList = mAdapter.getUuidsList();
+        ParcelUuid[] uuidsArray = new ParcelUuid[uuidsList.size()];
+        uuidsList.toArray(uuidsArray);
+        return uuidsArray;
     }
 
     public boolean isDiscovering() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeAudioContentMetadata.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeAudioContentMetadata.java
new file mode 100644
index 0000000..9df0f4d
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeAudioContentMetadata.java
@@ -0,0 +1,43 @@
+/*
+ * 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.bluetooth;
+
+import android.bluetooth.BluetoothLeAudioContentMetadata;
+
+public class LocalBluetoothLeAudioContentMetadata {
+
+    private static final String TAG = "LocalBluetoothLeAudioContentMetadata";
+    private final BluetoothLeAudioContentMetadata mContentMetadata;
+    private final String mLanguage;
+    private final byte[] mRawMetadata;
+    private String mProgramInfo;
+
+    LocalBluetoothLeAudioContentMetadata(BluetoothLeAudioContentMetadata contentMetadata) {
+        mContentMetadata = contentMetadata;
+        mProgramInfo = contentMetadata.getProgramInfo();
+        mLanguage = contentMetadata.getLanguage();
+        mRawMetadata = contentMetadata.getRawMetadata();
+    }
+
+    public void setProgramInfo(String programInfo) {
+        mProgramInfo = programInfo;
+    }
+
+    public String getProgramInfo() {
+        return mProgramInfo;
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
new file mode 100644
index 0000000..bb47c5e
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
@@ -0,0 +1,192 @@
+/*
+ * 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.bluetooth;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothLeAudioContentMetadata;
+import android.bluetooth.BluetoothLeBroadcast;
+import android.bluetooth.BluetoothLeBroadcastMetadata;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothProfile.ServiceListener;
+import android.content.Context;
+import android.util.Log;
+
+/**
+ * LocalBluetoothLeBroadcast provides an interface between the Settings app
+ * and the functionality of the local {@link BluetoothLeBroadcast}.
+ */
+public class LocalBluetoothLeBroadcast implements BluetoothLeBroadcast.Callback {
+
+    private static final String TAG = "LocalBluetoothLeBroadcast";
+    private static final int UNKNOWN_VALUE_PLACEHOLDER = -1;
+    private static final boolean DEBUG = BluetoothUtils.D;
+
+    private BluetoothLeBroadcast mBluetoothLeBroadcast;
+    private LocalBluetoothProfileManager mProfileManager;
+    private BluetoothLeAudioContentMetadata mBluetoothLeAudioContentMetadata;
+    private BluetoothLeBroadcastMetadata mBluetoothLeBroadcastMetadata;
+    private BluetoothLeAudioContentMetadata.Builder mBuilder;
+    private int mBroadcastId = UNKNOWN_VALUE_PLACEHOLDER;
+    private boolean mIsProfileReady;
+
+    private final ServiceListener mServiceListener = new ServiceListener() {
+        @Override
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            if (profile == BluetoothProfile.LE_AUDIO_BROADCAST) {
+                if (DEBUG) {
+                    Log.d(TAG,"Bluetooth service connected");
+                }
+                mBluetoothLeBroadcast = (BluetoothLeBroadcast) proxy;
+                mProfileManager.callServiceConnectedListeners();
+                mIsProfileReady = true;
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(int profile) {
+            if (profile == BluetoothProfile.LE_AUDIO_BROADCAST) {
+                if (DEBUG) {
+                    Log.d(TAG,"Bluetooth service disconnected");
+                }
+                mIsProfileReady = false;
+            }
+        }
+    };
+
+    LocalBluetoothLeBroadcast(Context context, LocalBluetoothProfileManager profileManager) {
+        mProfileManager = profileManager;
+        BluetoothAdapter.getDefaultAdapter().
+                getProfileProxy(context, mServiceListener, BluetoothProfile.LE_AUDIO_BROADCAST);
+        mBuilder = new BluetoothLeAudioContentMetadata.Builder();
+    }
+
+    public void startBroadcast(byte[] broadcastCode, String language,
+            String programInfo) {
+        if (DEBUG) {
+            if (mBluetoothLeBroadcast == null) {
+                Log.d(TAG, "The BluetoothLeBroadcast is null when starting the broadcast.");
+                return;
+            }
+            Log.d(TAG, "startBroadcast: language = " + language + " ,programInfo = " + programInfo);
+        }
+        buildContentMetadata(language, programInfo);
+        mBluetoothLeBroadcast.startBroadcast(mBluetoothLeAudioContentMetadata, broadcastCode);
+    }
+
+    public void stopBroadcast() {
+        if (DEBUG) {
+            if (mBluetoothLeBroadcast == null) {
+                Log.d(TAG, "The BluetoothLeBroadcast is null when stopping the broadcast.");
+                return;
+            }
+            Log.d(TAG, "stopBroadcast()");
+        }
+        mBluetoothLeBroadcast.stopBroadcast(mBroadcastId);
+    }
+
+    public void updateBroadcast(String language, String programInfo) {
+        if (DEBUG) {
+            if (mBluetoothLeBroadcast == null) {
+                Log.d(TAG, "The BluetoothLeBroadcast is null when updating the broadcast.");
+                return;
+            }
+            Log.d(TAG,
+                    "updateBroadcast: language = " + language + " ,programInfo = " + programInfo);
+        }
+        mBluetoothLeAudioContentMetadata = mBuilder.setProgramInfo(programInfo).build();
+        mBluetoothLeBroadcast.updateBroadcast(mBroadcastId, mBluetoothLeAudioContentMetadata);
+    }
+
+    private void buildContentMetadata(String language, String programInfo) {
+        mBluetoothLeAudioContentMetadata = mBuilder.setLanguage(language).setProgramInfo(
+                programInfo).build();
+    }
+
+    public LocalBluetoothLeBroadcastMetadata getLocalBluetoothLeBroadcastMetaData() {
+        return new LocalBluetoothLeBroadcastMetadata(mBluetoothLeBroadcastMetadata);
+    }
+
+    @Override
+    public void onBroadcastStarted(int reason, int broadcastId) {
+        if (DEBUG) {
+            Log.d(TAG,
+                    "onBroadcastStarted(), reason = " + reason + ", broadcastId = " + broadcastId);
+        }
+    }
+
+    @Override
+    public void onBroadcastStartFailed(int reason) {
+        if (DEBUG) {
+            Log.d(TAG, "onBroadcastStartFailed(), reason = " + reason);
+        }
+    }
+
+    @Override
+    public void onBroadcastMetadataChanged(int broadcastId,
+            @NonNull BluetoothLeBroadcastMetadata metadata) {
+        if (DEBUG) {
+            Log.d(TAG, "onBroadcastMetadataChanged(), broadcastId = " + broadcastId);
+        }
+        mBluetoothLeBroadcastMetadata = metadata;
+    }
+
+    @Override
+    public void onBroadcastStopped(int reason, int broadcastId) {
+        if (DEBUG) {
+            Log.d(TAG,
+                    "onBroadcastStopped(), reason = " + reason + ", broadcastId = " + broadcastId);
+        }
+    }
+
+    @Override
+    public void onBroadcastStopFailed(int reason) {
+        if (DEBUG) {
+            Log.d(TAG, "onBroadcastStopFailed(), reason = " + reason);
+        }
+    }
+
+    @Override
+    public void onBroadcastUpdated(int reason, int broadcastId) {
+        if (DEBUG) {
+            Log.d(TAG,
+                    "onBroadcastUpdated(), reason = " + reason + ", broadcastId = " + broadcastId);
+        }
+    }
+
+    @Override
+    public void onBroadcastUpdateFailed(int reason, int broadcastId) {
+        if (DEBUG) {
+            Log.d(TAG,
+                    "onBroadcastUpdateFailed(), reason = " + reason + ", broadcastId = "
+                            + broadcastId);
+        }
+    }
+
+    @Override
+    public void onPlaybackStarted(int reason, int broadcastId) {
+    }
+
+    @Override
+    public void onPlaybackStopped(int reason, int broadcastId) {
+    }
+
+    public boolean isProfileReady() {
+        return mIsProfileReady;
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java
new file mode 100644
index 0000000..d904265
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java
@@ -0,0 +1,214 @@
+/*
+ * 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.bluetooth;
+
+import android.annotation.NonNull;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeBroadcast;
+import android.bluetooth.BluetoothLeBroadcastAssistant;
+import android.bluetooth.BluetoothLeBroadcastMetadata;
+import android.bluetooth.BluetoothLeBroadcastReceiveState;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothProfile.ServiceListener;
+import android.content.Context;
+import android.util.Log;
+
+import java.util.List;
+
+/**
+ * LocalBluetoothLeBroadcastAssistant provides an interface between the Settings app
+ * and the functionality of the local {@link BluetoothLeBroadcastAssistant}.
+ */
+public class LocalBluetoothLeBroadcastAssistant implements
+        BluetoothLeBroadcastAssistant.Callback {
+
+    private static final String TAG = "LocalBluetoothLeBroadcastAssistant";
+    private static final int UNKNOWN_VALUE_PLACEHOLDER = -1;
+    private static final boolean DEBUG = BluetoothUtils.D;
+
+    private LocalBluetoothProfileManager mProfileManager;
+    private BluetoothLeBroadcastAssistant mBluetoothLeBroadcastAssistant;
+    private BluetoothLeBroadcastMetadata mBluetoothLeBroadcastMetadata;
+    private BluetoothLeBroadcastMetadata.Builder mBuilder;
+    private boolean mIsProfileReady;
+
+    private final ServiceListener mServiceListener = new ServiceListener() {
+        @Override
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            if (profile == BluetoothProfile.LE_AUDIO_BROADCAST) {
+                if (DEBUG) {
+                    Log.d(TAG,"Bluetooth service connected");
+                }
+                mBluetoothLeBroadcastAssistant = (BluetoothLeBroadcastAssistant) proxy;
+                mProfileManager.callServiceConnectedListeners();
+                mIsProfileReady = true;
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(int profile) {
+            if (profile == BluetoothProfile.LE_AUDIO_BROADCAST) {
+                if (DEBUG) {
+                    Log.d(TAG,"Bluetooth service disconnected");
+                }
+                mIsProfileReady = false;
+            }
+        }
+    };
+
+    LocalBluetoothLeBroadcastAssistant(Context context,
+            LocalBluetoothProfileManager profileManager) {
+        mProfileManager = profileManager;
+        BluetoothAdapter.getDefaultAdapter().
+                getProfileProxy(context, mServiceListener,
+                        BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
+        mBuilder = new BluetoothLeBroadcastMetadata.Builder();
+    }
+
+    public void addSource(@NonNull BluetoothDevice sink, int sourceAddressType,
+            int presentationDelayMicros, int sourceAdvertisingSid, int broadcastId,
+            int paSyncInterval, boolean isEncrypted, byte[] broadcastCode,
+            BluetoothDevice sourceDevice, boolean isGroupOp) {
+        if (DEBUG) {
+            Log.d(TAG, "addSource()");
+        }
+        if (mBluetoothLeBroadcastAssistant == null) {
+            Log.d(TAG, "The BluetoothLeBroadcastAssistant is null");
+            return ;
+        }
+        buildMetadata(sourceAddressType, presentationDelayMicros, sourceAdvertisingSid, broadcastId,
+                paSyncInterval, isEncrypted, broadcastCode, sourceDevice);
+        mBluetoothLeBroadcastAssistant.addSource(sink, mBluetoothLeBroadcastMetadata, isGroupOp);
+    }
+
+    private void buildMetadata(int sourceAddressType, int presentationDelayMicros,
+            int sourceAdvertisingSid, int broadcastId, int paSyncInterval, boolean isEncrypted,
+            byte[] broadcastCode, BluetoothDevice sourceDevice) {
+        mBluetoothLeBroadcastMetadata =
+                mBuilder.setSourceDevice(sourceDevice, sourceAddressType)
+                        .setSourceAdvertisingSid(sourceAdvertisingSid)
+                        .setBroadcastId(broadcastId)
+                        .setPaSyncInterval(paSyncInterval)
+                        .setEncrypted(isEncrypted)
+                        .setBroadcastCode(broadcastCode)
+                        .setPresentationDelayMicros(presentationDelayMicros)
+                        .build();
+    }
+
+    public void removeSource(@NonNull BluetoothDevice sink, int sourceId) {
+        if (DEBUG) {
+            Log.d(TAG, "removeSource()");
+        }
+        if (mBluetoothLeBroadcastAssistant == null) {
+            Log.d(TAG, "The BluetoothLeBroadcastAssistant is null");
+            return ;
+        }
+        mBluetoothLeBroadcastAssistant.removeSource(sink, sourceId);
+    }
+
+    public void startSearchingForSources(@NonNull List<android.bluetooth.le.ScanFilter> filters) {
+        if (DEBUG) {
+            Log.d(TAG, "startSearchingForSources()");
+        }
+        if (mBluetoothLeBroadcastAssistant == null) {
+            Log.d(TAG, "The BluetoothLeBroadcastAssistant is null");
+            return ;
+        }
+        mBluetoothLeBroadcastAssistant.startSearchingForSources(filters);
+    }
+
+    @Override
+    public void onSourceAdded(@NonNull BluetoothDevice sink, int sourceId, int reason) {
+        if (DEBUG) {
+            Log.d(TAG, "onSourceAdded(), reason = " + reason + " , sourceId = " + sourceId);
+        }
+
+    }
+
+    @Override
+    public void onSourceAddFailed(@NonNull BluetoothDevice sink,
+            @NonNull BluetoothLeBroadcastMetadata source, int reason) {
+        if (DEBUG) {
+            Log.d(TAG, "onSourceAddFailed(), reason = " + reason);
+        }
+    }
+
+    @Override
+    public void onSourceRemoved(@NonNull BluetoothDevice sink, int sourceId, int reason) {
+        if (DEBUG) {
+            Log.d(TAG, "onSourceRemoved(), reason = " + reason + " , sourceId = " + sourceId);
+        }
+    }
+
+    @Override
+    public void onSourceRemoveFailed(@NonNull BluetoothDevice sink, int sourceId, int reason) {
+        if (DEBUG) {
+            Log.d(TAG, "onSourceRemoveFailed(), reason = " + reason + " , sourceId = " + sourceId);
+        }
+    }
+
+    @Override
+    public void onSearchStarted(int reason) {
+        if (DEBUG) {
+            Log.d(TAG, "onSearchStarted(), reason = " + reason);
+        }
+    }
+
+    @Override
+    public void onSearchStartFailed(int reason) {
+        if (DEBUG) {
+            Log.d(TAG, "onSearchStartFailed(), reason = " + reason);
+        }
+    }
+
+    @Override
+    public void onSearchStopped(int reason) {
+        if (DEBUG) {
+            Log.d(TAG, "onSearchStopped(), reason = " + reason);
+        }
+    }
+
+    @Override
+    public void onSearchStopFailed(int reason) {
+        if (DEBUG) {
+            Log.d(TAG, "onSearchStopFailed(), reason = " + reason);
+        }
+    }
+
+    @Override
+    public void onSourceFound(@NonNull BluetoothLeBroadcastMetadata source) {
+    }
+
+    @Override
+    public void onSourceModified(@NonNull BluetoothDevice sink, int sourceId, int reason) {
+    }
+
+    @Override
+    public void onSourceModifyFailed(@NonNull BluetoothDevice sink, int sourceId, int reason) {
+    }
+
+    @Override
+    public void onReceiveStateChanged(@NonNull BluetoothDevice sink, int sourceId,
+            @NonNull BluetoothLeBroadcastReceiveState state) {
+    }
+
+    public boolean isProfileReady() {
+        return mIsProfileReady;
+    }
+
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastMetadata.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastMetadata.java
new file mode 100644
index 0000000..cf4ba8b
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastMetadata.java
@@ -0,0 +1,298 @@
+/*
+ * 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.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeAudioCodecConfigMetadata;
+import android.bluetooth.BluetoothLeAudioContentMetadata;
+import android.bluetooth.BluetoothLeBroadcastChannel;
+import android.bluetooth.BluetoothLeBroadcastMetadata;
+import android.bluetooth.BluetoothLeBroadcastSubgroup;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class LocalBluetoothLeBroadcastMetadata {
+    private static final boolean DEBUG = BluetoothUtils.D;
+    private static final String TAG = "LocalBluetoothLeBroadcastMetadata";
+    private static final String METADATA_START = "<";
+    private static final String METADATA_END = ">";
+    private static final String PATTERN_REGEX = "<(.*?)>";
+
+    private BluetoothLeBroadcastSubgroup mSubgroup;
+    private List<BluetoothLeBroadcastSubgroup> mSubgroupList;
+
+    // BluetoothLeBroadcastMetadata
+    // Optional: Identity address type
+    private int mSourceAddressType;
+    // Optional: Must use identity address
+    private BluetoothDevice mSourceDevice;
+    private int mSourceAdvertisingSid;
+    private int mBroadcastId;
+    private int mPaSyncInterval;
+    private int mPresentationDelayMicros;
+    private boolean mIsEncrypted;
+    private byte[] mBroadcastCode;
+
+    // BluetoothLeBroadcastSubgroup
+    private long mCodecId;
+    private BluetoothLeAudioContentMetadata mContentMetadata;
+    private BluetoothLeAudioCodecConfigMetadata mConfigMetadata;
+    private BluetoothLeBroadcastChannel mChannel;
+
+    // BluetoothLeAudioCodecConfigMetadata
+    private long mAudioLocation;
+
+    // BluetoothLeAudioContentMetadata
+    private String mLanguage;
+    private String mProgramInfo;
+
+    // BluetoothLeBroadcastChannel
+    private boolean mIsSelected;
+    private int mChannelIndex;
+
+
+    LocalBluetoothLeBroadcastMetadata(BluetoothLeBroadcastMetadata metadata) {
+        mSourceAddressType = metadata.getSourceAddressType();
+        mSourceDevice = metadata.getSourceDevice();
+        mSourceAdvertisingSid = metadata.getSourceAdvertisingSid();
+        mBroadcastId = metadata.getBroadcastId();
+        mPaSyncInterval = metadata.getPaSyncInterval();
+        mIsEncrypted = metadata.isEncrypted();
+        mBroadcastCode = metadata.getBroadcastCode();
+        mPresentationDelayMicros = metadata.getPresentationDelayMicros();
+        mSubgroupList = metadata.getSubgroups();
+    }
+
+    public void setBroadcastCode(byte[] code) {
+        mBroadcastCode = code;
+    }
+
+    public int getBroadcastId() {
+        return mBroadcastId;
+    }
+
+    public String convertToQrCodeString() {
+        return new StringBuilder()
+                .append(BluetoothBroadcastUtils.SCHEME_BT_BROADCAST_METADATA)
+                .append(BluetoothBroadcastUtils.PREFIX_BT_ADDRESS_TYPE)
+                .append(METADATA_START).append(mSourceAddressType).append(METADATA_END)
+                .append(BluetoothBroadcastUtils.DELIMITER_QR_CODE)
+                .append(BluetoothBroadcastUtils.PREFIX_BT_DEVICE)
+                .append(METADATA_START).append(mSourceDevice).append(METADATA_END)
+                .append(BluetoothBroadcastUtils.DELIMITER_QR_CODE)
+                .append(BluetoothBroadcastUtils.PREFIX_BT_ADVERTISING_SID)
+                .append(METADATA_START).append(mSourceAdvertisingSid).append(METADATA_END)
+                .append(BluetoothBroadcastUtils.DELIMITER_QR_CODE)
+                .append(BluetoothBroadcastUtils.PREFIX_BT_BROADCAST_ID)
+                .append(METADATA_START).append(mBroadcastId).append(METADATA_END)
+                .append(BluetoothBroadcastUtils.DELIMITER_QR_CODE)
+                .append(BluetoothBroadcastUtils.PREFIX_BT_SYNC_INTERVAL)
+                .append(METADATA_START).append(mPaSyncInterval).append(METADATA_END)
+                .append(BluetoothBroadcastUtils.DELIMITER_QR_CODE)
+                .append(BluetoothBroadcastUtils.PREFIX_BT_IS_ENCRYPTED)
+                .append(METADATA_START).append(mIsEncrypted).append(METADATA_END)
+                .append(BluetoothBroadcastUtils.DELIMITER_QR_CODE)
+                .append(BluetoothBroadcastUtils.PREFIX_BT_BROADCAST_CODE)
+                .append(METADATA_START).append(Arrays.toString(mBroadcastCode)).append(METADATA_END)
+                .append(BluetoothBroadcastUtils.DELIMITER_QR_CODE)
+                .append(BluetoothBroadcastUtils.PREFIX_BT_PRESENTATION_DELAY)
+                .append(METADATA_START).append(mPresentationDelayMicros).append(METADATA_END)
+                .append(BluetoothBroadcastUtils.DELIMITER_QR_CODE)
+                .append(BluetoothBroadcastUtils.PREFIX_BT_SUBGROUPS)
+                .append(METADATA_START).append(mSubgroupList).append(METADATA_END)
+                .append(BluetoothBroadcastUtils.DELIMITER_QR_CODE)
+                .toString();
+    }
+
+    /**
+     * Example : prefix is with the “BT:”, and end by the Android Version.
+     * BT:T:<1>;D:<00:11:22:AA:BB:CC>;AS:<1>;B:…;V:T;;
+     *
+     * @return BluetoothLeBroadcastMetadata
+     */
+    public BluetoothLeBroadcastMetadata convertToBroadcastMetadata(String qrCodeString) {
+        if (DEBUG) {
+            Log.d(TAG, "Convert " + qrCodeString + "to BluetoothLeBroadcastMetadata");
+        }
+        Pattern pattern = Pattern.compile(PATTERN_REGEX);
+        Matcher match = pattern.matcher(qrCodeString);
+        if (match.find()) {
+            ArrayList<String> resultList = new ArrayList<>();
+            resultList.add(match.group(1));
+            mSourceAddressType = Integer.parseInt(resultList.get(0));
+            mSourceDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(
+                    resultList.get(1));
+            mSourceAdvertisingSid = Integer.parseInt(resultList.get(2));
+            mBroadcastId = Integer.parseInt(resultList.get(3));
+            mPaSyncInterval = Integer.parseInt(resultList.get(4));
+            mIsEncrypted = Boolean.valueOf(resultList.get(5));
+            mBroadcastCode = resultList.get(6).getBytes();
+            mPresentationDelayMicros = Integer.parseInt(resultList.get(7));
+            mSubgroup = convertToSubgroup(resultList.get(8));
+
+            if (DEBUG) {
+                Log.d(TAG, "Converted qrCodeString result: " + match.group());
+            }
+
+            return new BluetoothLeBroadcastMetadata.Builder()
+                    .setSourceDevice(mSourceDevice, mSourceAddressType)
+                    .setSourceAdvertisingSid(mSourceAdvertisingSid)
+                    .setBroadcastId(mBroadcastId)
+                    .setPaSyncInterval(mPaSyncInterval)
+                    .setEncrypted(mIsEncrypted)
+                    .setBroadcastCode(mBroadcastCode)
+                    .setPresentationDelayMicros(mPresentationDelayMicros)
+                    .addSubgroup(mSubgroup)
+                    .build();
+        } else {
+            if (DEBUG) {
+                Log.d(TAG,
+                        "The match fail, can not convert it to BluetoothLeBroadcastMetadata.");
+            }
+            return null;
+        }
+    }
+
+    private BluetoothLeBroadcastSubgroup convertToSubgroup(String subgroupString) {
+        if (DEBUG) {
+            Log.d(TAG, "Convert " + subgroupString + "to BluetoothLeBroadcastSubgroup");
+        }
+        Pattern pattern = Pattern.compile(PATTERN_REGEX);
+        Matcher match = pattern.matcher(subgroupString);
+        if (match.find()) {
+            ArrayList<String> resultList = new ArrayList<>();
+            resultList.add(match.group(1));
+            mCodecId = Long.getLong(resultList.get(0));
+            mConfigMetadata = convertToConfigMetadata(resultList.get(1));
+            mContentMetadata = convertToContentMetadata(resultList.get(2));
+            mChannel = convertToChannel(resultList.get(3), mConfigMetadata);
+
+            if (DEBUG) {
+                Log.d(TAG, "Converted subgroupString result: " + match.group());
+            }
+
+            return new BluetoothLeBroadcastSubgroup.Builder()
+                    .setCodecId(mCodecId)
+                    .setCodecSpecificConfig(mConfigMetadata)
+                    .setContentMetadata(mContentMetadata)
+                    .addChannel(mChannel)
+                    .build();
+        } else {
+            if (DEBUG) {
+                Log.d(TAG,
+                        "The match fail, can not convert it to BluetoothLeBroadcastSubgroup.");
+            }
+            return null;
+        }
+    }
+
+    private BluetoothLeAudioCodecConfigMetadata convertToConfigMetadata(
+            String configMetadataString) {
+        if (DEBUG) {
+            Log.d(TAG,
+                    "Convert " + configMetadataString + "to BluetoothLeAudioCodecConfigMetadata");
+        }
+        Pattern pattern = Pattern.compile(PATTERN_REGEX);
+        Matcher match = pattern.matcher(configMetadataString);
+        if (match.find()) {
+            ArrayList<String> resultList = new ArrayList<>();
+            resultList.add(match.group(1));
+            mAudioLocation = Long.getLong(resultList.get(0));
+
+            if (DEBUG) {
+                Log.d(TAG, "Converted configMetadataString result: " + match.group());
+            }
+
+            return new BluetoothLeAudioCodecConfigMetadata.Builder()
+                    .setAudioLocation(mAudioLocation)
+                    .build();
+        } else {
+            if (DEBUG) {
+                Log.d(TAG,
+                        "The match fail, can not convert it to "
+                                + "BluetoothLeAudioCodecConfigMetadata.");
+            }
+            return null;
+        }
+    }
+
+    private BluetoothLeAudioContentMetadata convertToContentMetadata(String contentMetadataString) {
+        if (DEBUG) {
+            Log.d(TAG, "Convert " + contentMetadataString + "to BluetoothLeAudioContentMetadata");
+        }
+        Pattern pattern = Pattern.compile(PATTERN_REGEX);
+        Matcher match = pattern.matcher(contentMetadataString);
+        if (match.find()) {
+            ArrayList<String> resultList = new ArrayList<>();
+            resultList.add(match.group(1));
+            mProgramInfo = resultList.get(0);
+            mLanguage = resultList.get(1);
+
+            if (DEBUG) {
+                Log.d(TAG, "Converted contentMetadataString result: " + match.group());
+            }
+
+            return new BluetoothLeAudioContentMetadata.Builder()
+                    .setProgramInfo(mProgramInfo)
+                    .setLanguage(mLanguage)
+                    .build();
+        } else {
+            if (DEBUG) {
+                Log.d(TAG,
+                        "The match fail, can not convert it to BluetoothLeAudioContentMetadata.");
+            }
+            return null;
+        }
+    }
+
+    private BluetoothLeBroadcastChannel convertToChannel(String channelString,
+            BluetoothLeAudioCodecConfigMetadata configMetadata) {
+        if (DEBUG) {
+            Log.d(TAG, "Convert " + channelString + "to BluetoothLeBroadcastChannel");
+        }
+        Pattern pattern = Pattern.compile(PATTERN_REGEX);
+        Matcher match = pattern.matcher(channelString);
+        if (match.find()) {
+            ArrayList<String> resultList = new ArrayList<>();
+            resultList.add(match.group(1));
+            mIsSelected = Boolean.valueOf(resultList.get(0));
+            mChannelIndex = Integer.parseInt(resultList.get(1));
+
+            if (DEBUG) {
+                Log.d(TAG, "Converted channelString result: " + match.group());
+            }
+
+            return new BluetoothLeBroadcastChannel.Builder()
+                    .setSelected(mIsSelected)
+                    .setChannelIndex(mChannelIndex)
+                    .setCodecMetadata(configMetadata)
+                    .build();
+        } else {
+            if (DEBUG) {
+                Log.d(TAG,
+                        "The match fail, can not convert it to BluetoothLeBroadcastChannel.");
+            }
+            return null;
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java b/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java
index c61f8a9..be420ac 100644
--- a/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java
@@ -31,6 +31,8 @@
 import android.telephony.TelephonyManager;
 import android.util.Log;
 
+import androidx.annotation.VisibleForTesting;
+
 /**
  * An interface class to manage connectivity subsystem recovery/restart operations.
  */
@@ -193,22 +195,30 @@
         mApmMonitorRegistered = false;
     }
 
-    private void startTrackingWifiRestart() {
+    @VisibleForTesting
+    void startTrackingWifiRestart() {
+        if (mWifiManager == null) return;
         mWifiManager.registerSubsystemRestartTrackingCallback(new HandlerExecutor(mHandler),
                 mWifiSubsystemRestartTrackingCallback);
     }
 
-    private void stopTrackingWifiRestart() {
+    @VisibleForTesting
+    void stopTrackingWifiRestart() {
+        if (mWifiManager == null) return;
         mWifiManager.unregisterSubsystemRestartTrackingCallback(
                 mWifiSubsystemRestartTrackingCallback);
     }
 
-    private void startTrackingTelephonyRestart() {
+    @VisibleForTesting
+    void startTrackingTelephonyRestart() {
+        if (mTelephonyManager == null) return;
         mTelephonyManager.registerTelephonyCallback(new HandlerExecutor(mHandler),
                 mTelephonyCallback);
     }
 
-    private void stopTrackingTelephonyRestart() {
+    @VisibleForTesting
+    void stopTrackingTelephonyRestart() {
+        if (mTelephonyManager == null) return;
         mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback);
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
index d01f2b4..94d90a8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
@@ -98,7 +98,7 @@
     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
     private static Drawable getUpdatableManagedUserDrawable(Context context) {
         DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
-        return dpm.getDrawableForDensity(
+        return dpm.getResources().getDrawableForDensity(
                 WORK_PROFILE_USER_ICON,
                 SOLID_COLORED,
                 context.getResources().getDisplayMetrics().densityDpi,
@@ -233,7 +233,7 @@
     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
     private static Drawable getUpdatableManagementBadge(Context context) {
         DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
-        return dpm.getDrawableForDensity(
+        return dpm.getResources().getDrawableForDensity(
                 WORK_PROFILE_ICON,
                 SOLID_COLORED,
                 context.getResources().getDisplayMetrics().densityDpi,
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index 9ca431d..a72f311 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -32,6 +32,8 @@
 import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET;
 import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;
 
+import static com.android.settingslib.media.LocalMediaManager.MediaDeviceState.STATE_SELECTED;
+
 import android.annotation.TargetApi;
 import android.app.Notification;
 import android.bluetooth.BluetoothAdapter;
@@ -465,6 +467,7 @@
         RoutingSessionInfo routingSessionInfo = getRoutingSessionInfo(packageName);
         if (routingSessionInfo != null) {
             infos.addAll(mRouterManager.getSelectedRoutes(routingSessionInfo));
+            infos.addAll(mRouterManager.getSelectableRoutes(routingSessionInfo));
         }
         final List<MediaRoute2Info> transferableRoutes =
                 mRouterManager.getTransferableRoutes(packageName);
@@ -496,9 +499,11 @@
                 mediaDevice = new InfoMediaDevice(mContext, mRouterManager, route,
                         mPackageName);
                 if (!TextUtils.isEmpty(mPackageName)
-                        && getRoutingSessionInfo().getSelectedRoutes().contains(route.getId())
-                        && mCurrentConnectedDevice == null) {
-                    mCurrentConnectedDevice = mediaDevice;
+                        && getRoutingSessionInfo().getSelectedRoutes().contains(route.getId())) {
+                    mediaDevice.setState(STATE_SELECTED);
+                    if (mCurrentConnectedDevice == null) {
+                        mCurrentConnectedDevice = mediaDevice;
+                    }
                 }
                 break;
             case TYPE_BUILTIN_SPEAKER:
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index 5520ea4..c2e36b7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -63,12 +63,14 @@
     @IntDef({MediaDeviceState.STATE_CONNECTED,
             MediaDeviceState.STATE_CONNECTING,
             MediaDeviceState.STATE_DISCONNECTED,
-            MediaDeviceState.STATE_CONNECTING_FAILED})
+            MediaDeviceState.STATE_CONNECTING_FAILED,
+            MediaDeviceState.STATE_SELECTED})
     public @interface MediaDeviceState {
         int STATE_CONNECTED = 0;
         int STATE_CONNECTING = 1;
         int STATE_DISCONNECTED = 2;
         int STATE_CONNECTING_FAILED = 3;
+        int STATE_SELECTED = 4;
     }
 
     private final Collection<DeviceCallback> mCallbacks = new CopyOnWriteArrayList<>();
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
index 3984ee9..2fb534d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
@@ -31,6 +31,8 @@
 import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES;
 import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET;
 
+import static com.android.settingslib.media.LocalMediaManager.MediaDeviceState.STATE_SELECTED;
+
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.media.MediaRoute2Info;
@@ -55,22 +57,22 @@
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({MediaDeviceType.TYPE_UNKNOWN,
+            MediaDeviceType.TYPE_PHONE_DEVICE,
             MediaDeviceType.TYPE_USB_C_AUDIO_DEVICE,
             MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE,
             MediaDeviceType.TYPE_FAST_PAIR_BLUETOOTH_DEVICE,
             MediaDeviceType.TYPE_BLUETOOTH_DEVICE,
             MediaDeviceType.TYPE_CAST_DEVICE,
-            MediaDeviceType.TYPE_CAST_GROUP_DEVICE,
-            MediaDeviceType.TYPE_PHONE_DEVICE})
+            MediaDeviceType.TYPE_CAST_GROUP_DEVICE})
     public @interface MediaDeviceType {
         int TYPE_UNKNOWN = 0;
-        int TYPE_USB_C_AUDIO_DEVICE = 1;
-        int TYPE_3POINT5_MM_AUDIO_DEVICE = 2;
-        int TYPE_FAST_PAIR_BLUETOOTH_DEVICE = 3;
-        int TYPE_BLUETOOTH_DEVICE = 4;
-        int TYPE_CAST_DEVICE = 5;
-        int TYPE_CAST_GROUP_DEVICE = 6;
-        int TYPE_PHONE_DEVICE = 7;
+        int TYPE_PHONE_DEVICE = 1;
+        int TYPE_USB_C_AUDIO_DEVICE = 2;
+        int TYPE_3POINT5_MM_AUDIO_DEVICE = 3;
+        int TYPE_FAST_PAIR_BLUETOOTH_DEVICE = 4;
+        int TYPE_BLUETOOTH_DEVICE = 5;
+        int TYPE_CAST_DEVICE = 6;
+        int TYPE_CAST_GROUP_DEVICE = 7;
     }
 
     @VisibleForTesting
@@ -305,12 +307,12 @@
      * The most recent used one + device group with usage info sorted by how many times the
      * device has been used.
      * 4. The order is followed below rule:
-     *    1. USB-C audio device
-     *    2. 3.5 mm audio device
-     *    3. Bluetooth device
-     *    4. Cast device
-     *    5. Cast group device
-     *    6. Phone
+     *    1. Phone
+     *    2. USB-C audio device
+     *    3. 3.5 mm audio device
+     *    4. Bluetooth device
+     *    5. Cast device
+     *    6. Cast group device
      *
      * So the device list will look like 5 slots ranked as below.
      * Rule 4 + Rule 1 + the most recently used device + Rule 3 + Rule 2
@@ -330,6 +332,12 @@
             }
         }
 
+        if (getState() == STATE_SELECTED) {
+            return -1;
+        } else if (another.getState() == STATE_SELECTED) {
+            return 1;
+        }
+
         // Both devices have same connection status, compare the range zone
         if (NearbyDevice.compareRangeZones(getRangeZone(), another.getRangeZone()) != 0) {
             return NearbyDevice.compareRangeZones(getRangeZone(), another.getRangeZone());
@@ -378,12 +386,12 @@
             return s1.compareToIgnoreCase(s2);
         } else {
             // Both devices have never been used, the priority is:
-            // 1. USB-C audio device
-            // 2. 3.5 mm audio device
-            // 3. Bluetooth device
-            // 4. Cast device
-            // 5. Cast group device
-            // 6. Phone
+            // 1. Phone
+            // 2. USB-C audio device
+            // 3. 3.5 mm audio device
+            // 4. Bluetooth device
+            // 5. Cast device
+            // 6. Cast group device
             return mType < another.mType ? -1 : 1;
         }
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeGenerator.java b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeGenerator.java
new file mode 100644
index 0000000..bc5824a
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeGenerator.java
@@ -0,0 +1,63 @@
+/*
+ * 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.qrcode;
+
+import android.graphics.Bitmap;
+import android.graphics.Color;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.EncodeHintType;
+import com.google.zxing.MultiFormatWriter;
+import com.google.zxing.WriterException;
+import com.google.zxing.common.BitMatrix;
+
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+public final class QrCodeGenerator {
+    /**
+     * Generates a barcode image with {@code contents}.
+     *
+     * @param contents The contents to encode in the barcode
+     * @param size     The preferred image size in pixels
+     * @return Barcode bitmap
+     */
+    public static Bitmap encodeQrCode(String contents, int size)
+            throws WriterException, IllegalArgumentException {
+        final Map<EncodeHintType, Object> hints = new HashMap<>();
+        if (!isIso88591(contents)) {
+            hints.put(EncodeHintType.CHARACTER_SET, StandardCharsets.UTF_8.name());
+        }
+
+        final BitMatrix qrBits = new MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE,
+                size, size, hints);
+        final Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.RGB_565);
+        for (int x = 0; x < size; x++) {
+            for (int y = 0; y < size; y++) {
+                bitmap.setPixel(x, y, qrBits.get(x, y) ? Color.BLACK : Color.WHITE);
+            }
+        }
+        return bitmap;
+    }
+
+    private static boolean isIso88591(String contents) {
+        CharsetEncoder encoder = StandardCharsets.ISO_8859_1.newEncoder();
+        return encoder.canEncode(contents);
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
index 0cb2c0b..63a9f0c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
@@ -78,6 +78,11 @@
     static final int REQUEST_CODE_TAKE_PHOTO = 1002;
     static final int REQUEST_CODE_CROP_PHOTO = 1003;
 
+    /**
+     * Delay to allow the photo picker exit animation to complete before the crop activity opens.
+     */
+    private static final long DELAY_BEFORE_CROP_MILLIS = 150;
+
     private static final String IMAGES_DIR = "multi_user";
     private static final String PRE_CROP_PICTURE_FILE_NAME = "PreCropEditUserPhoto.jpg";
     private static final String CROP_PICTURE_FILE_NAME = "CropEditUserPhoto.jpg";
@@ -131,13 +136,15 @@
                 mAvatarUi.returnUriResult(pictureUri);
                 return true;
             case REQUEST_CODE_TAKE_PHOTO:
-            case REQUEST_CODE_CHOOSE_PHOTO:
                 if (mTakePictureUri.equals(pictureUri)) {
                     cropPhoto(pictureUri);
                 } else {
-                    copyAndCropPhoto(pictureUri);
+                    copyAndCropPhoto(pictureUri, false);
                 }
                 return true;
+            case REQUEST_CODE_CHOOSE_PHOTO:
+                copyAndCropPhoto(pictureUri, true);
+                return true;
         }
         return false;
     }
@@ -154,7 +161,7 @@
         mAvatarUi.startActivityForResult(intent, REQUEST_CODE_CHOOSE_PHOTO);
     }
 
-    private void copyAndCropPhoto(final Uri pictureUri) {
+    private void copyAndCropPhoto(final Uri pictureUri, boolean delayBeforeCrop) {
         try {
             ThreadUtils.postOnBackgroundThread(() -> {
                 final ContentResolver cr = mContextInjector.getContentResolver();
@@ -165,11 +172,17 @@
                     Log.w(TAG, "Failed to copy photo", e);
                     return;
                 }
-                ThreadUtils.postOnMainThread(() -> {
+                Runnable cropRunnable = () -> {
                     if (!mAvatarUi.isFinishing()) {
                         cropPhoto(mPreCropPictureUri);
                     }
-                });
+                };
+                if (delayBeforeCrop) {
+                    ThreadUtils.postOnMainThreadDelayed(cropRunnable, DELAY_BEFORE_CROP_MILLIS);
+                } else {
+                    ThreadUtils.postOnMainThread(cropRunnable);
+                }
+
             }).get();
         } catch (InterruptedException | ExecutionException e) {
             Log.e(TAG, "Error performing copy-and-crop", e);
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
index 75bb70a..8a1e91b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
@@ -106,13 +106,13 @@
 
         FooterButton secondaryButton =
                 new FooterButton.Builder(this)
-                        .setText("Cancel")
+                        .setText(getString(android.R.string.cancel))
                         .setListener(view -> cancel())
                         .build();
 
         mDoneButton =
                 new FooterButton.Builder(this)
-                        .setText("Done")
+                        .setText(getString(R.string.done))
                         .setListener(view -> mAdapter.returnSelectionResult())
                         .build();
         mDoneButton.setEnabled(false);
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
index 69f1c17..2c1d5da 100644
--- a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
@@ -84,6 +84,13 @@
         getUiThreadHandler().post(runnable);
     }
 
+    /**
+     * Posts the runnable on the main thread with a delay.
+     */
+    public static void postOnMainThreadDelayed(Runnable runnable, long delayMillis) {
+        getUiThreadHandler().postDelayed(runnable, delayMillis);
+    }
+
     private static synchronized ExecutorService getThreadExecutor() {
         if (sThreadExecutor == null) {
             sThreadExecutor = Executors.newFixedThreadPool(
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AvatarPhotoControllerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AvatarPhotoControllerTest.java
index 1d08711..d988111 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AvatarPhotoControllerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AvatarPhotoControllerTest.java
@@ -89,6 +89,10 @@
 
     @After
     public void tearDown() {
+        String[] entries = mImagesDir.list();
+        for (String entry : entries) {
+            new File(mImagesDir, entry).delete();
+        }
         mImagesDir.delete();
     }
 
@@ -233,7 +237,8 @@
     public void internalCropUsedIfNoSystemCropperFound() throws IOException {
         when(mMockAvatarUi.startSystemActivityForResult(any(), anyInt())).thenReturn(false);
 
-        new File(mImagesDir, "file.txt").createNewFile();
+        File file = new File(mImagesDir, "file.txt");
+        saveBitmapToFile(file);
 
         Intent intent = new Intent();
         intent.setData(Uri.parse(
@@ -241,10 +246,6 @@
         mController.onActivityResult(
                 REQUEST_CODE_TAKE_PHOTO, Activity.RESULT_OK, intent);
 
-        Intent startIntent = verifyStartSystemActivityForResult(
-                "com.android.camera.action.CROP", REQUEST_CODE_CROP_PHOTO);
-        assertThat(startIntent.getData()).isNotEqualTo(mTakePhotoUri);
-
         verify(mMockAvatarUi, timeout(TIMEOUT_MILLIS)).returnUriResult(mCropPhotoUri);
 
         InputStream imageStream = mContext.getContentResolver().openInputStream(mCropPhotoUri);
diff --git a/packages/SettingsLib/tests/robotests/res/layout/preference_footer.xml b/packages/SettingsLib/tests/robotests/res/layout/preference_footer.xml
index c47bff7..766efa8 100644
--- a/packages/SettingsLib/tests/robotests/res/layout/preference_footer.xml
+++ b/packages/SettingsLib/tests/robotests/res/layout/preference_footer.xml
@@ -23,32 +23,46 @@
     android:paddingStart="?android:attr/listPreferredItemPaddingStart"
     android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
     android:background="?android:attr/selectableItemBackground"
+    android:orientation="vertical"
     android:clipToPadding="false">
 
     <LinearLayout
-        android:id="@+id/icon_container"
+        android:id="@+id/icon_frame"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:minWidth="60dp"
+        android:minWidth="56dp"
         android:gravity="start|top"
         android:orientation="horizontal"
         android:paddingEnd="12dp"
-        android:paddingTop="20dp"
+        android:paddingTop="16dp"
         android:paddingBottom="4dp">
         <ImageView
             android:id="@android:id/icon"
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content" />
+            android:layout_height="wrap_content"/>
     </LinearLayout>
 
-    <com.android.settingslib.widget.LinkTextView
-        android:id="@android:id/title"
+    <LinearLayout
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:paddingBottom="16dp"
-        android:paddingTop="16dp"
-        android:maxLines="10"
-        android:textColor="?android:attr/textColorSecondary"
-        android:ellipsize="marquee" />
+        android:orientation="vertical">
+        <TextView
+            android:id="@android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingTop="16dp"
+            android:paddingBottom="8dp"
+            android:textColor="?android:attr/textColorSecondary"
+            android:ellipsize="marquee" />
+
+        <com.android.settingslib.widget.LinkTextView
+            android:id="@+id/settingslib_learn_more"
+            android:text="@string/settingslib_learn_more_text"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:clickable="true"
+            android:visibility="gone"
+            style="@style/TextAppearance.Footer.Title.SettingsLib"/>
+    </LinearLayout>
 
 </LinearLayout>
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
index 852ac5c..7b94492 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
@@ -357,7 +357,8 @@
         mIntent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
         mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
         mIntent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
-        mIntent.putExtra(BluetoothDevice.EXTRA_REASON, BluetoothDevice.UNBOND_REASON_AUTH_TIMEOUT);
+        mIntent.putExtra(BluetoothDevice.EXTRA_UNBOND_REASON,
+                BluetoothDevice.UNBOND_REASON_AUTH_TIMEOUT);
         when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedDevice1);
         when(mCachedDevice1.getName()).thenReturn(DEVICE_NAME);
 
@@ -372,7 +373,7 @@
         mIntent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
         mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
         mIntent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
-        mIntent.putExtra(BluetoothDevice.EXTRA_REASON,
+        mIntent.putExtra(BluetoothDevice.EXTRA_UNBOND_REASON,
                 BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN);
         when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedDevice1);
         when(mCachedDevice1.getName()).thenReturn(DEVICE_NAME);
@@ -388,7 +389,8 @@
         mIntent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
         mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
         mIntent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
-        mIntent.putExtra(BluetoothDevice.EXTRA_REASON, BluetoothDevice.UNBOND_REASON_AUTH_REJECTED);
+        mIntent.putExtra(BluetoothDevice.EXTRA_UNBOND_REASON,
+                BluetoothDevice.UNBOND_REASON_AUTH_REJECTED);
         when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedDevice1);
         when(mCachedDevice1.getName()).thenReturn(DEVICE_NAME);
 
@@ -403,7 +405,8 @@
         mIntent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
         mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
         mIntent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
-        mIntent.putExtra(BluetoothDevice.EXTRA_REASON, BluetoothDevice.UNBOND_REASON_AUTH_FAILED);
+        mIntent.putExtra(BluetoothDevice.EXTRA_UNBOND_REASON,
+                BluetoothDevice.UNBOND_REASON_AUTH_FAILED);
         when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedDevice1);
         when(mCachedDevice1.getName()).thenReturn(DEVICE_NAME);
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManagerTest.java
new file mode 100644
index 0000000..ca53a18
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManagerTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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.connectivity;
+
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class ConnectivitySubsystemsRecoveryManagerTest {
+
+    @Rule
+    public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Spy
+    Context mContext = ApplicationProvider.getApplicationContext();
+    @Spy
+    Handler mMainHandler = ApplicationProvider.getApplicationContext().getMainThreadHandler();
+    @Mock
+    PackageManager mPackageManager;
+
+    ConnectivitySubsystemsRecoveryManager mConnectivitySubsystemsRecoveryManager;
+
+    @Before
+    public void setUp() {
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)).thenReturn(true);
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(true);
+    }
+
+    @Test
+    public void startTrackingWifiRestart_hasNoWifiFeature_shouldNotCrash() {
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)).thenReturn(false);
+        mConnectivitySubsystemsRecoveryManager =
+                new ConnectivitySubsystemsRecoveryManager(mContext, mMainHandler);
+
+        mConnectivitySubsystemsRecoveryManager.startTrackingWifiRestart();
+    }
+
+    @Test
+    public void stopTrackingWifiRestart_hasNoWifiFeature_shouldNotCrash() {
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)).thenReturn(false);
+        mConnectivitySubsystemsRecoveryManager =
+                new ConnectivitySubsystemsRecoveryManager(mContext, mMainHandler);
+
+        mConnectivitySubsystemsRecoveryManager.stopTrackingWifiRestart();
+    }
+
+    @Test
+    public void startTrackingTelephonyRestart_hasNoTelephonyFeature_shouldNotCrash() {
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(false);
+        mConnectivitySubsystemsRecoveryManager =
+                new ConnectivitySubsystemsRecoveryManager(mContext, mMainHandler);
+
+        mConnectivitySubsystemsRecoveryManager.startTrackingTelephonyRestart();
+    }
+
+    @Test
+    public void stopTrackingTelephonyRestart_hasNoTelephonyFeature_shouldNotCrash() {
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(false);
+        mConnectivitySubsystemsRecoveryManager =
+                new ConnectivitySubsystemsRecoveryManager(mContext, mMainHandler);
+
+        mConnectivitySubsystemsRecoveryManager.stopTrackingTelephonyRestart();
+    }
+}
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 3b18c57..61a28aa 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
@@ -19,7 +19,6 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.Context;
-import android.text.method.LinkMovementMethod;
 import android.view.LayoutInflater;
 import android.widget.TextView;
 
@@ -46,17 +45,6 @@
     }
 
     @Test
-    public void bindPreference_shouldLinkifyContent() {
-        final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
-                LayoutInflater.from(mContext).inflate(R.layout.preference_footer, null));
-
-        mFooterPreference.onBindViewHolder(holder);
-
-        assertThat(((TextView) holder.findViewById(android.R.id.title)).getMovementMethod())
-                .isInstanceOf(LinkMovementMethod.class);
-    }
-
-    @Test
     public void setSummary_summarySet_shouldSetAsTitle() {
         mFooterPreference.setSummary("summary");
 
diff --git a/packages/SettingsProvider/res/values-or/strings.xml b/packages/SettingsProvider/res/values-or/strings.xml
index 486d8ff..85add41 100644
--- a/packages/SettingsProvider/res/values-or/strings.xml
+++ b/packages/SettingsProvider/res/values-or/strings.xml
@@ -19,7 +19,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="4567566098528588863">"ସେଟିଙ୍ଗ ଷ୍ଟୋରେଜ୍‌"</string>
+    <string name="app_label" msgid="4567566098528588863">"ସେଟିଂସ ଷ୍ଟୋରେଜ୍‌"</string>
     <string name="wifi_softap_config_change" msgid="5688373762357941645">"ହଟସ୍ପଟ୍ ସେଟିଂସ୍ ବଦଳାଯାଇଛି"</string>
     <string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"ବିବରଣୀ ଦେଖିବାକୁ ଟାପ୍ କରନ୍ତୁ"</string>
 </resources>
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
index a50d4ae1..dc166b4 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
@@ -82,5 +82,6 @@
         Settings.Global.USER_PREFERRED_REFRESH_RATE,
         Settings.Global.USER_PREFERRED_RESOLUTION_HEIGHT,
         Settings.Global.USER_PREFERRED_RESOLUTION_WIDTH,
+        Settings.Global.POWER_BUTTON_LONG_PRESS
     };
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index c7673aa..f949f99 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -146,6 +146,7 @@
         Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS,
         Settings.Secure.TRUST_AGENTS_EXTEND_UNLOCK,
         Settings.Secure.UI_NIGHT_MODE,
+        Settings.Secure.UI_NIGHT_MODE_CUSTOM_TYPE,
         Settings.Secure.DARK_THEME_CUSTOM_START_TIME,
         Settings.Secure.DARK_THEME_CUSTOM_END_TIME,
         Settings.Secure.LOCK_SCREEN_WHEN_TRUST_LOST,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index fa3360c..2bdf819 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -253,6 +253,7 @@
         VALIDATORS.put(Secure.ODI_CAPTIONS_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.DARK_MODE_DIALOG_SEEN, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.UI_NIGHT_MODE, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.UI_NIGHT_MODE_CUSTOM_TYPE, NON_NEGATIVE_INTEGER_VALIDATOR);
         VALIDATORS.put(Secure.DARK_THEME_CUSTOM_START_TIME, NONE_NEGATIVE_LONG_VALIDATOR);
         VALIDATORS.put(Secure.DARK_THEME_CUSTOM_END_TIME, NONE_NEGATIVE_LONG_VALIDATOR);
         VALIDATORS.put(Secure.GLOBAL_ACTIONS_PANEL_ENABLED, BOOLEAN_VALIDATOR);
@@ -328,7 +329,5 @@
             return true;
         });
         VALIDATORS.put(Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED, BOOLEAN_VALIDATOR);
-        VALIDATORS.put(Secure.FAST_PAIR_SCAN_ENABLED, BOOLEAN_VALIDATOR);
-
     }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 6cfcb51..440bb67 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -53,6 +53,13 @@
     private static final String SETTING_ORIGINAL_KEY_SUFFIX = "_original";
     private static final float FLOAT_TOLERANCE = 0.01f;
 
+    /** See frameworks/base/core/res/res/values/config.xml#config_longPressOnPowerBehavior **/
+    private static final int LONG_PRESS_POWER_NOTHING = 0;
+    private static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
+    private static final int LONG_PRESS_POWER_FOR_ASSISTANT = 5;
+    /** See frameworks/base/core/res/res/values/config.xml#config_keyChordPowerVolumeUp **/
+    private static final int KEY_CHORD_POWER_VOLUME_UP_GLOBAL_ACTIONS = 2;
+
     private Context mContext;
     private AudioManager mAudioManager;
     private TelephonyManager mTelephonyManager;
@@ -190,6 +197,9 @@
                         && !displayColorModeVendorModeHintsMatch) {
                     return;
                 }
+            } else if (Settings.Global.POWER_BUTTON_LONG_PRESS.equals(name)) {
+                setLongPressPowerBehavior(cr, value);
+                return;
             }
 
             // Default case: write the restored value to settings
@@ -374,6 +384,67 @@
         }
     }
 
+    /**
+     * Correctly sets long press power button Behavior.
+     *
+     * The issue is that setting for LongPressPower button Behavior is not available on all devices
+     * and actually changes default Behavior of two properties - the long press power button
+     * and volume up + power button combo. OEM can also reconfigure these Behaviors in config.xml,
+     * so we need to be careful that we don't irreversibly change power button Behavior when
+     * restoring. Or switch to a non-default button Behavior.
+     */
+    private void setLongPressPowerBehavior(ContentResolver cr, String value) {
+        // We will not restore the value if the long press power setting option is unavailable.
+        if (!mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_longPressOnPowerForAssistantSettingAvailable)) {
+            return;
+        }
+
+        int longPressOnPowerBehavior;
+        try {
+            longPressOnPowerBehavior = Integer.parseInt(value);
+        } catch (NumberFormatException e) {
+            return;
+        }
+
+        if (longPressOnPowerBehavior < LONG_PRESS_POWER_NOTHING
+                || longPressOnPowerBehavior > LONG_PRESS_POWER_FOR_ASSISTANT) {
+            return;
+        }
+
+        // When user enables long press power for Assistant, we also switch the meaning
+        // of Volume Up + Power key chord to the "Show power menu" option.
+        // If the user disables long press power for Assistant, we switch back to default OEM
+        // Behavior configured in config.xml. If the default Behavior IS "LPP for Assistant",
+        // then we fall back to "Long press for Power Menu" Behavior.
+        if (longPressOnPowerBehavior == LONG_PRESS_POWER_FOR_ASSISTANT) {
+            Settings.Global.putInt(cr, Settings.Global.POWER_BUTTON_LONG_PRESS,
+                    LONG_PRESS_POWER_FOR_ASSISTANT);
+            Settings.Global.putInt(cr, Settings.Global.KEY_CHORD_POWER_VOLUME_UP,
+                    KEY_CHORD_POWER_VOLUME_UP_GLOBAL_ACTIONS);
+        } else {
+            // We're restoring "LPP for Assistant Disabled" state, prefer OEM config.xml Behavior
+            // if possible.
+            int longPressOnPowerDeviceBehavior = mContext.getResources().getInteger(
+                    com.android.internal.R.integer.config_longPressOnPowerBehavior);
+            if (longPressOnPowerDeviceBehavior == LONG_PRESS_POWER_FOR_ASSISTANT) {
+                // The default on device IS "LPP for Assistant Enabled" so fall back to power menu.
+                Settings.Global.putInt(cr, Settings.Global.POWER_BUTTON_LONG_PRESS,
+                        LONG_PRESS_POWER_GLOBAL_ACTIONS);
+            } else {
+                // The default is non-Assistant Behavior, so restore that default.
+                Settings.Global.putInt(cr, Settings.Global.POWER_BUTTON_LONG_PRESS,
+                        longPressOnPowerDeviceBehavior);
+            }
+
+            // Clear and restore default power + volume up Behavior as well.
+            int powerVolumeUpDefaultBehavior = mContext.getResources().getInteger(
+                    com.android.internal.R.integer.config_keyChordPowerVolumeUp);
+            Settings.Global.putInt(cr, Settings.Global.KEY_CHORD_POWER_VOLUME_UP,
+                    powerVolumeUpDefaultBehavior);
+        }
+    }
+
     /* package */ byte[] getLocaleData() {
         Configuration conf = mContext.getResources().getConfiguration();
         return conf.getLocales().toLanguageTags().getBytes();
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index aa6661b..fd7554f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -618,7 +618,7 @@
             return;
         }
         HistoricalOperation operation = new HistoricalOperation(
-                SystemClock.elapsedRealtime(), type,
+                System.currentTimeMillis(), type,
                 setting != null ? new Setting(setting) : null);
         if (mNextHistoricalOpIdx >= mHistoricalOperations.size()) {
             mHistoricalOperations.add(operation);
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java
index 7baa226..4f7b494 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java
@@ -16,6 +16,8 @@
 
 package com.android.providers.settings;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static junit.framework.Assert.assertEquals;
 
 import static org.mockito.ArgumentMatchers.eq;
@@ -27,13 +29,19 @@
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.res.Resources;
 import android.media.AudioManager;
 import android.net.Uri;
 import android.os.LocaleList;
+import android.provider.Settings;
 import android.telephony.TelephonyManager;
 
+import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.R;
+
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -52,20 +60,28 @@
     private SettingsHelper mSettingsHelper;
 
     @Mock private Context mContext;
+    @Mock private Resources mResources;
     @Mock private ContentResolver mContentResolver;
     @Mock private AudioManager mAudioManager;
     @Mock private TelephonyManager mTelephonyManager;
 
     @Before
     public void setUp() {
+        clearLongPressPowerValues();
         MockitoAnnotations.initMocks(this);
         when(mContext.getSystemService(eq(Context.AUDIO_SERVICE))).thenReturn(mAudioManager);
         when(mContext.getSystemService(eq(Context.TELEPHONY_SERVICE))).thenReturn(
                 mTelephonyManager);
+        when(mContext.getResources()).thenReturn(mResources);
 
         mSettingsHelper = spy(new SettingsHelper(mContext));
     }
 
+    @After
+    public void tearDown() {
+        clearLongPressPowerValues();
+    }
+
     @Test
     public void testOnBackupValue_settingReplaced_returnsRealValue() {
         when(mSettingsHelper.isReplacedSystemSetting(eq(SETTING_KEY))).thenReturn(true);
@@ -92,6 +108,110 @@
     }
 
     @Test
+    public void testRestoreValue_lppForAssistantEnabled_updatesValue() {
+        ContentResolver cr =
+                InstrumentationRegistry.getInstrumentation().getTargetContext()
+                        .getContentResolver();
+        when(mResources.getBoolean(
+                R.bool.config_longPressOnPowerForAssistantSettingAvailable)).thenReturn(
+                true);
+
+        mSettingsHelper.restoreValue(mContext, cr, new ContentValues(), Uri.EMPTY,
+                Settings.Global.POWER_BUTTON_LONG_PRESS, "5", 0);
+
+        assertThat(
+                Settings.Global.getInt(cr, Settings.Global.POWER_BUTTON_LONG_PRESS, -1))
+                    .isEqualTo(5);
+        assertThat(Settings.Global.getInt(cr, Settings.Global.KEY_CHORD_POWER_VOLUME_UP,
+                -1)).isEqualTo(2);
+    }
+
+    @Test
+    public void testRestoreValue_lppForAssistantNotEnabled_updatesValueToDefaultConfig() {
+        ContentResolver cr =
+                InstrumentationRegistry.getInstrumentation().getTargetContext()
+                        .getContentResolver();
+        when(mResources.getBoolean(
+                R.bool.config_longPressOnPowerForAssistantSettingAvailable)).thenReturn(
+                true);
+
+        when(mResources.getInteger(
+                R.integer.config_longPressOnPowerBehavior)).thenReturn(
+                1);
+        when(mResources.getInteger(
+                R.integer.config_keyChordPowerVolumeUp)).thenReturn(
+                1);
+
+        mSettingsHelper.restoreValue(mContext, cr, new ContentValues(), Uri.EMPTY,
+                Settings.Global.POWER_BUTTON_LONG_PRESS, "2", 0);
+
+        assertThat(
+                Settings.Global.getInt(cr, Settings.Global.POWER_BUTTON_LONG_PRESS, -1))
+                .isEqualTo(1);
+        assertThat(Settings.Global.getInt(cr, Settings.Global.KEY_CHORD_POWER_VOLUME_UP,
+                -1)).isEqualTo(1);
+    }
+
+    @Test
+    public void testRestoreValue_lppForAssistantNotEnabledDefaultConfig_updatesValue() {
+        ContentResolver cr =
+                InstrumentationRegistry.getInstrumentation().getTargetContext()
+                        .getContentResolver();
+        when(mResources.getBoolean(
+                R.bool.config_longPressOnPowerForAssistantSettingAvailable)).thenReturn(
+                true);
+
+        when(mResources.getInteger(
+                R.integer.config_longPressOnPowerBehavior)).thenReturn(
+                5);
+        when(mResources.getInteger(
+                R.integer.config_keyChordPowerVolumeUp)).thenReturn(
+                1);
+
+        mSettingsHelper.restoreValue(mContext, cr, new ContentValues(), Uri.EMPTY,
+                Settings.Global.POWER_BUTTON_LONG_PRESS, "2", 0);
+
+        assertThat(
+                Settings.Global.getInt(cr, Settings.Global.POWER_BUTTON_LONG_PRESS, -1))
+                    .isEqualTo(1);
+        assertThat(Settings.Global.getInt(cr, Settings.Global.KEY_CHORD_POWER_VOLUME_UP,
+                -1)).isEqualTo(1);
+    }
+
+    @Test
+    public void testRestoreValue_lppForAssistantNotAvailable_doesNotRestore() {
+        ContentResolver cr =
+                InstrumentationRegistry.getInstrumentation().getTargetContext()
+                        .getContentResolver();
+        when(mResources.getBoolean(
+                R.bool.config_longPressOnPowerForAssistantSettingAvailable)).thenReturn(
+                false);
+
+        mSettingsHelper.restoreValue(mContext, cr, new ContentValues(), Uri.EMPTY,
+                Settings.Global.POWER_BUTTON_LONG_PRESS, "5", 0);
+
+        assertThat((Settings.Global.getInt(cr, Settings.Global.POWER_BUTTON_LONG_PRESS,
+                -1))).isEqualTo(-1);
+    }
+
+
+    @Test
+    public void testRestoreValue_lppForAssistantInvalid_doesNotRestore() {
+        ContentResolver cr =
+                InstrumentationRegistry.getInstrumentation().getTargetContext()
+                        .getContentResolver();
+        when(mResources.getBoolean(
+                R.bool.config_longPressOnPowerForAssistantSettingAvailable)).thenReturn(
+                false);
+
+        mSettingsHelper.restoreValue(mContext, cr, new ContentValues(), Uri.EMPTY,
+                Settings.Global.POWER_BUTTON_LONG_PRESS, "trees", 0);
+
+        assertThat((Settings.Global.getInt(cr, Settings.Global.POWER_BUTTON_LONG_PRESS,
+                -1))).isEqualTo(-1);
+    }
+
+    @Test
     public void testResolveLocales() throws Exception {
         // Empty string from backup server
         assertEquals(LocaleList.forLanguageTags("en-US"),
@@ -184,4 +304,11 @@
                         LocaleList.forLanguageTags("en-US"),  // current
                         new String[] { "he-IL", "id-ID", "yi" }));  // supported
     }
+
+    private void clearLongPressPowerValues() {
+        ContentResolver cr = InstrumentationRegistry.getInstrumentation().getTargetContext()
+                .getContentResolver();
+        Settings.Global.putString(cr, Settings.Global.POWER_BUTTON_LONG_PRESS, null);
+        Settings.Global.putString(cr, Settings.Global.KEY_CHORD_POWER_VOLUME_UP, null);
+    }
 }
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
index f49e209..eaf0dcb 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
@@ -188,7 +188,6 @@
         int insertedCount = 0;
         try {
             for (; insertedCount < 1200; insertedCount++) {
-                Log.w(LOG_TAG, "Adding app specific setting: " + insertedCount);
                 insertStringViaProviderApi(SETTING_TYPE_SYSTEM,
                         String.valueOf(insertedCount), FAKE_SETTING_VALUE, false);
             }
@@ -197,7 +196,6 @@
             // expected
         } finally {
             for (; insertedCount >= 0; insertedCount--) {
-                Log.w(LOG_TAG, "Removing app specific setting: " + insertedCount);
                 deleteStringViaProviderApi(SETTING_TYPE_SYSTEM,
                         String.valueOf(insertedCount));
             }
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index dae63a8..03384a2 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -110,7 +110,7 @@
     <uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
     <uses-permission android:name="android.permission.READ_INSTALL_SESSIONS" />
     <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
-    <uses-permission android:name="android.permission.SEND_LOST_MODE_LOCATION_UPDATES" />
+    <uses-permission android:name="android.permission.TRIGGER_LOST_MODE" />
     <!-- ACCESS_BACKGROUND_LOCATION is needed for testing purposes only. -->
     <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
     <!-- ACCESS_MTP is needed for testing purposes only. -->
@@ -122,6 +122,8 @@
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/>
     <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
+    <!-- BLUETOOTH_PRIVILEGED is needed for testing purposes only. -->
+    <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
     <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
     <uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS" />
     <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
@@ -536,10 +538,11 @@
     <uses-permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" />
     <uses-permission android:name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" />
     <uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" />
+    <uses-permission android:name="android.permission.MANAGE_WIFI_INTERFACES" />
     <uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG" />
     <!-- Permission needed for CTS test - ConcurrencyTest#testP2pExternalApprover
-         P2P external approver API sets require MANAGE_WIFI_AUTO_JOIN permission. -->
-    <uses-permission android:name="android.permission.MANAGE_WIFI_AUTO_JOIN" />
+         P2P external approver API sets require MANAGE_WIFI_NETWORK_SELECTION permission. -->
+    <uses-permission android:name="android.permission.MANAGE_WIFI_NETWORK_SELECTION" />
 
     <!-- Permission required for CTS tests to enable/disable rate limiting toasts. -->
     <uses-permission android:name="android.permission.MANAGE_TOAST_RATE_LIMITING" />
@@ -668,6 +671,9 @@
     <!-- Permission required for CTS test - CtsTelephonyTestCases -->
     <uses-permission android:name="android.permission.BIND_TELECOM_CONNECTION_SERVICE" />
 
+    <!-- Permission required for CTS test - CtsAppEnumerationTestCases -->
+    <uses-permission android:name="android.permission.MAKE_UID_VISIBLE" />
+
     <application android:label="@string/app_label"
                 android:theme="@android:style/Theme.DeviceDefault.DayNight"
                 android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 0b8bd97..1ce4c64 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -161,6 +161,7 @@
 
     static final String EXTRA_BUGREPORT = "android.intent.extra.BUGREPORT";
     static final String EXTRA_BUGREPORT_TYPE = "android.intent.extra.BUGREPORT_TYPE";
+    static final String EXTRA_BUGREPORT_NONCE = "android.intent.extra.BUGREPORT_NONCE";
     static final String EXTRA_SCREENSHOT = "android.intent.extra.SCREENSHOT";
     static final String EXTRA_ID = "android.intent.extra.ID";
     static final String EXTRA_NAME = "android.intent.extra.NAME";
@@ -428,7 +429,7 @@
             final String bugreportFilePath = mInfo.bugreportFile.getAbsolutePath();
             if (mInfo.type == BugreportParams.BUGREPORT_MODE_REMOTE) {
                 sendRemoteBugreportFinishedBroadcast(mContext, bugreportFilePath,
-                        mInfo.bugreportFile);
+                        mInfo.bugreportFile, mInfo.nonce);
             } else {
                 cleanupOldFiles(MIN_KEEP_COUNT, MIN_KEEP_AGE, mBugreportsDir);
                 final Intent intent = new Intent(INTENT_BUGREPORT_FINISHED);
@@ -441,7 +442,7 @@
     }
 
     private static void sendRemoteBugreportFinishedBroadcast(Context context,
-            String bugreportFileName, File bugreportFile) {
+            String bugreportFileName, File bugreportFile, long nonce) {
         cleanupOldFiles(REMOTE_BUGREPORT_FILES_AMOUNT, REMOTE_MIN_KEEP_AGE,
                 bugreportFile.getParentFile());
         final Intent intent = new Intent(DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH);
@@ -452,6 +453,7 @@
         }
         intent.setDataAndType(bugreportUri, BUGREPORT_MIMETYPE);
         intent.putExtra(DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_HASH, bugreportHash);
+        intent.putExtra(DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_NONCE, nonce);
         intent.putExtra(EXTRA_BUGREPORT, bugreportFileName);
         context.sendBroadcastAsUser(intent, UserHandle.SYSTEM,
                 android.Manifest.permission.DUMP);
@@ -628,11 +630,12 @@
         String shareDescription = intent.getStringExtra(EXTRA_DESCRIPTION);
         int bugreportType = intent.getIntExtra(EXTRA_BUGREPORT_TYPE,
                 BugreportParams.BUGREPORT_MODE_INTERACTIVE);
+        long nonce = intent.getLongExtra(EXTRA_BUGREPORT_NONCE, 0);
         String baseName = getBugreportBaseName(bugreportType);
         String name = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date());
 
         BugreportInfo info = new BugreportInfo(mContext, baseName, name,
-                shareTitle, shareDescription, bugreportType, mBugreportsDir);
+                shareTitle, shareDescription, bugreportType, mBugreportsDir, nonce);
         synchronized (mLock) {
             if (info.bugreportFile.exists()) {
                 Log.e(TAG, "Failed to start bugreport generation, the requested bugreport file "
@@ -2065,6 +2068,11 @@
          */
         final int type;
 
+        /**
+         * Nonce of the bugreport
+         */
+        final long nonce;
+
         private final Object mLock = new Object();
 
         /**
@@ -2072,12 +2080,13 @@
          */
         BugreportInfo(Context context, String baseName, String name,
                 @Nullable String shareTitle, @Nullable String shareDescription,
-                @BugreportParams.BugreportMode int type, File bugreportsDir) {
+                @BugreportParams.BugreportMode int type, File bugreportsDir, long nonce) {
             this.context = context;
             this.name = this.initialName = name;
             this.shareTitle = shareTitle == null ? "" : shareTitle;
             this.shareDescription = shareDescription == null ? "" : shareDescription;
             this.type = type;
+            this.nonce = nonce;
             this.baseName = baseName;
             this.bugreportFile = new File(bugreportsDir, getFileName(this, ".zip"));
         }
@@ -2317,6 +2326,7 @@
             screenshotCounter = in.readInt();
             shareDescription = in.readString();
             type = in.readInt();
+            nonce = in.readLong();
         }
 
         @Override
@@ -2345,6 +2355,7 @@
             dest.writeInt(screenshotCounter);
             dest.writeString(shareDescription);
             dest.writeInt(type);
+            dest.writeLong(nonce);
         }
 
         @Override
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 7f8b2f5..dfe683d 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -314,6 +314,11 @@
     <!-- To change system captions state -->
     <uses-permission android:name="android.permission.SET_SYSTEM_AUDIO_CAPTION" />
 
+    <!-- Compat framework -->
+    <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" />
+    <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
+    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
+
     <protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
     <protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
     <protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" />
@@ -380,6 +385,7 @@
                   android:theme="@style/LongScreenshotActivity"
                   android:process=":screenshot"
                   android:exported="false"
+                  android:label="@string/screenshot_scroll_label"
                   android:finishOnTaskLaunch="true" />
 
         <service android:name=".screenrecord.RecordingService" />
@@ -794,7 +800,7 @@
                   android:noHistory="true"
                   android:showForAllUsers="true"
                   android:finishOnTaskLaunch="true"
-                  android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
+                  android:configChanges="screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden"
                   android:visibleToInstantApps="true">
         </activity>
 
@@ -805,7 +811,7 @@
                   android:showForAllUsers="true"
                   android:finishOnTaskLaunch="true"
                   android:launchMode="singleInstance"
-                  android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
+                  android:configChanges="screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden"
                   android:visibleToInstantApps="true">
         </activity>
 
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 9722b1f..c8e78c3 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -180,5 +180,30 @@
           }
       ]
     }
+  ],
+  "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/animation/res/values/ids.xml b/packages/SystemUI/animation/res/values/ids.xml
index ef60a24..4e9a4be 100644
--- a/packages/SystemUI/animation/res/values/ids.xml
+++ b/packages/SystemUI/animation/res/values/ids.xml
@@ -15,5 +15,14 @@
      limitations under the License.
 -->
 <resources>
+    <!-- DialogLaunchAnimator -->
     <item type="id" name="launch_animation_running"/>
+
+    <!-- ViewBoundsAnimator -->
+    <item type="id" name="tag_animator"/>
+    <item type="id" name="tag_layout_listener"/>
+    <item type="id" name="tag_override_bottom"/>
+    <item type="id" name="tag_override_left"/>
+    <item type="id" name="tag_override_right"/>
+    <item type="id" name="tag_override_top"/>
 </resources>
\ No newline at end of file
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
new file mode 100644
index 0000000..c480197
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
@@ -0,0 +1,328 @@
+/*
+ * 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.systemui.animation
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ObjectAnimator
+import android.animation.PropertyValuesHolder
+import android.util.IntProperty
+import android.view.View
+import android.view.ViewGroup
+import android.view.animation.Interpolator
+
+/**
+ * A class that allows changes in bounds within a view hierarchy to animate seamlessly between the
+ * start and end state.
+ */
+class ViewHierarchyAnimator {
+    // TODO(b/221418522): make this private once it can't be passed as an arg anymore.
+    enum class Bound(val label: String, val overrideTag: Int) {
+        LEFT("left", R.id.tag_override_left) {
+            override fun setValue(view: View, value: Int) {
+                view.left = value
+            }
+
+            override fun getValue(view: View): Int {
+                return view.left
+            }
+        },
+        TOP("top", R.id.tag_override_top) {
+            override fun setValue(view: View, value: Int) {
+                view.top = value
+            }
+
+            override fun getValue(view: View): Int {
+                return view.top
+            }
+        },
+        RIGHT("right", R.id.tag_override_right) {
+            override fun setValue(view: View, value: Int) {
+                view.right = value
+            }
+
+            override fun getValue(view: View): Int {
+                return view.right
+            }
+        },
+        BOTTOM("bottom", R.id.tag_override_bottom) {
+            override fun setValue(view: View, value: Int) {
+                view.bottom = value
+            }
+
+            override fun getValue(view: View): Int {
+                return view.bottom
+            }
+        };
+
+        abstract fun setValue(view: View, value: Int)
+        abstract fun getValue(view: View): Int
+    }
+
+    companion object {
+        /** Default values for the animation. These can all be overridden at call time. */
+        private const val DEFAULT_DURATION = 500L
+        private val DEFAULT_INTERPOLATOR = Interpolators.EMPHASIZED
+        private val DEFAULT_BOUNDS = setOf(Bound.LEFT, Bound.TOP, Bound.RIGHT, Bound.BOTTOM)
+
+        /** The properties used to animate the view bounds. */
+        private val PROPERTIES = mapOf(
+            Bound.LEFT to createViewProperty(Bound.LEFT),
+            Bound.TOP to createViewProperty(Bound.TOP),
+            Bound.RIGHT to createViewProperty(Bound.RIGHT),
+            Bound.BOTTOM to createViewProperty(Bound.BOTTOM)
+        )
+
+        private fun createViewProperty(bound: Bound): IntProperty<View> {
+            return object : IntProperty<View>(bound.label) {
+                override fun setValue(view: View, value: Int) {
+                    setBound(view, bound, value)
+                }
+
+                override fun get(view: View): Int {
+                    return getBound(view, bound) ?: bound.getValue(view)
+                }
+            }
+        }
+
+        /**
+         * Instruct the animator to watch for changes to the layout of [rootView] and its children
+         * and animate them. The animation can be limited to a subset of [bounds]. It uses the
+         * given [interpolator] and [duration].
+         *
+         * If a new layout change happens while an animation is already in progress, the animation
+         * is updated to continue from the current values to the new end state.
+         *
+         * The animator continues to respond to layout changes until [stopAnimating] is called.
+         *
+         * Successive calls to this method override the previous settings ([interpolator] and
+         * [duration]). The changes take effect on the next animation.
+         *
+         * TODO(b/221418522): remove the ability to select which bounds to animate and always
+         * animate all of them.
+         */
+        @JvmOverloads
+        fun animate(
+            rootView: View,
+            bounds: Set<Bound> = DEFAULT_BOUNDS,
+            interpolator: Interpolator = DEFAULT_INTERPOLATOR,
+            duration: Long = DEFAULT_DURATION
+        ) {
+            animate(rootView, bounds, interpolator, duration, false /* ephemeral */)
+        }
+
+        /**
+         * Like [animate], but only takes effect on the next layout update, then unregisters itself
+         * once the first animation is complete.
+         *
+         * TODO(b/221418522): remove the ability to select which bounds to animate and always
+         * animate all of them.
+         */
+        @JvmOverloads
+        fun animateNextUpdate(
+            rootView: View,
+            bounds: Set<Bound> = DEFAULT_BOUNDS,
+            interpolator: Interpolator = DEFAULT_INTERPOLATOR,
+            duration: Long = DEFAULT_DURATION
+        ) {
+            animate(rootView, bounds, interpolator, duration, true /* ephemeral */)
+        }
+
+        private fun animate(
+            rootView: View,
+            bounds: Set<Bound>,
+            interpolator: Interpolator,
+            duration: Long,
+            ephemeral: Boolean
+        ) {
+            val listener = createListener(bounds, interpolator, duration, ephemeral)
+            recursivelyAddListener(rootView, listener)
+        }
+
+        /**
+         * Instruct the animator to stop watching for changes to the layout of [rootView] and its
+         * children.
+         *
+         * Any animations already in progress continue until their natural conclusion.
+         */
+        fun stopAnimating(rootView: View) {
+            val listener = rootView.getTag(R.id.tag_layout_listener)
+            if (listener != null && listener is View.OnLayoutChangeListener) {
+                rootView.setTag(R.id.tag_layout_listener, null /* tag */)
+                rootView.removeOnLayoutChangeListener(listener)
+            }
+
+            if (rootView is ViewGroup) {
+                for (i in 0 until rootView.childCount) {
+                    stopAnimating(rootView.getChildAt(i))
+                }
+            }
+        }
+
+        private fun createListener(
+            bounds: Set<Bound>,
+            interpolator: Interpolator,
+            duration: Long,
+            ephemeral: Boolean
+        ): View.OnLayoutChangeListener {
+            return object : View.OnLayoutChangeListener {
+                override fun onLayoutChange(
+                    view: View?,
+                    left: Int,
+                    top: Int,
+                    right: Int,
+                    bottom: Int,
+                    oldLeft: Int,
+                    oldTop: Int,
+                    oldRight: Int,
+                    oldBottom: Int
+                ) {
+                    if (view == null) return
+
+                    val startLeft = getBound(view, Bound.LEFT) ?: oldLeft
+                    val startTop = getBound(view, Bound.TOP) ?: oldTop
+                    val startRight = getBound(view, Bound.RIGHT) ?: oldRight
+                    val startBottom = getBound(view, Bound.BOTTOM) ?: oldBottom
+
+                    (view.getTag(R.id.tag_animator) as? ObjectAnimator)?.cancel()
+
+                    if (view.visibility == View.GONE || view.visibility == View.INVISIBLE) {
+                        setBound(view, Bound.LEFT, left)
+                        setBound(view, Bound.TOP, top)
+                        setBound(view, Bound.RIGHT, right)
+                        setBound(view, Bound.BOTTOM, bottom)
+                        return
+                    }
+
+                    val startValues = mapOf(
+                        Bound.LEFT to startLeft,
+                        Bound.TOP to startTop,
+                        Bound.RIGHT to startRight,
+                        Bound.BOTTOM to startBottom
+                    )
+                    val endValues = mapOf(
+                        Bound.LEFT to left,
+                        Bound.TOP to top,
+                        Bound.RIGHT to right,
+                        Bound.BOTTOM to bottom
+                    )
+
+                    val boundsToAnimate = bounds.toMutableSet()
+                    if (left == startLeft) boundsToAnimate.remove(Bound.LEFT)
+                    if (top == startTop) boundsToAnimate.remove(Bound.TOP)
+                    if (right == startRight) boundsToAnimate.remove(Bound.RIGHT)
+                    if (bottom == startBottom) boundsToAnimate.remove(Bound.BOTTOM)
+
+                    if (boundsToAnimate.isNotEmpty()) {
+                        startAnimation(
+                            view,
+                            boundsToAnimate,
+                            startValues,
+                            endValues,
+                            interpolator,
+                            duration,
+                            ephemeral
+                        )
+                    }
+                }
+            }
+        }
+
+        private fun recursivelyAddListener(view: View, listener: View.OnLayoutChangeListener) {
+            // Make sure that only one listener is active at a time.
+            val oldListener = view.getTag(R.id.tag_layout_listener)
+            if (oldListener != null && oldListener is View.OnLayoutChangeListener) {
+                view.removeOnLayoutChangeListener(oldListener)
+            }
+
+            view.addOnLayoutChangeListener(listener)
+            view.setTag(R.id.tag_layout_listener, listener)
+            if (view is ViewGroup) {
+                for (i in 0 until view.childCount) {
+                    recursivelyAddListener(view.getChildAt(i), listener)
+                }
+            }
+        }
+
+        private fun getBound(view: View, bound: Bound): Int? {
+            return view.getTag(bound.overrideTag) as? Int
+        }
+
+        private fun setBound(view: View, bound: Bound, value: Int) {
+            view.setTag(bound.overrideTag, value)
+            bound.setValue(view, value)
+        }
+
+        /**
+         * Initiates the animation of a single bound by creating the animator, registering it with
+         * the [view], and starting it. If [ephemeral], the layout change listener is unregistered
+         * at the end of the animation, so no more animations happen.
+         */
+        private fun startAnimation(
+            view: View,
+            bounds: Set<Bound>,
+            startValues: Map<Bound, Int>,
+            endValues: Map<Bound, Int>,
+            interpolator: Interpolator,
+            duration: Long,
+            ephemeral: Boolean
+        ) {
+            val propertyValuesHolders = buildList {
+                bounds.forEach { bound ->
+                    add(
+                        PropertyValuesHolder.ofInt(
+                            PROPERTIES[bound],
+                            startValues.getValue(bound),
+                            endValues.getValue(bound)
+                        )
+                    )
+                }
+            }.toTypedArray()
+
+            val animator = ObjectAnimator.ofPropertyValuesHolder(view, *propertyValuesHolders)
+            animator.interpolator = interpolator
+            animator.duration = duration
+            animator.addListener(object : AnimatorListenerAdapter() {
+                var cancelled = false
+
+                override fun onAnimationEnd(animation: Animator) {
+                    view.setTag(R.id.tag_animator, null /* tag */)
+                    bounds.forEach { view.setTag(it.overrideTag, null /* tag */) }
+
+                    // When an animation is cancelled, a new one might be taking over. We shouldn't
+                    // unregister the listener yet.
+                    if (ephemeral && !cancelled) {
+                        val listener = view.getTag(R.id.tag_layout_listener)
+                        if (listener != null && listener is View.OnLayoutChangeListener) {
+                            view.setTag(R.id.tag_layout_listener, null /* tag */)
+                            view.removeOnLayoutChangeListener(listener)
+                        }
+                    }
+                }
+
+                override fun onAnimationCancel(animation: Animator?) {
+                    cancelled = true
+                }
+            })
+
+            bounds.forEach { bound -> setBound(view, bound, startValues.getValue(bound)) }
+
+            view.setTag(R.id.tag_animator, animator)
+            animator.start()
+        }
+    }
+}
diff --git a/packages/SystemUI/docs/broadcasts.md b/packages/SystemUI/docs/broadcasts.md
index e75ae29..0a35725 100644
--- a/packages/SystemUI/docs/broadcasts.md
+++ b/packages/SystemUI/docs/broadcasts.md
@@ -21,6 +21,7 @@
 * The `IntentFilter` may or may not contain categories.
 * The `IntentFilter` **does not** contain data types, data schemes, data authorities or data paths.
 * The broadcast **is not** gated behind a permission.
+* The broadcast **is not** ordered and doesn't need to set result data.
 
 Additionally, the dispatcher supports the following:
 
@@ -107,3 +108,8 @@
 ```
 
 Unregistering can be done even if the `BroadcastReceiver` has never been registered with `BroadcastDispatcher`. In that case, it is a No-Op.
+
+### A note on goAsync()
+
+If you're processing a broadcast in a background thread, you shouldn't call `goAsync()` and
+`finish()`. The system will keep sysui alive regardless, so it isn't needed.
diff --git a/packages/SystemUI/docs/media-controls.md b/packages/SystemUI/docs/media-controls.md
index 579f453..112e216 100644
--- a/packages/SystemUI/docs/media-controls.md
+++ b/packages/SystemUI/docs/media-controls.md
@@ -41,7 +41,7 @@
       * SeekBarViewModel.kt
          * Implements its own `computePosition()` for the seekbar (to avoid continually polling the `PlaybackState`, which involves binder calls)
          * Does some touch falsing (ignore flings, require drags to start near the thumb - otherwise users would often accidentally trigger the seekbar when they meant to move the carousel or shade)
-      * PlayerViewHolder.kt
+      * MediaViewHolder.kt
          * Holds references to the UI elements in the panel
 * Animation support:
    * MediaHierarchyManager.kt
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
index d8b050a..46dad02 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
@@ -31,37 +31,134 @@
 const val GOOGLE_BLUE = 0xFF1b6ef3.toInt()
 const val MIN_CHROMA = 5
 
-internal enum class ChromaStrategy {
-    EQ, GTE
-}
+internal interface Hue {
+    fun get(sourceColor: Cam): Double
 
-internal enum class HueStrategy {
-    SOURCE, ADD, SUBTRACT
-}
-
-internal class Chroma(val strategy: ChromaStrategy, val value: Double) {
-    fun get(sourceChroma: Double): Double {
-        return when (strategy) {
-            ChromaStrategy.EQ -> value
-            ChromaStrategy.GTE -> sourceChroma.coerceAtLeast(value)
+    /**
+     * Given a hue, and a mapping of hues to hue rotations, find which hues in the mapping the
+     * hue fall betweens, and use the hue rotation of the lower hue.
+     *
+     * @param sourceHue hue of source color
+     * @param hueAndRotations list of pairs, where the first item in a pair is a hue, and the
+     *    second item in the pair is a hue rotation that should be applied
+     */
+    fun getHueRotation(sourceHue: Float, hueAndRotations: List<Pair<Int, Int>>): Double {
+        for (i in 0..hueAndRotations.size) {
+            val previousIndex = if (i == 0) hueAndRotations.size - 1 else i - 1
+            val thisHue = hueAndRotations[i].first
+            val previousHue = hueAndRotations[previousIndex].first
+            if (ColorScheme.angleIsBetween(sourceHue, thisHue, previousHue)) {
+                return ColorScheme.wrapDegreesDouble(sourceHue.toDouble() +
+                        hueAndRotations[previousIndex].first)
+            }
         }
+
+        // If this statement executes, something is wrong, there should have been a rotation
+        // found using the arrays.
+        return sourceHue.toDouble()
     }
 }
 
-internal class Hue(val strategy: HueStrategy = HueStrategy.SOURCE, val value: Double = 0.0) {
-    fun get(sourceHue: Double): Double {
-        return when (strategy) {
-            HueStrategy.SOURCE -> sourceHue
-            HueStrategy.ADD -> ColorScheme.wrapDegreesDouble(sourceHue + value)
-            HueStrategy.SUBTRACT -> ColorScheme.wrapDegreesDouble(sourceHue - value)
-        }
+internal class HueSource : Hue {
+    override fun get(sourceColor: Cam): Double {
+        return sourceColor.hue.toDouble()
     }
 }
 
-internal class TonalSpec(val hue: Hue = Hue(), val chroma: Chroma) {
+internal class HueAdd(val amountDegrees: Double) : Hue {
+    override fun get(sourceColor: Cam): Double {
+        return ColorScheme.wrapDegreesDouble(sourceColor.hue.toDouble() + amountDegrees)
+    }
+}
+
+internal class HueSubtract(val amountDegrees: Double) : Hue {
+    override fun get(sourceColor: Cam): Double {
+        return ColorScheme.wrapDegreesDouble(sourceColor.hue.toDouble() - amountDegrees)
+    }
+}
+
+internal class HueVibrantSecondary() : Hue {
+    val hueToRotations = listOf(Pair(24, 15), Pair(53, 15), Pair(91, 15), Pair(123, 15),
+            Pair(141, 15), Pair(172, 15), Pair(198, 15), Pair(234, 18), Pair(272, 18),
+            Pair(302, 18), Pair(329, 30), Pair(354, 15))
+    override fun get(sourceColor: Cam): Double {
+        return getHueRotation(sourceColor.hue, hueToRotations)
+    }
+}
+
+internal class HueVibrantTertiary() : Hue {
+    val hueToRotations = listOf(Pair(24, 30), Pair(53, 30), Pair(91, 15), Pair(123, 30),
+            Pair(141, 27), Pair(172, 27), Pair(198, 30), Pair(234, 35), Pair(272, 30),
+            Pair(302, 30), Pair(329, 60), Pair(354, 30))
+    override fun get(sourceColor: Cam): Double {
+        return getHueRotation(sourceColor.hue, hueToRotations)
+    }
+}
+
+internal class HueExpressiveSecondary() : Hue {
+    val hueToRotations = listOf(Pair(24, 95), Pair(53, 45), Pair(91, 45), Pair(123, 20),
+            Pair(141, 45), Pair(172, 45), Pair(198, 15), Pair(234, 15),
+            Pair(272, 45), Pair(302, 45), Pair(329, 45), Pair(354, 45))
+    override fun get(sourceColor: Cam): Double {
+        return getHueRotation(sourceColor.hue, hueToRotations)
+    }
+}
+
+internal class HueExpressiveTertiary() : Hue {
+    val hueToRotations = listOf(Pair(24, 20), Pair(53, 20), Pair(91, 20), Pair(123, 45),
+            Pair(141, 20), Pair(172, 20), Pair(198, 90), Pair(234, 90), Pair(272, 20),
+            Pair(302, 20), Pair(329, 120), Pair(354, 120))
+    override fun get(sourceColor: Cam): Double {
+        return getHueRotation(sourceColor.hue, hueToRotations)
+    }
+}
+
+internal interface Chroma {
+    fun get(sourceColor: Cam): Double
+
+    /**
+     * Given a hue, and a mapping of hues to hue rotations, find which hues in the mapping the
+     * hue fall betweens, and use the hue rotation of the lower hue.
+     *
+     * @param sourceHue hue of source color
+     * @param hueAndChromas list of pairs, where the first item in a pair is a hue, and the
+     *    second item in the pair is a chroma that should be applied
+     */
+    fun getSpecifiedChroma(sourceHue: Float, hueAndChromas: List<Pair<Int, Int>>): Double {
+        for (i in 0..hueAndChromas.size) {
+            val previousIndex = if (i == 0) hueAndChromas.size - 1 else i - 1
+            val thisHue = hueAndChromas[i].first
+            val previousHue = hueAndChromas[previousIndex].first
+            if (ColorScheme.angleIsBetween(sourceHue, thisHue, previousHue)) {
+                return hueAndChromas[i].second.toDouble()
+            }
+        }
+
+        // If this statement executes, something is wrong, there should have been a rotation
+        // found using the arrays.
+        return sourceHue.toDouble()
+    }
+}
+
+internal class ChromaConstant(val chroma: Double) : Chroma {
+    override fun get(sourceColor: Cam): Double {
+        return chroma
+    }
+}
+
+internal class ChromaExpressiveNeutral() : Chroma {
+    val hueToChromas = listOf(Pair(24, 8), Pair(53, 8), Pair(91, 8), Pair(123, 8),
+            Pair(141, 6), Pair(172, 6), Pair(198, 8), Pair(234, 8), Pair(272, 8),
+            Pair(302, 8), Pair(329, 8), Pair(354, 8))
+    override fun get(sourceColor: Cam): Double {
+        return getSpecifiedChroma(sourceColor.hue, hueToChromas)
+    }
+}
+
+internal class TonalSpec(val hue: Hue = HueSource(), val chroma: Chroma) {
     fun shades(sourceColor: Cam): List<Int> {
-        val hue = hue.get(sourceColor.hue.toDouble())
-        val chroma = chroma.get(sourceColor.chroma.toDouble())
+        val hue = hue.get(sourceColor)
+        val chroma = chroma.get(sourceColor)
         return Shades.of(hue.toFloat(), chroma.toFloat()).toList()
     }
 }
@@ -76,46 +173,46 @@
 
 enum class Style(internal val coreSpec: CoreSpec) {
     SPRITZ(CoreSpec(
-            a1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 12.0)),
-            a2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 8.0)),
-            a3 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 16.0)),
-            n1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 4.0)),
-            n2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 8.0))
+            a1 = TonalSpec(HueSource(), ChromaConstant(12.0)),
+            a2 = TonalSpec(HueSource(), ChromaConstant(8.0)),
+            a3 = TonalSpec(HueSource(), ChromaConstant(16.0)),
+            n1 = TonalSpec(HueSource(), ChromaConstant(2.0)),
+            n2 = TonalSpec(HueSource(), ChromaConstant(2.0))
     )),
     TONAL_SPOT(CoreSpec(
-            a1 = TonalSpec(chroma = Chroma(ChromaStrategy.GTE, 32.0)),
-            a2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 16.0)),
-            a3 = TonalSpec(Hue(HueStrategy.ADD, 60.0), Chroma(ChromaStrategy.EQ, 24.0)),
-            n1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 4.0)),
-            n2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 8.0))
+            a1 = TonalSpec(HueSource(), ChromaConstant(36.0)),
+            a2 = TonalSpec(HueSource(), ChromaConstant(16.0)),
+            a3 = TonalSpec(HueAdd(60.0), ChromaConstant(24.0)),
+            n1 = TonalSpec(HueSource(), ChromaConstant(4.0)),
+            n2 = TonalSpec(HueSource(), ChromaConstant(8.0))
     )),
     VIBRANT(CoreSpec(
-            a1 = TonalSpec(chroma = Chroma(ChromaStrategy.GTE, 48.0)),
-            a2 = TonalSpec(Hue(HueStrategy.ADD, 15.0), Chroma(ChromaStrategy.EQ, 24.0)),
-            a3 = TonalSpec(Hue(HueStrategy.ADD, 30.0), Chroma(ChromaStrategy.GTE, 32.0)),
-            n1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 8.0)),
-            n2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 16.0))
+            a1 = TonalSpec(HueSource(), ChromaConstant(48.0)),
+            a2 = TonalSpec(HueVibrantSecondary(), ChromaConstant(24.0)),
+            a3 = TonalSpec(HueVibrantTertiary(), ChromaConstant(32.0)),
+            n1 = TonalSpec(HueSource(), ChromaConstant(6.0)),
+            n2 = TonalSpec(HueSource(), ChromaConstant(12.0))
     )),
     EXPRESSIVE(CoreSpec(
-            a1 = TonalSpec(Hue(HueStrategy.SUBTRACT, 60.0), Chroma(ChromaStrategy.GTE, 64.0)),
-            a2 = TonalSpec(Hue(HueStrategy.SUBTRACT, 30.0), Chroma(ChromaStrategy.EQ, 24.0)),
-            a3 = TonalSpec(chroma = Chroma(ChromaStrategy.GTE, 48.0)),
-            n1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 12.0)),
-            n2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 16.0))
+            a1 = TonalSpec(HueAdd(240.0), ChromaConstant(40.0)),
+            a2 = TonalSpec(HueExpressiveSecondary(), ChromaConstant(24.0)),
+            a3 = TonalSpec(HueExpressiveTertiary(), ChromaConstant(40.0)),
+            n1 = TonalSpec(HueAdd(15.0), ChromaExpressiveNeutral()),
+            n2 = TonalSpec(HueAdd(15.0), ChromaConstant(12.0))
     )),
     RAINBOW(CoreSpec(
-            a1 = TonalSpec(chroma = Chroma(ChromaStrategy.GTE, 48.0)),
-            a2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 16.0)),
-            a3 = TonalSpec(Hue(HueStrategy.ADD, 60.0), Chroma(ChromaStrategy.EQ, 24.0)),
-            n1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 0.0)),
-            n2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 0.0))
+            a1 = TonalSpec(HueSource(), ChromaConstant(48.0)),
+            a2 = TonalSpec(HueSource(), ChromaConstant(16.0)),
+            a3 = TonalSpec(HueAdd(60.0), ChromaConstant(24.0)),
+            n1 = TonalSpec(HueSource(), ChromaConstant(0.0)),
+            n2 = TonalSpec(HueSource(), ChromaConstant(0.0))
     )),
     FRUIT_SALAD(CoreSpec(
-            a1 = TonalSpec(Hue(HueStrategy.SUBTRACT, 50.0), Chroma(ChromaStrategy.GTE, 48.0)),
-            a2 = TonalSpec(Hue(HueStrategy.SUBTRACT, 50.0), Chroma(ChromaStrategy.EQ, 36.0)),
-            a3 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 36.0)),
-            n1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 10.0)),
-            n2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 16.0))
+            a1 = TonalSpec(HueSubtract(50.0), ChromaConstant(48.0)),
+            a2 = TonalSpec(HueSubtract(50.0), ChromaConstant(36.0)),
+            a3 = TonalSpec(HueSource(), ChromaConstant(36.0)),
+            n1 = TonalSpec(HueSource(), ChromaConstant(10.0)),
+            n2 = TonalSpec(HueSource(), ChromaConstant(16.0))
     )),
 }
 
@@ -296,6 +393,13 @@
             return seeds
         }
 
+        internal fun angleIsBetween(angle: Float, a: Int, b: Int): Boolean {
+            if (a < b) {
+                return a <= angle && angle <= b
+            }
+            return a <= angle || angle <= b
+        }
+
         private fun wrapDegrees(degrees: Int): Int {
             return when {
                 degrees < 0 -> {
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/Shades.java b/packages/SystemUI/monet/src/com/android/systemui/monet/Shades.java
index aab3538..c97b960 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/Shades.java
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/Shades.java
@@ -59,9 +59,6 @@
         shades[1] = ColorUtils.CAMToColor(hue, Math.min(40f, chroma), 95);
         for (int i = 2; i < 12; i++) {
             float lStar = (i == 6) ? MIDDLE_LSTAR : 100 - 10 * (i - 1);
-            if (lStar >= 90) {
-                chroma = Math.min(40f, chroma);
-            }
             shades[i] = ColorUtils.CAMToColor(hue, chroma, lStar);
         }
         return shades;
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
index 6d088f0..1fec331 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
@@ -17,6 +17,7 @@
 import android.annotation.Nullable;
 import android.app.PendingIntent;
 import android.content.Intent;
+import android.os.UserHandle;
 import android.view.View;
 
 import com.android.systemui.animation.ActivityLaunchAnimator;
@@ -70,6 +71,9 @@
     void startActivity(Intent intent, boolean dismissShade,
             @Nullable ActivityLaunchAnimator.Controller animationController,
             boolean showOverLockscreenWhenLocked);
+    void startActivity(Intent intent, boolean dismissShade,
+            @Nullable ActivityLaunchAnimator.Controller animationController,
+            boolean showOverLockscreenWhenLocked, UserHandle userHandle);
     void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade);
     void startActivity(Intent intent, boolean dismissShade, Callback callback);
     void postStartActivityDismissingKeyguard(Intent intent, int delay);
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index 8ad2009..75d95e6 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -123,6 +123,11 @@
     default void setScrollListener(ScrollListener scrollListener) {}
 
     /**
+     * Sets the amount of vertical over scroll that should be performed on QS.
+     */
+    default void setOverScrollAmount(int overScrollAmount) {}
+
+    /**
      * Callback for when QSPanel container is scrolled
      */
     @ProvidesInterface(version = ScrollListener.VERSION)
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index 06db7b7..f912a28 100644
--- a/packages/SystemUI/res-keyguard/values-it/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-it/strings.xml
@@ -53,7 +53,7 @@
     <string name="kg_wrong_pattern" msgid="5907301342430102842">"Sequenza errata"</string>
     <string name="kg_wrong_password" msgid="4143127991071670512">"Password errata"</string>
     <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN errato"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Riprova fra # secondo.}one{Riprova fra # secondo.}other{Riprova fra # secondi.}}"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Riprova fra # secondo.}other{Riprova fra # secondi.}}"</string>
     <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Inserisci il PIN della SIM."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Inserisci il PIN della SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
     <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Disattiva la eSIM per usare il dispositivo senza servizio dati mobile."</string>
@@ -69,13 +69,13 @@
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. \n\nRiprova tra <xliff:g id="NUMBER_1">%2$d</xliff:g> secondi."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Codice PIN della SIM errato. Devi contattare l\'operatore per sbloccare il dispositivo."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
-      <item quantity="one">Incorrect SIM PIN code, you have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
       <item quantity="other">Codice PIN della SIM errato. Hai ancora <xliff:g id="NUMBER_1">%d</xliff:g> tentativi a disposizione.</item>
+      <item quantity="one">Codice PIN della SIM errato. Hai ancora <xliff:g id="NUMBER_0">%d</xliff:g> tentativo a disposizione, dopodiché dovrai contattare l\'operatore per sbloccare il dispositivo.</item>
     </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"SIM inutilizzabile. Contatta il tuo operatore."</string>
     <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="3937306685604862886">
-      <item quantity="one">Incorrect SIM PUK code, you have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable.</item>
       <item quantity="other">Codice PUK della SIM errato. Hai ancora <xliff:g id="NUMBER_1">%d</xliff:g> tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile.</item>
+      <item quantity="one">Codice PUK della SIM errato. Hai ancora <xliff:g id="NUMBER_0">%d</xliff:g> tentativo a disposizione prima che la SIM diventi definitivamente inutilizzabile.</item>
     </plurals>
     <string name="kg_password_pin_failed" msgid="5136259126330604009">"Operazione con PIN della SIM non riuscita."</string>
     <string name="kg_password_puk_failed" msgid="6778867411556937118">"Operazione con PUK della SIM non riuscita."</string>
@@ -92,12 +92,12 @@
     <string name="kg_face_not_recognized" msgid="7903950626744419160">"Non riconosciuto"</string>
     <string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Per utilizzare lo sblocco con il volto, attiva "<b>"l\'accesso alla fotocamera"</b>" in Impostazioni &gt; Privacy"</string>
     <plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
-      <item quantity="one">Enter SIM PIN. You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
       <item quantity="other">Inserisci il codice PIN della SIM. Hai ancora <xliff:g id="NUMBER_1">%d</xliff:g> tentativi a disposizione.</item>
+      <item quantity="one">Inserisci il codice PIN della SIM. Hai ancora <xliff:g id="NUMBER_0">%d</xliff:g> tentativo a disposizione, dopodiché dovrai contattare l\'operatore per sbloccare il dispositivo.</item>
     </plurals>
     <plurals name="kg_password_default_puk_message" formatted="false" msgid="571308542462946935">
-      <item quantity="one">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact carrier for details.</item>
       <item quantity="other">La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora <xliff:g id="_NUMBER_1">%d</xliff:g> tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile. Per informazioni dettagliate, contatta l\'operatore.</item>
+      <item quantity="one">La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora <xliff:g id="_NUMBER_0">%d</xliff:g> tentativo a disposizione prima che la SIM diventi definitivamente inutilizzabile. Per informazioni dettagliate, contatta l\'operatore.</item>
     </plurals>
     <string name="clock_title_default" msgid="6342735240617459864">"Predefinito"</string>
     <string name="clock_title_bubble" msgid="2204559396790593213">"Bolla"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
index c3486bb..a8d8f34 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
@@ -53,7 +53,7 @@
     <string name="kg_wrong_pattern" msgid="5907301342430102842">"Padrão incorreto."</string>
     <string name="kg_wrong_password" msgid="4143127991071670512">"Palavra-passe incorreta."</string>
     <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN incorreto"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Tente novamente dentro de # segundo.}one{Tente novamente dentro de # segundo(s).}other{Tente novamente dentro de # segundos.}}"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Tente novamente dentro de # segundo.}other{Tente novamente dentro de # segundos.}}"</string>
     <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Introduza o PIN do cartão SIM."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Introduza o PIN do cartão SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
     <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Desative o eSIM para utilizar o dispositivo sem serviço móvel."</string>
@@ -69,13 +69,13 @@
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Desenhou a sua padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Código PIN do cartão SIM incorreto. Tem de contactar o seu operador para desbloquear o dispositivo."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
-      <item quantity="one">Código PIN do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de precisar de contactar o seu operador para desbloquear o dispositivo.</item>
       <item quantity="other">Código PIN do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas.</item>
+      <item quantity="one">Código PIN do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de precisar de contactar o seu operador para desbloquear o dispositivo.</item>
     </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"Cartão SIM inutilizável. Contacte o seu operador."</string>
     <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="3937306685604862886">
-      <item quantity="one">Código PUK do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar permanentemente inutilizável.</item>
       <item quantity="other">Código PUK do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas antes de o cartão SIM ficar permanentemente inutilizável.</item>
+      <item quantity="one">Código PUK do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar permanentemente inutilizável.</item>
     </plurals>
     <string name="kg_password_pin_failed" msgid="5136259126330604009">"Falha ao introduzir o PIN do cartão SIM!"</string>
     <string name="kg_password_puk_failed" msgid="6778867411556937118">"Falha ao introduzir o PUK do cartão SIM!"</string>
@@ -92,12 +92,12 @@
     <string name="kg_face_not_recognized" msgid="7903950626744419160">"Não reconhecido."</string>
     <string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Para utilizar o Desbloqueio facial, ative o "<b>"Acesso à câmara"</b>" em Definições &gt; Privacidade"</string>
     <plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
-      <item quantity="one">Introduza o PIN do cartão SIM. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de ser necessário contactar o operador para desbloquear o dispositivo.</item>
       <item quantity="other">Introduza o PIN do cartão SIM. Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas.</item>
+      <item quantity="one">Introduza o PIN do cartão SIM. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de ser necessário contactar o operador para desbloquear o dispositivo.</item>
     </plurals>
     <plurals name="kg_password_default_puk_message" formatted="false" msgid="571308542462946935">
-      <item quantity="one">O SIM encontra-se desativado. Introduza o código PUK para continuar. Tem mais <xliff:g id="_NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.</item>
       <item quantity="other">O SIM encontra-se desativado. Introduza o código PUK para continuar. Tem mais <xliff:g id="_NUMBER_1">%d</xliff:g> tentativas antes de o cartão SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.</item>
+      <item quantity="one">O SIM encontra-se desativado. Introduza o código PUK para continuar. Tem mais <xliff:g id="_NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.</item>
     </plurals>
     <string name="clock_title_default" msgid="6342735240617459864">"Predefinido"</string>
     <string name="clock_title_bubble" msgid="2204559396790593213">"Balão"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml
index 166be1b..8e58b90 100644
--- a/packages/SystemUI/res-keyguard/values-sv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sv/strings.xml
@@ -21,7 +21,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Ange pinkoden"</string>
-    <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Ange det grafiska lösenordet"</string>
+    <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Ange mönstret"</string>
     <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Ange ditt lösenord"</string>
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Ogiltigt kort."</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"Laddat"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sw600dp-land/dimens.xml b/packages/SystemUI/res-keyguard/values-sw600dp-land/dimens.xml
index 17765b5..ca8554c 100644
--- a/packages/SystemUI/res-keyguard/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw600dp-land/dimens.xml
@@ -22,7 +22,6 @@
     <!-- Overload default clock widget parameters -->
     <dimen name="widget_big_font_size">88dp</dimen>
 
-    <dimen name="qs_header_system_icons_area_height">0dp</dimen>
     <dimen name="qs_panel_padding_top">@dimen/qqs_layout_margin_top</dimen>
 
 </resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 8d205c1..9a6f5ed 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -129,4 +129,7 @@
     <dimen name="user_switcher_icon_selected_width">8dp</dimen>
     <dimen name="user_switcher_fullscreen_button_text_size">14sp</dimen>
     <dimen name="user_switcher_fullscreen_button_padding">12dp</dimen>
+
+    <!-- Translation y for appear animation -->
+    <dimen name="keyguard_host_view_translation_y">80dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 6375698..625ffd3 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -17,13 +17,14 @@
 */
 -->
 
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
     <!-- Keyguard PIN pad styles -->
     <style name="Keyguard.TextView" parent="@android:style/Widget.DeviceDefault.TextView">
         <item name="android:textSize">@dimen/kg_status_line_font_size</item>
     </style>
     <style name="Keyguard.TextView.EmergencyButton" parent="Theme.SystemUI">
-        <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
+        <item name="android:textColor">?androidprv:attr/textColorOnAccent</item>
         <item name="android:textSize">14dp</item>
         <item name="android:background">@drawable/kg_emergency_button_background</item>
         <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
diff --git a/packages/SystemUI/res/drawable/ic_circular_unchecked.xml b/packages/SystemUI/res/drawable/ic_circular_unchecked.xml
index 9b43cf6..779ab81 100644
--- a/packages/SystemUI/res/drawable/ic_circular_unchecked.xml
+++ b/packages/SystemUI/res/drawable/ic_circular_unchecked.xml
@@ -4,6 +4,6 @@
     android:viewportWidth="24"
     android:viewportHeight="24">
   <path
-      android:fillColor="@color/media_dialog_inactive_item_main_content"
+      android:fillColor="@color/media_dialog_item_main_content"
       android:pathData="M12,22q-2.075,0 -3.9,-0.788 -1.825,-0.787 -3.175,-2.137 -1.35,-1.35 -2.137,-3.175Q2,14.075 2,12t0.788,-3.9q0.787,-1.825 2.137,-3.175 1.35,-1.35 3.175,-2.137Q9.925,2 12,2t3.9,0.788q1.825,0.787 3.175,2.137 1.35,1.35 2.137,3.175Q22,9.925 22,12t-0.788,3.9q-0.787,1.825 -2.137,3.175 -1.35,1.35 -3.175,2.137Q14.075,22 12,22zM12,12zM12,20q3.325,0 5.663,-2.337Q20,15.325 20,12t-2.337,-5.662Q15.325,4 12,4T6.338,6.338Q4,8.675 4,12q0,3.325 2.338,5.663Q8.675,20 12,20z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_media_pause.xml b/packages/SystemUI/res/drawable/ic_media_pause.xml
index 1f4b2cf..0009b6c 100644
--- a/packages/SystemUI/res/drawable/ic_media_pause.xml
+++ b/packages/SystemUI/res/drawable/ic_media_pause.xml
@@ -1,26 +1,91 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ 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
-  -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="14dp"
-    android:height="16dp"
-    android:viewportWidth="14"
-    android:viewportHeight="16">
-    <path
-        android:pathData="M9.1818,15.6363H13.5455V0.3635H9.1818V15.6363ZM0.4546,15.6363H4.8182V0.3635H0.4546V15.6363Z"
-        android:fillColor="#FFFFFF"
-        android:fillType="evenOdd"/>
-</vector>
\ No newline at end of file
+<?xml version="1.0" encoding="utf-8"?>

+<!--

+  ~ 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

+-->

+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"

+                 xmlns:aapt="http://schemas.android.com/aapt">

+    <aapt:attr name="android:drawable">

+        <vector android:height="24dp"

+                android:width="24dp"

+                android:viewportHeight="24"

+                android:viewportWidth="24">

+            <group android:name="_R_G">

+                <group android:name="_R_G_L_1_G"

+                       android:translateX="12"

+                       android:translateY="12.125">

+                    <path android:name="_R_G_L_1_G_D_0_P_0"

+                          android:fillColor="#ffffff"

+                          android:fillAlpha="1"

+                          android:fillType="nonZero"

+                          android:pathData=" M-6 7 C-6,7 -2,7 -2,7 C-2,7 -2,-7 -2,-7 C-2,-7 -6,-7 -6,-7 C-6,-7 -6,7 -6,7c "/>

+                </group>

+                <group android:name="_R_G_L_0_G"

+                       android:translateX="12"

+                       android:translateY="12.125">

+                    <path android:name="_R_G_L_0_G_D_0_P_0"

+                          android:fillColor="#ffffff"

+                          android:fillAlpha="1"

+                          android:fillType="nonZero"

+                          android:pathData=" M2 7 C2,7 6,7 6,7 C6,7 6,-0.12 6,-0.12 C6,-0.12 6,-7 6,-7 C6,-7 2,-7 2,-7 C2,-7 2,7 2,7c "/>

+                </group>

+            </group>

+            <group android:name="time_group"/>

+        </vector>

+    </aapt:attr>

+    <target android:name="_R_G_L_1_G_D_0_P_0">

+        <aapt:attr name="android:animation">

+            <set android:ordering="together">

+                <objectAnimator android:propertyName="pathData"

+                                android:duration="333"

+                                android:startOffset="0"

+                                android:valueFrom="M-6 7 C-6,7 -2,7 -2,7 C-2,7 -2,-7 -2,-7 C-2,-7 -6,-7 -6,-7 C-6,-7 -6,7 -6,7c "

+                                android:valueTo="M-6 7 C-6,7 -2,3.94 -2,3.94 C-2,3.94 -2,-4.37 -2,-4.37 C-2,-4.37 -6,-7 -6,-7 C-6,-7 -6,7 -6,7c "

+                                android:valueType="pathType">

+                    <aapt:attr name="android:interpolator">

+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>

+                    </aapt:attr>

+                </objectAnimator>

+            </set>

+        </aapt:attr>

+    </target>

+    <target android:name="_R_G_L_0_G_D_0_P_0">

+        <aapt:attr name="android:animation">

+            <set android:ordering="together">

+                <objectAnimator android:propertyName="pathData"

+                                android:duration="333"

+                                android:startOffset="0"

+                                android:valueFrom="M2 7 C2,7 6,7 6,7 C6,7 6,-0.12 6,-0.12 C6,-0.12 6,-7 6,-7 C6,-7 2,-7 2,-7 C2,-7 2,7 2,7c "

+                                android:valueTo="M-5.62 7 C-5.62,7 -4.75,7 -4.75,7 C-4.75,7 6,-0.12 6,-0.12 C6,-0.12 -4.44,-7 -4.44,-7 C-4.44,-7 -5.62,-7 -5.62,-7 C-5.62,-7 -5.62,7 -5.62,7c "

+                                android:valueType="pathType">

+                    <aapt:attr name="android:interpolator">

+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>

+                    </aapt:attr>

+                </objectAnimator>

+            </set>

+        </aapt:attr>

+    </target>

+    <target android:name="time_group">

+        <aapt:attr name="android:animation">

+            <set android:ordering="together">

+                <objectAnimator android:propertyName="translateX"

+                                android:duration="517"

+                                android:startOffset="0"

+                                android:valueFrom="0"

+                                android:valueTo="1"

+                                android:valueType="floatType"/>

+            </set>

+        </aapt:attr>

+    </target>

+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_media_pause_container.xml b/packages/SystemUI/res/drawable/ic_media_pause_container.xml
new file mode 100644
index 0000000..b92e635
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_media_pause_container.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>

+<!--

+  ~ 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

+-->

+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"

+                 xmlns:aapt="http://schemas.android.com/aapt">

+    <aapt:attr name="android:drawable">

+        <vector android:height="48dp"

+                android:width="48dp"

+                android:viewportHeight="48"

+                android:viewportWidth="48">

+            <group android:name="_R_G">

+                <group android:name="_R_G_L_1_G"

+                       android:translateX="24"

+                       android:translateY="24"

+                       android:scaleX="0.5"

+                       android:scaleY="0.5"/>

+                <group android:name="_R_G_L_0_G"

+                       android:translateX="24"

+                       android:translateY="24"

+                       android:scaleX="0.5"

+                       android:scaleY="0.5">

+                    <path android:name="_R_G_L_0_G_D_0_P_0"

+                          android:fillColor="#ffddb3"

+                          android:fillAlpha="1"

+                          android:fillType="nonZero"

+                          android:pathData=" M48 -16 C48,-16 48,16 48,16 C48,33.67 33.67,48 16,48 C16,48 -16,48 -16,48 C-33.67,48 -48,33.67 -48,16 C-48,16 -48,-16 -48,-16 C-48,-33.67 -33.67,-48 -16,-48 C-16,-48 16,-48 16,-48 C33.67,-48 48,-33.67 48,-16c "/>

+                </group>

+            </group>

+            <group android:name="time_group"/>

+        </vector>

+    </aapt:attr>

+    <target android:name="_R_G_L_0_G_D_0_P_0">

+        <aapt:attr name="android:animation">

+            <set android:ordering="together">

+                <objectAnimator android:propertyName="pathData"

+                                android:duration="500"

+                                android:startOffset="0"

+                                android:valueFrom="M48 -16 C48,-16 48,16 48,16 C48,33.67 33.67,48 16,48 C16,48 -16,48 -16,48 C-33.67,48 -48,33.67 -48,16 C-48,16 -48,-16 -48,-16 C-48,-33.67 -33.67,-48 -16,-48 C-16,-48 16,-48 16,-48 C33.67,-48 48,-33.67 48,-16c "

+                                android:valueTo="M48 0.25 C48,0.25 48,0 48,0 C47.75,26 31.25,48 0,48 C0,48 0,48 0,48 C-30,48 -48,25.75 -48,-0.25 C-48,-0.25 -48,-0.25 -48,-0.25 C-47.75,-23.5 -32.25,-47.75 0.5,-48 C0.5,-48 0.5,-48 0.5,-48 C28,-47.75 47.75,-29.75 48,0.25c "

+                                android:valueType="pathType">

+                    <aapt:attr name="android:interpolator">

+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.526,0 0,1 1.0,1.0"/>

+                    </aapt:attr>

+                </objectAnimator>

+            </set>

+        </aapt:attr>

+    </target>

+    <target android:name="time_group">

+        <aapt:attr name="android:animation">

+            <set android:ordering="together">

+                <objectAnimator android:propertyName="translateX"

+                                android:duration="517"

+                                android:startOffset="0"

+                                android:valueFrom="0"

+                                android:valueTo="1"

+                                android:valueType="floatType"/>

+            </set>

+        </aapt:attr>

+    </target>

+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_media_play.xml b/packages/SystemUI/res/drawable/ic_media_play.xml
index 0eac1ad..eb32470 100644
--- a/packages/SystemUI/res/drawable/ic_media_play.xml
+++ b/packages/SystemUI/res/drawable/ic_media_play.xml
@@ -1,26 +1,91 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ 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
-  -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-    <path
-        android:pathData="M20,12L6,21V3L20,12ZM15.26,12L8.55,7.68V16.32L15.26,12Z"
-        android:fillColor="#FFFFFF"
-        android:fillType="evenOdd"/>
-</vector>
\ No newline at end of file
+<?xml version="1.0" encoding="utf-8"?>

+<!--

+  ~ 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

+-->

+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"

+                 xmlns:aapt="http://schemas.android.com/aapt">

+    <aapt:attr name="android:drawable">

+        <vector android:height="24dp"

+                android:width="24dp"

+                android:viewportHeight="24"

+                android:viewportWidth="24">

+            <group android:name="_R_G">

+                <group android:name="_R_G_L_1_G"

+                       android:translateX="12"

+                       android:translateY="12.125">

+                    <path android:name="_R_G_L_1_G_D_0_P_0"

+                          android:fillColor="#ffffff"

+                          android:fillAlpha="1"

+                          android:fillType="nonZero"

+                          android:pathData=" M-6 7 C-6,7 -2,3.94 -2,3.94 C-2,3.94 -2,-4.37 -2,-4.37 C-2,-4.37 -6,-7 -6,-7 C-6,-7 -6,7 -6,7c "/>

+                </group>

+                <group android:name="_R_G_L_0_G"

+                       android:translateX="12"

+                       android:translateY="12.125">

+                    <path android:name="_R_G_L_0_G_D_0_P_0"

+                          android:fillColor="#ffffff"

+                          android:fillAlpha="1"

+                          android:fillType="nonZero"

+                          android:pathData=" M-5.62 7 C-5.62,7 -4.75,7 -4.75,7 C-4.75,7 6,-0.12 6,-0.12 C6,-0.12 -4.44,-7 -4.44,-7 C-4.44,-7 -5.62,-7 -5.62,-7 C-5.62,-7 -5.62,7 -5.62,7c "/>

+                </group>

+            </group>

+            <group android:name="time_group"/>

+        </vector>

+    </aapt:attr>

+    <target android:name="_R_G_L_1_G_D_0_P_0">

+        <aapt:attr name="android:animation">

+            <set android:ordering="together">

+                <objectAnimator android:propertyName="pathData"

+                                android:duration="333"

+                                android:startOffset="0"

+                                android:valueFrom="M-6 7 C-6,7 -2,3.94 -2,3.94 C-2,3.94 -2,-4.37 -2,-4.37 C-2,-4.37 -6,-7 -6,-7 C-6,-7 -6,7 -6,7c "

+                                android:valueTo="M-6 7 C-6,7 -2,7 -2,7 C-2,7 -2,-7 -2,-7 C-2,-7 -6,-7 -6,-7 C-6,-7 -6,7 -6,7c "

+                                android:valueType="pathType">

+                    <aapt:attr name="android:interpolator">

+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>

+                    </aapt:attr>

+                </objectAnimator>

+            </set>

+        </aapt:attr>

+    </target>

+    <target android:name="_R_G_L_0_G_D_0_P_0">

+        <aapt:attr name="android:animation">

+            <set android:ordering="together">

+                <objectAnimator android:propertyName="pathData"

+                                android:duration="333"

+                                android:startOffset="0"

+                                android:valueFrom="M-5.62 7 C-5.62,7 -4.75,7 -4.75,7 C-4.75,7 6,-0.12 6,-0.12 C6,-0.12 -4.44,-7 -4.44,-7 C-4.44,-7 -5.62,-7 -5.62,-7 C-5.62,-7 -5.62,7 -5.62,7c "

+                                android:valueTo="M2 7 C2,7 6,7 6,7 C6,7 6,-0.12 6,-0.12 C6,-0.12 6,-7 6,-7 C6,-7 2,-7 2,-7 C2,-7 2,7 2,7c "

+                                android:valueType="pathType">

+                    <aapt:attr name="android:interpolator">

+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>

+                    </aapt:attr>

+                </objectAnimator>

+            </set>

+        </aapt:attr>

+    </target>

+    <target android:name="time_group">

+        <aapt:attr name="android:animation">

+            <set android:ordering="together">

+                <objectAnimator android:propertyName="translateX"

+                                android:duration="517"

+                                android:startOffset="0"

+                                android:valueFrom="0"

+                                android:valueTo="1"

+                                android:valueType="floatType"/>

+            </set>

+        </aapt:attr>

+    </target>

+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_media_play_container.xml b/packages/SystemUI/res/drawable/ic_media_play_container.xml
new file mode 100644
index 0000000..2fc9fc8
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_media_play_container.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>

+<!--

+  ~ 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

+-->

+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"

+                 xmlns:aapt="http://schemas.android.com/aapt">

+    <aapt:attr name="android:drawable">

+        <vector android:height="48dp"

+                android:width="48dp"

+                android:viewportHeight="48"

+                android:viewportWidth="48">

+            <group android:name="_R_G">

+                <group android:name="_R_G_L_0_G"

+                       android:translateX="24"

+                       android:translateY="24"

+                       android:scaleX="0.5"

+                       android:scaleY="0.5">

+                    <path android:name="_R_G_L_0_G_D_0_P_0"

+                          android:fillColor="#ffddb3"

+                          android:fillAlpha="1"

+                          android:fillType="nonZero"

+                          android:pathData=" M48 0.25 C48,0.25 48,0 48,0 C47.75,26 31.25,48 0,48 C0,48 0,48 0,48 C-30,48 -48,25.75 -48,-0.25 C-48,-0.25 -48,-0.25 -48,-0.25 C-47.75,-23.5 -32.25,-47.75 0.5,-48 C0.5,-48 0.5,-48 0.5,-48 C28,-47.75 47.75,-29.75 48,0.25c "/>

+                </group>

+            </group>

+            <group android:name="time_group"/>

+        </vector>

+    </aapt:attr>

+    <target android:name="_R_G_L_0_G_D_0_P_0">

+        <aapt:attr name="android:animation">

+            <set android:ordering="together">

+                <objectAnimator android:propertyName="pathData"

+                                android:duration="500"

+                                android:startOffset="0"

+                                android:valueFrom="M48 0.25 C48,0.25 48,0 48,0 C47.75,26 31.25,48 0,48 C0,48 0,48 0,48 C-30,48 -48,25.75 -48,-0.25 C-48,-0.25 -48,-0.25 -48,-0.25 C-47.75,-23.5 -32.25,-47.75 0.5,-48 C0.5,-48 0.5,-48 0.5,-48 C28,-47.75 47.75,-29.75 48,0.25c "

+                                android:valueTo="M48 -16 C48,-16 48,16 48,16 C48,33.67 33.67,48 16,48 C16,48 -16,48 -16,48 C-33.67,48 -48,33.67 -48,16 C-48,16 -48,-16 -48,-16 C-48,-33.67 -33.67,-48 -16,-48 C-16,-48 16,-48 16,-48 C33.67,-48 48,-33.67 48,-16c "

+                                android:valueType="pathType">

+                    <aapt:attr name="android:interpolator">

+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.518,0 0,1 1.0,1.0"/>

+                    </aapt:attr>

+                </objectAnimator>

+            </set>

+        </aapt:attr>

+    </target>

+    <target android:name="time_group">

+        <aapt:attr name="android:animation">

+            <set android:ordering="together">

+                <objectAnimator android:propertyName="translateX"

+                                android:duration="517"

+                                android:startOffset="0"

+                                android:valueFrom="0"

+                                android:valueTo="1"

+                                android:valueType="floatType"/>

+            </set>

+        </aapt:attr>

+    </target>

+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/media_output_status_check.xml b/packages/SystemUI/res/drawable/media_output_status_check.xml
index 1b750f8..5fbc42b 100644
--- a/packages/SystemUI/res/drawable/media_output_status_check.xml
+++ b/packages/SystemUI/res/drawable/media_output_status_check.xml
@@ -21,6 +21,6 @@
         android:viewportHeight="24"
         android:tint="?attr/colorControlNormal">
     <path
-        android:fillColor="@color/media_dialog_item_status"
+        android:fillColor="@color/media_dialog_item_main_content"
         android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/media_output_status_failed.xml b/packages/SystemUI/res/drawable/media_output_status_failed.xml
index 05c6358..0599e23 100644
--- a/packages/SystemUI/res/drawable/media_output_status_failed.xml
+++ b/packages/SystemUI/res/drawable/media_output_status_failed.xml
@@ -21,6 +21,6 @@
         android:viewportHeight="24"
         android:tint="?attr/colorControlNormal">
     <path
-        android:fillColor="@color/media_dialog_inactive_item_main_content"
+        android:fillColor="@color/media_dialog_item_main_content"
         android:pathData="M11,7h2v2h-2zM11,11h2v6h-2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/media_ttt_undo_background.xml b/packages/SystemUI/res/drawable/media_ttt_undo_background.xml
index ec74ee1..3e2e4f0 100644
--- a/packages/SystemUI/res/drawable/media_ttt_undo_background.xml
+++ b/packages/SystemUI/res/drawable/media_ttt_undo_background.xml
@@ -14,9 +14,14 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
 -->
-<shape
+<ripple
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-    <solid android:color="?androidprv:attr/colorAccentPrimary" />
-    <corners android:radius="24dp" />
-</shape>
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:color="?android:textColorPrimary">
+    <item android:id="@android:id/background">
+        <shape>
+            <solid android:color="?androidprv:attr/colorAccentPrimary"/>
+            <corners android:radius="24dp" />
+        </shape>
+    </item>
+</ripple>
diff --git a/packages/SystemUI/res/drawable/new_fgs_dot.xml b/packages/SystemUI/res/drawable/new_fgs_dot.xml
index 759ddaf..3669e1d 100644
--- a/packages/SystemUI/res/drawable/new_fgs_dot.xml
+++ b/packages/SystemUI/res/drawable/new_fgs_dot.xml
@@ -15,8 +15,9 @@
 ** limitations under the License.
 -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:shape="oval"
     android:width="12dp"
     android:height="12dp">
-    <solid android:color="@*android:color/red" />
+    <solid android:color="?androidprv:attr/colorAccentTertiary" />
 </shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_media_button_background.xml b/packages/SystemUI/res/drawable/qs_media_outline_button.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/qs_media_button_background.xml
rename to packages/SystemUI/res/drawable/qs_media_outline_button.xml
diff --git a/packages/SystemUI/res/drawable/qs_media_solid_button.xml b/packages/SystemUI/res/drawable/qs_media_solid_button.xml
new file mode 100644
index 0000000..baa4aae
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_media_solid_button.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+        android:shape="rectangle">
+        <solid android:color="?androidprv:attr/colorAccentPrimaryVariant" />
+        <corners android:radius="24dp"/>
+        <padding
+            android:left="16dp"
+            android:right="16dp"
+            android:top="8dp"
+            android:bottom="8dp" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/user_switcher_icon_large.xml b/packages/SystemUI/res/drawable/user_switcher_icon_large.xml
index 1ed7553..d81b518 100644
--- a/packages/SystemUI/res/drawable/user_switcher_icon_large.xml
+++ b/packages/SystemUI/res/drawable/user_switcher_icon_large.xml
@@ -27,7 +27,7 @@
     </shape>
   </item>
   <!-- When an item is selected, this layer will show a ring around the icon -->
-  <item>
+  <item android:id="@+id/ring">
     <shape android:shape="oval">
        <stroke
            android:width="@dimen/user_switcher_icon_selected_width"
@@ -35,7 +35,7 @@
     </shape>
   </item>
   <!-- Where the user drawable/bitmap will be placed -->
-  <item
+  <item android:id="@+id/user_avatar"
       android:drawable="@drawable/user_avatar_bg"
       android:width="@dimen/bouncer_user_switcher_icon_size"
       android:height="@dimen/bouncer_user_switcher_icon_size"
diff --git a/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml b/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml
index 8f6753a..0d32f73 100644
--- a/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml
+++ b/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml
@@ -36,6 +36,7 @@
         android:tooltipText="@*android:string/share"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintTop_toTopOf="@+id/copy_button"
+        android:tint="?android:attr/textColorPrimary"
         android:src="@drawable/ic_screenshot_share" />
 
     <ScrollView
@@ -43,10 +44,10 @@
         android:layout_height="0dp"
         android:layout_marginTop="8dp"
         app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintLeft_toLeftOf="parent"
         app:layout_constraintRight_toRightOf="parent"
         app:layout_constraintStart_toStartOf="@+id/copy_button"
+        app:layout_constraintEnd_toEndOf="@id/share"
         app:layout_constraintTop_toBottomOf="@+id/attribution">
 
         <EditText
diff --git a/packages/SystemUI/res/layout/clipboard_overlay.xml b/packages/SystemUI/res/layout/clipboard_overlay.xml
index 4f0b773..c0436b2 100644
--- a/packages/SystemUI/res/layout/clipboard_overlay.xml
+++ b/packages/SystemUI/res/layout/clipboard_overlay.xml
@@ -16,6 +16,7 @@
   -->
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:theme="@style/FloatingOverlay"
     android:alpha="0"
@@ -118,7 +119,8 @@
                       android:autoSizeTextType="uniform"
                       android:autoSizeMinTextSize="10sp"
                       android:autoSizeMaxTextSize="200sp"
-                      android:textColor="?android:attr/textColorPrimary"
+                      android:textColor="?attr/overlayButtonTextColor"
+                      android:background="?androidprv:attr/colorAccentSecondary"
                       android:layout_width="@dimen/clipboard_preview_size"
                       android:layout_height="@dimen/clipboard_preview_size"/>
             <ImageView
diff --git a/packages/SystemUI/res/layout/combined_qs_header.xml b/packages/SystemUI/res/layout/combined_qs_header.xml
index 405863d..ec82ccf 100644
--- a/packages/SystemUI/res/layout/combined_qs_header.xml
+++ b/packages/SystemUI/res/layout/combined_qs_header.xml
@@ -20,7 +20,7 @@
     android:id="@+id/split_shade_status_bar"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:minHeight="@dimen/split_shade_header_min_height"
+    android:minHeight="@dimen/large_screen_shade_header_min_height"
     android:clickable="false"
     android:focusable="true"
     android:paddingLeft="@dimen/qs_panel_padding"
@@ -61,8 +61,8 @@
     <include
         android:id="@+id/carrier_group"
         layout="@layout/qs_carrier_group"
-        app:layout_constraintHeight_min="@dimen/split_shade_header_min_height"
-        android:minHeight="@dimen/split_shade_header_min_height"
+        app:layout_constraintHeight_min="@dimen/large_screen_shade_header_min_height"
+        android:minHeight="@dimen/large_screen_shade_header_min_height"
         app:layout_constraintWidth_min="48dp"
         android:layout_width="0dp"
         android:layout_height="0dp"
@@ -78,7 +78,7 @@
 
     <com.android.systemui.statusbar.phone.StatusIconContainer
         android:id="@+id/statusIcons"
-        app:layout_constraintHeight_min="@dimen/split_shade_header_min_height"
+        app:layout_constraintHeight_min="@dimen/large_screen_shade_header_min_height"
         android:paddingEnd="@dimen/signal_cluster_battery_padding"
         android:layout_width="wrap_content"
         android:layout_height="48dp"
@@ -93,7 +93,7 @@
         android:id="@+id/batteryRemainingIcon"
         android:layout_width="wrap_content"
         android:layout_height="48dp"
-        app:layout_constraintHeight_min="@dimen/split_shade_header_min_height"
+        app:layout_constraintHeight_min="@dimen/large_screen_shade_header_min_height"
         app:textAppearance="@style/TextAppearance.QS.Status"
         app:layout_constraintStart_toEndOf="@id/statusIcons"
         app:layout_constraintEnd_toEndOf="parent"
diff --git a/packages/SystemUI/res/layout/dream_overlay_complication_clock_date.xml b/packages/SystemUI/res/layout/dream_overlay_complication_clock_date.xml
index 91d81a2..cb63300 100644
--- a/packages/SystemUI/res/layout/dream_overlay_complication_clock_date.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_complication_clock_date.xml
@@ -19,6 +19,7 @@
     android:id="@+id/date_view"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
+    android:paddingHorizontal="@dimen/dream_overlay_complication_shadow_padding"
     android:gravity="center_horizontal"
     android:textColor="@android:color/white"
     android:shadowColor="@color/keyguard_shadow_color"
diff --git a/packages/SystemUI/res/layout/dream_overlay_complication_weather.xml b/packages/SystemUI/res/layout/dream_overlay_complication_weather.xml
index 3900ea5..76fe58c 100644
--- a/packages/SystemUI/res/layout/dream_overlay_complication_weather.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_complication_weather.xml
@@ -19,6 +19,7 @@
     android:id="@+id/weather_view"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
+    android:paddingHorizontal="@dimen/dream_overlay_complication_shadow_padding"
     android:textColor="@android:color/white"
     android:shadowColor="@color/keyguard_shadow_color"
     android:shadowRadius="?attr/shadowRadius"
diff --git a/packages/SystemUI/res/layout/split_shade_header.xml b/packages/SystemUI/res/layout/large_screen_shade_header.xml
similarity index 93%
rename from packages/SystemUI/res/layout/split_shade_header.xml
rename to packages/SystemUI/res/layout/large_screen_shade_header.xml
index b6e96ce..250eabd 100644
--- a/packages/SystemUI/res/layout/split_shade_header.xml
+++ b/packages/SystemUI/res/layout/large_screen_shade_header.xml
@@ -18,8 +18,8 @@
     xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:id="@+id/split_shade_status_bar"
     android:layout_width="match_parent"
-    android:layout_height="@dimen/split_shade_header_height"
-    android:minHeight="@dimen/split_shade_header_min_height"
+    android:layout_height="@dimen/large_screen_shade_header_height"
+    android:minHeight="@dimen/large_screen_shade_header_min_height"
     android:clickable="false"
     android:focusable="true"
     android:paddingLeft="@dimen/qs_panel_padding"
@@ -32,7 +32,7 @@
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:minWidth="48dp"
-        android:minHeight="@dimen/split_shade_header_min_height"
+        android:minHeight="@dimen/large_screen_shade_header_min_height"
         android:gravity="start|center_vertical"
         android:paddingStart="@dimen/status_bar_left_clock_starting_padding"
         android:paddingEnd="@dimen/status_bar_left_clock_end_padding"
@@ -69,7 +69,7 @@
                 android:layout_gravity="end|center_vertical"
                 android:layout_marginStart="8dp"
                 android:focusable="false"
-                android:minHeight="@dimen/split_shade_header_min_height"
+                android:minHeight="@dimen/large_screen_shade_header_min_height"
                 android:minWidth="48dp" />
 
             <com.android.systemui.statusbar.phone.StatusIconContainer
diff --git a/packages/SystemUI/res/layout/media_output_list_item.xml b/packages/SystemUI/res/layout/media_output_list_item.xml
index 806804f..d39b0d5 100644
--- a/packages/SystemUI/res/layout/media_output_list_item.xml
+++ b/packages/SystemUI/res/layout/media_output_list_item.xml
@@ -33,7 +33,7 @@
             android:layout_height="match_parent"
             android:background="@drawable/media_output_item_background"
             android:layout_gravity="center_vertical|start">
-            <SeekBar
+            <com.android.systemui.media.dialog.MediaOutputSeekbar
                 android:id="@+id/volume_seekbar"
                 android:splitTrack="false"
                 android:visibility="gone"
@@ -62,41 +62,40 @@
             android:layout_height="wrap_content"
             android:layout_gravity="center_vertical|start"
             android:layout_marginStart="56dp"
+            android:layout_marginEnd="56dp"
             android:ellipsize="end"
             android:maxLines="1"
             android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
             android:textSize="16sp"/>
 
-        <RelativeLayout
+        <LinearLayout
             android:id="@+id/two_line_layout"
+            android:orientation="vertical"
             android:layout_width="wrap_content"
             android:layout_gravity="center_vertical|start"
             android:layout_height="48dp"
+            android:layout_marginEnd="56dp"
             android:layout_marginStart="56dp">
             <TextView
                 android:id="@+id/two_line_title"
-                android:gravity="center_vertical"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:ellipsize="end"
                 android:maxLines="1"
                 android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
-                android:textColor="@color/media_dialog_inactive_item_main_content"
+                android:textColor="@color/media_dialog_item_main_content"
                 android:textSize="16sp"/>
             <TextView
                 android:id="@+id/subtitle"
-                android:layout_gravity="center_vertical"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:layout_marginTop="4dp"
-                android:layout_alignParentBottom="true"
                 android:ellipsize="end"
                 android:maxLines="1"
-                android:textColor="@color/media_dialog_inactive_item_main_content"
+                android:textColor="@color/media_dialog_item_main_content"
                 android:textSize="14sp"
                 android:fontFamily="@*android:string/config_bodyFontFamily"
                 android:visibility="gone"/>
-        </RelativeLayout>
+        </LinearLayout>
 
         <ProgressBar
             android:id="@+id/volume_indeterminate_progress"
@@ -128,6 +127,7 @@
             android:layout_gravity="right|center"
             android:button="@drawable/ic_circle_check_box"
             android:visibility="gone"
+            android:clickable="false"
         />
     </FrameLayout>
 </LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/media_session_view.xml b/packages/SystemUI/res/layout/media_session_view.xml
index f030f31..e1f3eca 100644
--- a/packages/SystemUI/res/layout/media_session_view.xml
+++ b/packages/SystemUI/res/layout/media_session_view.xml
@@ -145,8 +145,7 @@
         android:layout_width="48dp"
         android:layout_height="48dp"
         android:layout_marginStart="@dimen/qs_media_padding"
-        android:layout_marginEnd="@dimen/qs_media_padding"
-         />
+        android:layout_marginEnd="@dimen/qs_media_padding" />
 
     <!-- See comment in media_session_collapsed.xml for how these barriers are used -->
     <androidx.constraintlayout.widget.Barrier
@@ -172,10 +171,19 @@
         app:layout_constraintStart_toStartOf="parent"
         />
 
+    <androidx.constraintlayout.widget.Barrier
+        android:id="@+id/media_action_barrier_top"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:barrierDirection="top"
+        app:constraint_referenced_ids="actionPrev,media_progress_bar,actionNext,action0,action1,action2,action3,action4"
+        />
+
     <!-- Button visibility will be controlled in code -->
     <ImageButton
         android:id="@+id/actionPrev"
-        style="@style/MediaPlayer.SessionAction"
+        style="@style/MediaPlayer.SessionAction.Secondary"
         android:layout_width="48dp"
         android:layout_height="48dp"
         android:layout_marginStart="4dp"
@@ -202,7 +210,7 @@
 
     <ImageButton
         android:id="@+id/actionNext"
-        style="@style/MediaPlayer.SessionAction"
+        style="@style/MediaPlayer.SessionAction.Secondary"
         android:layout_width="48dp"
         android:layout_height="48dp"
         android:layout_marginStart="0dp"
@@ -212,7 +220,7 @@
 
     <ImageButton
         android:id="@+id/action0"
-        style="@style/MediaPlayer.SessionAction"
+        style="@style/MediaPlayer.SessionAction.Secondary"
         android:layout_width="48dp"
         android:layout_height="48dp"
         android:layout_marginStart="@dimen/qs_media_action_spacing"
@@ -222,7 +230,7 @@
 
     <ImageButton
         android:id="@+id/action1"
-        style="@style/MediaPlayer.SessionAction"
+        style="@style/MediaPlayer.SessionAction.Secondary"
         android:layout_width="48dp"
         android:layout_height="48dp"
         android:layout_marginStart="@dimen/qs_media_action_spacing"
@@ -232,7 +240,7 @@
 
     <ImageButton
         android:id="@+id/action2"
-        style="@style/MediaPlayer.SessionAction"
+        style="@style/MediaPlayer.SessionAction.Secondary"
         android:layout_width="48dp"
         android:layout_height="48dp"
         android:layout_marginStart="@dimen/qs_media_action_spacing"
@@ -242,7 +250,7 @@
 
     <ImageButton
         android:id="@+id/action3"
-        style="@style/MediaPlayer.SessionAction"
+        style="@style/MediaPlayer.SessionAction.Secondary"
         android:layout_width="48dp"
         android:layout_height="48dp"
         android:layout_marginStart="@dimen/qs_media_action_spacing"
@@ -252,7 +260,7 @@
 
     <ImageButton
         android:id="@+id/action4"
-        style="@style/MediaPlayer.SessionAction"
+        style="@style/MediaPlayer.SessionAction.Secondary"
         android:layout_width="48dp"
         android:layout_height="48dp"
         android:layout_marginStart="@dimen/qs_media_action_spacing"
@@ -264,7 +272,7 @@
     <TextView
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginTop="@dimen/qs_media_padding"
+        android:layout_marginTop="0dp"
         android:layout_marginStart="@dimen/qs_media_padding"
         android:layout_marginEnd="@dimen/qs_media_padding"
         android:id="@+id/remove_text"
@@ -274,64 +282,56 @@
         android:marqueeRepeatLimit="marquee_forever"
         android:text="@string/controls_media_close_session"
         android:gravity="center_horizontal|top"
-        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/settings"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintBottom_toTopOf="@id/cancel" />
 
-    <FrameLayout
+    <ImageButton
         android:id="@+id/settings"
-        android:background="@drawable/qs_media_light_source"
+        android:src="@drawable/ic_settings"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
+        android:layout_marginTop="4dp"
+        android:layout_marginEnd="4dp"
+        android:background="@drawable/qs_media_light_source"
+        android:contentDescription="@string/controls_media_settings_button"
+        android:layout_gravity="top"
+        app:layout_constraintWidth_min="@dimen/min_clickable_item_size"
+        app:layout_constraintHeight_min="@dimen/min_clickable_item_size"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent">
+    </ImageButton>
+
+    <FrameLayout
+        android:id="@+id/dismiss"
+        android:background="@drawable/qs_media_light_source"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
         android:layout_marginStart="@dimen/qs_media_padding"
         android:layout_marginEnd="@dimen/qs_media_action_spacing"
         android:layout_marginBottom="@dimen/qs_media_padding"
         app:layout_constrainedWidth="true"
         app:layout_constraintWidth_min="@dimen/min_clickable_item_size"
         app:layout_constraintHeight_min="@dimen/min_clickable_item_size"
-        app:layout_constraintHorizontal_chainStyle="spread_inside"
+        app:layout_constraintHorizontal_chainStyle="packed"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintEnd_toStartOf="@id/cancel"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintTop_toBottomOf="@id/remove_text">
         <TextView
-            android:id="@+id/settings_text"
+            android:id="@+id/dismiss_text"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_gravity="center|bottom"
-            style="@style/MediaPlayer.OutlineButton"
-            android:text="@string/controls_media_settings_button" />
+            android:layout_gravity="center|top"
+            style="@style/MediaPlayer.SolidButton"
+            android:background="@drawable/qs_media_solid_button"
+            android:text="@string/controls_media_dismiss_button" />
     </FrameLayout>
-
     <FrameLayout
         android:id="@+id/cancel"
         android:background="@drawable/qs_media_light_source"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="@dimen/qs_media_action_spacing"
-        android:layout_marginEnd="@dimen/qs_media_action_spacing"
-        android:layout_marginBottom="@dimen/qs_media_padding"
-        app:layout_constrainedWidth="true"
-        app:layout_constraintWidth_min="@dimen/min_clickable_item_size"
-        app:layout_constraintHeight_min="@dimen/min_clickable_item_size"
-        app:layout_constraintStart_toEndOf="@id/settings"
-        app:layout_constraintEnd_toStartOf="@id/dismiss"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/remove_text">
-        <TextView
-            android:id="@+id/cancel_text"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center|bottom"
-            style="@style/MediaPlayer.OutlineButton"
-            android:text="@string/cancel" />
-    </FrameLayout>
-
-    <FrameLayout
-        android:id="@+id/dismiss"
-        android:background="@drawable/qs_media_light_source"
-        android:layout_width="0dp"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginStart="@dimen/qs_media_action_spacing"
         android:layout_marginEnd="@dimen/qs_media_padding"
@@ -339,16 +339,16 @@
         app:layout_constrainedWidth="true"
         app:layout_constraintWidth_min="@dimen/min_clickable_item_size"
         app:layout_constraintHeight_min="@dimen/min_clickable_item_size"
-        app:layout_constraintStart_toEndOf="@id/cancel"
+        app:layout_constraintStart_toEndOf="@id/dismiss"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintTop_toBottomOf="@id/remove_text">
         <TextView
-            android:id="@+id/dismiss_text"
+            android:id="@+id/cancel_text"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_gravity="center|bottom"
+            android:layout_gravity="center|top"
             style="@style/MediaPlayer.OutlineButton"
-            android:text="@string/controls_media_dismiss_button" />
+            android:text="@string/cancel" />
     </FrameLayout>
 </com.android.systemui.util.animation.TransitionLayout>
diff --git a/packages/SystemUI/res/layout/media_view.xml b/packages/SystemUI/res/layout/media_view.xml
deleted file mode 100644
index 9471b9f..0000000
--- a/packages/SystemUI/res/layout/media_view.xml
+++ /dev/null
@@ -1,300 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2019 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-
-<!-- Layout for media controls inside QSPanel carousel -->
-<com.android.systemui.util.animation.TransitionLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/qs_media_controls"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:clipChildren="false"
-    android:clipToPadding="false"
-    android:gravity="center_horizontal|fill_vertical"
-    android:forceHasOverlappingRendering="false"
-    android:background="@drawable/qs_media_background"
-    android:theme="@style/MediaPlayer">
-
-    <androidx.constraintlayout.widget.Guideline
-        android:id="@+id/center_vertical_guideline"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        app:layout_constraintGuide_percent="0.6" />
-
-    <androidx.constraintlayout.widget.Guideline
-        android:id="@+id/center_horizontal_guideline"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal"
-        app:layout_constraintGuide_begin="48dp" />
-
-    <!-- As per Material Design on Biderectionality, this is forced to LTR in code -->
-    <FrameLayout
-        android:id="@+id/notification_media_progress_time"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:forceHasOverlappingRendering="false">
-        <!-- width is set to "match_parent" to avoid extra layout calls -->
-        <TextView
-            android:id="@+id/media_elapsed_time"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_alignParentStart="true"
-            android:fontFamily="@*android:string/config_bodyFontFamily"
-            android:gravity="start"
-            android:textSize="12sp" />
-
-        <TextView
-            android:id="@+id/media_total_time"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_alignParentEnd="true"
-            android:fontFamily="@*android:string/config_bodyFontFamily"
-            android:gravity="end"
-            android:textSize="12sp" />
-    </FrameLayout>
-
-    <!--  Actions must be ordered left-to-right even in RTL layout.  However, they appear in a chain
-    with the artist name, and must as a group appear at the end of that chain.  This is
-    accomplished by having all actions appear in a LTR chain within the parent, and then biasing it
-    to the right side, then this barrier is used to bound the text views.  -->
-    <androidx.constraintlayout.widget.Barrier
-        android:id="@+id/media_action_barrier"
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:orientation="vertical"
-        app:layout_constraintTop_toBottomOf="@id/header_title"
-        app:barrierDirection="start"
-        app:constraint_referenced_ids="action0,action1,action2,action3,action4"
-         />
-
-    <ImageButton
-        android:id="@+id/action0"
-        style="@style/MediaPlayer.Action"
-        android:layout_width="48dp"
-        android:layout_height="48dp" />
-
-    <ImageButton
-        android:id="@+id/action1"
-        style="@style/MediaPlayer.Action"
-        android:layout_width="48dp"
-        android:layout_height="48dp" />
-
-    <ImageButton
-        android:id="@+id/action2"
-        style="@style/MediaPlayer.Action"
-        android:layout_width="48dp"
-        android:layout_height="48dp" />
-
-    <ImageButton
-        android:id="@+id/action3"
-        style="@style/MediaPlayer.Action"
-        android:layout_width="48dp"
-        android:layout_height="48dp" />
-
-    <ImageButton
-        android:id="@+id/action4"
-        style="@style/MediaPlayer.Action"
-        android:layout_width="48dp"
-        android:layout_height="48dp" />
-
-    <!-- Album Art -->
-    <ImageView
-        android:id="@+id/album_art"
-        android:layout_width="@dimen/qs_media_album_size"
-        android:layout_height="@dimen/qs_media_album_size"
-        android:layout_gravity="center_vertical"
-        style="@style/MediaPlayer.Album"
-        android:background="@drawable/qs_media_art_background"
-        android:clipToOutline="true" />
-
-    <!-- Seamless Output Switcher -->
-    <LinearLayout
-        android:id="@+id/media_seamless"
-        android:layout_width="0dp"
-        android:layout_height="48dp"
-        android:orientation="horizontal"
-        android:gravity="top|end"
-        android:paddingTop="@dimen/qs_media_padding"
-        android:paddingEnd="@dimen/qs_media_padding"
-        android:background="@drawable/qs_media_light_source"
-        android:forceHasOverlappingRendering="false">
-        <LinearLayout
-            android:id="@+id/media_seamless_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:minHeight="@dimen/qs_seamless_height"
-            android:theme="@style/MediaPlayer.SolidButton"
-            android:background="@drawable/qs_media_seamless_background"
-            android:orientation="horizontal"
-            android:contentDescription="@string/quick_settings_media_device_label">
-            <ImageView
-                android:id="@+id/media_seamless_image"
-                android:layout_width="@dimen/qs_seamless_icon_size"
-                android:layout_height="@dimen/qs_seamless_icon_size"
-                android:layout_gravity="center"
-                android:tint="?android:attr/textColorPrimary"
-                android:src="@*android:drawable/ic_media_seamless" />
-            <TextView
-                android:id="@+id/media_seamless_text"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center_vertical"
-                android:layout_marginStart="4dp"
-                android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
-                android:singleLine="true"
-                android:text="@*android:string/ext_media_seamless_action"
-                android:textDirection="locale"
-                android:textSize="12sp"
-                android:lineHeight="16sp" />
-        </LinearLayout>
-    </LinearLayout>
-
-    <!-- Seek Bar -->
-    <!-- As per Material Design on Biderectionality, this is forced to LTR in code -->
-    <SeekBar
-        android:id="@+id/media_progress_bar"
-        style="@style/MediaPlayer.ProgressBar"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:maxHeight="@dimen/qs_media_enabled_seekbar_height"
-        android:paddingTop="@dimen/qs_media_enabled_seekbar_vertical_padding"
-        android:layout_marginTop="-22dp"
-        android:paddingBottom="2dp"
-        android:splitTrack="false" />
-
-    <!-- Song name -->
-    <TextView
-        android:id="@+id/header_title"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
-        android:singleLine="true"
-        android:textSize="16sp" />
-
-    <!-- Artist name -->
-    <TextView
-        android:id="@+id/header_artist"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:fontFamily="@*android:string/config_headlineFontFamily"
-        android:singleLine="true"
-        style="@style/MediaPlayer.Subtitle"
-        android:textSize="14sp" />
-
-    <com.android.internal.widget.CachingIconView
-        android:id="@+id/icon"
-        style="@style/MediaPlayer.AppIcon"
-        android:layout_width="@dimen/qs_media_icon_size"
-        android:layout_height="@dimen/qs_media_icon_size" />
-
-    <!-- Long press menu -->
-    <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="@dimen/qs_media_padding"
-        android:layout_marginStart="@dimen/qs_media_padding"
-        android:layout_marginEnd="@dimen/qs_media_padding"
-        android:id="@+id/remove_text"
-        android:fontFamily="@*android:string/config_headlineFontFamily"
-        android:singleLine="true"
-        android:ellipsize="marquee"
-        android:marqueeRepeatLimit="marquee_forever"
-        android:text="@string/controls_media_close_session"
-        android:gravity="center_horizontal|top"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintBottom_toTopOf="@id/cancel"/>
-
-    <FrameLayout
-        android:id="@+id/settings"
-        android:background="@drawable/qs_media_light_source"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="@dimen/qs_media_padding"
-        android:layout_marginEnd="@dimen/qs_media_action_spacing"
-        android:layout_marginBottom="@dimen/qs_media_padding"
-        app:layout_constrainedWidth="true"
-        app:layout_constraintWidth_min="48dp"
-        app:layout_constraintHeight_min="48dp"
-        app:layout_constraintHorizontal_chainStyle="spread_inside"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toStartOf="@id/cancel"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/remove_text">
-
-        <TextView
-            android:id="@+id/settings_text"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center|bottom"
-            style="@style/MediaPlayer.OutlineButton"
-            android:text="@string/controls_media_settings_button" />
-    </FrameLayout>
-
-    <FrameLayout
-        android:id="@+id/cancel"
-        android:background="@drawable/qs_media_light_source"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="@dimen/qs_media_action_spacing"
-        android:layout_marginEnd="@dimen/qs_media_action_spacing"
-        android:layout_marginBottom="@dimen/qs_media_padding"
-        app:layout_constrainedWidth="true"
-        app:layout_constraintWidth_min="48dp"
-        app:layout_constraintHeight_min="48dp"
-        app:layout_constraintStart_toEndOf="@id/settings"
-        app:layout_constraintEnd_toStartOf="@id/dismiss"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/remove_text">
-
-        <TextView
-            android:id="@+id/cancel_text"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center|bottom"
-            style="@style/MediaPlayer.OutlineButton"
-            android:text="@string/cancel" />
-    </FrameLayout>
-
-    <FrameLayout
-        android:id="@+id/dismiss"
-        android:background="@drawable/qs_media_light_source"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="@dimen/qs_media_action_spacing"
-        android:layout_marginEnd="@dimen/qs_media_padding"
-        android:layout_marginBottom="@dimen/qs_media_padding"
-        app:layout_constrainedWidth="true"
-        app:layout_constraintWidth_min="48dp"
-        app:layout_constraintHeight_min="48dp"
-        app:layout_constraintStart_toEndOf="@id/cancel"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/remove_text">
-
-        <TextView
-            android:id="@+id/dismiss_text"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center|bottom"
-            style="@style/MediaPlayer.OutlineButton"
-            android:text="@string/controls_media_dismiss_button"
-        />
-    </FrameLayout>
-</com.android.systemui.util.animation.TransitionLayout>
diff --git a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
index 8122776..5aa6080 100644
--- a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
@@ -22,7 +22,10 @@
     android:layout_height="match_parent"
     android:layout_width="wrap_content"
     android:layout_gravity="center_vertical|end"
-    android:focusable="true" >
+    android:focusable="true"
+    android:clipChildren="false"
+    android:clipToPadding="false"
+    >
 
         <LinearLayout
             android:id="@+id/icons_container"
diff --git a/packages/SystemUI/res/layout/system_event_animation_window.xml b/packages/SystemUI/res/layout/system_event_animation_window.xml
index c92dec9..e6868b3 100644
--- a/packages/SystemUI/res/layout/system_event_animation_window.xml
+++ b/packages/SystemUI/res/layout/system_event_animation_window.xml
@@ -19,17 +19,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:layout_gravity="center_vertical|end"
-    android:paddingTop="@dimen/status_bar_padding_top"
-    android:paddingEnd="8dp"
+    android:clipChildren="false"
+    android:clipToPadding="false"
     >
-
-    <ImageView
-        android:id="@+id/dot_view"
-        android:layout_width="10dp"
-        android:layout_height="10dp"
-        android:layout_gravity="center_vertical|end"
-        android:src="@drawable/system_animation_ongoing_dot"
-        android:visibility="invisible"
-        />
-
 </FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index c0fdf68..32eb3ad 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Stelsel-UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Skakel Batterybespaarder aan?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Jy het <xliff:g id="PERCENTAGE">%s</xliff:g> batterykrag oor. Batterybespaarder skakel Donkertema aan, beperk agtergrondaktiwiteit en vertraag kennisgewings."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Batterybespaarder skakel Donkertema aan, beperk agtergrondaktiwiteit en vertraag kennisgewings."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> oor"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Kan nie deur USB laai nie"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Gebruik die laaier wat jy saam met jou toestel gekry het"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Skakel Batterybespaarder aan?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Meer oor Batterybespaarder"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Skakel aan"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Skakel Batterybespaarder aan"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Skakel aan"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Nee, dankie"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Outodraai skerm"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Gee <xliff:g id="APPLICATION">%1$s</xliff:g> toegang tot <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Laat <xliff:g id="APPLICATION">%1$s</xliff:g> toe om by <xliff:g id="USB_DEVICE">%2$s</xliff:g> in te gaan?\nOpneemtoestemming is nie aan hierdie program verleen nie, maar dit kan oudio deur hierdie USB-toestel vasvang."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Gesig is gestaaf"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bevestig"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tik op Bevestig om te voltooi"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Ontsluit met jou gesig. Druk om voort te gaan."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Gestaaf"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Gebruik PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Gebruik patroon"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"As jy met jou volgende poging \'n verkeerde patroon invoer, sal jou werkprofiel en die data daarvan uitgevee word."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"As jy met jou volgende poging \'n verkeerde PIN invoer, sal jou werkprofiel en die data daarvan uitgevee word."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"As jy met jou volgende poging \'n verkeerde wagwoord invoer, sal jou werkprofiel en die data daarvan uitgevee word."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Te veel verkeerde pogings. Hierdie toestel se data sal uitgevee word."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Te veel verkeerde pogings. Hierdie gebruiker sal uitgevee word."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Te veel verkeerde pogings. Hierdie werkprofiel en sy data sal uitgevee word."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Maak toe"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Raak die vingerafdruksensor"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Vingerafdrukikoon"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Kan nie gesig herken nie. Gebruik eerder vingerafdruk."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laai tans stadig • Vol oor <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laaidok • Vol oor <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Wissel gebruiker"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Voeg gebruiker by"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Nuwe gebruiker"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Verwyder gas?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle programme en data in hierdie sessie sal uitgevee word."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Verwyder"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welkom terug, gas!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Wiil jy jou sessie voortsit?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Begin van voor af"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ja, gaan voort"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Voeg nuwe gebruiker by?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Wanneer jy \'n nuwe gebruiker byvoeg, moet daardie persoon hul spasie opstel.\n\nEnige gebruiker kan programme vir al die ander gebruikers opdateer."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Gebruikerlimiet is bereik"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">Jy kan tot <xliff:g id="COUNT">%d</xliff:g> gebruikers byvoeg.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ontsluit om te gebruik"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Kon nie jou kaarte kry nie; probeer later weer"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Sluitskerminstellings"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-kode"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Tik om te skandeer"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skandeer QR-kode"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Werkprofiel"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Vliegtuigmodus"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Jy sal nie jou volgende wekker <xliff:g id="WHEN">%1$s</xliff:g> hoor nie"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swiep om meer te sien"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Laai tans aanbevelings"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Media"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Versteek hierdie mediasessie?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Die huidige mediasessie kan nie versteek word nie."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Maak toe"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Versteek"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Hervat"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Instellings"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> deur <xliff:g id="ARTIST_NAME">%2$s</xliff:g> speel tans vanaf <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Beweeg nader aan <xliff:g id="DEVICENAME">%1$s</xliff:g> om hier te speel"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Speel tans op <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Speel tans op hierdie foon"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Iets is fout"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Onaktief, gaan program na"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nie gekry nie"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrole is nie beskikbaar nie"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Bind nuwe toestel saam"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Maak die program oop om hierdie sessie uit te saai."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Onbekende program"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Hou op uitsaai"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Bounommer"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Bounommer is na knipbord gekopieer."</string>
     <string name="basic_status" msgid="2315371112182658176">"Maak gesprek oop"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑fi onbeskikbaar"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioriteitmodus"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Wekker gestel"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Assistent-gasmodus is geaktiveer"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera en mikrofoon is af"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# kennisgewing}other{# kennisgewings}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 43ad005..28f35d3 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"የስርዓት UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"ባትሪ ቆጣቢ ይብራ?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"<xliff:g id="PERCENTAGE">%s</xliff:g> ቀሪ ባትሪ አለዎት። የባትሪ ኃይል ቆጣቢ ጠቆር ያለ ገጽታ ያበራል፣ የበስተጀርባ እንቅስቃሴን ይገድባል እና ማሳወቂያዎችን ያዘገያል።"</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"የባትሪ ኃይል ቆጣቢ ጠቆር ያለ ገጽታ ያበራል፣ የበስተጀርባ እንቅስቃሴን ይገድባል እና ማሳወቂያዎችን ያዘገያል።"</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> ይቀራል"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"በዩኤስቢ በኩል ኃይል መሙላት አይቻልም"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"ከእርስዎ መሣሪያ ጋር የመጣውን ኃይል መሙያ ይጠቀሙ"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"ባትሪ ቆጣቢ ይብራ?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"ስለ ባትሪ ቆጣቢ"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"አብራ"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"ባትሪ ቆጣቢን አብራ"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"አብራ"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"አይ፣ አመሰግናለሁ"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"ማያ በራስ ሰር አሽከርክር"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> <xliff:g id="USB_DEVICE">%2$s</xliff:g>ን እንዲደርስበት ይፈቀድለት?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> <xliff:g id="USB_DEVICE">%2$s</xliff:g>ን እንዲደርስ ይፈቀድለት?\nይህ መተግበሪያ የመቅዳት ፈቃድ አልተሰጠውም፣ ነገር ግን በዩኤስቢ መሣሪያ በኩል ኦዲዮን መቅዳት ይችላል።"</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"መልክ ተረጋግጧል"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ተረጋግጧል"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ለማጠናቀቅ አረጋግጥን መታ ያድርጉ"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"በፊትዎ የተከፈተ። ለመቀጠል ይጫኑ።"</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"የተረጋገጠ"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"ፒን ይጠቀሙ"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ሥርዓተ ጥለትን ተጠቀም"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"በሚቀጥለው ሙከራ ላይ ትክክል ያልሆነ ሥርዓተ ጥለት ካስገቡ የእርስዎ የሥራ መገለጫ እና ውሂቡ ይሰረዛሉ።"</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"በሚቀጥለው ሙከራ ላይ ትክክል ያልሆነ ፒን ካስገቡ የእርስዎ የሥራ መገለጫ እና ውሂቡ ይሰረዛሉ።"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"በሚቀጥለው ሙከራ ላይ ትክክል ያልሆነ የይለፍ ቃል ካስገቡ የእርስዎ የሥራ መገለጫ እና ውሂቡ ይሰረዛሉ።"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"በጣም ብዙ ትክክል ያልሆኑ ሙከራዎች። ይህ የመሣሪያ ውሂብ ይሰረዛል።"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"በጣም ብዙ ትክክል ያልሆኑ ሙከራዎች። ይህ ተጠቃሚ ይሰረዛል።"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"በጣም ብዙ ትክክል ያልሆኑ ሙከራዎች። የዚህ የሥራ መገለጫ እና ውሂቡ ይሰረዛሉ።"</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"አሰናብት"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"የጣት አሻራ ዳሳሹን ይንኩ"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"የጣት አሻራ አዶ"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"መልክን መለየት አልተቻለም። በምትኩ የጣት አሻራ ይጠቀሙ።"</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • በዝግታ ኃይልን በመሙላት ላይ • በ<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ውስጥ ይሞላል"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • የባትሪ ኃይል መሙያ መትከያ • በ<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ውስጥ ይሞላል"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ተጠቃሚ ቀይር"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"ተጠቃሚ አክል"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"አዲስ ተጠቃሚ"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"እንግዳ ይወገድ?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"በዚህ ክፍለ-ጊዜ ውስጥ ያሉ ሁሉም መተግበሪያዎች እና ውሂብ ይሰረዛሉ።"</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"አስወግድ"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"እንኳን በደህና ተመለሱ እንግዳ!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"ክፍለ-ጊዜዎን መቀጠል ይፈልጋሉ?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"እንደገና ጀምር"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"አዎ፣ ቀጥል"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"አዲስ ተጠቃሚ ይታከል?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"እርስዎ አንድ አዲስ ተጠቃሚ ሲያክሉ ያ ሰው የራሱ ቦታ ማዘጋጀት አለበት።\n\nማንኛውም ተጠቃሚ መተግበሪያዎችን ለሌሎች ተጠቃሚዎች ሁሉ ሊያዘምን ይችላል።"</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"የተጠቃሚ ገደብ ላይ ተደርሷል"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> ተጠቃሚዎች ብቻ ናቸው ሊፈጠሩ የሚችሉት።</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ለማየት ይክፈቱ"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"የእርስዎን ካርዶች ማግኘት ላይ ችግር ነበር፣ እባክዎ ቆይተው እንደገና ይሞክሩ"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"የገጽ መቆለፊያ ቅንብሮች"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR ኮድ"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"ለመቃኘት መታ ያድርጉ"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR ኮድ ቃኝ"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"የስራ መገለጫ"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"የአውሮፕላን ሁነታ"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"የእርስዎን ቀጣይ ማንቂያ <xliff:g id="WHEN">%1$s</xliff:g> አይሰሙም"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"ተጨማሪ ለማየት ያንሸራትቱ"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ምክሮችን በመጫን ላይ"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"ሚዲያ"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"ይህ የሚዲያ ክፍለ ጊዜ ይደበቅ?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"የአሁኑ የሚዲያ ክፍለ ጊዜ ሊደበቅ አይቻልም።"</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"አሰናብት"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ደብቅ"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"ከቆመበት ቀጥል"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"ቅንብሮች"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> በ<xliff:g id="ARTIST_NAME">%2$s</xliff:g> ከ<xliff:g id="APP_LABEL">%3$s</xliff:g> እየተጫወተ ነው"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"እዚህ ለመጫወት ወደ <xliff:g id="DEVICENAME">%1$s</xliff:g> ቀረብ ይበሉ"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"በ<xliff:g id="DEVICENAME">%1$s</xliff:g> ላይ በማጫወት ላይ"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"በዚህ ስልክ በመጫወት ላይ"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"የሆነ ችግር ተፈጥሯል"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"ንቁ ያልኾነ፣ መተግበሪያን ይፈትሹ"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"አልተገኘም"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"መቆጣጠሪያ አይገኝም"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"አዲስ መሣሪያ ያጣምሩ"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ይህን ክፍለ ጊዜ cast ለማድረግ፣ እባክዎ መተግበሪያውን ይክፈቱ።"</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"የማይታወቅ መተግበሪያ"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Cast ማድረግ አቁም"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"የግንብ ቁጥር"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"የገንባ ቁጥር ወደ ቅንጥብ ሰሌዳ ተቀድቷል።"</string>
     <string name="basic_status" msgid="2315371112182658176">"ውይይት ይክፈቱ"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi አይገኝም"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"የቅድሚያ ሁነታ"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ማንቂያ ተቀናብሯል"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"የረዳት እንግዳ ሁነታ ነቅቷል"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ካሜራ እና ማይክሮፎን ጠፍተዋል"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ማሳወቂያ}one{# ማሳወቂያዎች}other{# ማሳወቂያዎች}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 5ec5e9b..e41e049 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"واجهة مستخدم النظام"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"هل تريد تفعيل ميزة \"توفير شحن البطارية\"؟"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"يتبقى لديك <xliff:g id="PERCENTAGE">%s</xliff:g> من شحن البطارية. يؤدي استخدام ميزة \"توفير شحن البطارية\" إلى تفعيل وضع \"المظهر الداكن\" وتقييد الأنشطة في الخلفية وتأخير الإشعارات."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"يؤدي استخدام ميزة \"توفير شحن البطارية\" إلى تفعيل وضع \"المظهر الداكن\" وتقييد الأنشطة في الخلفية وتأخير الإشعارات."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"متبقي <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"‏يتعذّر الشحن باستخدام USB."</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"استخدم الشاحن المرفق بجهازك."</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"هل تريد تفعيل ميزة توفير شحن البطارية؟"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"لمحة عن ميزة \"توفير شحن البطارية\""</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"تفعيل"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"هل تريد تفعيل ميزة توفير شحن البطارية؟"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"تفعيل"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"لا، شكرًا"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"التدوير التلقائي للشاشة"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"هل تريد السماح لتطبيق <xliff:g id="APPLICATION">%1$s</xliff:g> بالدخول إلى <xliff:g id="USB_DEVICE">%2$s</xliff:g>؟"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"‏هل تريد السماح لتطبيق <xliff:g id="APPLICATION">%1$s</xliff:g> بالدخول إلى <xliff:g id="USB_DEVICE">%2$s</xliff:g>؟\nلم يتم منح هذا التطبيق إذن تسجيل، ولكن يمكنه تسجيل الصوت من خلال جهاز USB هذا."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"تمّت مصادقة الوجه."</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"تمّ التأكيد."</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"يمكنك النقر على \"تأكيد\" لإكمال المهمة."</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"تم فتح قفل الجهاز بالتعرف على وجهك. اضغط للمتابعة."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"مصادقة"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"استخدام رقم تعريف شخصي"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"استخدام نقش"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"عند إدخال نقش غير صحيح في المحاولة التالية، سيتم حذف ملفك الشخصي للعمل وبياناته."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"عند إدخال رقم تعريف شخصي غير صحيح في المحاولة التالية، سيتم حذف ملفك الشخصي للعمل وبياناته."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"عند إدخال كلمة مرور غير صحيحة في المحاولة التالية، سيتم حذف ملفك الشخصي للعمل وبياناته."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"لقد استنفدت عدد المحاولات غير الصحيحة وسيتم حذف بيانات هذا الجهاز."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"لقد استنفدت عدد المحاولات غير الصحيحة وسيتم حذف هذا المستخدم."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"لقد استنفدت عدد المحاولات غير الصحيحة وسيتم حذف الملف الشخصي للعمل وبياناته."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"إغلاق"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"المس مستشعر بصمة الإصبع"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"رمز بصمة الإصبع"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"يتعذّر التعرّف على الوجه. استخدِم بصمة الإصبع بدلاً من ذلك."</string>
@@ -334,17 +327,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • جارٍ الشحن ببطء • ستمتلئ البطارية خلال <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • جارٍ الشحن على وحدة الإرساء • ستمتلئ البطارية خلال <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"تبديل المستخدم"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"إضافة مستخدم"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"مستخدم جديد"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"هل تريد إزالة جلسة الضيف؟"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"سيتم حذف كل التطبيقات والبيانات في هذه الجلسة."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"إزالة"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"مرحبًا بك مجددًا في جلسة الضيف"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"هل تريد متابعة جلستك؟"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"البدء من جديد"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"نعم، متابعة"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"هل تريد إضافة مستخدم جديد؟"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"عند إضافة مستخدم جديد، عليه إعداد مساحته.\n\nويُمكن لأي مستخدم تحديث التطبيقات لجميع المستخدمين الآخرين."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"تم الوصول إلى أقصى عدد للمستخدمين"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="zero">يمكنك إضافة ما يصل إلى <xliff:g id="COUNT">%d</xliff:g> مستخدم.</item>
@@ -474,8 +462,8 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"فتح القفل للاستخدام"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"حدثت مشكلة أثناء الحصول على البطاقات، يُرجى إعادة المحاولة لاحقًا."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"إعدادات شاشة القفل"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"رمز الاستجابة السريعة"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"انقر للمسح ضوئيًا"</string>
+    <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"الملف الشخصي للعمل"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"وضع الطيران"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"لن تسمع المنبّه القادم في <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -812,9 +800,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"مرّر سريعًا لرؤية المزيد."</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"جارٍ تحميل الاقتراحات"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"الوسائط"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"هل تريد إخفاء جلسة الوسائط هذه؟"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"لا يمكن إخفاء جلسة الوسائط الحالية."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"إغلاق"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"إخفاء"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"استئناف التشغيل"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"الإعدادات"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"يتم تشغيل <xliff:g id="SONG_NAME">%1$s</xliff:g> للفنان <xliff:g id="ARTIST_NAME">%2$s</xliff:g> من تطبيق <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string>
@@ -832,7 +821,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"يُرجى الاقتراب من <xliff:g id="DEVICENAME">%1$s</xliff:g> لتشغيل الوسائط هنا."</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"جارٍ تشغيل الوسائط على <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"جارٍ تشغيل الوسائط على هذا الهاتف"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"حدث خطأ."</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"غير نشط، تحقّق من التطبيق."</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"لم يتم العثور عليه."</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"عنصر التحكّم غير متوفّر"</string>
@@ -851,6 +841,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"إقران جهاز جديد"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"لبث هذه الجلسة، يُرجى فتح التطبيق"</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"تطبيق غير معروف"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"إيقاف البث"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"رقم الإصدار"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"تم نسخ رقم الإصدار إلى الحافظة."</string>
     <string name="basic_status" msgid="2315371112182658176">"محادثة مفتوحة"</string>
@@ -928,7 +919,7 @@
       <item quantity="one">تطبيق واحد (<xliff:g id="COUNT_0">%s</xliff:g>) نشط</item>
     </plurals>
     <string name="fgs_dot_content_description" msgid="2865071539464777240">"معلومات جديدة"</string>
-    <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"# تطبيق نشط"</string>
+    <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"التطبيقات النشطة"</string>
     <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"إيقاف"</string>
     <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"متوقّف"</string>
     <string name="clipboard_edit_text_copy" msgid="770856373439969178">"نسخ"</string>
@@ -944,8 +935,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"‏شبكة Wi‑Fi غير متاحة"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"وضع الأولوية"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"تم ضبط المنبه."</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"‏تم تفعيل وضع الضيف لاستخدام \"مساعد Google\"."</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"الكاميرا والميكروفون غير مفعّلين."</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{إشعار واحد}zero{# إشعار}two{إشعاران}few{# إشعارات}many{# إشعارًا}other{# إشعار}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 00f7790..8101322 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"ছিষ্টেম ইউআই"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"বেটাৰী সঞ্চয়কাৰী অন কৰিবনে?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"আপোনাৰ <xliff:g id="PERCENTAGE">%s</xliff:g> বেটাৰী বাকী আছে। বেটাৰী সঞ্চয়কাৰীয়ে গাঢ় ৰঙৰ থীম অন কৰে, নেপথ্যৰ কাৰ্যকলাপ সীমাবদ্ধ কৰে আৰু জাননী পলম কৰে।"</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"বেটাৰী সঞ্চয়কাৰীয়ে গাঢ় ৰঙৰ থীম অন কৰে, নেপথ্যৰ কাৰ্যকলাপ সীমাবদ্ধ কৰে আৰু জাননী পলম কৰে।"</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> বাকী আছে"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"ইউএছবি জৰিয়তে চ্চাৰ্জ কৰিব নোৱাৰি"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"আপোনাৰ ডিভাইচৰ লগত পোৱা চ্চাৰ্জাৰটো ব্যৱহাৰ কৰক।"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"বেটাৰী সঞ্চয়কাৰী অন কৰেনে?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"বেটাৰী সঞ্চয়কাৰীৰ বিষয়ে"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"অন কৰক"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"বেটাৰী সঞ্চয়কাৰী অন কৰক"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"অন কৰক"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"নালাগে, ধন্যবাদ"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"স্বয়ং-ঘূৰ্ণন স্ক্ৰীন"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>ত প্ৰৱেশ কৰিবলৈ <xliff:g id="APPLICATION">%1$s</xliff:g>ক অনুমতি দিবনে?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g>ক <xliff:g id="USB_DEVICE">%2$s</xliff:g> এক্সেছ কৰিবলৈ অনুমতি দিবনে?\nএই এপ্‌টোক ৰেকর্ড কৰাৰ অনুমতি দিয়া হোৱা নাই কিন্তু ই এই ইউএছবি ডিভাইচটোৰ জৰিয়তে অডিঅ\' ৰেকর্ড কৰিব পাৰে।"</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"মুখমণ্ডলৰ বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰা হ’ল"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"নিশ্চিত কৰিলে"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"সম্পূৰ্ণ কৰিবলৈ নিশ্চিত কৰক-ত টিপক"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"আপোনাৰ মুখাৱয়বৰ দ্বাৰা আনলক কৰা হৈছে। অব্যাহত ৰাখিবলৈ দবাওক।"</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰা হ’ল"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"পিন ব্যৱহাৰ কৰক"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"আৰ্হি ব্যৱহাৰ কৰক"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"আপুনি পৰৱৰ্তী প্ৰয়াসত এটা ভুল আৰ্হি দিলে, আপোনাৰ কৰ্মস্থানৰ প্ৰ’ফাইল আৰু ইয়াৰ ডেটা মচি পেলোৱা হ’ব।"</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"আপুনি পৰৱৰ্তী প্ৰয়াসত এটা ভুল পিন দিলে, আপোনাৰ কৰ্মস্থানৰ প্ৰ’ফাইল আৰু ইয়াৰ ডেটা মচি পেলোৱা হ’ব।"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"আপুনি পৰৱৰ্তী প্ৰয়াসত এটা ভুল পাছৱৰ্ড দিলে, আপোনাৰ কৰ্মস্থানৰ প্ৰ’ফাইল আৰু ইয়াৰ ডেটা মচি পেলোৱা হ’ব।"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"বহুসংখ্যক ভুল প্ৰয়াস। এই ডিভাইচটোৰ ডেটা মচা হ\'ব।"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"বহুসংখ্যক ভুল প্ৰয়াস। এই ব্যৱহাৰকাৰীক মচা হ\'ব।"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"বহুসংখ্যক ভুল প্ৰয়াস। এই কৰ্মস্থানৰ প্ৰ\'ফাইলটো আৰু তাৰ লগত জড়িত ডেটা মচা হ\'ব।"</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"অগ্ৰাহ্য কৰক"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ফিংগাৰপ্ৰিণ্ট ছেন্সৰটো স্পৰ্শ কৰক"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ফিংগাৰপ্ৰিণ্ট আইকন"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"মুখাৱয়ব চিনিব নোৱাৰি। ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক।"</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • লাহে লাহে চাৰ্জ হৈ আছে • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>ত সম্পূৰ্ণ হ’ব"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • চাৰ্জিং ডক • সম্পূৰ্ণ হ’বলৈ <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> লাগিব"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ব্যৱহাৰকাৰী সলনি কৰক"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"ব্যৱহাৰকাৰী যোগ কৰক"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"নতুন ব্যৱহাৰকাৰী"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"অতিথি আঁতৰাবনে?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই ছেশ্বনৰ আটাইবোৰ এপ্ আৰু ডেটা মচা হ\'ব।"</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"আঁতৰাওক"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"অতিথি, আপোনাক পুনৰ স্বাগতম!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"আপুনি আপোনাৰ ছেশ্বন অব্যাহত ৰাখিব বিচাৰেনে?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"আকৌ আৰম্ভ কৰক"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"হয়, অব্যাহত ৰাখক"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"নতুন ব্যৱহাৰকাৰী যোগ কৰিবনে?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"আপুনি যেতিয়া এজন নতুন ব্যৱহাৰকাৰী যোগ কৰে, তেওঁ নিজৰ স্থান ছেট আপ কৰা প্ৰয়োজন।\n\nযিকোনো ব্যৱহাৰকাৰীয়ে নিজৰ লগতে আন ব্যৱহাৰকাৰীৰো এপ্ আপডে’ট কৰিব পাৰে।"</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"অধিকতম ব্যৱহাৰকাৰী সৃষ্টি কৰা হ’ল"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">আপুনি <xliff:g id="COUNT">%d</xliff:g> জনলৈকে ব্যৱহাৰকাৰী যোগ কৰিব পাৰে।</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ব্যৱহাৰ কৰিবলৈ আনলক কৰক"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"আপোনাৰ কাৰ্ড লাভ কৰোঁতে এটা সমস্যা হৈছে, অনুগ্ৰহ কৰি পাছত পুনৰ চেষ্টা কৰক"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"লক স্ক্ৰীনৰ ছেটিং"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"কিউআৰ ক\'ড"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"স্কেন কৰিবলৈ টিপক"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"কিউআৰ ক’ড স্কেন কৰক"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"কৰ্মস্থানৰ প্ৰ\'ফাইল"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"এয়াৰপ্লেইন ম\'ড"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"আপুনি আপোনাৰ পিছৰটো এলাৰ্ম <xliff:g id="WHEN">%1$s</xliff:g> বজাত শুনা নাপাব"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"অধিক চাবলৈ ছোৱাইপ কৰক"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"চুপাৰিছসমূহ ল’ড কৰি থকা হৈছে"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"মিডিয়া"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"এই মিডিয়াৰ ছেশ্বনটো লুকুৱাবনে?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"বৰ্তমানৰ মিডিয়াৰ ছেশ্বনটো লুকুৱাব নোৱাৰি।"</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"অগ্ৰাহ্য কৰক"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"লুকুৱাওক"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"পুনৰ আৰম্ভ কৰক"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"ছেটিং"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g>ত <xliff:g id="ARTIST_NAME">%2$s</xliff:g>ৰ <xliff:g id="SONG_NAME">%1$s</xliff:g> গীতটো প্লে’ হৈ আছে"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ইয়াত খেলিবলৈ <xliff:g id="DEVICENAME">%1$s</xliff:g>ৰ আৰু ওচৰলৈ যাওক"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ত প্লে কৰি থকা হৈছে"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"এই ফ’নটোত প্লে কৰি থকা হৈছে"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"কিবা ভুল হ’ল"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"সক্ৰিয় নহয়, এপ্‌টো পৰীক্ষা কৰক"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"বিচাৰি পোৱা নগ’ল"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"নিয়ন্ত্ৰণটো উপলব্ধ নহয়"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"নতুন ডিভাইচ পেয়াৰ কৰক"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"এই ছেশ্বনটো কাষ্ট কৰিবলৈ, অনুগ্ৰহ কৰি এপ্‌টো খোলক"</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"অজ্ঞাত এপ্"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"কাষ্ট বন্ধ কৰক"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"বিল্ডৰ নম্বৰ"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"ক্লিপব’ৰ্ডলৈ বিল্ডৰ নম্বৰ প্ৰতিলিপি কৰা হ’ল।"</string>
     <string name="basic_status" msgid="2315371112182658176">"বাৰ্তালাপ খোলক"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ৱাই-ফাই উপলব্ধ নহয়"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"অগ্ৰাধিকাৰ ম’ড"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"এলাৰ্ম ছেট কৰা হ’ল"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Assistantৰ অতিথি ম’ড সক্ষম কৰা হৈছে"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"কেমেৰা আৰু মাইক অফ হৈ আছে"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# টা জাননী}one{# টা জাননী}other{# টা জাননী}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index a1956b3..c9388b5 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Sistemin İstifadə İnterfeysi"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Enerjiyə Qənaət aktiv edilsin?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"<xliff:g id="PERCENTAGE">%s</xliff:g> enerji qalıb. Enerjiyə Qənaət rejimi Tünd temanı aktivləşdirir, arxa fon fəaliyyətini məhdudlaşdırır və bildirişləri gecikdirir."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Enerjiyə Qənaət rejimi Tünd temanı aktivləşdirir, arxa fon fəaliyyətini məhdudlaşdırır və bildirişləri gecikdirir."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> qalır"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"USB vasitəsilə enerji yığa bilməz"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Cihazla verilən adapterdən istifadə edin"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Batareya Qənaəti aktiv edilsin?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Enerjiyə Qənaət Haqqında"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Aktivləşdirin"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Batareya Qənaətini aktiv edin"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Aktiv edin"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Xeyr, təşəkkür"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Ekranın avtomatik dönməsi"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə <xliff:g id="USB_DEVICE">%2$s</xliff:g> cihazına giriş icazəsi verilsin?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə <xliff:g id="USB_DEVICE">%2$s</xliff:g> cihazına giriş icazəsi verilsin?\nBu tətbiqə qeydə almaq icazəsi verilməyib lakin, bu USB vasitəsilə səs yaza bilər."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Üz doğrulandı"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Təsdiqləndi"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tamamlamaq üçün \"Təsdiq edin\" seçiminə toxunun"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Üzünüzlə kiliddən çıxarılıb. Davam etmək üçün basın."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Doğrulandı"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN istifadə edin"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Model istifadə edin"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Növbəti cəhddə yanlış model daxil etsəniz, iş profili və datası silinəcək."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Növbəti cəhddə yanlış PIN daxil etsəniz, iş profili və datası silinəcək."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Növbəti cəhddə yanlış parol daxil etsəniz, iş profili və datası silinəcək."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Həddindən artıq yanlış cəhd. Bu cihazın datası silinəcək."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Həddindən artıq yanlış cəhd. Bu istifadəçi silinəcək."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Həddindən artıq yanlış cəhd. Bu iş profili və oradakı data silinəcək."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Ötürün"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Barmaq izi sensoruna klikləyin"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Barmaq izi ikonası"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tanımaq olmur. Barmaq izini işlədin."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Asta şarj edilir • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> sonra dolacaq"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Şarj Doku • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> sonra dolacaq"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"İstifadəçi əlavə edin"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Yeni istifadəçi"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Qonaq silinsin?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu sessiyada bütün tətbiqlər və data silinəcək."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Yığışdır"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Xoş gəlmisiniz!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Sessiya davam etsin?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Yenidən başlayın"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Bəli, davam edin"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Yeni istifadəçi əlavə edilsin?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Yeni istifadəçi əlavə etdiyiniz zaman həmin şəxs öz yerini quraşdırmalıdır. \n\n İstənilən istifadəçi bütün digər istifadəçilərdən olan tətbiqləri güncəlləşdirə bilər."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"İstifadəçi limitinə çatmısınız"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">Maksimum <xliff:g id="COUNT">%d</xliff:g> istifadəçi əlavə edə bilərsiniz.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"İstifadə etmək üçün kiliddən çıxarın"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Kartların əldə edilməsində problem oldu, sonra yenidən cəhd edin"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Kilid ekranı ayarları"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR kodu"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Skanlamaq üçün toxunun"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR kodu skanlayın"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"İş profili"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Təyyarə rejimi"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> zaman növbəti xəbərdarlığınızı eşitməyəcəksiniz"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Digərlərini görmək üçün sürüşdürün"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Tövsiyələr yüklənir"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Media"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Bu media sessiyası gizlədilsin?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Cari media sessiyası gizlədilə bilməz."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"İmtina edin"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Gizlədin"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Davam edin"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Ayarlar"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> tərəfindən <xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%3$s</xliff:g> tətbiqindən oxudulur"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Burada oxutmaq üçün <xliff:g id="DEVICENAME">%1$s</xliff:g> cihazına yaxınlaşın"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında oxudulur"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Bu telefonda oxudulur"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Xəta oldu"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Aktiv deyil, tətbiqi yoxlayın"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Tapılmadı"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Nəzarət əlçatan deyil"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Cihaz əlavə edin"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Bu sessiyanı yayımlamaq üçün tətbiqi açın."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Naməlum tətbiq"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Yayımı dayandırın"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Montaj nömrəsi"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Versiya nömrəsi mübadilə buferinə kopyalandı."</string>
     <string name="basic_status" msgid="2315371112182658176">"Açıq söhbət"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi əlçatan deyil"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritet rejimi"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Siqnal ayarlanıb"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Assistent qonaq rejimi aktivdir"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera və mikrofon deaktivdir"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# bildiriş}other{# bildiriş}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 2019e9d..2e0e503 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"UI sistema"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Želite li da uključite Uštedu baterije?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Preostali nivo napunjenosti baterije je <xliff:g id="PERCENTAGE">%s</xliff:g>. Ušteda baterije uključuje Tamnu temu, ograničava aktivnosti u pozadini i odlaže obaveštenja."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Ušteda baterije uključuje Tamnu temu, ograničava aktivnosti u pozadini i odlaže obaveštenja."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Još <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Punjenje preko USB-a nije uspelo"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Koristite punjač koji ste dobili uz uređaj"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Želite da uključite Uštedu baterije?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"O Uštedi baterije"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Uključi"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Uključi Uštedu baterije"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Uključi"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Ne, hvala"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Automatsko rotiranje ekrana"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Želite li da dozvolite da <xliff:g id="APPLICATION">%1$s</xliff:g> pristupa uređaju <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Želite li da dozvolite da <xliff:g id="APPLICATION">%1$s</xliff:g> pristupa uređaju <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nOva aplikacija nema dozvolu za snimanje, ali bi mogla da snima zvuk pomoću ovog USB uređaja."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Lice je potvrđeno"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrđeno"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Dodirnite Potvrdi da biste završili"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Otključali ste licem. Pritisnite da biste nastavili."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Identitet je potvrđen"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Koristite PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Koristite šablon"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ako unesete netačan šablon pri sledećem pokušaju, izbrisaćemo poslovni profil i njegove podatke."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ako unesete netačan PIN pri sledećem pokušaju, izbrisaćemo poslovni profil i njegove podatke."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ako unesete netačnu lozinku pri sledećem pokušaju, izbrisaćemo poslovni profil i njegove podatke."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Previše netačnih pokušaja. Izbrisaćemo podatke sa ovog uređaja."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Previše netačnih pokušaja. Izbrisaćemo ovog korisnika."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Previše netačnih pokušaja. Izbrisaćemo ovaj poslovni profil i njegove podatke."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Odbaci"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dodirnite senzor za otisak prsta"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona otiska prsta"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Lice nije prepoznato. Koristite otisak prsta."</string>
@@ -328,17 +321,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Sporo se puni • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> do kraja punjenja"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Bazna stanica za punjenje • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> do kraja punjenja"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Zameni korisnika"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Dodaj korisnika"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Novi korisnik"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Želite li da uklonite gosta?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci u ovoj sesiji će biti izbrisani."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ukloni"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Dobro došli nazad, goste!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li da nastavite sesiju?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Počni iz početka"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Da, nastavi"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Dodajete novog korisnika?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Kada dodate novog korisnika, ta osoba treba da podesi svoj prostor.\n\nSvaki korisnik može da ažurira aplikacije za sve ostale korisnike."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Dostignut maksimalni broj korisnika"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">Možete da dodate najviše <xliff:g id="COUNT">%d</xliff:g> korisnika.</item>
@@ -465,8 +453,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Otključaj radi korišćenja"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Došlo je do problema pri preuzimanju kartica. Probajte ponovo kasnije"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Podešavanja zaključanog ekrana"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR kôd"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Dodirnite da biste skenirali"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skenirajte QR kôd"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Poslovni profil"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Režim rada u avionu"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Nećete čuti sledeći alarm u <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -794,9 +781,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Prevucite da biste videli još"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Učitavaju se preporuke"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Mediji"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Želite li da sakrijete ovu sesiju medija?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Aktuelna sesija medija ne može da bude sakrivena."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Odbaci"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Sakrij"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Podešavanja"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> izvođača <xliff:g id="ARTIST_NAME">%2$s</xliff:g> se pušta iz aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -814,7 +802,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Približite se uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g> da biste na njemu puštali"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Pušta se na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Pušta se na ovom telefonu"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Došlo je do greške"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno. Vidite aplikaciju"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string>
@@ -833,6 +822,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Upari novi uređaj"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Da biste prebacivali ovu sesiju, otvorite aplikaciju."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Nepoznata aplikacija"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zaustavi prebacivanje"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj verzije"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Broj verzije je kopiran u privremenu memoriju."</string>
     <string name="basic_status" msgid="2315371112182658176">"Otvorite konverzaciju"</string>
@@ -923,8 +913,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WiFi nije dostupan"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritetni režim"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm je podešen"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Omogućen je režim gosta u Pomoćniku"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera i mikrofon su isključeni"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# obaveštenje}one{# obaveštenje}few{# obaveštenja}other{# obaveštenja}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index c10a36d..ea9d9ca 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Інтэрфейс сістэмы"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Уключыць рэжым энергазберажэння?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Засталося <xliff:g id="PERCENTAGE">%s</xliff:g> зараду акумулятара. Рэжым энергазберажэння ўключае цёмную тэму, абмяжоўвае дзеянні ў фонавым рэжыме і затрымлівае апавяшчэнні."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Рэжым энергазберажэння ўключае цёмную тэму, абмяжоўвае дзеянні ў фонавым рэжыме і затрымлівае апавяшчэнні."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Засталося <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Не ўдалося выканаць зарадку праз USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Выкарыстоўвайце зараднае прыстасаванне з камплекта прылады"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Уключыць рэжым эканоміі зараду?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Інфармацыя пра рэжым эканоміі зараду"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Уключыць"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Уключыць рэжым эканоміі зараду"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Уключыць"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Не, дзякуй"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Аўтаматычны паварот экрана"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Дазволіць праграме <xliff:g id="APPLICATION">%1$s</xliff:g> доступ да прылады <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Даць праграме \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" доступ да прылады \"<xliff:g id="USB_DEVICE">%2$s</xliff:g>\"?\nУ гэтай праграмы няма дазволу на запіс, аднак яна зможа запісваць аўдыя праз гэту прыладу USB."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Твар распазнаны"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Пацверджана"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Націсніце \"Пацвердзіць\", каб завяршыць"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Разблакіравана распазнаваннем твару. Націсніце для працягу."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Распазнана"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Увесці PIN-код"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Выкарыстаць узор разблакіроўкі"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Калі вы ўведзяце няправільны ўзор разблакіроўкі яшчэ раз, ваш працоўны профіль і звязаныя з ім даныя будуць выдалены."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Калі вы ўведзяце няправільны PIN-код яшчэ раз, ваш працоўны профіль і звязаныя з ім даныя будуць выдалены."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Калі вы ўведзяце няправільны пароль яшчэ раз, ваш працоўны профіль і звязаныя з ім даныя будуць выдалены."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Занадта шмат няўдалых спроб. Даныя будуць выдалены з гэтай прылады."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Занадта шмат няўдалых спроб. Гэты карыстальнік будзе выдалены."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Занадта шмат няўдалых спроб. Гэты працоўны профіль і звязаныя з ім даныя будуць выдалены."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Адхіліць"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Дакраніцеся да сканера адбіткаў пальцаў"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Значок адбіткаў пальцаў"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Твар не распазнаны. Скарыстайце адбітак пальца."</string>
@@ -330,17 +323,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ідзе павольная зарадка • Поўны зарад праз <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ідзе зарадка праз док-станцыю • Поўнасцю зарадзіцца праз <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Перайсці да іншага карыстальніка"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Дадаць карыстальніка"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Новы карыстальнік"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Выдаліць госця?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усе праграмы і даныя гэтага сеанса будуць выдалены."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Выдаліць"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"З вяртаннем, госць!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Хочаце працягнуць сеанс?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Пачаць зноў"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Так, працягнуць"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Дадаць новага карыстальніка?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Пасля стварэння профілю яго трэба наладзіць.\n\nЛюбы карыстальнік прылады можа абнаўляць праграмы ўсіх іншых карыстальнікаў."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Дасягнуты ліміт карыстальнікаў"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">Можна дадаць <xliff:g id="COUNT">%d</xliff:g> карыстальніка.</item>
@@ -468,8 +456,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Разблакіраваць для выкарыстання"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Узнікла праблема з загрузкай вашых карт. Паўтарыце спробу пазней"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Налады экрана блакіроўкі"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-код"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Націсніце, каб адсканіраваць"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Сканіраванне QR-кода"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Працоўны профіль"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Рэжым палёту"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Вы не пачуеце наступны будзільнік <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -800,9 +787,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Правядзіце пальцам, каб убачыць больш інфармацыі"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Загружаюцца рэкамендацыі"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Мультымедыя"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Схаваць гэты сеанс мультымедыя?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Не ўдалося схаваць бягучы сеанс мультымедыя."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Адхіліць"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Схаваць"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Узнавіць"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Налады"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"У праграме \"<xliff:g id="APP_LABEL">%3$s</xliff:g>\" прайграецца кампазіцыя \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\", выканаўца – <xliff:g id="ARTIST_NAME">%2$s</xliff:g>"</string>
@@ -820,7 +808,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Падыдзіце бліжэй да прылады \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\", каб прайграць на гэтай"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Прайграецца на прыладзе \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\""</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Прайграецца на гэтым тэлефоне"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Нешта пайшло не так"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Неактыўна, праверце праграму"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Не знойдзена"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Кіраванне недаступнае"</string>
@@ -839,6 +828,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Спалучыць з новай прыладай"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Для трансляцыі гэтага сеанса адкрыйце праграму."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Невядомая праграма"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Спыніць трансляцыю"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Нумар зборкі"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Нумар зборкі скапіраваны ў буфер абмену."</string>
     <string name="basic_status" msgid="2315371112182658176">"Адкрытая размова"</string>
@@ -930,8 +920,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Сетка Wi‑Fi недаступная"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Прыярытэтны рэжым"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Будзільнік зададзены"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Гасцявы рэжым для Памочніка ўключаны"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камера і мікрафон выключаны"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# апавяшчэнне}one{# апавяшчэнне}few{# апавяшчэнні}many{# апавяшчэнняў}other{# апавяшчэння}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index a107504..25c90ce 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Системен ПИ"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Да се включи ли режимът за запазване на батерията?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Оставащ заряд на батерията: <xliff:g id="PERCENTAGE">%s</xliff:g>. Режимът за запазване на батерията включва тъмната тема, ограничава активността на заден план и отлага известията."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Режимът за запазване на батерията включва тъмната тема, ограничава активността на заден план и отлага известията."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Остава/т <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Зареждането през USB не е възможно"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Използвайте оригиналното зарядно устройство"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Да се включи ли режимът за запазване на батерията?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Всичко за режима за запазване на батерията"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Включване"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Включване на режима за запазване на батерията"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Включване"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Не, благодаря"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Авт. завъртане на екрана"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Да се разреши ли на <xliff:g id="APPLICATION">%1$s</xliff:g> достъп до <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Наистина ли искате да разрешите на <xliff:g id="APPLICATION">%1$s</xliff:g> достъп до <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nНа приложението не е предоставено разрешение за записване, но е възможно да запише звук чрез това USB устройство."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Лицето е удостоверено"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Потвърдено"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Докоснете „Потвърждаване“ за завършване"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Отключено чрез лицето ви. Натиснете, за да продължите."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Удостоверено"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Използване на ПИН"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Използване на фигура"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ако въведете неправилна фигура при следващия опит, служебният ви потребителски профил и данните в него ще бъдат изтрити."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ако въведете неправилен ПИН код при следващия опит, служебният ви потребителски профил и данните в него ще бъдат изтрити."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ако въведете неправилна парола при следващия опит, служебният ви потребителски профил и данните в него ще бъдат изтрити."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Твърде много неправилни опити. Данните от това устройство ще бъдат изтрити."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Твърде много неправилни опити. Този потребител ще бъде изтрит."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Твърде много неправилни опити. Този служебен потребителски профил и данните в него ще бъдат изтрити."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Отхвърляне"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Докоснете сензора за отпечатъци"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Икона за отпечатък"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Лицето не е разпознато. Използвайте отпечатък."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Зарежда се бавно • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до пълно зареждане"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Докинг станция за зареждане • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до пълно зареждане"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Превключване между потребителите"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Добавяне на потребител"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Нов потребител"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Да се премахне ли гостът?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Всички приложения и данни в тази сесия ще бъдат изтрити."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Премахване"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Добре дошли отново в сесията като гост!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Искате ли да продължите сесията си?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Започване отначало"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Да, продължавам"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Да се добави ли нов потребител?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Когато добавите нов потребител, той трябва да настрои работното си пространство.\n\nВсеки потребител може да актуализира приложенията за всички останали потребители."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Достигнахте огранич. за потребители"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">Можете да добавите до <xliff:g id="COUNT">%d</xliff:g> потребители.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Отключване с цел използване"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"При извличането на картите ви възникна проблем. Моля, опитайте отново по-късно"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Настройки за заключения екран"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR код"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Докоснете за сканиране"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Сканиране на QR код"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Потребителски профил в Work"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Самолетен режим"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Няма да чуете следващия си будилник в <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Прекарайте пръст, за да видите повече"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Препоръките се зареждат"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Мултимедия"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Да се скрие ли тази сесия за мултимедия?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Текущата сесия за мултимедия не бе скрита."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Отхвърляне"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Скриване"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Възобновяване"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Настройки"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> на <xliff:g id="ARTIST_NAME">%2$s</xliff:g> се възпроизвежда от <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Приближете се до <xliff:g id="DEVICENAME">%1$s</xliff:g> за възпроизвеждане на това устройство"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Възпроизвежда се на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Възпроизвежда се на този телефон"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Нещо се обърка"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, проверете прилож."</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Не е намерено"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Контролата не е налице"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Сдвояване на ново устройство"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"За да предавате тази сесия, моля, отворете приложението."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Неизвестно приложение"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Спиране на предаването"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер на компилацията"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Номерът на компилацията е копиран в буферната памет."</string>
     <string name="basic_status" msgid="2315371112182658176">"Отворен разговор"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi не е налице"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Приоритетен режим"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Будилникът е зададен"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Режимът на гост за Асистент е активиран"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камерата и микрофонът са изключени"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# известие}other{# известия}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index b5040e9..a967a5c 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"সিস্টেম UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"\'ব্যাটারি সেভার\' চালু করতে চান?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"আপনার আর <xliff:g id="PERCENTAGE">%s</xliff:g> ব্যাটারি আছে। ব্যাটারি সেভার ডার্ক থিম চালু করে, ব্যাকগ্রাউন্ড অ্যাক্টিভিটি সীমিত করে এবং বিজ্ঞপ্তিতে দেরি করে।"</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"ব্যাটারি সেভার ডার্ক থিম চালু করে, ব্যাকগ্রাউন্ড অ্যাক্টিভিটি সীমিত করে এবং বিজ্ঞপ্তিতে দেরি করে।"</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> অবশিষ্ট আছে"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"ইউএসবি দিয়ে চার্জ করা যাবে না"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"ডিভাইসের সাথে যে চার্জারটি পেয়েছেন, সেটি ব্যবহার করুন"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"ব্যাটারি সেভার চালু করবেন?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"ব্যাটারি সেভার সম্পর্কে"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"চালু করুন"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"ব্যাটারি সেভার চালু করুন"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"চালু করুন"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"না থাক"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"অটো-রোটেট স্ক্রিন"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> কে <xliff:g id="USB_DEVICE">%2$s</xliff:g> অ্যাক্সেস করতে দেবেন?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> অ্যাক্সেস করতে <xliff:g id="APPLICATION">%1$s</xliff:g>-কে কি অনুমতি দেবেন?\nএই অ্যাপকে রেকর্ড করার অনুমতি দেওয়া হয়নি কিন্তু USB ডিভাইসের মাধ্যমে সেটি অডিও রেকর্ড করতে পারে।"</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ফেস যাচাই করা হয়েছে"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"কনফার্ম করা হয়েছে"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"সম্পূর্ণ করতে \'কনফার্ম করুন\' বোতামে ট্যাপ করুন"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"আপনার মুখ মাধ্যমে আনলক করা হয়েছে। চালিয়ে যেতে প্রেস করুন।"</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"প্রমাণীকৃত"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"পিন ব্যবহার করুন"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"প্যাটার্ন ব্যবহার করুন"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"আপনি পরের বারও ভুল প্যাটার্ন দিলে আপনার অফিস প্রোফাইল এবং তার ডেটা মুছে দেওয়া হবে।"</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"আপনি পরের বারও ভুল পিন দিলে আপনার অফিস প্রোফাইল এবং তার ডেটা মুছে দেওয়া হবে।"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"আপনি পরের বারও ভুল পাসওয়ার্ড দিলে আপনার অফিস প্রোফাইল এবং তার ডেটা মুছে দেওয়া হবে।"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"বহুবার ভুল লেখা হয়েছে। এই ডিভাইসের ডেটা মুছে যাবে।"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"বহুবার ভুল লেখা হয়েছে। এই ব্যবহারকারীর ডেটা মুছে যাবে।"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"বহুবার ভুল লেখা হয়েছে। এই অফিসের প্রোফাইল ও সংশ্লিষ্ট ডেটা মুছে যাবে।"</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"বাতিল করুন"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"আঙ্গুলের ছাপের সেন্সর স্পর্শ করুন"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"আঙ্গুলের ছাপের আইকন"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"মুখ শনাক্ত করতে পারছি না। পরিবর্তে আঙ্গুলের ছাপ ব্যবহার করুন।"</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ধীরে চার্জ হচ্ছে • পুরো চার্জ হতে <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> লাগবে"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • চার্জিং ডক • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>-এর মধ্যে সম্পূর্ণ হয়ে যাবে"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ব্যবহারকারী পাল্টে দিন"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"ব্যবহারকারী জুড়ুন"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"নতুন ব্যবহারকারী"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"অতিথি সরাবেন?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই সেশনের সব অ্যাপ ও ডেটা মুছে ফেলা হবে।"</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"সরান"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"অতিথি, আপনি ফিরে আসায় আপনাকে স্বাগত!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"আপনি কি আপনার সেশনটি চালিয়ে যেতে চান?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"আবার শুরু করুন"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"হ্যাঁ, চালিয়ে যান"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"নতুন ব্যবহারকারীকে যোগ করবেন?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"আপনি একজন নতুন ব্যবহারকারী যোগ করলে তাকে তার জায়গা সেট-আপ করে নিতে হবে৷\n\nযেকোনও ব্যবহারকারী অন্য সব ব্যবহারকারীর জন্য অ্যাপ আপডেট করতে পারবেন৷"</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"আর কোনও প্রোফাইল যোগ করা যাবে না"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">আপনি <xliff:g id="COUNT">%d</xliff:g> জন পর্যন্ত ব্যবহারকারীর প্রোফাইল যোগ করতে পারেন।</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ব্যবহার করতে আনলক করুন"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"আপনার কার্ড সংক্রান্ত তথ্য পেতে সমস্যা হয়েছে, পরে আবার চেষ্টা করুন"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"লক স্ক্রিন সেটিংস"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR কোড"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"স্ক্যান করতে ট্যাপ করুন"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR কোড স্ক্যান করুন"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"কাজের প্রোফাইল"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"বিমান মোড"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"আপনি আপনার পরবর্তী <xliff:g id="WHEN">%1$s</xliff:g> অ্যালার্ম শুনতে পাবেন না"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"আরও দেখতে সোয়াইপ করুন"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"সাজেশন লোড করা হচ্ছে"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"মিডিয়া"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"এই মিডিয়া সেশন লুকিয়ে রাখতে চান?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"বর্তমান মিডিয়া সেশন লুকিয়ে রাখা যাবে না।"</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"খারিজ করুন"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"লুকান"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"আবার চালু করুন"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"সেটিংস"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g>-এর <xliff:g id="SONG_NAME">%1$s</xliff:g> গানটি <xliff:g id="APP_LABEL">%3$s</xliff:g> অ্যাপে চলছে"</string>
@@ -808,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"এখান থেকে চালাতে <xliff:g id="DEVICENAME">%1$s</xliff:g>-এর কাছে নিয়ে যান"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>-এ ভিডিও চালানো হচ্ছে"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"এই ফোনে চালানো হচ্ছে"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"কোনও সমস্যা হয়েছে"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"কোনও সমস্যা হয়েছে। আবার চেষ্টা করুন।"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"বন্ধ আছে, অ্যাপ চেক করুন"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"খুঁজে পাওয়া যায়নি"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"কন্ট্রোল উপলভ্য নেই"</string>
@@ -827,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"নতুন ডিভাইস পেয়ার করুন"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"এই সেশন কাস্ট করার জন্য, অ্যাপ খুলুন।"</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"অজানা অ্যাপ"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"কাস্ট করা বন্ধ করুন"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"বিল্ড নম্বর"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"বিল্ড নম্বর ক্লিপবোর্ডে কপি করা হয়েছে।"</string>
     <string name="basic_status" msgid="2315371112182658176">"খোলা কথোপকথন"</string>
@@ -916,7 +905,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ওয়াই-ফাই উপলভ্য নেই"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"প্রায়োরিটি মোড"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"অ্যালার্ম সেট করা হয়েছে"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Assistant-এর \'অতিথি মোড\' চালু করা হয়েছে"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ক্যামেরা ও মাইক্রোফোন বন্ধ আছে"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{#টি বিজ্ঞপ্তি}one{#টি বিজ্ঞপ্তি}other{#টি বিজ্ঞপ্তি}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index b0691fe..c5a73e5 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Sistemski UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Uključiti Uštedu baterije?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Preostalo vam je još <xliff:g id="PERCENTAGE">%s</xliff:g> baterije. Ušteda baterije uključuje tamnu temu, ograničava aktivnost u pozadini i odgađa obavještenja."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Ušteda baterije uključuje tamnu temu, ograničava aktivnost u pozadini i odgađa obavještenja."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Preostalo <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Punjenje putem USB-a nije moguće"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Koristite punjač koji ste dobili uz uređaj"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Uključiti Uštedu baterije?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Informacije o Uštedi baterije"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Uključi"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Uključi Uštedu baterije"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Uključi"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Ne, hvala"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Automatsko rotiranje ekrana"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Dozvoliti aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> pristup uređaju: <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Dozvoliti aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> pristup uređaju <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nOvoj aplikaciji nije dato odobrenje za snimanje, ali može snimati zvuk putem ovog USB uređaja."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Lice je provjereno"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrđeno"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Dodirnite Potvrdi da završite"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Otključano vašim licem. Pritisnite da nastavite."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentificirano"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Koristi PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Koristi uzorak"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ako u sljedećem pokušaju unesete neispravan uzorak, vaš radni profil i njegovi podaci će se izbrisati."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ako u sljedećem pokušaju unesete neispravan PIN, vaš radni profil i njegovi podaci će se izbrisati."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ako u sljedećem pokušaju unesete neispravnu lozinku, vaš radni profil i njegovi podaci će se izbrisati."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Previše je neispravnih pokušaja. Podaci ovog uređaja će se izbrisati."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Previše je neispravnih pokušaja. Ovaj korisnik će se izbrisati."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Previše je neispravnih pokušaja. Ovaj radni profil i njegovi podaci će se izbrisati."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Odbaci"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dodirnite senzor za otisak prsta"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona za otisak prsta"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nije moguće prepoznati lice. Koristite otisak prsta."</string>
@@ -328,17 +321,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Sporo punjenje • Potpuna napunjenost za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Priključna stanica za punjenje • Potpuna napunjenost za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Zamijeni korisnika"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Dodaj korisnika"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Novi korisnik"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Ukloniti gosta?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci iz ove sesije će se izbrisati."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ukloni"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Zdravo! Lijepo je opet vidjeti goste."</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li nastaviti sesiju?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Počni ispočetka"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Da, nastavi"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Dodati novog korisnika?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Kada dodate novog korisnika, ta osoba treba postaviti svoj prostor.\n\nSvaki korisnik može ažurirati aplikacije za sve ostale korisnike."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Dostignut limit za broj korisnika"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">Možete dodati najviše <xliff:g id="COUNT">%d</xliff:g> korisnika.</item>
@@ -465,8 +453,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Otključajte da koristite"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Došlo je do problema prilikom preuzimanja vaših kartica. Pokušajte ponovo kasnije"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Postavke zaključavanja ekrana"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR kôd"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Dodirnite da skenirate"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skenirajte QR kôd"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Profil za posao"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Način rada u avionu"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Nećete čuti sljedeći alarm u <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -794,9 +781,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Prevucite da vidite više"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Učitavanje preporuka"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Mediji"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Sakriti ovu sesiju medija?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Trenutna sesija medija se ne može sakriti."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Odbaci"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Sakrij"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Postavke"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Pjesma <xliff:g id="SONG_NAME">%1$s</xliff:g> izvođača <xliff:g id="ARTIST_NAME">%2$s</xliff:g> se reproducira pomoću aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -814,7 +802,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Približite se uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g> da na njemu reproducirate"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproducira se na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Reproducira se na ovom telefonu"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Nešto nije uredu"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, vidite aplikaciju"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string>
@@ -833,6 +822,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Uparite novi uređaj"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Da emitirate ovu sesiju, otvorite aplikaciju."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Nepoznata aplikacija"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zaustavi emitiranje"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj verzije"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Broj verzije je kopiran u međumemoriju."</string>
     <string name="basic_status" msgid="2315371112182658176">"Otvoreni razgovor"</string>
@@ -923,7 +913,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WiFi je nedostupan"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Način rada Prioriteti"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm je postavljen"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Način rada za gosta Asistenta je omogućen"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera i mikrofon su isključeni"</string>
-    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# obavijest}one{# obavijest}few{# obavijesti}other{# obavijesti}}"</string>
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# obavještenje}one{# obavještenje}few{# obavještenja}other{# obavještenja}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index da4cba7..13abf75 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"IU del sistema"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Vols activar Estalvi de bateria?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Et queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de bateria. Estalvi de bateria activa el tema fosc, restringeix l\'activitat en segon pla i endarrereix les notificacions."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Estalvi de bateria activa el tema fosc, restringeix l\'activitat en segon pla i endarrereix les notificacions."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g>."</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"No es pot carregar per USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Fes servir el carregador original del dispositiu"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Vols activar la funció Estalvi de bateria?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Sobre la funció Estalvi de bateria"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Activa"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Activa la funció Estalvi de bateria"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Activa"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"No, gràcies"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Gira la pantalla automàticament"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Vols permetre que <xliff:g id="APPLICATION">%1$s</xliff:g> accedeixi a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Vols permetre que <xliff:g id="APPLICATION">%1$s</xliff:g> accedeixi a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nAquesta aplicació no té permís de gravació, però pot capturar àudio a través d\'aquest dispositiu USB."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Cara autenticada"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmat"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toca Confirma per completar"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"S\'ha desbloquejat amb la cara. Prem per continuar."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticat"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Utilitza el PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Utilitza el patró"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Si tornes a introduir un patró incorrecte, se suprimirà el perfil de treball i les dades que contingui."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Si tornes a introduir un PIN incorrecte, se suprimirà el perfil de treball i les dades que contingui."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Si tornes a introduir una contrasenya incorrecta, se suprimirà el perfil de treball i les dades que contingui."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Has superat el nombre d\'intents incorrectes permesos. Se suprimiran les dades del dispositiu."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Has superat el nombre d\'intents incorrectes permesos. Se suprimirà l\'usuari."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Has superat el nombre d\'intents incorrectes permesos. Se suprimirà el perfil de treball i les dades que contingui."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Ignora"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toca el sensor d\'empremtes digitals"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Icona d\'empremta digital"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"No podem detectar la cara. Usa l\'empremta digital."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carregant lentament • Es completarà d\'aquí a <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Base de càrrega • Es completarà d\'aquí a <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Canvia d\'usuari"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Afegeix un usuari"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Usuari nou"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vols suprimir el convidat?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Totes les aplicacions i les dades d\'aquesta sessió se suprimiran."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Suprimeix"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Benvingut de nou, convidat."</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vols continuar amb la sessió?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Torna a començar"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Sí, continua"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Vols afegir un usuari nou?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Quan s\'afegeix un usuari nou, aquest usuari ha de configurar-se l\'espai.\n\nQualsevol usuari pot actualitzar les aplicacions de la resta d\'usuaris."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"S\'ha assolit el límit d\'usuaris"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">Pots afegir fins a <xliff:g id="COUNT">%d</xliff:g> usuaris.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloqueja per utilitzar"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Hi ha hagut un problema en obtenir les teves targetes; torna-ho a provar més tard"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Configuració de la pantalla de bloqueig"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"Codi QR"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Toca per escanejar"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Escaneja un codi QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Perfil de treball"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Mode d\'avió"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> no sentiràs la pròxima alarma"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Llisca per veure\'n més"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Carregant les recomanacions"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Multimèdia"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Vols amagar aquesta sessió multimèdia?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"La sessió multimèdia actual no es pot amagar."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ignora"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Amaga"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Reprèn"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Configuració"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>) s\'està reproduint des de l\'aplicació <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Acosta\'t a <xliff:g id="DEVICENAME">%1$s</xliff:g> per reproduir el contingut aquí"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"S\'està reproduint a <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"S\'està reproduint en aquest telèfon"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"S\'ha produït un error"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactiu; comprova l\'aplicació"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"No s\'ha trobat"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"El control no està disponible"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincula un dispositiu nou"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Per emetre aquesta sessió, obre l\'aplicació."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplicació desconeguda"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Atura l\'emissió"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilació"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"El número de compilació s\'ha copiat al porta-retalls."</string>
     <string name="basic_status" msgid="2315371112182658176">"Conversa oberta"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi no disponible"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Mode Prioritat"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarma definida"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Mode de convidat de l\'Assistent activat"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Càmera i micròfon desactivats"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificació}other{# notificacions}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index e93fc29..4feb8dc 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"UI systému"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Zapnout spořič baterie?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Zbývá <xliff:g id="PERCENTAGE">%s</xliff:g> baterie. Spořič baterie zapne tmavý motiv, omezí aktivitu na pozadí a pozdrží oznámení."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Spořič baterie zapne tmavý motiv, omezí aktivitu na pozadí a pozdrží oznámení."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Zbývá <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Nabíjení přes USB nefunguje"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Používejte originální nabíječku, která byla dodána spolu se zařízením."</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Zapnout spořič baterie?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Informace o spořiči baterie"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Zapnout"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Zapnout spořič baterie"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Zapnout"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Ne, díky"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Automatické otočení obrazovky"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Povolit aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g> přístup k zařízení <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Povolit aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g> přístup k zařízení <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nTato aplikace nemá oprávnění k nahrávání, ale může zaznamenávat zvuk prostřednictvím tohoto zařízení USB."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Obličej byl ověřen"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrzeno"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ověření dokončíte klepnutím na Potvrdit"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Odemyká se obličejem. Pokračujte stisknutím."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Ověřeno"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Použít kód PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Použít gesto"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Pokud při příštím pokusu zadáte nesprávné gesto, váš pracovní profil a přidružená data budou smazána."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Pokud při příštím pokusu zadáte nesprávný PIN, váš pracovní profil a přidružená data budou smazána."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Pokud při příštím pokusu zadáte nesprávné heslo, váš pracovní profil a přidružená data budou smazána."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Příliš mnoho neplatných pokusů. Data v tomto zařízení budou smazána."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Příliš mnoho neplatných pokusů. Tento uživatel bude smazán."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Příliš mnoho neplatných pokusů. Tento pracovní profil a přidružená data budou smazána."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Zavřít"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dotkněte se snímače otisků prstů"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona otisku prstu"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Obličej se nepodařilo rozpoznat. Použijte místo něj otisk prstu."</string>
@@ -330,17 +323,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Pomalé nabíjení • Plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Nabíjecí dok • Plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Přepnout uživatele"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Přidat uživatele"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Nový uživatel"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Odstranit hosta?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Veškeré aplikace a data v této relaci budou vymazána."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Odstranit"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Vítejte zpět v relaci hosta!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcete v relaci pokračovat?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Začít znovu"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ano, pokračovat"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Přidat nového uživatele?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Když přidáte nového uživatele, musí si nastavit vlastní prostor.\n\nJakýkoli uživatel může aktualizovat aplikace všech ostatních uživatelů."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Bylo dosaženo limitu uživatelů"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="few">Lze přidat až <xliff:g id="COUNT">%d</xliff:g> uživatele.</item>
@@ -468,8 +456,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Odemknout a použít"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Při načítání karet došlo k problému, zkuste to později"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Nastavení obrazovky uzamčení"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR kód"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Klepnutím naskenujete kód"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Naskenovat QR kód"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Pracovní profil"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Režim Letadlo"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Svůj další budík <xliff:g id="WHEN">%1$s</xliff:g> neuslyšíte"</string>
@@ -800,9 +787,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Přejetím prstem zobrazíte další položky"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Načítání doporučení"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Média"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Skrýt tuto mediální relaci?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Aktuální mediální relaci nelze skrýt."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Zavřít"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Skrýt"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Pokračovat"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Nastavení"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Skladba <xliff:g id="SONG_NAME">%1$s</xliff:g> od interpreta <xliff:g id="ARTIST_NAME">%2$s</xliff:g> hrajte z aplikace <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -820,7 +808,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Pokud zde chcete přehrávat média, přibližte se k zařízení <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Přehrávání v zařízení <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Přehrávání v tomto telefonu"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Něco se pokazilo"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivní, zkontrolujte aplikaci"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nenalezeno"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Ovládání není k dispozici"</string>
@@ -839,6 +828,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Spárovat nové zařízení"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Pokud chcete odesílat relaci, otevřete aplikaci."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Neznámá aplikace"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zastavit odesílání"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Číslo sestavení"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Číslo sestavení bylo zkopírováno do schránky."</string>
     <string name="basic_status" msgid="2315371112182658176">"Otevřít konverzaci"</string>
@@ -930,7 +920,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Síť Wi‑Fi není k dispozici"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritní režim"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Je nastaven budík"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"U Asistenta je aktivován režim hosta"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Fotoaparát a mikrofon jsou vypnuté"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# oznámení}few{# oznámení}many{# oznámení}other{# oznámení}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index bf460fe..a018f11 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"System-UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Vil du aktivere Batterisparefunktion?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Du har <xliff:g id="PERCENTAGE">%s</xliff:g> batteri tilbage. Batterisparefunktion aktiverer Mørkt tema, begrænser aktivitet i baggrunden og udskyder notifikationer."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Batterisparefunktion aktiverer Mørkt tema, begrænser aktivitet i baggrunden og udskyder notifikationer."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> tilbage"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Enheden kan ikke oplades via USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Brug den oplader, der fulgte med din enhed"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Vil du aktivere Batterisparefunktion?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Om Batterisparefunktion"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Aktivér"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Aktivér batterisparefunktion"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Aktivér"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Nej tak"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Roter skærm automatisk"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Vil du give <xliff:g id="APPLICATION">%1$s</xliff:g> adgang til <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Vil du give <xliff:g id="APPLICATION">%1$s</xliff:g> adgang til <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nDenne app har ikke fået tilladelse til at optage, men optager muligvis lyd via denne USB-enhed."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Ansigtet er godkendt"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bekræftet"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tryk på Bekræft for at udføre"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Låst op med ansigtsgenkendelse. Tryk for at fortsætte."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Godkendt"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Brug pinkode"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Brug mønster"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Hvis du angiver et forkert mønster i næste forsøg, slettes din arbejdsprofil og de tilhørende data."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Hvis du angiver en forkert pinkode i næste forsøg, slettes din arbejdsprofil og de tilhørende data."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Hvis du angiver en forkert adgangskode i næste forsøg, slettes din arbejdsprofil og de tilhørende data."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"For mange forkerte forsøg. Dataene på denne enhed slettes."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"For mange forkerte forsøg. Denne bruger slettes."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"For mange forkerte forsøg. Denne arbejdsprofil og de tilhørende data slettes."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Afvis"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Sæt fingeren på fingeraftrykslæseren"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikon for fingeraftryk"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansigtet kan ikke genkendes. Brug fingeraftryk i stedet."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Oplader langsomt • Fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Oplader i dockingstation • Fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Skift bruger"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Tilføj bruger"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Ny bruger"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vil du fjerne gæsten?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps og data i denne session slettes."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Fjern"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Velkommen tilbage, gæst!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vil du fortsætte din session?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start forfra"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ja, fortsæt"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Vil du tilføje en ny bruger?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Når du tilføjer en ny bruger, skal personen konfigurere sit område.\n\nAlle brugere kan opdatere apps for alle de andre brugere."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Grænsen for antal brugere er nået"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">Du kan tilføje op til <xliff:g id="COUNT">%d</xliff:g> bruger.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lås op for at bruge"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Dine kort kunne ikke hentes. Prøv igen senere."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lås skærmindstillinger"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-kode"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Tryk for at scanne"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Scan QR-kode"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Arbejdsprofil"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Flytilstand"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Du vil ikke kunne høre din næste alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Stryg for at se mere"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Indlæser anbefalinger"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Medie"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Vil du skjule denne mediesession?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Den aktuelle mediesession kan ikke skjules."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Luk"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Skjul"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Genoptag"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Indstillinger"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> af <xliff:g id="ARTIST_NAME">%2$s</xliff:g> afspilles via <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Ryk tættere på <xliff:g id="DEVICENAME">%1$s</xliff:g> for at afspille her"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Afspilles på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Afspilles på denne telefon"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Noget gik galt"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Tjek appen"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Ikke fundet"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Styringselement ikke tilgængeligt"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Par ny enhed"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Åbn appen for at caste denne session."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Ukendt app"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stop med at caste"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildnummer"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Buildnummeret blev kopieret til udklipsholderen."</string>
     <string name="basic_status" msgid="2315371112182658176">"Åben samtale"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Ingen tilgængelig Wi-Fi-forbindelse"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Tilstanden Prioritet"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmen er indstillet"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Gæstetilstand i Assistent er aktiveret"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera og mikrofon er slået fra"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notifikation}one{# notifikation}other{# notifikationer}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 6197b3f..fd42681 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"System-UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Energiesparmodus aktivieren?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Dein Akkustand beträgt <xliff:g id="PERCENTAGE">%s</xliff:g>. Im Energiesparmodus wird das dunkle Design aktiviert und es werden Hintergrundaktivitäten eingeschränkt sowie Benachrichtigungen verzögert empfangen."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Im Energiesparmodus wird das dunkle Design aktiviert und es werden Hintergrundaktivitäten eingeschränkt sowie Benachrichtigungen verzögert empfangen."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> verbleibend"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Aufladen über USB nicht möglich"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Verwende das mit dem Gerät gelieferte Ladegerät"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Energiesparmodus aktivieren?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Über den Energiesparmodus"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Aktivieren"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Energiesparmodus aktivieren"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Aktivieren"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Nein danke"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Bildschirm automatisch drehen"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> den Zugriff auf <xliff:g id="USB_DEVICE">%2$s</xliff:g> gewähren?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> den Zugriff auf <xliff:g id="USB_DEVICE">%2$s</xliff:g> gewähren?\nDiese App hat noch nicht die Berechtigung zum Aufnehmen erhalten, könnte jedoch Audio über dieses USB-Gerät aufnehmen."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Gesicht authentifiziert"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bestätigt"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Zum Abschließen auf \"Bestätigen\" tippen"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Mit dem Gesicht entsperrt. Drücken, um fortzufahren."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authentifiziert"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN verwenden"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Muster verwenden"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Wenn du beim nächsten Versuch ein falsches Muster eingibst, werden dein Arbeitsprofil und die zugehörigen Daten gelöscht."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Wenn du beim nächsten Versuch eine falsche PIN eingibst, werden dein Arbeitsprofil und die zugehörigen Daten gelöscht."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Wenn du beim nächsten Versuch ein falsches Passwort eingibst, werden dein Arbeitsprofil und die zugehörigen Daten gelöscht."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Zu viele Fehlversuche. Die Daten auf diesem Gerät werden gelöscht."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Zu viele Fehlversuche. Dieser Nutzer wird vom Gerät entfernt."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Zu viele Fehlversuche. Dieses Arbeitsprofil und die zugehörigen Daten werden gelöscht."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Schließen"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Berühre den Fingerabdrucksensor"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Fingerabdruck-Symbol"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Gesicht wurde nicht erkannt. Verwende stattdessen den Fingerabdruck."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Wird langsam geladen • Voll in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ladestation • Voll in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Nutzer wechseln"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Nutzer hinzufügen"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Neuer Nutzer"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Gast entfernen?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle Apps und Daten in dieser Sitzung werden gelöscht."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Entfernen"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Willkommen zurück im Gastmodus"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Möchtest du deine Sitzung fortsetzen?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Neu starten"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ja, weiter"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Neuen Nutzer hinzufügen?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Wenn du einen neuen Nutzer hinzufügst, muss dieser seinen Bereich einrichten.\n\nJeder Nutzer kann Apps für alle anderen Nutzer aktualisieren."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Nutzerlimit erreicht"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">Du kannst bis zu <xliff:g id="COUNT">%d</xliff:g> Nutzer hinzufügen.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Zum Verwenden entsperren"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Beim Abrufen deiner Karten ist ein Fehler aufgetreten – bitte versuch es später noch einmal"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Einstellungen für den Sperrbildschirm"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-Code"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Zum Scannen tippen"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR-Code scannen"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Arbeitsprofil"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Flugmodus"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Lautloser Weckruf <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -686,7 +673,7 @@
     <string name="notification_channel_general" msgid="4384774889645929705">"Nachrichten"</string>
     <string name="notification_channel_storage" msgid="2720725707628094977">"Speicher"</string>
     <string name="notification_channel_hints" msgid="7703783206000346876">"Hinweise"</string>
-    <string name="instant_apps" msgid="8337185853050247304">"Instant-Apps"</string>
+    <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
     <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> wird ausgeführt"</string>
     <string name="instant_apps_message" msgid="6112428971833011754">"App wurde geöffnet, ohne vorher installiert zu werden."</string>
     <string name="instant_apps_message_with_help" msgid="1816952263531203932">"App wurde geöffnet, ohne vorher installiert zu werden. Tippe, um weitere Informationen zu erhalten."</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Wischen, um weitere zu sehen"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Empfehlungen werden geladen"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Medien"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Diese Mediensitzung ausblenden?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Die Mediensitzung kann nicht ausgeblendet werden."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ausblenden"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ausblenden"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Fortsetzen"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Einstellungen"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> von <xliff:g id="ARTIST_NAME">%2$s</xliff:g> wird gerade über <xliff:g id="APP_LABEL">%3$s</xliff:g> wiedergegeben"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Platziere für die Wiedergabe dein Gerät näher an „<xliff:g id="DEVICENAME">%1$s</xliff:g>“"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Wird auf „<xliff:g id="DEVICENAME">%1$s</xliff:g>“ abgespielt"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Wird auf diesem Smartphone abgespielt"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Ein Fehler ist aufgetreten"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv – sieh in der App nach"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nicht gefunden"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Steuerelement nicht verfügbar"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Neues Gerät koppeln"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Öffne zum Streamen dieser Sitzung die App."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Unbekannte App"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Streaming beenden"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build-Nummer"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Build-Nummer in Zwischenablage kopiert."</string>
     <string name="basic_status" msgid="2315371112182658176">"Offene Unterhaltung"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WLAN nicht verfügbar"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritätsmodus"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Wecker gestellt"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Assistant-Gastmodus aktiviert"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera und Mikrofon ausgeschaltet"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# Benachrichtigung}other{# Benachrichtigungen}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index dc0d98b..bbc2ee3 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"UI συστήματ."</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Ενεργοποίηση Εξοικονόμησης μπαταρίας;"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Απομένει <xliff:g id="PERCENTAGE">%s</xliff:g> μπαταρία. Η Εξοικονόμηση μπαταρίας ενεργοποιεί το Σκούρο θέμα, περιορίζει τη δραστηριότητα στο παρασκήνιο και καθυστερεί τις ειδοποιήσεις."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Η Εξοικονόμηση μπαταρίας ενεργοποιεί το Σκούρο θέμα, περιορίζει τη δραστηριότητα στο παρασκήνιο και καθυστερεί τις ειδοποιήσεις."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Απομένουν <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Δεν είναι δυνατή η φόρτιση μέσω USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Χρησιμοποιήστε τον φορτιστή που συνοδεύει τη συσκευή σας"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Να ενεργοποιηθεί η Εξοικονόμηση μπαταρίας;"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Σχετικά με την Εξοικονόμηση μπαταρίας"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Ενεργοποίηση"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Ενεργοποίηση Εξοικονόμησης μπαταρίας"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Ενεργοποίηση"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Όχι, ευχαριστώ"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Αυτόματη περιστροφή οθόνης"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Να επιτρέπεται η πρόσβαση της εφαρμογής <xliff:g id="APPLICATION">%1$s</xliff:g> στη συσκευή <xliff:g id="USB_DEVICE">%2$s</xliff:g>;"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Να επιτρέπεται στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g> να έχει πρόσβαση στη συσκευή <xliff:g id="USB_DEVICE">%2$s</xliff:g>;\nΔεν έχει εκχωρηθεί άδεια εγγραφής σε αυτήν την εφαρμογή, αλλά μέσω αυτής της συσκευής USB θα μπορεί να εγγράφει ήχο."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Έγινε έλεγχος ταυτότητας προσώπου"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Επιβεβαιώθηκε"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Πατήστε Επιβεβαίωση για ολοκλήρωση"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Ξεκλειδώθηκε με το πρόσωπό σας. Πατήστε για συνέχεια."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Ολοκληρώθηκε ο έλεγχος ταυτότητας"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Χρήση PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Χρήση μοτίβου"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Εάν εισαγάγετε εσφαλμένο μοτίβο στην επόμενη προσπάθεια, το προφίλ εργασίας σας και τα δεδομένα του θα διαγραφούν."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Εάν εισαγάγετε εσφαλμένο PIN στην επόμενη προσπάθεια, το προφίλ εργασίας σας και τα δεδομένα του θα διαγραφούν."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Εάν εισαγάγετε εσφαλμένο κωδικό πρόσβασης στην επόμενη προσπάθεια, το προφίλ εργασίας σας και τα δεδομένα του θα διαγραφούν."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Πάρα πολλές ανεπιτυχείς προσπάθειες. Τα δεδομένα αυτής της συσκευής θα διαγραφούν."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Πάρα πολλές ανεπιτυχείς προσπάθειες. Αυτός ο χρήστης θα διαγραφεί."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Πάρα πολλές ανεπιτυχείς προσπάθειες. Αυτό το προφίλ εργασίας και τα δεδομένα του θα διαγραφούν."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Παράβλεψη"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Αγγίξτε τον αισθητήρα δακτυλικού αποτυπώματος"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Εικονίδιο δακτυλικών αποτυπωμάτων"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Το πρόσωπο δεν αναγνωρίζεται. Χρησιμ. δακτ. αποτ."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Αργή φόρτιση • Πλήρης φόρτιση σε <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Βάση φόρτισης • Πλήρης φόρτιση σε <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Εναλλαγή χρήστη"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Προσθήκη χρήστη"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Νέος χρήστης"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Κατάργηση επισκέπτη;"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Όλες οι εφαρμογές και τα δεδομένα αυτής της περιόδου σύνδεσης θα διαγραφούν."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Κατάργηση"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Kαλώς ορίσατε ξανά!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Θέλετε να συνεχίσετε την περίοδο σύνδεσής σας;"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Έναρξη από την αρχή"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ναι, συνέχεια"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Προσθήκη νέου χρήστη;"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Κατά την προσθήκη ενός νέου χρήστη, αυτός θα πρέπει να ρυθμίσει τον χώρο του.\n\nΟποιοσδήποτε χρήστης μπορεί να ενημερώσει τις εφαρμογές για όλους τους άλλους χρήστες."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Συμπληρώθηκε το όριο χρηστών"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">Μπορείτε να προσθέσετε έως <xliff:g id="COUNT">%d</xliff:g> χρήστες.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ξεκλείδωμα για χρήση"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Παρουσιάστηκε πρόβλημα με τη λήψη των καρτών σας. Δοκιμάστε ξανά αργότερα"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Ρυθμίσεις κλειδώματος οθόνης"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"Κωδικός QR"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Πατήστε για σάρωση"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Σάρωση κωδικού QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Προφίλ εργασίας"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Λειτουργία πτήσης"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Δεν θα ακούσετε το επόμενο ξυπνητήρι σας <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Σύρετε για να δείτε περισσότερα."</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Φόρτωση προτάσεων"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Μέσα"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Απόκρυψη αυτής της περιόδου λειτουργίας μέσου;"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Αδυναμία απόκρ. τρέχουσας περιόδ. λειτουργ. μέσου."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Παράβλεψη"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Απόκρυψη"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Συνέχιση"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Ρυθμίσεις"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Γίνεται αναπαραγωγή του <xliff:g id="SONG_NAME">%1$s</xliff:g> από <xliff:g id="ARTIST_NAME">%2$s</xliff:g> στην εφαρμογή <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string>
@@ -808,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Μετακινηθείτε πιο κοντά στη συσκευή <xliff:g id="DEVICENAME">%1$s</xliff:g> για αναπαραγωγή εδώ"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Αναπαραγωγή στη συσκευή <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Αναπαραγωγή σε αυτό το τηλέφωνο"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Παρουσιάστηκε κάποιο πρόβλημα"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"Παρουσιάστηκε κάποιο πρόβλημα. Δοκιμάστε ξανά."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Ανενεργό, έλεγχος εφαρμογής"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Δεν βρέθηκε."</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Μη διαθέσιμο στοιχείο ελέγχου"</string>
@@ -827,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Σύζευξη νέας συσκευής"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Για μετάδοση της περιόδου σύνδεσης, ανοίξτε την εφαρμογή."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Άγνωστη εφαρμογή"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Διακοπή μετάδοσης"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Αριθμός έκδοσης"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Ο αριθμός έκδοσης αντιγράφηκε στο πρόχειρο."</string>
     <string name="basic_status" msgid="2315371112182658176">"Άνοιγμα συνομιλίας"</string>
@@ -916,7 +905,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Το Wi‑Fi δεν είναι διαθέσιμο"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Λειτουργία προτεραιότητας"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Το ξυπνητήρι ρυθμίστηκε"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Η λειτουργία επισκέπτη του Βοηθού ενεργοποιήθηκε"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Η κάμερα και το μικρόφωνο έχουν απενεργοποιηθεί"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ειδοποίηση}other{# ειδοποιήσεις}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index fcbe0a6..10fcd34 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -29,7 +29,8 @@
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Turn on Battery Saver?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"About Battery Saver"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Turn on"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Turn on Battery Saver"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Turn on"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"No thanks"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Auto-rotate screen"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Allow <xliff:g id="APPLICATION">%1$s</xliff:g> to access <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Allow <xliff:g id="APPLICATION">%1$s</xliff:g> to access <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nThis app has not been granted record permission but could capture audio through this USB device."</string>
@@ -130,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Face authenticated"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmed"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tap Confirm to complete"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Unlocked by your face. Press to continue."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authenticated"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Use PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Use pattern"</string>
@@ -151,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"If you enter an incorrect pattern on the next attempt, your work profile and its data will be deleted."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"If you enter an incorrect PIN on the next attempt, your work profile and its data will be deleted."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"If you enter an incorrect password on the next attempt, your work profile and its data will be deleted."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Too many incorrect attempts. This device’s data will be deleted."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Too many incorrect attempts. This user will be deleted."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Too many incorrect attempts. This work profile and its data will be deleted."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Dismiss"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Touch the fingerprint sensor"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Fingerprint icon"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string>
@@ -323,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging slowly • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging dock • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Add user"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"New user"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remove guest?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remove"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welcome back, guest!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Do you want to continue your session?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start again"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Yes, continue"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Add new user?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"When you add a new user, that person needs to set up their space.\n\nAny user can update apps for all other users."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"User limit reached"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">You can add up to <xliff:g id="COUNT">%d</xliff:g> users.</item>
@@ -459,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Unlock to use"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"There was a problem getting your cards. Please try again later."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lock screen settings"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR code"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Tap to scan"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Scan QR code"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Work profile"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Aeroplane mode"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"You won\'t hear your next alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -785,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe to see more"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Media"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Hide this media session?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"The current media session cannot be hidden."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dismiss"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Hide"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> is playing from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -805,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g> to play here"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Playing on this phone"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Something went wrong"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
@@ -824,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"To cast this session, please open the app."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Unknown app"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stop casting"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
     <string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
@@ -910,15 +902,9 @@
     <string name="add" msgid="81036585205287996">"Add"</string>
     <string name="manage_users" msgid="1823875311934643849">"Manage users"</string>
     <string name="drag_split_not_supported" msgid="4326847447699729722">"This notification does not support dragging to Split screen."</string>
-    <!-- no translation found for dream_overlay_status_bar_wifi_off (4497069245055003582) -->
-    <skip />
-    <!-- no translation found for dream_overlay_status_bar_priority_mode (5428462123314728739) -->
-    <skip />
-    <!-- no translation found for dream_overlay_status_bar_alarm_set (566707328356590886) -->
-    <skip />
-    <!-- no translation found for dream_overlay_status_bar_assistant_guest_mode_enabled (3715897096012469615) -->
-    <skip />
-    <!-- no translation found for dream_overlay_status_bar_camera_mic_off (3199425257833773569) -->
-    <skip />
+    <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi unavailable"</string>
+    <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Priority mode"</string>
+    <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string>
+    <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera and mic are off"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}other{# notifications}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 2e6514a..6289676 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -29,7 +29,8 @@
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Turn on Battery Saver?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"About Battery Saver"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Turn on"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Turn on Battery Saver"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Turn on"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"No thanks"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Auto-rotate screen"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Allow <xliff:g id="APPLICATION">%1$s</xliff:g> to access <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Allow <xliff:g id="APPLICATION">%1$s</xliff:g> to access <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nThis app has not been granted record permission but could capture audio through this USB device."</string>
@@ -130,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Face authenticated"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmed"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tap Confirm to complete"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Unlocked by your face. Press to continue."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authenticated"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Use PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Use pattern"</string>
@@ -151,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"If you enter an incorrect pattern on the next attempt, your work profile and its data will be deleted."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"If you enter an incorrect PIN on the next attempt, your work profile and its data will be deleted."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"If you enter an incorrect password on the next attempt, your work profile and its data will be deleted."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Too many incorrect attempts. This device’s data will be deleted."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Too many incorrect attempts. This user will be deleted."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Too many incorrect attempts. This work profile and its data will be deleted."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Dismiss"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Touch the fingerprint sensor"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Fingerprint icon"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string>
@@ -323,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging slowly • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging dock • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Add user"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"New user"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remove guest?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remove"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welcome back, guest!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Do you want to continue your session?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start again"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Yes, continue"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Add new user?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"When you add a new user, that person needs to set up their space.\n\nAny user can update apps for all other users."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"User limit reached"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">You can add up to <xliff:g id="COUNT">%d</xliff:g> users.</item>
@@ -459,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Unlock to use"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"There was a problem getting your cards. Please try again later."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lock screen settings"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR code"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Tap to scan"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Scan QR code"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Work profile"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Airplane mode"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"You won\'t hear your next alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -785,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe to see more"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Media"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Hide this media session?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"The current media session cannot be hidden."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dismiss"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Hide"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> is playing from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -805,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g> to play here"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Playing on this phone"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Something went wrong"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
@@ -824,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"To cast this session, please open the app."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Unknown app"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stop casting"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
     <string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
@@ -910,15 +902,9 @@
     <string name="add" msgid="81036585205287996">"Add"</string>
     <string name="manage_users" msgid="1823875311934643849">"Manage users"</string>
     <string name="drag_split_not_supported" msgid="4326847447699729722">"This notification does not support dragging to Split screen."</string>
-    <!-- no translation found for dream_overlay_status_bar_wifi_off (4497069245055003582) -->
-    <skip />
-    <!-- no translation found for dream_overlay_status_bar_priority_mode (5428462123314728739) -->
-    <skip />
-    <!-- no translation found for dream_overlay_status_bar_alarm_set (566707328356590886) -->
-    <skip />
-    <!-- no translation found for dream_overlay_status_bar_assistant_guest_mode_enabled (3715897096012469615) -->
-    <skip />
-    <!-- no translation found for dream_overlay_status_bar_camera_mic_off (3199425257833773569) -->
-    <skip />
+    <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi unavailable"</string>
+    <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Priority mode"</string>
+    <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string>
+    <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera and mic are off"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}other{# notifications}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index fcbe0a6..10fcd34 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -29,7 +29,8 @@
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Turn on Battery Saver?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"About Battery Saver"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Turn on"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Turn on Battery Saver"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Turn on"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"No thanks"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Auto-rotate screen"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Allow <xliff:g id="APPLICATION">%1$s</xliff:g> to access <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Allow <xliff:g id="APPLICATION">%1$s</xliff:g> to access <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nThis app has not been granted record permission but could capture audio through this USB device."</string>
@@ -130,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Face authenticated"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmed"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tap Confirm to complete"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Unlocked by your face. Press to continue."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authenticated"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Use PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Use pattern"</string>
@@ -151,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"If you enter an incorrect pattern on the next attempt, your work profile and its data will be deleted."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"If you enter an incorrect PIN on the next attempt, your work profile and its data will be deleted."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"If you enter an incorrect password on the next attempt, your work profile and its data will be deleted."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Too many incorrect attempts. This device’s data will be deleted."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Too many incorrect attempts. This user will be deleted."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Too many incorrect attempts. This work profile and its data will be deleted."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Dismiss"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Touch the fingerprint sensor"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Fingerprint icon"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string>
@@ -323,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging slowly • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging dock • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Add user"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"New user"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remove guest?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remove"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welcome back, guest!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Do you want to continue your session?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start again"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Yes, continue"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Add new user?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"When you add a new user, that person needs to set up their space.\n\nAny user can update apps for all other users."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"User limit reached"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">You can add up to <xliff:g id="COUNT">%d</xliff:g> users.</item>
@@ -459,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Unlock to use"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"There was a problem getting your cards. Please try again later."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lock screen settings"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR code"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Tap to scan"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Scan QR code"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Work profile"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Aeroplane mode"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"You won\'t hear your next alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -785,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe to see more"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Media"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Hide this media session?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"The current media session cannot be hidden."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dismiss"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Hide"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> is playing from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -805,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g> to play here"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Playing on this phone"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Something went wrong"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
@@ -824,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"To cast this session, please open the app."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Unknown app"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stop casting"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
     <string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
@@ -910,15 +902,9 @@
     <string name="add" msgid="81036585205287996">"Add"</string>
     <string name="manage_users" msgid="1823875311934643849">"Manage users"</string>
     <string name="drag_split_not_supported" msgid="4326847447699729722">"This notification does not support dragging to Split screen."</string>
-    <!-- no translation found for dream_overlay_status_bar_wifi_off (4497069245055003582) -->
-    <skip />
-    <!-- no translation found for dream_overlay_status_bar_priority_mode (5428462123314728739) -->
-    <skip />
-    <!-- no translation found for dream_overlay_status_bar_alarm_set (566707328356590886) -->
-    <skip />
-    <!-- no translation found for dream_overlay_status_bar_assistant_guest_mode_enabled (3715897096012469615) -->
-    <skip />
-    <!-- no translation found for dream_overlay_status_bar_camera_mic_off (3199425257833773569) -->
-    <skip />
+    <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi unavailable"</string>
+    <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Priority mode"</string>
+    <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string>
+    <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera and mic are off"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}other{# notifications}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index fcbe0a6..10fcd34 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -29,7 +29,8 @@
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Turn on Battery Saver?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"About Battery Saver"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Turn on"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Turn on Battery Saver"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Turn on"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"No thanks"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Auto-rotate screen"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Allow <xliff:g id="APPLICATION">%1$s</xliff:g> to access <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Allow <xliff:g id="APPLICATION">%1$s</xliff:g> to access <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nThis app has not been granted record permission but could capture audio through this USB device."</string>
@@ -130,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Face authenticated"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmed"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tap Confirm to complete"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Unlocked by your face. Press to continue."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authenticated"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Use PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Use pattern"</string>
@@ -151,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"If you enter an incorrect pattern on the next attempt, your work profile and its data will be deleted."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"If you enter an incorrect PIN on the next attempt, your work profile and its data will be deleted."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"If you enter an incorrect password on the next attempt, your work profile and its data will be deleted."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Too many incorrect attempts. This device’s data will be deleted."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Too many incorrect attempts. This user will be deleted."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Too many incorrect attempts. This work profile and its data will be deleted."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Dismiss"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Touch the fingerprint sensor"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Fingerprint icon"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string>
@@ -323,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging slowly • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging dock • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Add user"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"New user"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remove guest?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remove"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welcome back, guest!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Do you want to continue your session?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start again"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Yes, continue"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Add new user?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"When you add a new user, that person needs to set up their space.\n\nAny user can update apps for all other users."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"User limit reached"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">You can add up to <xliff:g id="COUNT">%d</xliff:g> users.</item>
@@ -459,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Unlock to use"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"There was a problem getting your cards. Please try again later."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lock screen settings"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR code"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Tap to scan"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Scan QR code"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Work profile"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Aeroplane mode"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"You won\'t hear your next alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -785,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe to see more"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Media"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Hide this media session?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"The current media session cannot be hidden."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dismiss"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Hide"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> is playing from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -805,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g> to play here"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Playing on this phone"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Something went wrong"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
@@ -824,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"To cast this session, please open the app."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Unknown app"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stop casting"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
     <string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
@@ -910,15 +902,9 @@
     <string name="add" msgid="81036585205287996">"Add"</string>
     <string name="manage_users" msgid="1823875311934643849">"Manage users"</string>
     <string name="drag_split_not_supported" msgid="4326847447699729722">"This notification does not support dragging to Split screen."</string>
-    <!-- no translation found for dream_overlay_status_bar_wifi_off (4497069245055003582) -->
-    <skip />
-    <!-- no translation found for dream_overlay_status_bar_priority_mode (5428462123314728739) -->
-    <skip />
-    <!-- no translation found for dream_overlay_status_bar_alarm_set (566707328356590886) -->
-    <skip />
-    <!-- no translation found for dream_overlay_status_bar_assistant_guest_mode_enabled (3715897096012469615) -->
-    <skip />
-    <!-- no translation found for dream_overlay_status_bar_camera_mic_off (3199425257833773569) -->
-    <skip />
+    <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi unavailable"</string>
+    <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Priority mode"</string>
+    <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string>
+    <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera and mic are off"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}other{# notifications}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index f05e75b..aef122a 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -29,7 +29,8 @@
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‎‎‎‏‏‏‎‎‏‏‎‎‎‏‎‎‎‏‏‏‏‎‎‏‏‏‎‎‎‎‎‎‎‎‏‏‏‎‏‎‏‎‏‏‏‏‎‏‏‎‏‎‏‎Turn on Battery Saver?‎‏‎‎‏‎"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‎‎‏‏‎‎‏‏‎‏‏‏‏‎‎‎‎‏‎‎‎‎‎‏‎‎‏‏‏‎‏‎‏‎‏‏‏‏‏‎‏‎‎‏‎About Battery Saver‎‏‎‎‏‎"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‏‏‏‎‎‏‎‏‎‎‎‏‎‎‎‏‏‎‏‎‎‏‎‏‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‎‎‏‏‎‎‏‏‏‏‎‏‏‏‎‎Turn on‎‏‎‎‏‎"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‎‎‎‎‎‏‏‎‏‎‏‎‎‎‏‏‏‎‎‏‎‏‏‎‎‎‎‏‎‎‎‎‏‏‎‎‏‎‏‎‎‎‏‏‏‏‏‏‎‎‎‏‎Turn on Battery Saver‎‏‎‎‏‎"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‎‏‎‏‏‎‎‏‏‏‎‏‏‎‏‏‏‎‎‏‎‎‎‎‎‏‎‏‎‎‎‏‎‎‏‎‎‏‎‎‏‎‎‎Turn on‎‏‎‎‏‎"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‏‏‏‎‏‏‎‏‎‏‏‎‏‏‏‎‏‎‏‏‎‎‏‎‎‏‎‎No thanks‎‏‎‎‏‎"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‏‎‏‎‎‎‏‎‎‎‎‏‏‎‏‎‏‏‏‎‏‎‏‎‎‎‏‏‎‎‏‎‏‏‏‏‎‏‏‏‎‎‎Auto-rotate screen‎‏‎‎‏‎"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‎‎‏‎‎‎‎‏‏‏‎‏‏‏‎‎‏‎‎‎‎‏‏‏‎‏‏‎‏‎‎‎‏‏‎‏‎‎‏‎‎‏‏‎‎‎‏‎‎‏‏‎‎‎Allow ‎‏‎‎‏‏‎<xliff:g id="APPLICATION">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to access ‎‏‎‎‏‏‎<xliff:g id="USB_DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‎‎‏‎‏‏‏‎‏‎‏‏‎‏‎‏‎‎‏‏‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‎‏‎‎‎‎Allow ‎‏‎‎‏‏‎<xliff:g id="APPLICATION">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to access ‎‏‎‎‏‏‎<xliff:g id="USB_DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎This app has not been granted record permission but could capture audio through this USB device.‎‏‎‎‏‎"</string>
@@ -130,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‎‎‏‏‏‎‏‏‎‎‎‏‎‏‎‏‎‏‏‏‎‎‎‎‎‎‏‏‎‎‎‏‏‏‎‎‏‎‎‏‏‏‎‎‎‎Face authenticated‎‏‎‎‏‎"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‎‏‎‏‎‏‎‎‎‎‎‏‏‏‎‎‎‏‏‏‎‎‎‎‏‏‏‎‎‎‎‎‎‏‏‏‎‏‏‎‏‎‏‎‎‏‎‏‎‏‎‎Confirmed‎‏‎‎‏‎"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎‏‏‎‏‏‏‎‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‏‎‏‏‎‎‎‎‏‎‏‏‏‏‏‎‎Tap Confirm to complete‎‏‎‎‏‎"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‏‏‎‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‎‎‎‎‏‏‏‎‎‏‏‏‎‏‏‎‎‎‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‎‎Unlocked by your face. Press to continue.‎‏‎‎‏‎"</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‎‎‏‎‏‏‎‎‏‎‎‎‏‎‎‏‏‏‏‎‏‏‎‏‏‎‏‏‎‎‎‎‏‎‏‎‏‏‏‎‏‎‎‎‏‎‏‎‎‏‎‎‎Authenticated‎‏‎‎‏‎"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‎‎‎‏‏‎‎‏‎‎‏‎‎‏‎‎‎‎‏‎‏‏‎‏‎‎‏‏‏‎‏‏‏‎‏‏‏‎‏‏‎‎‎‎‏‎‏‎Use PIN‎‏‎‎‏‎"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‏‎‎‎‏‎‏‎‏‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‎‏‎‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‎‏‎‏‎‏‏‏‎‏‎‎Use pattern‎‏‎‎‏‎"</string>
@@ -151,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‎‎‏‎‎‏‏‏‏‎‎‏‏‎‏‎‎‎‎‏‏‎‎‏‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎‎‎‎‏‎‎‏‏‏‎‎If you enter an incorrect pattern on the next attempt, your work profile and its data will be deleted.‎‏‎‎‏‎"</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‏‏‏‎‏‏‎‏‏‏‏‎‎‏‎‎‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎If you enter an incorrect PIN on the next attempt, your work profile and its data will be deleted.‎‏‎‎‏‎"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‎‏‎‎‏‎‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎If you enter an incorrect password on the next attempt, your work profile and its data will be deleted.‎‏‎‎‏‎"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎‎‏‎‎‎‏‏‎‏‎‎‎‏‎‎‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‎‏‎‏‎‏‏‎‏‎‏‏‏‏‏‏‎‎‎‏‎‎Too many incorrect attempts. This device’s data will be deleted.‎‏‎‎‏‎"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‏‏‎‏‎‎‏‎‏‎‎‎‏‎‎‎‏‏‎‎‏‎‏‏‎‏‎‎‎‎‎‏‎‏‏‏‏‏‎‎‏‎‎‎‏‏‏‏‏‏‎‏‏‎Too many incorrect attempts. This user will be deleted.‎‏‎‎‏‎"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‎‏‏‎‏‏‎‎‎‎‎‎‎‏‏‎‎‎‎‎‎‎‏‎‏‏‏‏‏‏‎‎‏‎‎‏‎‎‏‏‎‎‎‏‎‎‎‎‏‏‏‎‎‏‎‎Too many incorrect attempts. This work profile and its data will be deleted.‎‏‎‎‏‎"</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‎‏‏‏‎‎‏‏‏‎‎‏‎‏‎‎‎‏‏‎‏‎‏‏‏‏‏‎‏‎‏‎‎Dismiss‎‏‎‎‏‎"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‎‏‏‎‏‏‎‎‏‎‎‏‎‏‎‏‏‎‎‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‎‏‎‏‎‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎Touch the fingerprint sensor‎‏‎‎‏‎"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‏‏‎‎‏‎‎‏‏‏‎‏‎‎‏‎‎‏‏‎‏‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‎‏‎‏‎Fingerprint icon‎‏‎‎‏‎"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‏‏‎‏‎‏‏‏‏‎‏‎‎‏‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‎‏‎‏‎‎‏‏‎‎‎‏‎‎‎‏‎‎‎Can’t recognize face. Use fingerprint instead.‎‏‎‎‏‎"</string>
@@ -323,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‎‎‏‏‎‎‎‎‏‎‏‏‎‎‏‎‎‎‎‎‏‏‏‎‎‏‎‏‏‎‎‏‎‏‎‏‎‎‏‎‏‏‎‎‎‎‏‎‎‏‎‎‏‎‎‏‎‎‏‎‎‏‏‎<xliff:g id="PERCENTAGE">%2$s</xliff:g>‎‏‎‎‏‏‏‎ • Charging slowly • Full in ‎‏‎‎‏‏‎<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‏‏‎‏‎‏‎‏‎‎‎‎‎‎‎‎‏‏‏‎‏‏‏‏‎‎‏‏‏‏‎‎‏‎‎‎‏‎‎‏‎‎‎‏‎‏‏‎‎‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="PERCENTAGE">%2$s</xliff:g>‎‏‎‎‏‏‏‎ • Charging Dock • Full in ‎‏‎‎‏‏‎<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‏‏‎‎‏‏‎‎‎‏‏‏‎‏‎‎‎‎‏‏‎‎‏‎‎‎‎‎‏‏‏‎‏‎‏‏‏‎‏‏‏‎‎‎‎‏‎‏‏‎‏‎‎‎Switch user‎‏‎‎‏‎"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‎‎‏‎‏‏‏‎‏‏‏‎‎‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‏‎‏‎‏‏‎‎‏‏‏‏‎‎‎‎‎‏‏‏‏‏‏‏‏‎‎Add user‎‏‎‎‏‎"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‎‎‎‎‎‏‎‏‏‎‎‎‎‏‎‏‎‎‎‎‏‎‎‏‎‎‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‎‏‎‎‎‎‏‏‎‎‏‏‎‏‎New user‎‏‎‎‏‎"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‏‏‎‏‏‎‏‎‏‎‏‏‎‎‏‎‏‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‎‎‏‏‏‎‎Remove guest?‎‏‎‎‏‎"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‎‎‏‎‏‏‏‎‏‎‏‎‏‎‏‎‎‎‎‎‏‎‎‏‎‏‏‎‎‏‏‎‏‎‎‏‏‏‎‏‏‏‏‎‏‎‏‏‏‎‏‎All apps and data in this session will be deleted.‎‏‎‎‏‎"</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‏‎‏‎‎‎‎‎‎‏‎‏‎‏‎‏‎‏‎‎‏‏‏‎‏‎‏‎‏‏‏‎‎‏‏‎‎‏‎‎‎‎‏‏‏‎‎‎‏‏‎‏‎Remove‎‏‎‎‏‎"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‏‎‎‏‎‏‎‏‎‏‏‎‏‎‎‎‎‏‎‎‏‎‏‏‏‎‎‏‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‎‎‎Welcome back, guest!‎‏‎‎‏‎"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‎‏‏‎‎‏‎‏‎‎‏‎‎‎‏‎‎‏‎‏‏‏‏‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‎‎‏‎‏‏‏‏‏‎‎‎‏‎Do you want to continue your session?‎‏‎‎‏‎"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‏‏‏‎‏‎‎‎‏‎‎‎‏‎‏‏‏‏‏‏‎‎‎‏‎‏‎‎‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‎‎‏‏‏‎‏‎Start over‎‏‎‎‏‎"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‏‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‎‏‏‎‎‏‏‎‏‎‎‎‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‏‎‎‎‏‏‎‏‎Yes, continue‎‏‎‎‏‎"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‎‏‏‏‎‎‎‏‎‏‎‏‏‏‎‎‏‎‏‏‎‎‎‎‎‏‎‏‏‏‏‏‏‎‎‏‎‏‎‏‎‏‏‎‏‏‎‎‏‎‎‎‎Add new user?‎‏‎‎‏‎"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‎‏‎‎‏‎‏‏‎‏‎‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‎‎‎‎‏‏‎‎‎‏‎‎‎‏‎‎‏‏‏‏‎‏‎‎‎‏‏‏‎When you add a new user, that person needs to set up their space.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Any user can update apps for all other users.‎‏‎‎‏‎"</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‏‎‏‏‎‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‎‎‎‎‎‎‏‎‎‏‏‏‎‏‏‏‎‎‏‏‎‏‏‎‎‎‏‏‎‏‎‎‏‎‎‏‎User limit reached‎‏‎‎‏‎"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‏‏‎‏‏‏‎‎‎‎‏‎‎‏‎‎‏‎‏‎‎‏‏‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‏‎‏‏‏‎‎You can add up to ‎‏‎‎‏‏‎<xliff:g id="COUNT">%d</xliff:g>‎‏‎‎‏‏‏‎ users.‎‏‎‎‏‎</item>
@@ -459,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‎‏‎‏‎‎‎‏‎‏‏‎‏‏‎‎‎‏‎‏‎‏‎‏‏‎‎‎‎‎‎‏‏‎‎‏‏‏‎‏‎‏‏‏‏‎‏‎‎‎‏‎‏‎‎Unlock to use‎‏‎‎‏‎"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‏‏‎‎‎‏‏‎‎‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‏‎‎‎‎‎‎‎‎‎‏‎‎‎‏‏‎‎‏‏‎‏‏‎There was a problem getting your cards, please try again later‎‏‎‎‏‎"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‎‏‏‏‎‏‎‏‏‎‏‏‎‏‏‎‎‎‎‏‎‏‎‎‏‎‏‎‎‏‎‎‎‏‎‏‎‎‏‏‎‎‎‏‏‏‏‏‎‏‎‎‏‎‎Lock screen settings‎‏‎‎‏‎"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‎‎‏‏‏‏‎‏‎‎‎‏‏‎‎‏‎‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‏‏‏‎‏‏‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‎QR code‎‏‎‎‏‎"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‎‎‎‎‎‎‎‏‎‎‎‏‎‎‏‎‏‎‎‎‎‎‏‎‎‏‎‏‏‏‏‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎Tap to scan‎‏‎‎‏‎"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‏‏‎‏‎‏‎‏‎‎‏‎‎‎‏‏‏‎‏‎‏‎‎‎‏‏‎‏‏‏‎‏‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‎‏‎Scan QR code‎‏‎‎‏‎"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‎‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‎‎‏‏‎‎‏‎‎‎‎‏‏‎‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‎‎‎‎Work profile‎‏‎‎‏‎"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‎‎‏‎‏‎‎‎‎‎‏‏‎‏‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‎‎‏‎Airplane mode‎‏‎‎‏‎"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‏‏‎‎‏‎‎‏‎‎‎‎‎‎‏‏‏‏‎‎‎‎‎‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎You won\'t hear your next alarm ‎‏‎‎‏‏‎<xliff:g id="WHEN">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
@@ -785,9 +775,9 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‎‏‏‏‎‎‏‏‎‏‎‏‏‎‎‎‎‎‏‎‏‏‏‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‏‏‎‏‎‏‏‏‏‎‏‏‎Swipe to see more‎‏‎‎‏‎"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‏‏‎‏‎‎‏‏‎‏‎‏‏‎‏‎‏‏‎‏‏‏‏‏‎‎‏‎‎‏‎‏‎‏‏‏‎‎‎‏‎‎‏‎‎‎‏‎‏‎‏‎‎‎Loading recommendations‎‏‎‎‏‎"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‏‏‏‎‏‎‎‏‏‎‎‏‏‎‎‎‎‏‏‏‎‎‏‎‏‏‎‏‎‎‎‎‏‎‏‎‎‎‎‎‏‎‏‎Media‎‏‎‎‏‎"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‎‏‏‏‎‎‏‏‎‎‎‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‏‎‏‎‏‎‎‎‏‎‎‎‏‏‎‎‎Hide this media session?‎‏‎‎‏‎"</string>
+    <string name="controls_media_close_session" msgid="4780485355795635052">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‎‏‎‏‏‏‏‎‏‏‎‎‏‎‎‎‎‏‏‎‏‎‎‏‎‏‏‏‏‎‎‎‏‎‎‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎‏‏‎‎‎Hide this media control for ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
     <string name="controls_media_active_session" msgid="3146882316024153337">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‏‏‎‎‏‎‎‏‎‎‏‎‎‏‎‏‎‎‎‎‎‎‎‏‎‎‏‏‏‏‏‎‎‏‎The current media session cannot be hidden.‎‏‎‎‏‎"</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‏‏‎‎‎‎‏‏‎‏‏‏‏‎‎‎‎‏‏‎‎‎‏‎‎‏‎‏‎‎‎‏‎‎‎‏‏‎‏‎‎‏‎‏‏‎‏‎‏‎Dismiss‎‏‎‎‏‎"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎‎‎‎‎‎‎‏‎‏‎‎‏‎‎‏‎‎‎‏‏‎‏‏‎‏‎‎‏‏‎‏‎‏‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‎Hide‎‏‎‎‏‎"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‏‎‏‎‏‎‎‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‏‏‏‏‎‎‎‏‏‎‎‏‎‏‎‎‏‎‎‎‏‏‏‎‎‎‎‏‎‏‎Resume‎‏‎‎‏‎"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‏‎‏‏‏‎‏‎‏‏‎‏‎‎‎‎‎‎‏‎‏‏‎‏‎‎‎‏‏‎‏‏‎‏‏‎‎‎‎‎‎‏‏‎‎‎‏‏‎‎‎‎Settings‎‏‎‎‏‎"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‏‏‎‎‎‎‎‏‎‎‏‎‎‏‏‎‏‏‏‎‏‏‎‎‏‏‎‎‏‎‏‎‎‎‏‏‏‏‎‏‎‏‏‏‎‏‎‎‎‏‎‎‏‏‎<xliff:g id="SONG_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ by ‎‏‎‎‏‏‎<xliff:g id="ARTIST_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎ is playing from ‎‏‎‎‏‏‎<xliff:g id="APP_LABEL">%3$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
@@ -805,7 +795,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‎‏‏‎‎‎‎‏‏‎‎‏‎‏‎‎‏‏‏‏‎‏‎‎‏‏‎‏‏‏‎‎‎‏‏‏‏‎‏‏‎‏‎‏‎‏‎‎‏‎‎‎‎Move closer to ‎‏‎‎‏‏‎<xliff:g id="DEVICENAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to play here‎‏‎‎‏‎"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‏‏‎‎‏‎‏‎‏‎‏‎‎‏‎‏‎‎‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‏‏‏‎‏‏‎‎‎‏‏‎‎‎‎‏‎‏‎‎Playing on ‎‏‎‎‏‏‎<xliff:g id="DEVICENAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‎‎‏‎‏‎‎‎‎‎‎‎‎‎‎‏‏‏‏‎‏‏‏‎‏‎‎‎‎‎‎‎‏‏‎‎‎‏‏‏‏‎‏‎‎‏‏‏‎‎‏‎‎‎Playing on this phone‎‏‎‎‏‎"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‏‎‎‏‎‎‎‏‏‎‏‏‎‎‎‏‏‎‎‎‎‏‎‏‎‎‏‎‎‎‏‎‎‎‎‎‎‎‏‏‎‎‏‎‎‎‎‏‎‎‎‎‏‏‎Something went wrong‎‏‎‎‏‎"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‏‏‎‎‎‏‏‎‎‏‎‎‏‏‎‎‎‎‏‏‏‎‎‏‏‏‏‏‎‎‎‎‎‏‎‏‎‏‏‎‏‎‏‏‎‎‏‎‏‏‎Something went wrong. Try again.‎‏‎‎‏‎"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‎‎‎‎‏‎‏‏‎‎‎‏‏‏‎‎‎‏‏‏‎‏‎‎‎‏‎‏‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‏‏‏‏‏‏‎‎Inactive, check app‎‏‎‎‏‎"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‎‏‎‎‏‎‏‎‎‎‎‏‎‏‏‏‎‏‎‎‏‎‎‏‏‎‏‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‏‏‏‎‎Not found‎‏‎‎‏‎"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‏‎‎‏‎‏‎‎‎‎‎‏‎‏‎‎‏‎‎‎‎‏‎‎‏‏‎‎‏‎‏‎‎Control is unavailable‎‏‎‎‏‎"</string>
@@ -824,6 +814,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‏‎‏‎‏‏‎‎‏‏‎‎‎‏‎‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‎‏‏‎‎Pair new device‎‏‎‎‏‎"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎‏‎‎‏‏‏‎‏‏‎‎‏‎‏‎‎‏‎‎‏‎‏‎‏‎‏‏‏‏‎‎‏‏‎‏‎‎‎‎‏‏‎‎‎‎‏‎‎‏‏‎To cast this session, please open the app.‎‏‎‎‏‎"</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‏‎‏‏‎‎‎‏‏‎‎‎‏‎‏‎‎‎‎‏‏‏‎‎‎‏‎‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‎Unknown app‎‏‎‎‏‎"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‏‎‏‎‏‏‏‎‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‏‏‎‎‏‎‎‏‎‏‏‎‏‎‏‎‏‎‎‎‎‎‏‎‎‏‎‏‎‏‎Stop casting‎‏‎‎‏‎"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‏‎‎‎‎‎‎‏‏‏‎‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‎‎‏‎‎Build number‎‏‎‎‏‎"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‎‏‎‏‏‏‎‎‏‎‎‏‎‏‎‏‎‎‎‎‏‏‏‎‎‏‎‎‎‎‎‎‎‏‏‏‎‎‏‎‏‏‏‏‎‎‎‎‏‎‎‎‏‏‎‎Build number copied to clipboard.‎‏‎‎‏‎"</string>
     <string name="basic_status" msgid="2315371112182658176">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‏‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎‎‏‎‎‏‎‏‏‎‎‎‏‏‎‏‏‎‎‏‎‎‏‏‎‏‎‎‏‎‎‎‎‎‎‎‎Open conversation‎‏‎‎‏‎"</string>
@@ -913,7 +904,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‏‎‎‎‏‏‎‎‏‏‎‎‏‎‏‎‎‏‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‏‏‎‎‏‏‎‏‎‏‏‏‎‏‏‏‏‏‎‎Wi‑Fi unavailable‎‏‎‎‏‎"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‎‏‎‎‎‏‏‏‎‎‎‏‏‎‏‎‏‏‎‎‏‎‎‏‏‏‏‎‎‏‎‎‎‏‏‎Priority mode‎‏‎‎‏‎"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‏‎‎‏‎‏‎‏‎‎‎‎‎‎‎‎‎‏‏‎‎‏‎‎‏‏‏‎‎‎‏‎‎‏‎‏‎‎‏‎‎‏‏‎‎Alarm set‎‏‎‎‏‎"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‎‏‎‎‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‎‎‎‏‎‎‏‏‏‎‏‏‎‏‏‏‎‏‎‏‎‎‏‎‏‎‏‎‏‏‎‏‏‏‏‎Assistant guest mode enabled‎‏‎‎‏‎"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‏‎‎‏‏‎‏‎‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎‎‎‏‏‎‏‎‏‎‎‏‏‎‎‎‎‎‏‏‏‎‏‎‎‎‎‎‎‎‎‏‎Camera and mic are off‎‏‎‎‏‎"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‎‏‎‎‏‏‎‎‎‏‏‏‎‏‎‏‎‎‎‎‏‏‏‎‏‎‎‏‏‏‎‎‎‎‏‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‎# notification‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‎‏‎‎‏‏‎‎‎‏‏‏‎‏‎‏‎‎‎‎‏‏‏‎‏‎‎‏‏‏‎‎‎‎‏‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‎# notifications‎‏‎‎‏‎}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 4363ce9..4acc257 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"IU del sistema"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"¿Quieres activar el Ahorro de batería?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Tienes <xliff:g id="PERCENTAGE">%s</xliff:g> de batería restante. El Ahorro de batería activa el Tema oscuro, restringe la actividad en segundo plano y retrasa las notificaciones."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"El Ahorro de batería activa el Tema oscuro, restringe la actividad en segundo plano y retrasa las notificaciones."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería."</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"No se puede cargar mediante USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Usa el cargador que se incluyó con el dispositivo"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"¿Deseas activar Ahorro de batería?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Acerca del Ahorro de batería"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Activar"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Activar el Ahorro de batería"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Activar"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"No, gracias"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Girar la pantalla automáticamente"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"¿Deseas permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> acceda a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"¿Quieres permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> acceda a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nLa app no tiene permiso para grabar, pero podría capturar audio mediante este dispositivo USB."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Se autenticó el rostro"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmado"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Presiona Confirmar para completar"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Disp. desbloqueado con rostro. Presiona para continuar."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticado"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Usar PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Usar patrón"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Si ingresas un patrón incorrecto en el próximo intento, se borrarán tu perfil de trabajo y sus datos."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Si ingresas un PIN incorrecto en el próximo intento, se borrarán tu perfil de trabajo y sus datos."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Si ingresas una contraseña incorrecta en el próximo intento, se borrarán tu perfil de trabajo y sus datos."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Hubo demasiados intentos incorrectos. Se borrarán los datos del dispositivo."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Hubo demasiados intentos incorrectos. Se borrará este usuario."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Hubo demasiados intentos incorrectos. Se borrarán este perfil de trabajo y sus datos."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Descartar"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toca el sensor de huellas dactilares"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ícono de huella dactilar"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"No se reconoce el rostro. Usa la huella dactilar."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando lento • Se completará en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Conectado y cargando • Carga completa en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar usuario"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Agregar usuario"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Usuario nuevo"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"¿Quitar invitado?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Se eliminarán las aplicaciones y los datos de esta sesión."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Quitar"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"¡Hola de nuevo, invitado!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"¿Quieres retomar la sesión?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Volver a empezar"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Sí, continuar"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"¿Agregar usuario nuevo?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Cuando agregas un nuevo usuario, esa persona debe configurar su espacio.\n\nCualquier usuario puede actualizar las aplicaciones del resto de los usuarios."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Alcanzaste el límite de usuarios"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">Puedes agregar hasta <xliff:g id="COUNT">%d</xliff:g> usuarios.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Ocurrió un problema al obtener las tarjetas; vuelve a intentarlo más tarde"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Configuración de pantalla de bloqueo"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"Código QR"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Presiona para escanear"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Escanear código QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabajo"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Modo de avión"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"No oirás la próxima alarma a la(s) <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Desliza el dedo para ver más elementos"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Cargando recomendaciones"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Contenido multimedia"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"¿Quieres ocultar esta sesión multimedia?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"No se puede ocultar la sesión multimedia actual."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Descartar"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Reanudar"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Configuración"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Se está reproduciendo <xliff:g id="SONG_NAME">%1$s</xliff:g>, de <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Acércate a <xliff:g id="DEVICENAME">%1$s</xliff:g> para reproducir aquí"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproduciendo en <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Reproduciendo en este teléfono"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Ocurrió un error"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Verifica la app"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"No se encontró"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"El control no está disponible"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincular dispositivo nuevo"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Para transmitir esta sesión, abre la app"</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"App desconocida"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Detener transmisión"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Se copió el número de compilación en el portapapeles."</string>
     <string name="basic_status" msgid="2315371112182658176">"Conversación abierta"</string>
@@ -916,7 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"La red Wi-Fi no está disponible"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modo prioridad"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Se estableció la alarma"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Se habilitó el Modo de Invitado de Asistente"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"La cámara y el micrófono están apagados"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificación}other{# notificaciones}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 0e7be44..1a62172 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"UI del sistema"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"¿Activar Ahorro de batería?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Te queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería. Ahorro de batería activa el tema oscuro, restringe la actividad en segundo plano y retrasa las notificaciones."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Ahorro de batería activa el tema oscuro, restringe la actividad en segundo plano y retrasa las notificaciones."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"No se puede cargar por USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Utiliza el cargador original incluido con el dispositivo"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"¿Activar Ahorro de batería?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Información de Ahorro de batería"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Activar"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Activar Ahorro de batería"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Activar"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"No, gracias"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Girar pantalla automáticamente"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"¿Permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> acceda a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"¿Quieres que <xliff:g id="APPLICATION">%1$s</xliff:g> pueda acceder a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nEsta aplicación no tiene permisos para grabar, pero podría captar audio a través de este dispositivo USB."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Cara autenticada"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmada"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toca Confirmar para completar la acción"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Desbloqueada con la cara. Pulsa para continuar."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Se ha autenticado"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Usar PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Usar patrón"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Si vuelves a introducir un patrón incorrecto, tu perfil de trabajo y sus datos se eliminarán."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Si vuelves a introducir un PIN incorrecto, tu perfil de trabajo y sus datos se eliminarán."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Si vuelves a introducir una contraseña incorrecta, tu perfil de trabajo y sus datos se eliminarán."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Se han producido demasiados intentos fallidos. Los datos de este dispositivo se eliminarán."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Se han producido demasiados intentos fallidos. Este usuario se eliminará."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Se han producido demasiados intentos fallidos. Este perfil de trabajo y sus datos se eliminarán."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Cerrar"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toca el sensor de huellas digitales"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Icono de huella digital"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"No se reconoce la cara. Usa la huella digital."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carga lenta • En <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> terminará de cargarse"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Base de carga • En <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> terminará de cargar"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar de usuario"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Añadir usuario"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Nuevo usuario"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"¿Quitar invitado?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Se eliminarán todas las aplicaciones y datos de esta sesión."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Quitar"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Hola de nuevo, invitado"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"¿Quieres continuar con la sesión?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Volver a empezar"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Sí, continuar"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"¿Añadir nuevo usuario?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Al añadir un nuevo usuario, este debe configurar su espacio.\n\nCualquier usuario puede actualizar las aplicaciones del resto de usuarios."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Has alcanzado el límite de usuarios"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">Puedes añadir hasta <xliff:g id="COUNT">%d</xliff:g> usuarios.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Se ha producido un problema al obtener tus tarjetas. Inténtalo de nuevo más tarde."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Ajustes de pantalla de bloqueo"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"Código QR"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Toca para escanear"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Escanear código QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabajo"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Modo avión"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"No oirás la próxima alarma (<xliff:g id="WHEN">%1$s</xliff:g>)"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Desliza el dedo para ver más"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Cargando recomendaciones"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Multimedia"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"¿Ocultar esta sesión multimedia?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"La sesión multimedia no se puede ocultar."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Cerrar"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Reanudar"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Ajustes"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Se está reproduciendo <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Acércate a <xliff:g id="DEVICENAME">%1$s</xliff:g> para jugar aquí"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproduciendo en <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Reproduciendo en este dispositivo"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Se ha producido un error"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"Se ha producido un error. Inténtalo de nuevo."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo, comprobar aplicación"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"No se ha encontrado"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Control no disponible"</string>
@@ -827,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Emparejar nuevo dispositivo"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Para enviar esta sesión, abre la aplicación."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplicación desconocida"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Dejar de enviar contenido"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Número de compilación copiado en el portapapeles."</string>
     <string name="basic_status" msgid="2315371112182658176">"Conversación abierta"</string>
@@ -916,8 +905,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi no disponible"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modo prioritario"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarma añadida"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Modo invitado del asistente habilitado"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"La cámara y el micrófono están desactivados"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificación}other{# notificaciones}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 0c9d46e..1911798 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Süsteemi UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Kas lülitada akusäästja sisse?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Teil on jäänud <xliff:g id="PERCENTAGE">%s</xliff:g> akutoidet. Akusäästja lülitab sisse tumeda teema, piirab taustategevusi ja viivitab märguannete saatmisega."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Akusäästja lülitab sisse tumeda teema, piirab taustategevusi ja viivitab märguannete saatmisega."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Jäänud on <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Ei saa USB kaudu laadida"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Kasutage seadmega kaasas olnud laadijat"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Kas lülitada akusäästja sisse?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Teave akusäästja kohta"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Lülita sisse"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Akusäästja sisselülitamine"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Lülita sisse"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Tänan, ei"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Kuva automaatne pööramine"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Kas lubada rakendusele <xliff:g id="APPLICATION">%1$s</xliff:g> juurdepääs seadmele <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Kas lubada rakendusel <xliff:g id="APPLICATION">%1$s</xliff:g> seadmele <xliff:g id="USB_DEVICE">%2$s</xliff:g> juurde pääseda?\nSellele rakendusele pole antud salvestamise luba, kuid see saab heli jäädvustada selle USB-seadme kaudu."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Nägu on autenditud"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Kinnitatud"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Lõpuleviimiseks puudutage nuppu Kinnita"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Avati teie näoga. Vajutage jätkamiseks."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenditud"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Kasuta PIN-koodi"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Kasuta mustrit"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Kui sisestate järgmisel katsel vale mustri, kustutatakse teie tööprofiil ja selle andmed."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Kui sisestate järgmisel katsel vale PIN-koodi, kustutatakse teie tööprofiil ja selle andmed."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Kui sisestate järgmisel katsel vale parooli, kustutatakse teie tööprofiil ja selle andmed."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Liiga palju valesid katseid. Selle seadme andmed kustutatakse."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Liiga palju valesid katseid. See kasutaja kustutatakse."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Liiga palju valesid katseid. See tööprofiil ja selle andmed kustutatakse."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Sulge"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Puudutage sõrmejäljeandurit"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Sõrmejälje ikoon"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nägu ei õnnestu tuvastada. Kasutage sõrmejälge."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Aeglane laadimine • Täis <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> pärast"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laadimisdokk • Täis <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> pärast"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Kasutaja vahetamine"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Lisa kasutaja"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Uus kasutaja"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Kas eemaldada külaline?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Seansi kõik rakendused ja andmed kustutatakse."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Eemalda"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Tere tulemast tagasi, külaline!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Kas soovite seansiga jätkata?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Alusta uuesti"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Jah, jätka"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Kas lisada uus kasutaja?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Kui lisate uue kasutaja, siis peab ta seadistama oma ruumi.\n\nIga kasutaja saab värskendada rakendusi kõigi kasutajate jaoks."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Kasutajate limiit on täis"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">Võite lisada kuni <xliff:g id="COUNT">%d</xliff:g> kasutajat.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Avage kasutamiseks"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Teie kaartide hankimisel ilmnes probleem, proovige hiljem uuesti"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lukustuskuva seaded"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-kood"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Skannimiseks puudutamine"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skannige QR-kood"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Tööprofiil"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Lennukirežiim"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Te ei kuule järgmist äratust kell <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Pühkige sõrmega, et näha rohkem"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Soovituste laadimine"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Meedia"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Kas peita see meediaseanss?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Praegust meediaseanssi ei saa peita."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Loobu"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Peida"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Jätka"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Seaded"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> esitajalt <xliff:g id="ARTIST_NAME">%2$s</xliff:g> esitatakse rakenduses <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Siin esitamiseks liigutage seadmele <xliff:g id="DEVICENAME">%1$s</xliff:g> lähemale"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Esitatakse seadmes <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Esitatakse selles telefonis"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Midagi läks valesti"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Passiivne, vaadake rakendust"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Ei leitud"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Juhtelement pole saadaval"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Uue seadme sidumine"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Selle seansi ülekandmiseks avage rakendus."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Tundmatu rakendus"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Lõpeta ülekanne"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Järgunumber"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Järgunumber kopeeriti lõikelauale."</string>
     <string name="basic_status" msgid="2315371112182658176">"Avage vestlus"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WiFi pole saadaval"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Režiim Prioriteetne"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm on määratud"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Assistendi külalisrežiim on lubatud"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kaamera ja mikrofon on välja lülitatud"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# märguanne}other{# märguannet}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 90d24e5..3f51b06 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Sistemaren interfazea"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Bateria-aurrezlea aktibatu nahi duzu?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Bateriaren <xliff:g id="PERCENTAGE">%s</xliff:g> gelditzen zaizu. Bateria-aurrezleak gai iluna aktibatzen du, atzeko planoko jarduerak murrizten, eta jakinarazpenak atzeratzen."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Bateria-aurrezleak gai iluna aktibatzen du, atzeko planoko jarduerak murrizten, eta jakinarazpenak atzeratzen."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> gelditzen da"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Ezin da USB bidez kargatu"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Erabili gailuaren kargagailua"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Bateria-aurrezlea aktibatu nahi duzu?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Bateria-aurrezleari buruz"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Aktibatu"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Aktibatu bateria-aurrezlea"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Aktibatu"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Ez, eskerrik asko"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Biratu pantaila automatikoki"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> atzitzeko baimena eman nahi diozu <xliff:g id="APPLICATION">%1$s</xliff:g> aplikazioari?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> erabiltzeko baimena eman nahi diozu <xliff:g id="APPLICATION">%1$s</xliff:g> aplikazioari?\nAplikazioak ez du grabatzeko baimenik, baina baliteke USB bidezko gailu horren bidez audioa grabatzea."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Autentifikatu da aurpegia"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Berretsita"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Amaitzeko, sakatu \"Berretsi\""</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Aurpegiaren bidez desblokeatu da. Sakatu aurrera egiteko."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentifikatuta"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Erabili PINa"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Erabili eredua"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Hurrengo saiakeran eredua oker marrazten baduzu, laneko profila eta bertako datuak ezabatuko dira."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Hurrengo saiakeran PINa oker idazten baduzu, laneko profila eta bertako datuak ezabatuko dira."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Hurrengo saiakeran pasahitza oker idazten baduzu, laneko profila eta bertako datuak ezabatuko dira."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Saiakera oker gehiegi egin dituzu. Gailuko datuak ezabatu egingo dira."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Saiakera oker gehiegi egin dituzu. Erabiltzailea ezabatu egingo da."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Saiakera oker gehiegi egin dituzu. Laneko profila eta bertako datuak ezabatu egingo dira."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Baztertu"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Sakatu hatz-marken sentsorea"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Hatz-markaren ikonoa"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ez da hauteman aurpegia. Erabili hatz-marka."</string>
@@ -197,7 +190,7 @@
     <string name="accessibility_casting_turned_off" msgid="1387906158563374962">"Pantaila igortzeari utzi zaio."</string>
     <string name="accessibility_brightness" msgid="5391187016177823721">"Bistaratu distira"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="2286843518689837719">"Datu-konexioa pausatu egin da"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="9131615296036724838">"Datuen erabilera pausatu da"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="9131615296036724838">"Datu-erabilera pausatu da"</string>
     <string name="data_usage_disabled_dialog" msgid="7933201635215099780">"Iritsi zara ezarri zenuen datu-mugara. Datu-konexioa erabiltzeari utzi diozu.\n\nDatu-konexioa erabiltzeari berrekiten badiozu, baliteke zerbait ordaindu behar izatea datuak erabiltzeagatik."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="2796648546086408937">"Jarraitu erabiltzen"</string>
     <string name="accessibility_location_active" msgid="2845747916764660369">"Aplikazioen kokapen-eskaerak aktibo daude"</string>
@@ -261,7 +254,7 @@
     <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Linterna"</string>
     <string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Kamera abian da"</string>
     <string name="quick_settings_cellular_detail_title" msgid="792977203299358893">"Datu-konexioa"</string>
-    <string name="quick_settings_cellular_detail_data_usage" msgid="6105969068871138427">"Datuen erabilera"</string>
+    <string name="quick_settings_cellular_detail_data_usage" msgid="6105969068871138427">"Datu-erabilera"</string>
     <string name="quick_settings_cellular_detail_remaining_data" msgid="1136599216568805644">"Geratzen diren datuak"</string>
     <string name="quick_settings_cellular_detail_over_limit" msgid="4561921367680636235">"Mugaren gainetik"</string>
     <string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"<xliff:g id="DATA_USED">%s</xliff:g> erabilita"</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mantso kargatzen • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> guztiz kargatu arte"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Oinarrian kargatzen • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> guztiz kargatu arte"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Aldatu erabiltzailea"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Gehitu erabiltzaile bat"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Erabiltzaile berria"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Gonbidatua kendu nahi duzu?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Saioko aplikazio eta datu guztiak ezabatuko dira."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Kendu"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Ongi etorri berriro, gonbidatu hori!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Saioarekin jarraitu nahi duzu?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Hasi berriro"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Bai, jarraitu"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Beste erabiltzaile bat gehitu?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Erabiltzaile bat gehitzen duzunean, erabiltzaile horrek bere eremua konfiguratu beharko du.\n\nEdozein erabiltzailek egunera ditzake beste erabiltzaile guztien aplikazioak."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Erabiltzaile-mugara iritsi zara"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">Gehienez, <xliff:g id="COUNT">%d</xliff:g> erabiltzaile gehi ditzakezu.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desblokeatu erabiltzeko"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Arazo bat izan da txartelak eskuratzean. Saiatu berriro geroago."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Pantaila blokeatuaren ezarpenak"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR kodea"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Sakatu eskaneatzeko"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Eskaneatu QR kodea"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Work profila"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Hegaldi modua"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Ez duzu entzungo hurrengo alarma (<xliff:g id="WHEN">%1$s</xliff:g>)"</string>
@@ -702,7 +689,7 @@
     <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Ez molestatzeko modua aktibatu du aplikazio batek (<xliff:g id="ID_1">%s</xliff:g>)."</string>
     <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Ez molestatzeko modua aktibatu du arau automatiko edo aplikazio batek."</string>
     <string name="running_foreground_services_title" msgid="5137313173431186685">"Aplikazioak abian dira atzeko planoan"</string>
-    <string name="running_foreground_services_msg" msgid="3009459259222695385">"Sakatu bateria eta datuen erabilerari buruzko xehetasunak ikusteko"</string>
+    <string name="running_foreground_services_msg" msgid="3009459259222695385">"Sakatu bateria eta datu-erabilerari buruzko xehetasunak ikusteko"</string>
     <string name="mobile_data_disable_title" msgid="5366476131671617790">"Datu-konexioa desaktibatu nahi duzu?"</string>
     <string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g> erabilita ezingo dituzu erabili datuak edo Internet. Wifi-sare baten bidez soilik konektatu ahal izango zara Internetera."</string>
     <string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"Zure operadorea"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Pasatu hatza aukera gehiago ikusteko"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Gomendioak kargatzen"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Multimedia-edukia"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Multimedia-saioa ezkutatu nahi duzu?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Ezin da ezkutatu multimedia-saioa."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Baztertu"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ezkutatu"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Berrekin"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Ezarpenak"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>) ari da erreproduzitzen <xliff:g id="APP_LABEL">%3$s</xliff:g> bidez"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Gerturatu <xliff:g id="DEVICENAME">%1$s</xliff:g> gailura bertan erreproduzitzen ari dena hemen erreproduzitzeko"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> gailuan erreproduzitzen"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Telefono honetan erreproduzitzen"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Arazoren bat izan da"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Inaktibo; egiaztatu aplikazioa"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Ez da aurkitu"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Ez dago erabilgarri kontrolatzeko aukera"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parekatu beste gailu batekin"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Saioa ireki nahi baduzu, ireki aplikazioa."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplikazio ezezaguna"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Utzi igortzeari"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Konpilazio-zenbakia"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Kopiatu da konpilazio-zenbakia arbelean."</string>
     <string name="basic_status" msgid="2315371112182658176">"Elkarrizketa irekia"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wifi-konexioa ez dago erabilgarri"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Lehentasun modua"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarma ezarrita dago"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Laguntzailea zerbitzuaren gonbidatu modua gaituta dago"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera eta mikrofonoa desaktibatuta daude"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# jakinarazpen}other{# jakinarazpen}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 99e214b..dd6a6cb 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"میانای کاربر سیستم"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"«بهینه‌سازی باتری» روشن شود؟"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"<xliff:g id="PERCENTAGE">%s</xliff:g> از باتری‌تان باقی مانده است. «بهینه‌سازی باتری» زمینه تیره را روشن می‌کند، فعالیت‌های پس‌زمینه را محدود می‌کند، و اعلان‌ها را به‌تأخیر می‌اندازد."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"«بهینه‌سازی باتری» زمینه تیره را روشن می‌کند، فعالیت‌های پس‌زمینه را محدود می‌کند، و اعلان‌ها را به‌تأخیر می‌اندازد."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> باقی مانده است"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"‏ازطریق USB شارژ نمی‌شود"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"از شارژر ارائه‌شده با دستگاه استفاده کنید"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"«بهینه‌سازی باتری» روشن شود؟"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"درباره «بهینه‌سازی باتری»"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"روشن کردن"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"«بهینه‌سازی باتری» را روشن کنید"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"روشن کردن"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"نه متشکرم"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"چرخش خودکار صفحه"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"به <xliff:g id="APPLICATION">%1$s</xliff:g> برای دسترسی به <xliff:g id="USB_DEVICE">%2$s</xliff:g> اجازه داده شود؟"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"‏به <xliff:g id="APPLICATION">%1$s</xliff:g> اجازه می‌دهید به <xliff:g id="USB_DEVICE">%2$s</xliff:g>دسترسی داشته باشد؟\nمجوز ضبط به این برنامه داده نشده است اما می‌تواند صدا را ازطریق این دستگاه USB ضبط کند."</string>
@@ -100,7 +98,7 @@
     <string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"درحال ضبط صفحه‌نمایش"</string>
     <string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"درحال ضبط صفحه‌نمایش و صدا"</string>
     <string name="screenrecord_taps_label" msgid="1595690528298857649">"نمایش قسمت‌های لمس‌شده روی صفحه‌نمایش"</string>
-    <string name="screenrecord_stop_label" msgid="72699670052087989">"توقف"</string>
+    <string name="screenrecord_stop_label" msgid="72699670052087989">"متوقف کردن"</string>
     <string name="screenrecord_share_label" msgid="5025590804030086930">"هم‌رسانی"</string>
     <string name="screenrecord_save_title" msgid="1886652605520893850">"قطعه ضبط‌شده از صفحه‌نمایش ذخیره شد"</string>
     <string name="screenrecord_save_text" msgid="3008973099800840163">"برای مشاهده ضربه بزنید"</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"چهره اصالت‌سنجی شد"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"تأیید شد"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"برای تکمیل، روی تأیید ضربه بزنید"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"قفل با چهره‌تان باز شد. برای ادامه دادن، فشار دهید."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"راستی‌آزمایی‌شده"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"استفاده از پین"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"استفاده از الگو"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"اگر در تلاش بعدی الگوی نادرستی وارد کنید، داده‌های نمایه کاری شما و داده‌های آن حذف خواهد شد."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"اگر در تلاش بعدی‌ پین نادرستی وارد کنید، نمایه کاری شما و داده‌های آن حذف خواهند شد."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"اگر در تلاش بعدی‌ گذرواژه نادرستی وارد کنید، نمایه کاری شما و داده‌های آن حذف خواهند شد."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"تلاش‌های نادرست بسیار زیادی انجام شده است. داده‌های این دستگاه حذف خواهد شد."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"تلاش‌های اشتباه بسیار زیادی انجام شده است. این کاربر حذف خواهد شد."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"تلاش‌های اشتباه بسیار زیادی انجام شده است. این نمایه کاری و داده‌های آن‌ حذف خواهند شد."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"رد کردن"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"حسگر اثر انگشت را لمس کنید"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"نماد اثر انگشت"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"چهره شناسایی نشد. درعوض از اثر انگشت استفاده کنید."</string>
@@ -273,7 +266,7 @@
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"تا طلوع"</string>
     <string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"ساعت <xliff:g id="TIME">%s</xliff:g> روشن می‌شود"</string>
     <string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"تا <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"طرح زمینه تیره"</string>
+    <string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"زمینه تیره"</string>
     <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"بهینه‌سازی باتری"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"غروب روشن می‌شود"</string>
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"تا طلوع آفتاب"</string>
@@ -286,7 +279,7 @@
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"‏NFC فعال است"</string>
     <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"ضبط صفحه‌نمایش"</string>
     <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"شروع"</string>
-    <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"توقف"</string>
+    <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"متوقف کردن"</string>
     <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"حالت تک حرکت"</string>
     <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"میکروفون دستگاه لغو انسداد شود؟"</string>
     <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"دوربین دستگاه لغو انسداد شود؟"</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • درحال شارژ کردن آهسته • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> تا شارژ کامل"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • پایه شارژ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> تا شارژ کامل"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"تغییر کاربر"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"افزودن کاربر"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"کاربر جدید"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"مهمان حذف شود؟"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"همه برنامه‌ها و داده‌های این جلسه حذف خواهد شد."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"حذف"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"مهمان گرامی، بازگشتتان را خوش آمد می‌گوییم!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"آیا می‌خواهید جلسه‌تان را ادامه دهید؟"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"شروع مجدد"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"بله، ادامه داده شود"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"کاربر جدیدی اضافه می‌کنید؟"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"وقتی کاربر جدیدی اضافه می‌کنید آن فرد باید فضای خودش را تنظیم کند.\n\nهر کاربری می‌تواند برنامه‌ها را برای همه کاربران دیگر به‌روزرسانی کند."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"به تعداد مجاز تعداد کاربر رسیده‌اید"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">می‌توانید حداکثر <xliff:g id="COUNT">%d</xliff:g> کاربر اضافه کنید.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"برای استفاده، قفل را باز کنید"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"هنگام دریافت کارت‌ها مشکلی پیش آمد، لطفاً بعداً دوباره امتحان کنید"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"تنظیمات صفحه قفل"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"رمزینه پاسخ‌سریع"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"برای اسکن کردن، ضربه بزنید"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"اسکن رمزینه پاسخ‌سریع"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"نمایه کاری"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"حالت هواپیما"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"در ساعت <xliff:g id="WHEN">%1$s</xliff:g>، دیگر صدای زنگ ساعت را نمی‌شنوید"</string>
@@ -549,7 +536,7 @@
     <string name="keyboard_key_enter" msgid="8633362970109751646">"ورود"</string>
     <string name="keyboard_key_backspace" msgid="4095278312039628074">"پس‌بر"</string>
     <string name="keyboard_key_media_play_pause" msgid="8389984232732277478">"پخش/مکث"</string>
-    <string name="keyboard_key_media_stop" msgid="1509943745250377699">"توقف"</string>
+    <string name="keyboard_key_media_stop" msgid="1509943745250377699">"متوقف کردن"</string>
     <string name="keyboard_key_media_next" msgid="8502476691227914952">"بعدی"</string>
     <string name="keyboard_key_media_previous" msgid="5637875709190955351">"قبلی"</string>
     <string name="keyboard_key_media_rewind" msgid="3450387734224327577">"عقب بردن"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"برای دیدن موارد بیشتر، تند بکشید"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"درحال بار کردن توصیه‌ها"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"رسانه"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"این جلسه رسانه پنهان شود؟"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"جلسه رسانه کنونی نمی‌تواند پنهان شود."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"رد کردن"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"پنهان کردن"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"ازسرگیری"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"تنظیمات"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> از <xliff:g id="ARTIST_NAME">%2$s</xliff:g> ازطریق <xliff:g id="APP_LABEL">%3$s</xliff:g> پخش می‌شود"</string>
@@ -808,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"برای پخش در اینجا، به <xliff:g id="DEVICENAME">%1$s</xliff:g> نزدیک‌تر شوید"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"درحال پخش در <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"درحال پخش در این تلفن"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"مشکلی رخ داد"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"مشکلی پیش آمد. دوباره امتحان کنید."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"غیرفعال، برنامه را بررسی کنید"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"پیدا نشد"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"کنترل دردسترس نیست"</string>
@@ -827,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"مرتبط کردن دستگاه جدید"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"برای ارسال محتوای این جلسه، لطفاً برنامه را باز کنید."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"برنامه ناشناس"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"توقف ارسال محتوا"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"شماره ساخت"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"شماره ساخت در بریده‌دان کپی شد."</string>
     <string name="basic_status" msgid="2315371112182658176">"باز کردن مکالمه"</string>
@@ -901,8 +890,8 @@
     </plurals>
     <string name="fgs_dot_content_description" msgid="2865071539464777240">"اطلاعات جدید"</string>
     <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"برنامه‌های فعال"</string>
-    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"توقف"</string>
-    <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"متوقف شد"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"متوقف کردن"</string>
+    <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"متوقف شده"</string>
     <string name="clipboard_edit_text_copy" msgid="770856373439969178">"کپی کردن"</string>
     <string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"کپی شد"</string>
     <string name="clipboard_edit_source" msgid="9156488177277788029">"از <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
@@ -916,8 +905,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"‏Wi‑Fi دردسترس نیست"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"حالت اولویت"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"زنگ ساعت تنظیم شد"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"«حالت مهمان» «دستیار» فعال شد"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"دوربین و میکروفون خاموش هستند"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# اعلان}one{# اعلان}other{# اعلان}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 5aca1ce..758d2f0 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Käyttöliitt."</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Laitetaanko virransäästö päälle?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Akkua jäljellä <xliff:g id="PERCENTAGE">%s</xliff:g>. Virransäästö laittaa tumman teeman päälle, rajoittaa taustatoimintoja ja viivästyttää ilmoituksia."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Virransäästö laittaa tumman teeman päälle, rajoittaa taustatoimintoja ja viivästyttää ilmoituksia."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> jäljellä"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Lataaminen USB:llä ei onnistu"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Käytä laitteesi mukana tullutta laturia"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Otetaanko virransäästö käyttöön?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Tietoa virransäästöstä"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Ota käyttöön"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Ota virransäästö käyttöön"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Laita päälle"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Ei kiitos"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Näytön automaattinen kääntö"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Saako <xliff:g id="APPLICATION">%1$s</xliff:g> käyttöoikeuden (<xliff:g id="USB_DEVICE">%2$s</xliff:g>)?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Saako <xliff:g id="APPLICATION">%1$s</xliff:g> tämän pääsyoikeuden: <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nSovellus ei ole saanut tallennuslupaa, mutta voi tallentaa ääntä tämän USB-laitteen avulla."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Kasvot tunnistettu"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Vahvistettu"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Valitse lopuksi Vahvista"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Lukitus avattu kasvojen avulla. Jatka painamalla."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Todennettu"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Käytä PIN-koodia"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Käytä kuviota"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Jos annat väärän kuvion seuraavalla yrityskerralla, työprofiilisi ja sen data poistetaan."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Jos annat väärän PIN-koodin seuraavalla yrityskerralla, työprofiilisi ja sen data poistetaan."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Jos annat väärän salasanan seuraavalla yrityskerralla, työprofiilisi ja sen data poistetaan."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Liian monta virheellistä yritystä. Laitteen data poistetaan."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Liian monta virheellistä yritystä. Tämä käyttäjä poistetaan."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Liian monta virheellistä yritystä. Tämä työprofiili ja sen data poistetaan."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Ohita"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Kosketa sormenjälkitunnistinta"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Sormenjälkikuvake"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Kasvoja ei voi tunnistaa. Käytä sormenjälkeä."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Latautuu hitaasti • Täynnä <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> päästä"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ladataan telineellä • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> kunnes täynnä"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Vaihda käyttäjää"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Lisää käyttäjä"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Uusi käyttäjä"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Poistetaaanko vieras?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Kaikki sovellukset ja tämän istunnon tiedot poistetaan."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Poista"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Tervetuloa takaisin!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Haluatko jatkaa istuntoa?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Aloita alusta"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Kyllä, haluan jatkaa"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Lisätäänkö uusi käyttäjä?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Kun lisäät uuden käyttäjän, hänen tulee määrittää oman tilansa asetukset.\n\nKaikki käyttäjät voivat päivittää sovelluksia muille käyttäjille."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Käyttäjäraja saavutettu"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">Voit lisätä korkeintaan <xliff:g id="COUNT">%d</xliff:g> käyttäjää.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Avaa lukitus ja käytä"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Korttien noutamisessa oli ongelma, yritä myöhemmin uudelleen"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lukitusnäytön asetukset"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-koodi"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Skannaa napauttamalla"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skannaa QR-koodi"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Työprofiili"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Lentokonetila"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Et kuule seuraavaa hälytystäsi (<xliff:g id="WHEN">%1$s</xliff:g>)."</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Pyyhkäise nähdäksesi lisää"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Ladataan suosituksia"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Media"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Piilotetaanko median käyttökerta?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Tätä median käyttökertaa ei voi piilottaa."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ohita"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Piilota"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Jatka"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Asetukset"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> soittaa nyt tätä: <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>)"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Siirrä <xliff:g id="DEVICENAME">%1$s</xliff:g> lähemmäs toistaaksesi täällä"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Toistetaan: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Toistetaan tällä puhelimella"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Tapahtui virhe"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Epäaktiivinen, tarkista sovellus"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Ei löydy"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Ohjain ei ole käytettävissä"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Muodosta uusi laitepari"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Jos haluat striimata tämän käyttökerran, avaa sovellus."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Tuntematon sovellus"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Lopeta striimaus"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Koontiversion numero"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Koontiversion numero kopioitu leikepöydälle"</string>
     <string name="basic_status" msgid="2315371112182658176">"Avaa keskustelu"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi ei ole saatavilla"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Tärkeät-tila"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Hälytys asetettu"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Assistantin vierastila käytössä"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera ja mikrofoni ovat pois päältä"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ilmoitus}other{# ilmoitusta}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 1a599b5..6157cc5 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"IU système"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Activer l\'économiseur de pile?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Il vous reste <xliff:g id="PERCENTAGE">%s</xliff:g> d\'autonomie. L\'économiseur de pile active le thème sombre, limite l\'activité en arrière-plan et retarde les notifications."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"L\'économiseur de pile active le thème sombre, limite l\'activité en arrière-plan et retarde les notifications."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> restants"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Impossible de charger l\'appareil par USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Servez-vous du chargeur fourni avec votre appareil"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Activer l\'économiseur de pile?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"À propos du mode Économiseur de pile"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Activer"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Activer l\'économiseur de pile"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Activer"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Non merci"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Rotation auto de l\'écran"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Autoriser <xliff:g id="APPLICATION">%1$s</xliff:g> à accéder à <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Autorisé <xliff:g id="APPLICATION">%1$s</xliff:g> à accéder à <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nCette application n\'a pas été autorisée à effectuer des enregistrements, mais elle pourrait enregistrer du contenu audio par l\'intermédiaire de cet appareil USB."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Visage authentifié"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmé"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Touchez Confirmer pour terminer"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Déverrouillé par votre visage. Appuyez pour continuer."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authentifié"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Utiliser un NIP"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Utiliser un schéma"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Si vous entrez un schéma incorrect à la prochaine tentative suivante, votre profil professionnel et ses données seront supprimés."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Si vous entrez un NIP incorrect à la prochaine tentative, votre profil professionnel et ses données seront supprimés."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Si vous entrez un mot de passe incorrect à la prochaine tentative suivante, votre profil professionnel et ses données seront supprimés."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Trop de tentatives incorrectes. Les données de cet appareil seront supprimées."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Trop de tentatives incorrectes. Cet utilisateur sera supprimé."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Trop de tentatives incorrectes. Ce profil professionnel et ses données seront supprimés."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Fermer"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Touchez le capteur d\'empreintes digitales"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Icône d\'empreinte digitale"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Visage non reconnu. Utilisez plutôt l\'empreinte digitale."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"En recharge lente : <xliff:g id="PERCENTAGE">%2$s</xliff:g> • Terminée <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Station de recharge • Recharge terminée dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Changer d\'utilisateur"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Ajouter un utilisateur"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Nouvel utilisateur"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Supprimer l\'invité?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Supprimer"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bienvenue à nouveau dans la session Invité"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Voulez-vous poursuivre la session?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recommencer"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Oui, continuer"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Ajouter un utilisateur?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Lorsque vous ajoutez un utilisateur, celui-ci doit configurer son espace.\n\nTout utilisateur peut mettre à jour les applications pour tous les autres utilisateurs."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Limite d\'utilisateurs atteinte"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">Vous pouvez ajouter jusqu\'à <xliff:g id="COUNT">%d</xliff:g> utilisateur.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Déverrouiller pour utiliser"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Un problème est survenu lors de la récupération de vos cartes, veuillez réessayer plus tard"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Paramètres de l\'écran de verrouillage"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"Code QR"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Touchez pour numériser"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Numériser le code QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Profil professionnel"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Mode Avion"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Vous n\'entendrez pas votre prochaine alarme à <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Balayez l\'écran pour en afficher davantage"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Chargement des recommandations…"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Commandes multimédias"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Masquer cette session multimédia?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Impossible de masquer la session multimédia actuelle"</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Fermer"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Masquer"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Reprendre"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Paramètres"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> par <xliff:g id="ARTIST_NAME">%2$s</xliff:g> est en cours de lecteur à partir de <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Rapprochez-vous de <xliff:g id="DEVICENAME">%1$s</xliff:g> pour lire le contenu"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Lecture sur <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Lecture sur ce téléphone"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Un problème est survenu"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifiez l\'appli"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"La commande n\'est pas accessible"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Associer un autre appareil"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Pour diffuser cette session, veuillez ouvrir l\'application."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Application inconnue"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Arrêter la diffusion"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Numéro de version"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Le numéro de version a été copié dans le presse-papiers."</string>
     <string name="basic_status" msgid="2315371112182658176">"Ouvrir la conversation"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi-Fi non disponible"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Mode priorité"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"L\'alarme a été réglée"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Mode Invité de l\'assistant activé"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"L\'appareil photo et le micro sont désactivés"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}one{# notification}other{# notifications}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 1465bdb..cc5dbe9 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Interface"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Activer l\'économiseur de batterie ?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Il vous reste <xliff:g id="PERCENTAGE">%s</xliff:g> de batterie. L\'économiseur de batterie active le thème sombre, limite les activités en arrière-plan et retarde les notifications."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"L\'économiseur de batterie active le thème sombre, limite les activités en arrière-plan et retarde les notifications."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> restants"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Impossible de recharger via USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Utiliser le chargeur d\'origine fourni avec votre appareil"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Activer l\'économiseur de batterie ?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"À propos de l\'économiseur de batterie"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Activer"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Activer l\'économiseur de batterie"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Activer"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Non, merci"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Rotation automatique de l\'écran"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Autoriser <xliff:g id="APPLICATION">%1$s</xliff:g> à accéder à <xliff:g id="USB_DEVICE">%2$s</xliff:g> ?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Autoriser <xliff:g id="APPLICATION">%1$s</xliff:g> à accéder à <xliff:g id="USB_DEVICE">%2$s</xliff:g> ?\nCette application n\'a pas été autorisée à effectuer des enregistrements, mais elle pourrait enregistrer du contenu audio via ce périphérique USB."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Visage authentifié"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmé"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Appuyez sur \"Confirmer\" pour terminer"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Déverrouillé par votre visage. Appuyez pour continuer."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authentifié"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Utiliser un code PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Utiliser un schéma"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Si vous dessinez un schéma incorrect lors de la prochaine tentative, votre profil professionnel et les données associées seront supprimés."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Si vous saisissez un code incorrect lors de la prochaine tentative, votre profil professionnel et les données associées seront supprimés."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Si vous saisissez un mot de passe incorrect lors de la prochaine tentative, votre profil professionnel et les données associées seront supprimés."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Trop de tentatives incorrectes. Les données de cet appareil vont être supprimées."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Trop de tentatives incorrectes. Ce compte utilisateur va être supprimé."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Trop de tentatives incorrectes. Ce profil professionnel et les données associées vont être supprimés."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Fermer"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Appuyez sur le lecteur d\'empreinte digitale"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Icône d\'empreinte digitale"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Visage non reconnu. Utilisez votre empreinte."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Recharge lente • Chargé dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Station de charge • Chargé dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Changer d\'utilisateur"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Ajouter un utilisateur"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Nouvel utilisateur"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Supprimer l\'invité ?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Supprimer"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bienvenue à nouveau dans la session Invité"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Voulez-vous poursuivre la dernière session ?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Non, nouvelle session"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Oui, continuer"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Ajouter un utilisateur ?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Lorsque vous ajoutez un utilisateur, celui-ci doit configurer son espace.\n\nN\'importe quel utilisateur peut mettre à jour les applications pour tous les autres utilisateurs."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Limite nombre utilisateurs atteinte"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">Vous pouvez ajouter <xliff:g id="COUNT">%d</xliff:g> profil utilisateur.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Déverrouiller pour utiliser"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Problème de récupération de vos cartes. Réessayez plus tard"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Paramètres de l\'écran de verrouillage"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"Code QR"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Appuyer pour scanner"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Scanner un code QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Profil professionnel"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Mode Avion"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Vous n\'entendrez pas votre prochaine alarme <xliff:g id="WHEN">%1$s</xliff:g>."</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Balayer l\'écran pour voir plus d\'annonces"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Chargement des recommandations"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Multimédia"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Masquer cette session multimédia ?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Session multimédia en cours impossible à masquer."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Fermer"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Masquer"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Reprendre"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Paramètres"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> par <xliff:g id="ARTIST_NAME">%2$s</xliff:g> est en cours de lecture depuis <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Rapprochez l\'appareil pour transférer la diffusion à votre <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Lecture sur <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Lire sur ce téléphone"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Un problème est survenu"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifier l\'appli"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Commande indisponible"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Associer un nouvel appareil"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Pour caster cette session, veuillez ouvrir l\'appli."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Appli inconnue"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Arrêter la diffusion"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Numéro de build"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Numéro de build copié dans le presse-papiers."</string>
     <string name="basic_status" msgid="2315371112182658176">"Conversation ouverte"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi non disponible"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Mode Prioritaire"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarme réglée"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Mode Invité activé pour l\'Assistant"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Appareil photo et micro désactivés"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}one{# notification}other{# notifications}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 5faa3df..ce0340e 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"IU do sistema"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Queres activar a función Aforro de batería?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Quédache un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería. Coa función Aforro de batería, actívase o tema escuro, restrínxese a actividade en segundo plano e atrásanse as notificacións."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Coa función Aforro de batería, actívase o tema escuro, restrínxese a actividade en segundo plano e atrásanse as notificacións."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> restante"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Non se puido realizar a carga por USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Utiliza o cargador que incluía o dispositivo"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Queres activar a función Aforro de batería?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Acerca de Aforro de batería"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Activar"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Activar a función Aforro de batería"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Activar"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Non, grazas"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Xirar pantalla automaticamente"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Queres permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> acceda a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Queres permitir que a aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> acceda ao dispositivo (<xliff:g id="USB_DEVICE">%2$s</xliff:g>)?\nEsta aplicación non está autorizada para realizar gravacións, pero pode capturar audio a través deste dispositivo USB."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Autenticouse a cara"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmada"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toca Confirmar para completar o proceso"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Desbloqueouse coa túa cara. Preme para continuar."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticado"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Usar PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Usar padrón"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Se indicas un padrón incorrecto no seguinte intento, eliminaranse o teu perfil de traballo e os datos asociados."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Se indicas un PIN incorrecto no seguinte intento, eliminaranse o teu perfil de traballo e os datos asociados."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Se indicas un contrasinal incorrecto no seguinte intento, eliminaranse o teu perfil de traballo e os datos asociados."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Realizaches demasiados intentos incorrectos. Eliminaranse os datos deste dispositivo."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Realizaches demasiados intentos incorrectos. Eliminarase este usuario."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Realizaches demasiados intentos incorrectos. Eliminaranse este perfil de traballo e os datos asociados."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Ignorar"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toca o sensor de impresión dixital"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Icona de impresión dixital"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Non se recoñeceu a cara. Usa a impresión dixital."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando lentamente • A carga completarase en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Base de carga • Carga completa dentro de <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar usuario"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Engadir usuario"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Novo usuario"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Queres quitar o convidado?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Eliminaranse todas as aplicacións e datos desta sesión."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Quitar"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Benvido de novo, convidado"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Queres continuar coa túa sesión?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Comezar de novo"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Si, continuar"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Engadir un usuario novo?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Cando engadas un usuario novo, este deberá configurar o seu espazo.\n\nCalquera usuario pode actualizar as aplicacións para todos os demais usuarios."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Alcanzouse o límite de usuarios"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">Podes engadir ata <xliff:g id="COUNT">%d</xliff:g> usuarios.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Produciuse un problema ao obter as tarxetas. Téntao de novo máis tarde"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Configuración da pantalla de bloqueo"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"Código QR"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Tocar para escanear"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Escanear código QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Perfil de traballo"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Modo avión"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Non escoitarás a alarma seguinte <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Pasar o dedo para ver máis"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Cargando recomendacións"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Contido multimedia"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Queres ocultar esta sesión multimedia?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Non se pode ocultar esta sesión multimedia."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ignorar"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Configuración"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Estase reproducindo <xliff:g id="SONG_NAME">%1$s</xliff:g>, de <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Achégate ao dispositivo (<xliff:g id="DEVICENAME">%1$s</xliff:g>) para reproducir o contido neste"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproducindo contido noutro dispositivo (<xliff:g id="DEVICENAME">%1$s</xliff:g>)"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Reproducindo contido neste teléfono"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Produciuse un erro"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Comproba a app"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Non se atopou"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"O control non está dispoñible"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincular dispositivo novo"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Para emitir esta sesión, abre a aplicación."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplicación descoñecida"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Deter emisión"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Copiouse o número de compilación no portapapeis."</string>
     <string name="basic_status" msgid="2315371112182658176">"Conversa aberta"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"A wifi non está dispoñible"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modo de prioridade"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarma definida"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"O modo Convidados do Asistente está activado"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A cámara e o micrófono están desactivados"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificación}other{# notificacións}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 763d39d..19b7792 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"સિસ્ટમ UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"બૅટરી સેવર ચાલુ કરીએ?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"તમારી પાસે <xliff:g id="PERCENTAGE">%s</xliff:g> બૅટરી બાકી છે. બૅટરી સેવર ઘેરી થીમની સુવિધા ચાલુ કરે છે, બૅકગ્રાઉન્ડ પ્રવૃત્તિ પ્રતિબંધિત કરે છે અને નોટિફિકેશન વિલંબે મોકલે છે."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"બૅટરી સેવર ઘેરી થીમની સુવિધા ચાલુ કરે છે, બૅકગ્રાઉન્ડ પ્રવૃત્તિ પ્રતિબંધિત કરે છે અને નોટિફિકેશન વિલંબે મોકલે છે."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> બાકી"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"USB મારફતે ચાર્જ કરી શકતા નથી"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"તમારા ઉપકરણ સાથે આવેલ ચાર્જરનો ઉપયોગ કરો"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"બૅટરી સેવર ચાલુ કરીએ?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"બૅટરી સેવર વિશે"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ચાલુ કરો"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"બૅટરી સેવર ચાલુ કરો"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"ચાલુ કરો"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"ના, આભાર"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"ઑટો રોટેટ સ્ક્રીન"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>ના ઍક્સેસ માટે <xliff:g id="APPLICATION">%1$s</xliff:g>ને મંજૂરી આપીએ?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g>ને <xliff:g id="USB_DEVICE">%2$s</xliff:g> ઍક્સેસ કરવાની મંજૂરી આપીએ?\nઆ ઍપને રેકૉર્ડ કરવાની પરવાનગી આપવામાં આવી નથી પરંતુ તે આ USB ડિવાઇસ મારફત ઑડિયો કૅપ્ચર કરી શકે છે."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ચહેરાનું પ્રમાણીકરણ થયું"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"પુષ્ટિ કરી"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"પરીક્ષણ પૂર્ણ કરવા કન્ફર્મ કરોને ટૅપ કરો"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"તમારા ચહેરા વડે અનલૉક કર્યું. આગળ વધવા માટે ટૅપ કરો."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"પ્રમાણિત"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"પિનનો ઉપયોગ કરો"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"પૅટર્નનો ઉપયોગ કરો"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"જો તમે આગલા પ્રયત્નમાં ખોટી પૅટર્ન દાખલ કરશો, તો તમારી કાર્યાલયની પ્રોફાઇલ અને તેનો ડેટા ડિલીટ કરવામાં આવશે."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"જો તમે આગલા પ્રયત્નમાં ખોટો પિન દાખલ કરશો, તો તમારી કાર્યાલયની પ્રોફાઇલ અને તેનો ડેટા ડિલીટ કરવામાં આવશે."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"જો તમે આગલા પ્રયત્નમાં ખોટો પાસવર્ડ દાખલ કરશો, તો તમારી કાર્યાલયની પ્રોફાઇલ અને તેનો ડેટા ડિલીટ કરવામાં આવશે."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"ઘણા બધા ખોટા પ્રયત્નો. આ ડિવાઇસનો ડેટા ડિલીટ કરવામાં આવશે."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"ઘણા બધા ખોટા પ્રયત્નો. આ વપરાશકર્તાને ડિલીટ કરવામાં આવશે."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"ઘણા બધા ખોટા પ્રયત્નો. આ કાર્યાલયની પ્રોફાઇલ અને તેનો ડેટા ડિલીટ કરવામાં આવશે."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"છોડી દો"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ફિંગરપ્રિન્ટના સેન્સરને સ્પર્શ કરો"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ફિંગરપ્રિન્ટનું આઇકન"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ચહેરો ઓળખી શકતા નથી. તેને બદલે ફિંગરપ્રિન્ટ વાપરો."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ધીમેથી ચાર્જ થઈ રહ્યું છે • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>માં ચાર્જ થઈ જશે"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ડૉકથી ચાર્જ થઈ રહ્યું છે • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>માં સંપૂર્ણ ચાર્જ થઈ જશે"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"વપરાશકર્તા સ્વિચ કરો"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"વપરાશકર્તા ઉમેરો"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"નવો વપરાશકર્તા"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"અતિથિ દૂર કરીએ?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"આ સત્રમાંની તમામ ઍપ અને ડેટા કાઢી નાખવામાં આવશે."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"કાઢી નાખો"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"ફરી સ્વાગત છે, અતિથિ!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"શું તમે તમારું સત્ર ચાલુ રાખવા માંગો છો?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"શરૂ કરો"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"હા, ચાલુ રાખો"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"નવા વપરાશકર્તાને ઉમેરીએ?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"જ્યારે તમે કોઈ નવા વપરાશકર્તાને ઉમેરો છો, ત્યારે તે વ્યક્તિને તેમનું સ્થાન સેટ કરવાની જરૂર પડે છે.\n\nકોઈપણ વપરાશકર્તા બધા અન્ય વપરાશકર્તાઓ માટે ઍપને અપડેટ કરી શકે છે."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"વપરાશકર્તા સંખ્યાની મર્યાદા"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">તમે <xliff:g id="COUNT">%d</xliff:g> વપરાશકર્તા સુધી ઉમેરી શકો છો.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ઉપયોગ કરવા માટે અનલૉક કરો"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"તમારા કાર્ડની માહિતી મેળવવામાં સમસ્યા આવી હતી, કૃપા કરીને થોડા સમય પછી ફરી પ્રયાસ કરો"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"લૉક સ્ક્રીનના સેટિંગ"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR કોડ"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"સ્કૅન કરવા માટે ટૅપ કરો"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR કોડ સ્કૅન કરો"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"ઑફિસની પ્રોફાઇલ"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"એરપ્લેન મોડ"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"તમે <xliff:g id="WHEN">%1$s</xliff:g> એ તમારો આગલો એલાર્મ સાંભળશો નહીં"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"વધુ જોવા માટે સ્વાઇપ કરો"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"સુઝાવ લોડ કરી રહ્યાં છીએ"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"મીડિયા"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"શું આ મીડિયા સત્ર છુપાવીએ?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"હાલનું મીડિયા સત્ર છુપાવી શકાતું નથી."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"છોડી દો"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"છુપાવો"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"ફરી શરૂ કરો"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"સેટિંગ"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> પર <xliff:g id="ARTIST_NAME">%2$s</xliff:g>નું <xliff:g id="SONG_NAME">%1$s</xliff:g> ગીત ચાલી રહ્યું છે"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"આમાં ચલાવવા માટે ડિવાઇસને <xliff:g id="DEVICENAME">%1$s</xliff:g>ની નજીક ખસેડો"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> પર ચલાવવામાં આવી રહ્યું છે"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"આ ફોન પર ચલાવવામાં આવી રહ્યું છે"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"કંઈક ખોટું થયું"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"નિષ્ક્રિય, ઍપને ચેક કરો"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"મળ્યું નથી"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"નિયંત્રણ ઉપલબ્ધ નથી"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"નવા ડિવાઇસ સાથે જોડાણ કરો"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"આ સત્ર કાસ્ટ કરવા માટે, કૃપા કરીને ઍપ ખોલો."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"અજાણી ઍપ"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"કાસ્ટ કરવાનું રોકો"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"બિલ્ડ નંબર"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"બિલ્ડ નંબર ક્લિપબૉર્ડ પર કૉપિ કર્યો."</string>
     <string name="basic_status" msgid="2315371112182658176">"વાતચીત ખોલો"</string>
@@ -916,7 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"વાઇ-ફાઇ ઉપલબ્ધ નથી"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"પ્રાધાન્યતા મોડ"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"અલાર્મ સેટ"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Assistant અતિથિ મોડ ચાલુ કર્યો"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"કૅમેરા અને માઇક બંધ છે"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# નોટિફિકેશન}one{# નોટિફિકેશન}other{# નોટિફિકેશન}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 27e5091..115c7d3 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"सिस्‍टम यूआई"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"क्या आपको बैटरी सेवर मोड चालू करना है?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"आपकी बैटरी <xliff:g id="PERCENTAGE">%s</xliff:g> बची है. बैटरी सेवर मोड पर, गहरे रंग वाली थीम चालू होती है और बैकग्राउंड में चल रही गतिविधियों पर रोक लग जाती है. इसके अलावा, आपको सूचनाएं भी देरी से मिलती हैं."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"बैटरी सेवर मोड पर, गहरे रंग वाली थीम चालू होती है और बैकग्राउंड में चल रही गतिविधियों पर रोक लग जाती है. इसके अलावा, आपको सूचनाएं भी देरी से मिलती हैं."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> शेष"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"यूएसबी के ज़रिए चार्ज नहीं किया जा सकता"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"अपने डिवाइस के साथ मिलने वाले चार्जर का इस्तेमाल करें"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"क्या आप बैटरी सेवर चालू करना चाहते हैं?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"बैटरी सेवर के बारे में"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"चालू करें"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"बैटरी सेवर चालू करें"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"चालू करें"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"रहने दें"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"स्‍क्रीन अपने आप घुमाना"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> को <xliff:g id="USB_DEVICE">%2$s</xliff:g> के ऐक्सेस की अनुमति दें?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> को <xliff:g id="USB_DEVICE">%2$s</xliff:g> ऐक्सेस करने की अनुमति देना चाहते हैं?\nइस ऐप्लिकेशन को रिकॉर्ड करने की अनुमति नहीं दी गई है. हालांकि, ऐप्लिकेशन इस यूएसबी डिवाइस से ऑडियो कैप्चर कर सकता है."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"चेहरे की पुष्टि हो गई"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"पुष्टि हो गई"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"\'पुष्टि करें\' पर टैप करके पूरा करें"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"आपके चेहरे से अनलॉक किया गया. जारी रखने के लिए टैप करें."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"पुष्टि हो गई"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"पिन इस्तेमाल करें"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"पैटर्न इस्तेमाल करें"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"अगर आप फिर से गलत पैटर्न डालते हैं, तो आपकी वर्क प्रोफ़ाइल और उसका डेटा मिटा दिया जाएगा."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"अगर आप फिर से गलत पिन डालते हैं, तो आपकी वर्क प्रोफ़ाइल और उसका डेटा मिटा दिया जाएगा."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"अगर आप फिर से गलत पासवर्ड डालते हैं, तो आपकी वर्क प्रोफ़ाइल और उसका डेटा मिटा दिया जाएगा."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"कई बार गलत कोशिशें की गई हैं. इस डिवाइस का डेटा मिटा दिया जाएगा."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"कई बार गलत कोशिशें की गई हैं. इस उपयोगकर्ता की जानकारी मिटा दी जाएगी."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"कई बार गलत कोशिशें की गई हैं. यह वर्क प्रोफ़ाइल और इसका डेटा मिटा दिया जाएगा."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"खारिज करें"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"फ़िंगरप्रिंट सेंसर को छुएं"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"फ़िंगरप्रिंट आइकॉन"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"चेहरे की पहचान नहीं हुई. फ़िंगरप्रिंट इस्तेमाल करें."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • धीरे चार्ज हो रहा है • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> में पूरा चार्ज हो जाएगा"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • डॉक पर चार्ज हो रहा है • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> में पूरा चार्ज हो जाएगा"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"उपयोगकर्ता बदलें"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"उपयोगकर्ता जोड़ें"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"नया उपयोगकर्ता"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"क्या आप मेहमान को हटाना चाहते हैं?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"इस सत्र के सभी ऐप्लिकेशन और डेटा को हटा दिया जाएगा."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"निकालें"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"मेहमान, आपका फिर से स्वागत है!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"क्‍या आप अपना सत्र जारी रखना चाहते हैं?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"फिर से शुरू करें"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"हां, जारी रखें"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"नया उपयोगकर्ता जोड़ें?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"जब आप कोई नया उपयोगकर्ता जोड़ते हैं, तो उसे अपनी जगह सेट करनी होती है.\n\nकोई भी उपयोगकर्ता बाकी सभी उपयोगकर्ताओं के लिए ऐप्लिकेशन अपडेट कर सकता है."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"अब और उपयोगकर्ता नहीं जोड़े जा सकते"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">आप ज़्यादा से ज़्यादा <xliff:g id="COUNT">%d</xliff:g> उपयोगकर्ता जोड़ सकते हैं.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"इस्तेमाल करने के लिए, डिवाइस अनलॉक करें"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"आपके कार्ड की जानकारी पाने में कोई समस्या हुई है. कृपया बाद में कोशिश करें"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"लॉक स्क्रीन की सेटिंग"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"क्यूआर कोड"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"स्कैन करने के लिए टैप करें"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"क्यूआर कोड स्कैन करें"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"वर्क प्रोफ़ाइल"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"हवाई जहाज़ मोड"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"आपको <xliff:g id="WHEN">%1$s</xliff:g> पर अपना अगला अलार्म नहीं सुनाई देगा"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"ज़्यादा देखने के लिए स्वाइप करें"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"सुझाव लोड हो रहे हैं"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"मीडिया"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"क्या आप इस मीडिया सेशन को छिपाना चाहते हैं?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"मौजूदा मीडिया सेशन को छिपाया नहीं जा सकता."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"खारिज करें"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"छिपाएं"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"फिर से शुरू करें"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"सेटिंग"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> पर, <xliff:g id="ARTIST_NAME">%2$s</xliff:g> का <xliff:g id="SONG_NAME">%1$s</xliff:g> चल रहा है"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"अपने डिवाइस पर मीडिया फ़ाइल ट्रांसफ़र करने के लिए, उसे <xliff:g id="DEVICENAME">%1$s</xliff:g> के पास ले जाएं"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> पर मीडिया चल रहा है"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"इस फ़ोन पर मीडिया चल रहा है"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"कोई गड़बड़ी हुई"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"काम नहीं कर रहा, ऐप जांचें"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"कंट्रोल नहीं है"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"कंट्रोल मौजूद नहीं है"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नया डिवाइस जोड़ें"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"इस सेशन को कास्ट करने के लिए, कृपया ऐप्लिकेशन खोलें."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"अनजान ऐप्लिकेशन"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"कास्टिंग करना रोकें"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नंबर"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नंबर को क्लिपबोर्ड पर कॉपी किया गया."</string>
     <string name="basic_status" msgid="2315371112182658176">"ऐसी बातचीत जिसमें इंटरैक्शन डेटा मौजूद नहीं है"</string>
@@ -902,7 +892,7 @@
     <string name="fgs_dot_content_description" msgid="2865071539464777240">"नई जानकारी"</string>
     <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"ये ऐप्लिकेशन चालू हैं"</string>
     <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"बंद करें"</string>
-    <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"रुका हुआ है"</string>
+    <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"बंद है"</string>
     <string name="clipboard_edit_text_copy" msgid="770856373439969178">"कॉपी करें"</string>
     <string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"कॉपी किया गया"</string>
     <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> से"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"वाई-फ़ाई उपलब्ध नहीं है"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"प्राथमिकता मोड"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"अलार्म सेट किया गया"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Assistant का मेहमान मोड चालू किया गया"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"कैमरा और माइक बंद हैं"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# सूचना}one{# सूचना}other{# सूचनाएं}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index d3905e7..10d7ab5 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"UI sustava"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Želite li uključiti štednju baterije?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Imate još <xliff:g id="PERCENTAGE">%s</xliff:g> baterije. Štednja baterije uključuje tamnu temu, ograničava aktivnosti u pozadini i odgađa obavijesti."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Štednja baterije uključuje tamnu temu, ograničava aktivnosti u pozadini i odgađa obavijesti."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Preostalo <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Punjenje putem USB-a nije moguće"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Koristite punjač koji ste dobili s uređajem"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Uključiti Štednju baterije?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"O Štednji baterije"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Uključi"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Uključite Štednju baterije"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Uključi"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Ne, hvala"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Automatski zakreni zaslon"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Želite li dopustiti aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> pristup uređaju <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Želite li dopustiti aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> da pristupa uređaju <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nTa aplikacija nema dopuštenje za snimanje, no mogla bi primati zvuk putem tog USB uređaja."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Lice je autentificirano"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrđeno"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Dodirnite Potvrdi za dovršetak"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Otključano vašim licem. Pritisnite da biste nastavili."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentičnost provjerena"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Koristite PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Koristite uzorak"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ako pri sljedećem pokušaju unesete netočan uzorak, izbrisat će se vaš poslovni profil i njegovi podaci."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ako pri sljedećem pokušaju unesete netočan PIN, izbrisat će se vaš poslovni profil i njegovi podaci."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ako pri sljedećem pokušaju unesete netočnu zaporku, izbrisat će se vaš poslovni profil i njegovi podaci."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Previše netočnih pokušaja. S uređaja će se izbrisati podaci."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Previše netočnih pokušaja. Ovaj će se korisnik izbrisati."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Previše netočnih pokušaja. Ovaj će se poslovni profil izbrisati zajedno sa svim svojim podacima."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Odbaci"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dodirnite senzor otiska prsta"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona otiska prsta"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Prepoznavanje lica nije uspjelo. Upotrijebite otisak prsta."</string>
@@ -328,17 +321,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • sporo punjenje • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> do napunjenosti"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Priključna stanica za punjenje • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> do napunjenosti"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Promjena korisnika"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Dodavanje korisnika"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Novi korisnik"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Ukloniti gosta?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci u ovoj sesiji bit će izbrisani."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ukloni"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Dobro došli natrag, gostu!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li nastaviti sesiju?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Počni ispočetka"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Da, nastavi"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Dodati novog korisnika?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Kada dodate novog korisnika, ta osoba mora postaviti vlastiti prostor.\n\nBilo koji korisnik može ažurirati aplikacije za sve ostale korisnike."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Dosegnuto je ograničenje korisnika"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">Možete dodati najviše <xliff:g id="COUNT">%d</xliff:g> korisnika.</item>
@@ -465,8 +453,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Otključajte da biste koristili"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Pojavio se problem prilikom dohvaćanja kartica, pokušajte ponovo kasnije"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Postavke zaključanog zaslona"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR kôd"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Dodirnite za skeniranje"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skeniraj QR kôd"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Poslovni profil"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Način rada u zrakoplovu"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Nećete čuti sljedeći alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -794,9 +781,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Prijeđite prstom da vidite više"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Učitavanje preporuka"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Mediji"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Želite li sakriti medijsku sesiju?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Trenutačna medijska sesija ne može se sakriti."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Odbaci"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Sakrij"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Postavke"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g>, <xliff:g id="ARTIST_NAME">%2$s</xliff:g> reproducira se putem aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -814,7 +802,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Približite se uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g> da biste na njemu reproducirali"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproducira se na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Reproducira se na ovom telefonu"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Nešto nije u redu"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, provjerite aplik."</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string>
@@ -833,6 +822,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Uparite novi uređaj"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Da biste emitirali ovu sesiju, otvorite aplikaciju."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Nepoznata aplikacija"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zaustavi emitiranje"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj međuverzije"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Broj međuverzije kopiran je u međuspremnik."</string>
     <string name="basic_status" msgid="2315371112182658176">"Otvoreni razgovor"</string>
@@ -923,7 +913,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi nije dostupan"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritetni način rada"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm je postavljen"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Omogućen je način rada za goste u Asistentu"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Fotoaparat i mikrofon su isključeni"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# obavijest}one{# obavijest}few{# obavijesti}other{# obavijesti}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 3b94d8f..68e94b1 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Rendszer UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Bekapcsolja az Akkumulátorkímélő módot?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Az akkumulátor töltöttségi szintje <xliff:g id="PERCENTAGE">%s</xliff:g>. Az Akkumulátorkímélő mód bekapcsolja a Sötét témát, korlátozza a háttérbeli tevékenységeket, és késlelteti az értesítéseket."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Az Akkumulátorkímélő mód bekapcsolja a Sötét témát, korlátozza a háttérbeli tevékenységeket, és késlelteti az értesítéseket."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> maradt"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Nem tölthető USB-n keresztül"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Használja az eszközhöz kapott eredeti töltőt"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Bekapcsolja az Akkumulátorkímélő módot?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Az Akkumulátorkímélő módról"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Bekapcsolás"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Akkumulátorkímélő mód bekapcsolása"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Bekapcsolás"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Most nem"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Képernyő automatikus forgatása"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Engedélyezi a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> számára, hogy hozzáférjen a következőhöz: <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Lehetővé teszi a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazásnak, hogy hozzáférjen a következőhöz: <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nEz az alkalmazás nem rendelkezik rögzítési engedéllyel, de ezzel az USB-eszközzel képes a hangfelvételre."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Arc hitelesítve"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Megerősítve"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Koppintson a Megerősítés lehetőségre"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Zárolás feloldva arccal. Nyomja meg a folytatáshoz."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Hitelesítve"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN-kód használata"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Minta használata"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Amennyiben helytelen mintát ad meg a következő kísérletnél, a rendszer törli munkaprofilját és a kapcsolódó adatokat."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Amennyiben helytelen PIN-kódot ad meg a következő kísérletnél, a rendszer törli munkaprofilját és a kapcsolódó adatokat."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Amennyiben helytelen jelszót ad meg a következő kísérletnél, a rendszer törli munkaprofilját és a kapcsolódó adatokat."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Túl sok sikertelen próbálkozás. A rendszer törli az adatokat az eszközről."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Túl sok sikertelen próbálkozás. A rendszer törli ezt a felhasználót."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Túl sok sikertelen próbálkozás. A rendszer törli ezt a munkaprofilt és a kapcsolódó adatokat."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Elvetés"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Érintse meg az ujjlenyomat-érzékelőt"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ujjlenyomat ikonja"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Az arc nem felismerhető. Használjon ujjlenyomatot."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Lassú töltés • A teljes töltöttségig: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Töltődokk • A teljes töltöttségig: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Felhasználóváltás"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Felhasználó hozzáadása"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Új felhasználó"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Eltávolítja a vendég munkamenetet?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"A munkamenetben található összes alkalmazás és adat törlődni fog."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Eltávolítás"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Örülünk, hogy visszatért, vendég!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Folytatja a munkamenetet?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Újrakezdés"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Igen, folytatom"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Új felhasználó hozzáadása?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Ha új felhasználót ad hozzá, az illetőnek be kell állítania saját tárterületét.\n\nBármely felhasználó frissítheti az alkalmazásokat valamennyi felhasználó számára."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Maximális felhasználószám elérve"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">Legfeljebb <xliff:g id="COUNT">%d</xliff:g> felhasználót adhat hozzá.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Oldja fel a használathoz"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Probléma merült fel a kártyák lekérésekor, próbálja újra később"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lezárási képernyő beállításai"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-kód"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Koppintson a beolvasáshoz"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR-kód beolvasása"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Munkahelyi profil"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Repülős üzemmód"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Nem fogja hallani az ébresztést ekkor: <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Továbbiak megtekintéséhez csúsztasson"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Javaslatok betöltése…"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Média"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Elrejti ezt a média-munkamenetet?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Az aktuális média-munkamenet nem rejthető el."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Elvetés"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Elrejtés"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Folytatás"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Beállítások"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> <xliff:g id="SONG_NAME">%1$s</xliff:g> című száma hallható itt: <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Menjen közelebb a(z) <xliff:g id="DEVICENAME">%1$s</xliff:g> eszközhöz, hogy itt játszhassa le a tartalmat"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Lejátszás folyamatban a(z) <xliff:g id="DEVICENAME">%1$s</xliff:g> eszközön"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Lejátszás ezen a telefonon"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Hiba történt"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Inaktív, ellenőrizze az appot"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nem található"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Nem hozzáférhető vezérlő"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Új eszköz párosítása"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"A munkamenet átküldéséhez nyissa meg az alkalmazást."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Ismeretlen alkalmazás"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Átküldés leállítása"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildszám"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Buildszám a vágólapra másolva."</string>
     <string name="basic_status" msgid="2315371112182658176">"Beszélgetés megnyitása"</string>
@@ -916,7 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"A Wi‑Fi nem áll rendelkezésre"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritás mód"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Ébresztő beállítva"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"A Segéd vendég módja engedélyezve"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A kamera és a mikrofon ki vannak kapcsolva"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# értesítés}other{# értesítés}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 488aa76..999a37f 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Համակարգի ինտերֆեյս"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Միացնե՞լ մարտկոցի տնտեսման ռեժիմը"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Մարտկոցի լիցքը՝ <xliff:g id="PERCENTAGE">%s</xliff:g>։ Մարտկոցի տնտեսման ռեժիմում միացվում է մուգ թեման, աշխատանքը ֆոնային ռեժիմում սահմանափակվում է, իսկ ծանուցումները՝ հետաձգվում։"</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Մարտկոցի տնտեսման ռեժիմում միացվում է մուգ թեման, աշխատանքը ֆոնային ռեժիմում սահմանափակվում է, իսկ ծանուցումները՝ հետաձգվում։"</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Մնաց <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Սարքը հնարավոր չէ լիցքավորել USB-ի միջոցով"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Օգտագործեք սարքի լիցքավորիչը"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Միացնե՞լ մարտկոցի տնտեսումը"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Մարտկոցի տնտեսման ռեժիմի մասին"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Միացնել"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Միացնել մարտկոցի տնտեսումը"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Միացնել"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Ոչ, շնորհակալություն"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Ինքնապտտվող էկրան"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Թույլատրե՞լ <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին օգտագործել <xliff:g id="USB_DEVICE">%2$s</xliff:g> լրասարքը։"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Թույլատրե՞լ <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին օգտագործել <xliff:g id="USB_DEVICE">%2$s</xliff:g>ը։\nՀավելվածը ձայնագրելու թույլտվություն չունի, սակայն կկարողանա գրանցել ձայնն այս USB սարքի միջոցով։"</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Դեմքը ճանաչվեց"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Հաստատվեց"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ավարտելու համար հպեք «Հաստատել»"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Ապակողպվեց դեմքով։ Սեղմեք՝ շարունակելու համար։"</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Նույնականացված է"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Օգտագործել PIN կոդ"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Օգտագործել նախշ"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Հաջորդ փորձի ժամանակ սխալ նախշ մուտքագրելու դեպքում ձեր աշխատանքային պրոֆիլը և դրա տվյալները կջնջվեն։"</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Հաջորդ փորձի ժամանակ սխալ PIN կոդ մուտքագրելու դեպքում աշխատանքային պրոֆիլը և դրա տվյալները կջնջվեն։"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Հաջորդ փորձի ժամանակ սխալ գաղտնաբառ մուտքագրելու դեպքում աշխատանքային պրոֆիլը և դրա տվյալները կջնջվեն։"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Չափից շատ սխալ փորձեր են արվել։ Այս սարքի տվյալները կջնջվեն։"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Չափից շատ սխալ փորձեր են արվել։ Oգտատիրոջ պրոֆիլը կջնջվի։"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Չափից շատ սխալ փորձեր են արվել։ Աշխատանքային պրոֆիլը և դրա տվյալները կջնջվեն։"</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Փակել"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Հպեք մատնահետքի սկաներին"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Մատնահետքի պատկերակ"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Դեմքը չի հաջողվում ճանաչել։ Օգտագործեք մատնահետքը։"</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Դանդաղ լիցքավորում • Մնացել է <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Լիցքավորում դոկ-կայանի միջոցով • Մնացել է <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Անջատել օգտվողին"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Ավելացնել օգտատեր"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Նոր օգտատեր"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Հեռացնե՞լ հյուրին"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Այս աշխատաշրջանի բոլոր ծրագրերն ու տվյալները կջնջվեն:"</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Հեռացնել"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Բարի վերադարձ, հյուր"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Շարունակե՞լ աշխատաշրջանը։"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Վերսկսել"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Այո, շարունակել"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Ավելացնե՞լ նոր օգտատեր"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Երբ նոր օգտատեր եք ավելացնում, նա պետք է կարգավորի իր պրոֆիլը:\n\nՑանկացած օգտատեր կարող է թարմացնել հավելվածները մյուս բոլոր հաշիվների համար:"</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Սահմանաչափը սպառված է"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">Հնարավոր է ավելացնել առավելագույնը <xliff:g id="COUNT">%d</xliff:g> օգտատեր։</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ապակողպել՝ օգտագործելու համար"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Չհաջողվեց բեռնել քարտերը։ Նորից փորձեք։"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Կողպէկրանի կարգավորումներ"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR կոդ"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Հպեք՝ սկանավորելու համար"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Սկանավորել QR կոդը"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Android for Work-ի պրոֆիլ"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Ավիառեժիմ"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Ժամը <xliff:g id="WHEN">%1$s</xliff:g>-ի զարթուցիչը չի զանգի"</string>
@@ -549,7 +536,7 @@
     <string name="keyboard_key_enter" msgid="8633362970109751646">"Մուտք"</string>
     <string name="keyboard_key_backspace" msgid="4095278312039628074">"Հետշարժ"</string>
     <string name="keyboard_key_media_play_pause" msgid="8389984232732277478">"Նվագարկում/դադար"</string>
-    <string name="keyboard_key_media_stop" msgid="1509943745250377699">"Դադարեցնել"</string>
+    <string name="keyboard_key_media_stop" msgid="1509943745250377699">"Կանգնեցնել"</string>
     <string name="keyboard_key_media_next" msgid="8502476691227914952">"Հաջորդը"</string>
     <string name="keyboard_key_media_previous" msgid="5637875709190955351">"Նախորդը"</string>
     <string name="keyboard_key_media_rewind" msgid="3450387734224327577">"Հետ անցնել"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Սահեցրեք մատը՝ ավելին իմանալու համար"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Բեռնման խորհուրդներ"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Մեդիա"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Թաքցնե՞լ մեդիայի աշխատաշրջանը"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Չհաջողվեց թաքցնել մեդիայի ընթացիկ աշխատաշրջանը։"</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Փակել"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Թաքցնել"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Շարունակել"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Կարգավորումներ"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Այժմ նվագարկվում է <xliff:g id="SONG_NAME">%1$s</xliff:g> երգը <xliff:g id="ARTIST_NAME">%2$s</xliff:g>-ի կատարմամբ <xliff:g id="APP_LABEL">%3$s</xliff:g> հավելվածից"</string>
@@ -808,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Ավելի մոտեցեք «<xliff:g id="DEVICENAME">%1$s</xliff:g>» սարքին՝ նվագարկումը սկսելու համար"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Նվագարկվում է «<xliff:g id="DEVICENAME">%1$s</xliff:g>» սարքում"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Նվագարկվում է այս հեռախոսում"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Սխալ առաջացավ"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"Սխալ առաջացավ։ Նորից փորձեք։"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Ակտիվ չէ, ստուգեք հավելվածը"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Չի գտնվել"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Կառավարման տարրը հասանելի չէ"</string>
@@ -827,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Նոր սարքի զուգակցում"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Այս աշխատաշրջանը հեռարձակելու համար բացեք հավելվածը"</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Անհայտ հավելված"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Կանգնեցնել հեռարձակումը"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Կառուցման համարը"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Կառուցման համարը պատճենվեց սեղմատախտակին։"</string>
     <string name="basic_status" msgid="2315371112182658176">"Բաց զրույց"</string>
@@ -901,7 +890,7 @@
     </plurals>
     <string name="fgs_dot_content_description" msgid="2865071539464777240">"Նոր տեղեկություն"</string>
     <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Ակտիվ հավելվածներ"</string>
-    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Դադարեցնել"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Կանգնեցնել"</string>
     <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Կանգնեցված է"</string>
     <string name="clipboard_edit_text_copy" msgid="770856373439969178">"Պատճենել"</string>
     <string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Պատճենվեց"</string>
@@ -916,8 +905,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi-ը հասանելի չէ"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Առաջնահերթության ռեժիմ"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Զարթուցիչը դրված է"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Օգնականի հյուրի ռեժիմը միացված է"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Տեսախցիկը և խոսափողն անջատված են"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ծանուցում}one{# ծանուցում}other{# ծանուցում}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 0913166..ba14562 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"UI Sistem"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Aktifkan Penghemat Baterai?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Daya baterai tersisa <xliff:g id="PERCENTAGE">%s</xliff:g>. Penghemat Baterai akan mengaktifkan Tema gelap, membatasi aktivitas latar belakang, dan menunda notifikasi."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Penghemat Baterai akan mengaktifkan Tema gelap, membatasi aktivitas latar belakang, dan menunda notifikasi."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Tersisa <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Tidak dapat mengisi daya melalui USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Gunakan pengisi daya yang disertakan dengan perangkat"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Aktifkan Penghemat Baterai?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Tentang Penghemat Baterai"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Aktifkan"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Aktifkan Penghemat Baterai"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Aktifkan"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Lain kali"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Putar layar otomatis"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Izinkan <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Izinkan <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nAplikasi ini belum diberi izin merekam, tetapi dapat merekam audio melalui perangkat USB ini."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Wajah diautentikasi"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Dikonfirmasi"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ketuk Konfirmasi untuk menyelesaikan"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Kunci dibuka dengan wajah Anda. Tekan untuk melanjutkan."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Diautentikasi"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Gunakan PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Gunakan pola"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Jika Anda memasukkan pola yang salah saat mencoba lagi, profil kerja dan datanya akan dihapus."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Jika Anda memasukkan PIN yang salah saat mencoba lagi, profil kerja dan datanya akan dihapus."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Jika Anda memasukkan sandi yang salah saat mencoba lagi, profil kerja dan datanya akan dihapus."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Terlalu banyak percobaan yang salah. Data perangkat ini akan dihapus."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Terlalu banyak percobaan yang salah. Pengguna ini akan dihapus."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Terlalu banyak percobaan yang salah. Profil kerja ini dan datanya akan dihapus."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Tutup"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Sentuh sensor sidik jari"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikon sidik jari"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tidak dapat mengenali wajah. Gunakan sidik jari."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mengisi daya dengan lambat • Penuh dalam waktu <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mengisi Daya dengan Dok • Penuh dalam waktu <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Beralih pengguna"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Tambahkan pengguna"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Pengguna baru"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Hapus tamu?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua aplikasi dan data di sesi ini akan dihapus."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Hapus"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Selamat datang kembali, tamu!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Lanjutkan sesi Anda?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Mulai ulang"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ya, lanjutkan"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Tambahkan pengguna baru?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Saat Anda menambahkan pengguna baru, orang tersebut perlu menyiapkan ruangnya sendiri.\n\nPengguna mana pun dapat mengupdate aplikasi untuk semua pengguna lain."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Batas pengguna tercapai"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">Anda dapat menambahkan hingga <xliff:g id="COUNT">%d</xliff:g> pengguna.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Buka kunci untuk menggunakan"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Terjadi masalah saat mendapatkan kartu Anda, coba lagi nanti"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Setelan layar kunci"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"Kode QR"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Ketuk untuk memindai"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Pindai kode QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Profil kerja"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Mode pesawat"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Anda tidak akan mendengar alarm berikutnya <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Geser untuk melihat selengkapnya"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Memuat rekomendasi"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Media"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Sembunyikan sesi media ini?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Sesi media aktif tidak dapat disembunyikan."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Tutup"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Sembunyikan"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Lanjutkan"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Setelan"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> oleh <xliff:g id="ARTIST_NAME">%2$s</xliff:g> sedang diputar dari <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Dekatkan ke <xliff:g id="DEVICENAME">%1$s</xliff:g> untuk memutar di sini"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Diputar di <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Diputar di ponsel ini"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Terjadi error"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Nonaktif, periksa aplikasi"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemukan"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrol tidak tersedia"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sambungkan perangkat baru"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Buka aplikasi untuk mentransmisikan sesi ini."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplikasi tidak dikenal"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Hentikan transmisi"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Nomor build"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Nomor versi disalin ke papan klip."</string>
     <string name="basic_status" msgid="2315371112182658176">"Membuka percakapan"</string>
@@ -901,7 +891,7 @@
     </plurals>
     <string name="fgs_dot_content_description" msgid="2865071539464777240">"Informasi baru"</string>
     <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aplikasi aktif"</string>
-    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Berhenti"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Hentikan"</string>
     <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Dihentikan"</string>
     <string name="clipboard_edit_text_copy" msgid="770856373439969178">"Salin"</string>
     <string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Disalin"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi tidak tersedia"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Mode prioritas"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm disetel"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Mode Tamu Asisten diaktifkan"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera dan mikrofon nonaktif"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notifikasi}other{# notifikasi}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index cddb8f8..72dc98e 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Kerfisviðmót"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Kveikja á rafhlöðusparnaði?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"<xliff:g id="PERCENTAGE">%s</xliff:g> rafhlöðuhleðsla eftir. Rafhlöðusparnaður kveikir á dökku þema, dregur úr bakgrunnsvirkni og seinkar tilkynningum."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Rafhlöðusparnaður kveikir á dökku þema, dregur úr bakgrunnsvirkni og seinkar tilkynningum."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> eftir"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Ekki er hægt að hlaða í gegnum USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Notaðu hleðslutækið sem fylgdi tækinu þínu"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Kveikja á rafhlöðusparnaði?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Um rafhlöðusparnað"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Kveikja"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Kveikja á rafhlöðusparnaði"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Kveikja"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Nei, takk"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Snúa skjá sjálfkrafa"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Viltu veita <xliff:g id="APPLICATION">%1$s</xliff:g> aðgang að <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Viltu veita <xliff:g id="APPLICATION">%1$s</xliff:g> aðgang að <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nÞetta forrit hefur ekki fengið heimild fyrir upptöku en gæti tekið upp hljóð í gegnum þetta USB-tæki."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Andlit staðfest"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Staðfest"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ýttu á „Staðfesta“ til að ljúka"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Opnað með andlitinu á þér. Ýttu til að halda áfram."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Auðkennt"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Nota PIN-númer"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Nota mynstur"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ef þú slærð inn rangt mynstur í næstu tilraun verður vinnusniðinu þínu og gögnum þess eytt."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ef þú slærð inn rangt PIN-númer í næstu tilraun verður vinnusniðinu þínu og gögnum þess eytt."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ef þú slærð inn rangt aðgangsorð í næstu tilraun verður vinnusniðinu þínu og gögnum þess eytt."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Of margar rangar tilraunir. Gögnum tækisins verður eytt."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Of margar rangar tilraunir. Þessum notanda verður eytt."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Of margar rangar tilraunir. Þessu vinnusniði og gögnum þess verður eytt."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Loka"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Snertu fingrafaralesarann"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Fingrafaratákn"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Andlit þekkist ekki. Notaðu fingrafar í staðinn."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Hæg hleðsla • Full hleðsla eftir <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Hleður í dokku • Full hleðsla eftir <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Skipta um notanda"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Bæta notanda við"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Nýr notandi"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Fjarlægja gest?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Öllum forritum og gögnum í þessari lotu verður eytt."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Fjarlægja"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Velkominn aftur, gestur!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Viltu halda áfram með lotuna?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Byrja upp á nýtt"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Já, halda áfram"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Bæta nýjum notanda við?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Þegar þú bætir nýjum notanda við þarf sá notandi að setja upp svæðið sitt.\n\nHvaða notandi sem er getur uppfært forrit fyrir alla aðra notendur."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Notandahámarki náð"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">Þú getur bætt við allt að <xliff:g id="COUNT">%d</xliff:g> notanda.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Taktu úr lás til að nota"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Vandamál kom upp við að sækja kortin þín. Reyndu aftur síðar"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Stillingar fyrir læstan skjá"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-kóði"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Ýttu til að skanna"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skanna QR-kóða"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Vinnusnið"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Flugstilling"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Ekki mun heyrast í vekjaranum <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Strjúktu til að sjá meira"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Hleður tillögum"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Margmiðlunarefni"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Fela þessa efnislotu?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Ekki tókst að fela opna efnislotu."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Hunsa"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Fela"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Halda áfram"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Stillingar"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> með <xliff:g id="ARTIST_NAME">%2$s</xliff:g> er í spilun á <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Færðu tækið nær <xliff:g id="DEVICENAME">%1$s</xliff:g> til að spila hér"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Í spilun í <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Í spilun í þessum síma"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Eitthvað fór úrskeiðis"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Óvirkt, athugaðu forrit"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Fannst ekki"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Stýring er ekki tiltæk"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Para nýtt tæki"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Opnaðu forritið til að senda þessa lotu út."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Óþekkt forrit"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stöðva útsendingu"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Útgáfunúmer smíðar"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Útgáfunúmer smíðar afritað á klippiborð."</string>
     <string name="basic_status" msgid="2315371112182658176">"Opna samtal"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WiFi ekki tiltækt"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Forgangsstilling"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Vekjari stilltur"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Kveikt á gestastillingu Hjálpara"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Slökkt á myndavél og hljóðnema"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# tilkynning}one{# tilkynning}other{# tilkynningar}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index ed125cd..bb3ff8f 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"UI sistema"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Vuoi attivare il risparmio energetico?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Batteria rimanente: <xliff:g id="PERCENTAGE">%s</xliff:g>. Il risparmio energetico attiva il tema scuro, limita l\'attività in background e ritarda le notifiche."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Il risparmio energetico attiva il tema scuro, limita l\'attività in background e ritarda le notifiche."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> rimanente"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Impossibile ricaricare tramite USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Utilizza il caricabatterie fornito in dotazione con il dispositivo"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Attivare Risparmio energetico?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Informazioni su Risparmio energetico"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Attiva"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Attiva Risparmio energetico"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Attiva"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"No, grazie"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Rotazione automatica schermo"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Consentire a <xliff:g id="APPLICATION">%1$s</xliff:g> di accedere a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Vuoi consentire all\'app <xliff:g id="APPLICATION">%1$s</xliff:g> di accedere a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nA questa app non è stata concessa l\'autorizzazione di registrazione, ma l\'app potrebbe acquisire l\'audio tramite questo dispositivo USB."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Volto autenticato"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confermato"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tocca Conferma per completare"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Dispositivo sbloccato con il volto. Premi per continuare."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticazione eseguita"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Utilizza PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Usa sequenza"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Se al prossimo tentativo inserirai una sequenza sbagliata, il tuo profilo di lavoro e i relativi dati verranno eliminati."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Se al prossimo tentativo inserirai un PIN sbagliato, il tuo profilo di lavoro e i relativi dati verranno eliminati."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Se al prossimo tentativo inserirai una password sbagliata, il tuo profilo di lavoro e i relativi dati verranno eliminati."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Troppi tentativi sbagliati. I dati del dispositivo verranno eliminati."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Troppi tentativi sbagliati. Questo utente verrà eliminato."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Troppi tentativi sbagliati. Questo profilo di lavoro e i relativi dati verranno eliminati."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Ignora"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Tocca il sensore di impronte"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Icona dell\'impronta"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Impossibile riconoscere il volto. Usa l\'impronta."</string>
@@ -205,8 +198,8 @@
     <string name="accessibility_clear_all" msgid="970525598287244592">"Cancella tutte le notifiche."</string>
     <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192">
-      <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> more notifications inside.</item>
       <item quantity="other">Altre <xliff:g id="NUMBER_1">%s</xliff:g> notifiche nel gruppo.</item>
+      <item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g> altra notifica nel gruppo.</item>
     </plurals>
     <string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"Lo schermo è bloccato in orientamento orizzontale."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"Lo schermo è bloccato in orientamento verticale."</string>
@@ -255,8 +248,8 @@
     <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Attivazione…"</string>
     <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Risp. dati attivo"</string>
     <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="3142308865165871976">
-      <item quantity="one">%d devices</item>
       <item quantity="other">%d dispositivi</item>
+      <item quantity="one">%d dispositivo</item>
     </plurals>
     <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Torcia"</string>
     <string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Fotocamera in uso"</string>
@@ -326,21 +319,16 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ricarica lenta • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> alla ricarica completa"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • In carica nel dock • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> alla ricarica completa"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambio utente"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Aggiungi utente"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Nuovo utente"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Rimuovere l\'ospite?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tutte le app e i dati di questa sessione verranno eliminati."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Rimuovi"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Ti ridiamo il benvenuto alla sessione Ospite."</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vuoi continuare la sessione?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Ricomincia"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Sì, continua"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Aggiungere un nuovo utente?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Il nuovo utente, una volta aggiunto, deve impostare il proprio spazio.\n\nQualsiasi utente può aggiornare le app per tutti gli altri."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Limite di utenti raggiunto"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
-      <item quantity="one">You can add up to <xliff:g id="COUNT">%d</xliff:g> users.</item>
       <item quantity="other">Puoi aggiungere fino a <xliff:g id="COUNT">%d</xliff:g> utenti.</item>
+      <item quantity="one">È possibile creare un solo utente.</item>
     </plurals>
     <string name="user_remove_user_title" msgid="9124124694835811874">"Rimuovere l\'utente?"</string>
     <string name="user_remove_user_message" msgid="6702834122128031833">"Tutte le app e i dati di questo utente verranno eliminati."</string>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Sblocca per usare"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Si è verificato un problema durante il recupero delle tue carte. Riprova più tardi."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Impostazioni schermata di blocco"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"Codice QR"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Tocca per scansionare"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Scansiona codice QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Profilo di lavoro"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Modalità aereo"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Non sentirai la tua prossima sveglia <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -528,12 +515,12 @@
     <string name="snooze_undo" msgid="2738844148845992103">"Annulla"</string>
     <string name="snoozed_for_time" msgid="7586689374860469469">"Posticipato di <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
     <plurals name="snoozeHourOptions" formatted="false" msgid="2066838694120718170">
-      <item quantity="one">%d hours</item>
       <item quantity="other">%d ore</item>
+      <item quantity="one">%d ora</item>
     </plurals>
     <plurals name="snoozeMinuteOptions" formatted="false" msgid="8998483159208055980">
-      <item quantity="one">%d minutes</item>
       <item quantity="other">%d minuti</item>
+      <item quantity="one">%d minuto</item>
     </plurals>
     <string name="battery_detail_switch_title" msgid="6940976502957380405">"Risparmio energetico"</string>
     <string name="keyboard_key_button_template" msgid="8005673627272051429">"Pulsante <xliff:g id="NAME">%1$s</xliff:g>"</string>
@@ -756,8 +743,8 @@
     <string name="quick_controls_title" msgid="6839108006171302273">"Controllo dispositivi"</string>
     <string name="controls_providers_title" msgid="6879775889857085056">"Scegli un\'app per aggiungere controlli"</string>
     <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
-      <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> controlli aggiunti.</item>
       <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> controlli aggiunti.</item>
+      <item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g> controllo aggiunto.</item>
     </plurals>
     <string name="controls_removed" msgid="3731789252222856959">"Rimosso"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Aggiunto ai preferiti"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Scorri per vedere altro"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Caricamento dei consigli"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Contenuti multimediali"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Vuoi nascondere questa sessione multimediale?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Imposs. nascondere sessione multimediale corrente."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ignora"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Nascondi"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Riprendi"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Impostazioni"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> di <xliff:g id="ARTIST_NAME">%2$s</xliff:g> è in riproduzione da <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Avvicinati a <xliff:g id="DEVICENAME">%1$s</xliff:g> per riprodurre i contenuti qui"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"In riproduzione su <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"In riproduzione su questo telefono"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Si è verificato un errore"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Inattivo, controlla l\'app"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Controllo non trovato"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Il controllo non è disponibile"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Accoppia nuovo dispositivo"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Per trasmettere questa sessione devi aprire l\'app."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"App sconosciuta"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Interrompi trasmissione"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Numero build"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Numero build copiato negli appunti."</string>
     <string name="basic_status" msgid="2315371112182658176">"Apri conversazione"</string>
@@ -896,8 +886,8 @@
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Non aggiungerlo"</string>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleziona utente"</string>
     <plurals name="fgs_manager_footer_label" formatted="false" msgid="9091110396713032871">
-      <item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> app attiva</item>
       <item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> app attive</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> app attiva</item>
     </plurals>
     <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nuove informazioni"</string>
     <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"App attive"</string>
@@ -916,7 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi non disponibile"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modalità Priorità"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Sveglia impostata"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Modalità Ospite dell\'assistente attiva"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Fotocamera e microfono non attivi"</string>
-    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notifica}one{# notifica}other{# notifiche}}"</string>
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notifica}other{# notifiche}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index f88605a..c33247a 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"ממשק משתמש של המערכת"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"להפעיל את התכונה \'חיסכון בסוללה\'?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"אחוז הטעינה של הסוללה: <xliff:g id="PERCENTAGE">%s</xliff:g>. התכונה \'חיסכון בסוללה\' מפעילה עיצוב כהה, מגבילה את הפעילת ברקע ומשהה את ההתראות."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"התכונה \'חיסכון בסוללה\' מפעילה עיצוב כהה, מגבילה את הפעילת ברקע ומשהה את ההתראות."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"נותרו <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"‏לא ניתן לטעון באמצעות USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"שימוש במטען שסופק עם המכשיר"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"להפעיל את תכונת החיסכון בסוללה?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"מידע על מצב \'חיסכון בסוללה\'"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"הפעלה"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"הפעלת תכונת החיסכון בסוללה"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"הפעלה"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"לא תודה"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"סיבוב אוטומטי של המסך"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"לתת לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g> גישה אל <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"‏האם לאפשר לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g> גישה אל <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nאפליקציה זו לא קיבלה הרשאה להקליט אך יכולה לתעד אודיו באמצעות מכשיר USB זה."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"זיהוי הפנים בוצע"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"יש אישור"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"יש להקיש על \'אישור\' לסיום התהליך"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"הנעילה בוטלה עם זיהוי הפנים שלך. יש ללחוץ כדי להמשיך."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"מאומת"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"שימוש בקוד אימות"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"שימוש בקו ביטול נעילה"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"הזנת קו ביטול נעילה שגוי בניסיון הבא תגרום למחיקת פרופיל העבודה והנתונים המשויכים אליו."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"הזנה של קוד אימות שגוי בניסיון הבא תגרום למחיקת פרופיל העבודה והנתונים המשויכים אליו."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"הזנת סיסמה שגויה בניסיון הבא תגרום למחיקת פרופיל העבודה והנתונים המשויכים אליו."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"נעשו יותר מדי ניסיונות שגויים. הנתונים במכשיר יימחקו."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"בוצעו יותר מדי ניסיונות שגויים. המשתמש הזה יימחק."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"נעשו יותר מדי ניסיונות שגויים. פרופיל העבודה הזה והנתונים המשויכים אליו יימחקו."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"סגירה"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"יש לגעת בחיישן טביעות האצבע"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"סמל טביעת אצבע"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"לא ניתן לזהות את הפנים. יש להשתמש בטביעת אצבע במקום."</string>
@@ -330,17 +323,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • בטעינה איטית • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> עד לסיום"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • אביזר העגינה בטעינה • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> עד לסיום"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"החלפת משתמש"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"הוספת משתמש"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"משתמש חדש"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"להסיר אורח?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"כל האפליקציות והנתונים בסשן הזה יימחקו."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"הסרה"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"שמחים לראותך שוב!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"האם ברצונך להמשיך בפעילות באתר?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"סשן חדש"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"כן, להמשיך"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"להוסיף משתמש חדש?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"כשמוסיפים משתמש חדש, המשתמש הזה צריך להגדיר את השטח שלו.\n\nכל משתמש יכול לעדכן אפליקציות עבור כל המשתמשים האחרים."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"הגעת למגבלת המשתמשים שניתן להוסיף"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="two">ניתן להוסיף עד <xliff:g id="COUNT">%d</xliff:g> משתמשים.</item>
@@ -468,8 +456,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"יש לבטל את הנעילה כדי להשתמש"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"הייתה בעיה בקבלת הכרטיסים שלך. כדאי לנסות שוב מאוחר יותר"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"הגדרות מסך הנעילה"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"‏קוד QR"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"צריך להקיש כדי לסרוק"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"‏סריקת קוד QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"פרופיל עבודה"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"מצב טיסה"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"לא ניתן יהיה לשמוע את ההתראה הבאה שלך <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -800,9 +787,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"יש להחליק כדי להציג עוד פריטים"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ההמלצות בטעינה"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"מדיה"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"להסתיר את סשן המדיה?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"לא ניתן להסתיר את סשן המדיה הנוכחי."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"סגירה"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"הסתרה"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"המשך"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"הגדרות"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> של <xliff:g id="ARTIST_NAME">%2$s</xliff:g> מופעל מ-<xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -820,7 +808,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"צריך להתקרב אל <xliff:g id="DEVICENAME">%1$s</xliff:g> כדי להפעיל כאן"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"פועלת ב-<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"פועלת בטלפון הזה"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"משהו השתבש"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"לא פעיל, יש לבדוק את האפליקציה"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"לא נמצא"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"הפקד לא זמין"</string>
@@ -839,6 +828,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"התאמה של מכשיר חדש"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"‏כדי להעביר (cast) את הסשן הזה, צריך לפתוח את האפליקציה."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"אפליקציה לא ידועה"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"‏עצירת ההעברה (casting)"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"‏מספר Build"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"‏מספר ה-Build הועתק ללוח."</string>
     <string name="basic_status" msgid="2315371112182658176">"פתיחת שיחה"</string>
@@ -930,8 +920,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"‏Wi‑Fi לא זמין"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"מצב עדיפות"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ההתראה מוגדרת"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"‏מצב אורח ב‑Assistant מופעל"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"המצלמה והמיקרופון כבויים"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{התראה אחת}two{# התראות}many{# התראות}other{# התראות}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index b946344..181f046 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"システム UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"バッテリー セーバーを ON にしますか?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"バッテリー残量は <xliff:g id="PERCENTAGE">%s</xliff:g> です。バッテリー セーバーを有効にすると、ダークモードが ON になります。また、バックグラウンド アクティビティが制限され、通知が届くのが遅くなります。"</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"バッテリー セーバーを有効にすると、ダークモードが ON になります。また、バックグラウンド アクティビティが制限され、通知が届くのが遅くなります。"</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"残量が<xliff:g id="PERCENTAGE">%s</xliff:g>です"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"USB 経由では充電できません"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"デバイスに付属の充電器を使用してください"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"バッテリー セーバーを ON にしますか?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"バッテリー セーバーについて"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ONにする"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"バッテリー セーバーを ON"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"ON にする"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"いいえ"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"自動回転画面"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> に <xliff:g id="USB_DEVICE">%2$s</xliff:g> へのアクセスを許可しますか?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> に <xliff:g id="USB_DEVICE">%2$s</xliff:g>へのアクセスを許可しますか?\nこのアプリに録音権限は付与されていませんが、アクセスを許可すると、この USB デバイスから音声を収集できるようになります。"</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"顔を認証しました"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"確認しました"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"完了するには [確認] をタップしてください"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"顔認識でロックを解除しました。押して続行してください。"</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"認証済み"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN を使用"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"パターンを使用"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"パターンをあと 1 回間違えると、仕事用プロファイルと関連データが削除されます。"</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"PIN をあと 1 回間違えると、仕事用プロファイルと関連データが削除されます。"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"パスワードをあと 1 回間違えると、仕事用プロファイルと関連データが削除されます。"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"間違えた回数が上限を超えました。このデバイスのデータが削除されます。"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"間違えた回数が上限を超えました。このユーザーが削除されます。"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"間違えた回数が上限を超えました。この仕事用プロファイルと関連データが削除されます。"</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"閉じる"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"指紋認証センサーをタッチ"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"指紋アイコン"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"顔を認識できません。指紋認証を使用してください。"</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 低速充電中 • 完了まで <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ホルダーで充電中 • 完了まで <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ユーザーを切り替える"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"ユーザーを追加"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"新しいユーザー"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ゲストを削除しますか?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"このセッションでのアプリとデータはすべて削除されます。"</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"削除"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"おかえりなさい、ゲストさん"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"セッションを続行しますか?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"最初から開始"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"続行"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"新しいユーザーを追加しますか?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"新しいユーザーを追加したら、そのユーザーは自分のスペースをセットアップする必要があります。\n\nすべてのユーザーは他のユーザーに代わってアプリを更新できます。"</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"ユーザー数が上限に達しました"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">最大 <xliff:g id="COUNT">%d</xliff:g> 人のユーザーを追加できます。</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ロックを解除して使用"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"カードの取得中に問題が発生しました。しばらくしてからもう一度お試しください"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ロック画面の設定"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR コード"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"タップしてスキャンします"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR コードのスキャン"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"仕事用プロファイル"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"機内モード"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"次回のアラーム(<xliff:g id="WHEN">%1$s</xliff:g>)は鳴りません"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"スワイプすると他の構造が表示されます"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"候補を読み込んでいます"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"メディア"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"このメディア セッションを非表示にしますか?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"現在のメディア セッションは非表示にできません。"</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"閉じる"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"非表示"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"再開"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"設定"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g>(アーティスト名: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>)が <xliff:g id="APP_LABEL">%3$s</xliff:g> で再生中"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ここで再生するには<xliff:g id="DEVICENAME">%1$s</xliff:g>に近づいてください"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>で再生しています"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"このスマートフォンで再生しています"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"エラーが発生しました"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"無効: アプリをご確認ください"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"見つかりませんでした"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"コントロールを使用できません"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"新しいデバイスとのペア設定"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"このセッションをキャストするには、アプリを開いてください。"</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"不明なアプリ"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"キャストを停止"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"ビルド番号"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"ビルド番号をクリップボードにコピーしました。"</string>
     <string name="basic_status" msgid="2315371112182658176">"空の会話"</string>
@@ -916,7 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi-Fi を利用できません"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"優先順位モード"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"アラームを設定しました"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"アシスタント ゲストモードを有効にしました"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"カメラとマイクが OFF です"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# 件の通知}other{# 件の通知}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 31d7606..97417d9 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"სისტემის UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"გსურთ ბატარეის დამზოგის ჩართვა?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"თქვენი ბატარეა დატენილია <xliff:g id="PERCENTAGE">%s</xliff:g>-ზე. ბატარეის დამზოგი ჩართავს მუქ თემას, შეზღუდავს აქტივობას ფონურ რეჟიმში და შეტყობინებების მიღება შეფერხდება."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"ბატარეის დამზოგი ჩართავს მუქ თემას, შეზღუდავს აქტივობას ფონურ რეჟიმში და შეტყობინებების მიღება შეფერხდება."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"დარჩენილია <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"USB-თ დატენვა ვერ ხერხდება"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"გამოიყენეთ დამტენი, რომელიც თქვენს მოწყობილობას მოჰყვა"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"გსურთ ბატარეის დამზოგის ჩართვა?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"ბატარეის დამზოგის შესახებ"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ჩართვა"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"ბატარეის დამზოგის ჩართვა"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"ჩართვა"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"არა, გმადლობთ"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"ეკრანის ავტოროტაცია"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"მიეცეს <xliff:g id="APPLICATION">%1$s</xliff:g>-ს <xliff:g id="USB_DEVICE">%2$s</xliff:g>-ზე წვდომის უფლება?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"დართავთ <xliff:g id="APPLICATION">%1$s</xliff:g>-ს <xliff:g id="USB_DEVICE">%2$s</xliff:g>-ზე წვდომის ნებას?\nამ აპს არ აქვს მინიჭებული ჩაწერის ნებართვა, მაგრამ შეუძლია ჩაიწეროს აუდიო ამ USB მოწყობილობის მეშვეობით."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"სახის ამოცნობილია"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"დადასტურებული"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"დასასრულებლად შეეხეთ „დადასტურებას“"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"განბლოკილია თქვენი სახით. დააჭირეთ გასაგრძელებლად."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ავტორიზებულია"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN-კოდის გამოყენება"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ნიმუშის გამოყენება"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"შემდეგი მცდელობისას განმბლოკავი ნიმუშის არასწორად შეყვანის შემთხვევაში, თქვენი სამსახურის პროფილი და მისი მონაცემები წაიშლება."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"შემდეგი მცდელობისას PIN-კოდის არასწორად შეყვანის შემთხვევაში, თქვენი სამსახურის პროფილი და მისი მონაცემები წაიშლება."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"შემდეგი მცდელობისას პაროლის არასწორად შეყვანის შემთხვევაში, თქვენი სამსახურის პროფილი და მისი მონაცემები წაიშლება."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"დაფიქსირდა ზედმეტად ბევრი არასწორი მცდელობა. შედეგად, ამ მოწყობილობის მონაცემები წაიშლება."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"დაფიქსირდა ზედმეტად ბევრი არასწორი მცდელობა. შედეგად, ეს მომხმარებელი წაიშლება."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"დაფიქსირდა ზედმეტად ბევრი არასწორი მცდელობა. შედეგად, სამსახურის ეს პროფილი და მისი მონაცემები წაიშლება."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"დახურვა"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"შეეხეთ თითის ანაბეჭდის სენსორს"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"თითის ანაბეჭდის ხატულა"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"სახის ამოცნობა ვერ ხერხდება. სანაცვლოდ თითის ანაბეჭდი გამოიყენეთ."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ნელა იტენება • სრულ დატენვამდე <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • დამტენი სამაგრი • დატენამდე დარჩა <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"მომხმარებლის გადართვა"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"მომხმარებლის დამატება"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"ახალი მომხმარებელი"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"სტუმრის ამოშლა?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ამ სესიის ყველა აპი და მონაცემი წაიშლება."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ამოშლა"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"სტუმარო, გვიხარია, რომ დაბრუნდით!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"გსურთ, თქვენი სესიის გაგრძელება?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ხელახლა დაწყება"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"დიახ, გავაგრძელოთ"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"დაემატოს ახალი მომხმარებელი?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"ახალი მომხმარებლის დამატებისას, ამ მომხმარებელს საკუთარი სივრცის შექმნა მოუწევს.\n\nნებისმიერ მომხმარებელს შეუძლია აპები ყველა სხვა მომხმარებლისათვის განაახლოს."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"მიღწეულია მომხმარებელთა ლიმიტი"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">შესაძლებელია <xliff:g id="COUNT">%d</xliff:g>-მდე მომხმარებლის დამატება.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"გამოსაყენებლად განბლოკვა"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"თქვენი ბარათების მიღებისას პრობლემა წარმოიშვა. ცადეთ ხელახლა მოგვიანებით"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ჩაკეტილი ეკრანის პარამეტრები"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR კოდი"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"შეეხეთ დასასკანირებლად"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR კოდის სკანირება"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"სამსახურის პროფილი"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"თვითმფრინავის რეჟიმი"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"ვერ გაიგონებთ მომდევნო მაღვიძარას <xliff:g id="WHEN">%1$s</xliff:g>-ზე"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"გადაფურცლეთ მეტის სანახავად"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"მიმდინარეობს რეკომენდაციების ჩატვირთვა"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"მედია"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"დაიმალოს მედიის ეს სესია?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"მედიის მიმდინარე სესიის დამალვა შეუძლებელია."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"დახურვა"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"დამალვა"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"გაგრძელება"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"პარამეტრები"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g>, <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, უკრავს <xliff:g id="APP_LABEL">%3$s</xliff:g>-დან"</string>
@@ -808,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"მიუახლოვდით <xliff:g id="DEVICENAME">%1$s</xliff:g>-ს მისი მეშვეობით დასაკრავად"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"მიმდინარეობს დაკვრა <xliff:g id="DEVICENAME">%1$s</xliff:g>-ზე"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"მიმდინარეობს დაკვრა ამ ტელეფონზე"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"რაღაც შეცდომაა"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"რაღაც შეცდომა მოხდა. ცადეთ ხელახლა."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"არააქტიურია, გადაამოწმეთ აპი"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"ვერ მოიძებნა"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"კონტროლი მიუწვდომელია"</string>
@@ -827,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ახალი მოწყობილობის დაწყვილება"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ამ სესიის ტრანსლირებისთვის გახსენით აპი."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"უცნობი აპი"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ტრანსლირების შეწყვეტა"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"ანაწყობის ნომერი"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"ანაწყობის ნომერი დაკოპირებულია გაცვლის ბუფერში."</string>
     <string name="basic_status" msgid="2315371112182658176">"მიმოწერის გახსნა"</string>
@@ -916,7 +905,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi მიუწვდომელია"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"პრიორიტეტული რეჟიმი"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"მაღვიძარა დაყენებულია"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"ასისტენტის სტუმრის რეჟიმი ჩართულია"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"კამერა და მიკროფონი გამორთულია"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# შეტყობინება}other{# შეტყობინება}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index c8abf95..713201b 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Жүйе интерфейсі"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Батареяны үнемдеу режимі қосылсын ба?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"<xliff:g id="PERCENTAGE">%s</xliff:g> заряд қалды. Батареяны үнемдеу режимі қараңғы тақырыпты іске қосады, фондық әрекеттерге шектеу қояды және хабарландыруларды кідіртеді."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Батареяны үнемдеу режимі қараңғы тақырыпты іске қосады, фондық әрекеттерге шектеу қояды және хабарландыруларды кідіртеді."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> қалды"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"USB арқылы зарядтау мүмкін емес"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Құрылғымен бірге берілген зарядтау құралын пайдаланыңыз"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Батареяны үнемдеу режимін қосу керек пе?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Батареяны үнемдеу режимі туралы ақпарат"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Қосу"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Батареяны үнемдеу режимін қосу"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Қосу"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Жоқ, рақмет"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Авто айналатын экран"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасына <xliff:g id="USB_DEVICE">%2$s</xliff:g> құрылғысына кіруге рұқсат берілсін бе?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасына <xliff:g id="USB_DEVICE">%2$s</xliff:g> құрылғысын пайдалануға рұқсат етілсін бе?\nҚолданбаның жазу рұқсаты жоқ, бірақ осы USB құрылғысы арқылы аудио жаза алады."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Бет танылды."</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Расталды"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Аяқтау үшін \"Растау\" түймесін түртіңіз."</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Құлып бетіңіз арқылы ашылды. Жалғастыру үшін басыңыз."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Аутентификацияланған"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN кодын пайдалану"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Өрнекті пайдалану"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Келесі әрекет кезінде қате өрнек енгізсеңіз, жұмыс профиліңіз бен оның деректері жойылады."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Келесі әрекет кезінде қате PIN кодын енгізсеңіз, жұмыс профиліңіз бен оның деректері жойылады."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Келесі әрекет кезінде қате құпия сөз енгізсеңіз, жұмыс профиліңіз бен оның деректері жойылады."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Тым көп қате әрекет жасалды. Бұл құрылғылардың деректері жойылады."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Тым көп қате әрекет жасалды. Бұл пайдаланушы жойылады."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Тым көп қате әрекет жасалды. Бұл жұмыс профилі мен оның деректері жойылады."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Жабу"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Саусақ ізін оқу сканерін түртіңіз"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Саусақ ізі белгішесі"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Бет танылмады. Орнына саусақ ізін пайдаланыңыз."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Баяу зарядталуда • Толуына <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> қалды."</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Қондыру станциясында зарядталуда • Толуына <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> қалды."</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Пайдаланушыны ауыстыру"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Пайдаланушы қосу"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Жаңа пайдаланушы"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Қонақты жою керек пе?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Осы сеанстағы барлық қолданбалар мен деректер жойылады."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Алып тастау"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Қош келдіңіз, қонақ!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Сеансты жалғастыру керек пе?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Қайта бастау"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Иә, жалғастыру"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Жаңа пайдаланушы қосылсын ба?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Жаңа пайдаланушыны қосқанда, сол адам өз кеңістігін реттеуі керек.\n\nКез келген пайдаланушы барлық басқа пайдаланушылар үшін қолданбаларды жаңарта алады."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Пайдаланушылар саны шегіне жетті"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> пайдаланушыға дейін енгізуге болады.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Пайдалану үшін құлыпты ашу"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Карталарыңыз алынбады, кейінірек қайталап көріңіз."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Экран құлпының параметрлері"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR коды"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Сканерлеу үшін түртіңіз."</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR кодын сканерлеу"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Жұмыс профилі"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Ұшақ режимі"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Келесі <xliff:g id="WHEN">%1$s</xliff:g> дабылыңызды есітпейсіз"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Толығырақ ақпарат алу үшін сырғытыңыз."</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Жүктеуге қатысты ұсыныстар"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Мультимедиа"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Бұл мультимедиа сеансы жасырылсын ба?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Ағымдағы мультимедиа сеансын жасыру мүмкін емес."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Жабу"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Жасыру"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Жалғастыру"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Параметрлер"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> қолданбасында <xliff:g id="ARTIST_NAME">%2$s</xliff:g> орындайтын \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" әні ойнатылуда."</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Осы жерде ойнау үшін <xliff:g id="DEVICENAME">%1$s</xliff:g> құрылғысына жақындаңыз"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> құрылғысында ойнатылуда."</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Осы телефонда ойнатылуда."</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Бірдеңе дұрыс болмады."</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Өшірулі. Қолданба тексеріңіз."</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Табылмады"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Басқару виджеті қолжетімсіз"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Жаңа құрылғымен жұптау"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Бұл сеансты трансляциялау үшін қолданбаны ашыңыз."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Белгісіз қолданба"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Трансляцияны тоқтату"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Құрама нөмірі"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Құрама нөмірі буферге көшірілді."</string>
     <string name="basic_status" msgid="2315371112182658176">"Ашық әңгіме"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi қолжетімсіз"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Басымдық режимі"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Оятқыш орнатылды"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Assistant қонақ режимі қосылды"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камера мен микрофон өшірулі"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# хабарландыру}other{# хабарландыру}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 78e6c84..9ca2645 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"UI ប្រព័ន្ធ"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"បើក​មុខងារ​សន្សំ​ថ្មឬ?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"អ្នក​នៅសល់ថ្ម <xliff:g id="PERCENTAGE">%s</xliff:g> ទៀត។ មុខងារសន្សំថ្មបើករចនាប័ទ្មងងឹត ដាក់កំហិតសកម្មភាពនៅផ្ទៃខាងក្រោយ និងពន្យារពេលជូនដំណឹង។"</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"មុខងារសន្សំថ្មបើករចនាប័ទ្មងងឹត ដាក់កំហិតសកម្មភាពនៅផ្ទៃខាងក្រោយ និងពន្យារពេលជូនដំណឹង។"</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"នៅ​សល់ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"មិន​អាច​សាក​តាម USB បានទេ"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"សូមប្រើ​ឆ្នាំង​សាក​ដែល​ភ្ជាប់​មក​ជាមួយ​ឧបករណ៍​របស់អ្នក"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"បើក​មុខងារ​សន្សំ​ថ្ម?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"អំពី​មុខងារ​សន្សំ​ថ្ម"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"បើក"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"បើក​មុខងារ​សន្សំ​ថ្ម"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"បើក"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"ទេ អរគុណ"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"បង្វិល​អេក្រង់​ស្វ័យ​ប្រវត្តិ"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"អនុញ្ញាត <xliff:g id="APPLICATION">%1$s</xliff:g> ឱ្យចូលប្រើ <xliff:g id="USB_DEVICE">%2$s</xliff:g> មែនទេ?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"អនុញ្ញាតឱ្យ <xliff:g id="APPLICATION">%1$s</xliff:g> ចូលប្រើ <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nកម្មវិធីនេះ​មិនទាន់បាន​ទទួលសិទ្ធិ​ថតសំឡេងនៅឡើយទេ ប៉ុន្តែ​អាចថត​សំឡេង​តាមរយៈ​ឧបករណ៍ USB នេះបាន។"</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"បានផ្ទៀងផ្ទាត់​មុខ"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"បានបញ្ជាក់"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ចុច \"បញ្ជាក់\" ដើម្បីបញ្ចប់"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"បានដោះសោ​ដោយប្រើ​មុខរបស់អ្នក។ ចុច ដើម្បីបន្ត។"</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"បាន​ផ្ទៀងផ្ទាត់"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"ប្រើកូដ PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ប្រើ​លំនាំ"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"ប្រសិនបើអ្នក​បញ្ចូលលំនាំមិនត្រឹមត្រូវ នៅពេលព្យាយាមបញ្ចូល​លើកក្រោយ កម្រងព័ត៌មាន​ការងាររបស់អ្នក និងទិន្នន័យរបស់កម្រងព័ត៌មាននេះនឹងត្រូវ​បានលុប។"</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"ប្រសិនបើអ្នក​បញ្ចូលកូដ PIN មិនត្រឹមត្រូវ នៅពេលព្យាយាមបញ្ចូល​លើកក្រោយ កម្រងព័ត៌មានការងាររបស់អ្នក និងទិន្នន័យរបស់កម្រងព័ត៌មាននេះ​នឹងត្រូវបានលុប។"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"ប្រសិនបើអ្នក​បញ្ចូលពាក្យសម្ងាត់មិន​ត្រឹមត្រូវ នៅពេលព្យាយាមបញ្ចូល​លើកក្រោយ កម្រងព័ត៌មាន​ការងាររបស់អ្នក និងទិន្នន័យ​របស់កម្រងព័ត៌មាននេះនឹងត្រូវបានលុប។"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"ដោយសារ​មានការព្យាយាម​ដោះសោ​មិនត្រឹមត្រូវ​ច្រើនដងពេក ទិន្នន័យ​របស់​ឧបករណ៍នេះ​នឹងត្រូវបាន​លុប។"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"ដោយសារ​មានការព្យាយាម​ដោះសោ​មិនត្រឹមត្រូវ​ច្រើនដងពេក អ្នកប្រើប្រាស់នេះ​នឹងត្រូវបាន​ដកចេញ។"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"ដោយសារមានការព្យាយាមដោះសោមិនត្រឹមត្រូវច្រើនដងពេក កម្រងព័ត៌មានការងារនេះ និងទិន្នន័យរបស់វានឹងត្រូវបានលុប។"</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"ច្រានចោល"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ប៉ះ​ឧបករណ៍​ចាប់ស្នាម​ម្រាមដៃ"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"រូប​ស្នាម​ម្រាមដៃ"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"មិនអាចសម្គាល់មុខបានទេ។ សូមប្រើស្នាមម្រាមដៃជំនួសវិញ។"</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • កំពុង​សាកថ្ម​យឺត • ពេញក្នុងរយៈពេល <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ឧបករណ៍ភ្ជាប់សាកថ្ម • ពេញក្នុងរយៈពេល <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ទៀត"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ប្ដូរ​អ្នក​ប្រើ"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"បញ្ចូល​អ្នកប្រើ"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"អ្នកប្រើ​ថ្មី"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ដកភ្ញៀវចេញឬ?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"កម្មវិធី និងទិន្នន័យ​ទាំងអស់​ក្នុង​វគ្គ​នេះ​នឹង​ត្រូវ​លុប។"</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ដកចេញ"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"សូម​ស្វាគមន៍​ការ​ត្រឡប់​មកវិញ, ភ្ញៀវ!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"តើ​អ្នក​ចង់​បន្ត​វគ្គ​របស់​អ្នក​ទេ?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ចាប់ផ្ដើមសាជាថ្មី"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"បាទ​/ចាស ​បន្ត"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"បញ្ចូល​អ្នកប្រើ​ថ្មីឬ?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"នៅពេល​អ្នក​បញ្ចូល​អ្នកប្រើ​ថ្មី អ្នកប្រើ​នោះ​ត្រូវ​រៀបចំកន្លែងរបស់​គេ។\n\nអ្នក​ប្រើ​ណា​ក៏​អាច​ដំឡើងកំណែ​កម្មវិធី​សម្រាប់​អ្នកប្រើទាំងអស់ផ្សេងទៀត​បាន​ដែរ។"</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"​បាន​ឈាន​ដល់ចំនួន​កំណត់អ្នកប្រើប្រាស់"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">អ្នកអាចបញ្ចូល​អ្នក​ប្រើប្រាស់បាន​រហូតដល់ <xliff:g id="COUNT">%d</xliff:g> នាក់។</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ដោះសោដើម្បីប្រើប្រាស់"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"មានបញ្ហា​ក្នុងការទាញយក​កាត​របស់អ្នក សូម​ព្យាយាមម្ដងទៀត​នៅពេលក្រោយ"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ការកំណត់អេក្រង់ចាក់សោ"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"​កូដ QR"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"ចុច​ដើម្បីស្កេន"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"ស្កេន​កូដ QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"ប្រវត្តិរូបការងារ"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"ពេលជិះយន្តហោះ"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"អ្នកនឹងមិនលឺម៉ោងរោទ៍ <xliff:g id="WHEN">%1$s</xliff:g> បន្ទាប់របស់អ្នកទេ"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"អូសដើម្បី​មើលច្រើនទៀត"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"កំពុងផ្ទុក​ការណែនាំ"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"មេឌៀ"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"លាក់វគ្គមេឌៀនេះឬ?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"មិនអាចលាក់វគ្គមេឌៀបច្ចុប្បន្នបានទេ។"</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ច្រាន​ចោល"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"លាក់"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"បន្ត"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"ការកំណត់"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ច្រៀងដោយ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> កំពុងចាក់ពី <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"រំកិលឱ្យកាន់តែជិត <xliff:g id="DEVICENAME">%1$s</xliff:g> ដើម្បីចាក់នៅទីនេះ"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"កំពុង​ចាក់​​នៅ​លើ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"កំពុង​ចាក់​​នៅ​លើទូរសព្ទនេះ"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"មានអ្វីមួយខុសប្រក្រតី"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"មានអ្វីមួយខុសប្រក្រតី។ សូមព្យាយាមម្ដងទៀត។"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"អសកម្ម ពិនិត្យមើល​កម្មវិធី"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"រកមិន​ឃើញទេ"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"មិនអាច​គ្រប់គ្រង​បានទេ"</string>
@@ -827,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ផ្គូផ្គង​ឧបករណ៍ថ្មី"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ដើម្បីភ្ជាប់វគ្គនេះ សូមបើកកម្មវិធី។"</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"កម្មវិធី​ដែលមិន​ស្គាល់"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"បញ្ឈប់ការភ្ជាប់"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"លេខ​កំណែបង្កើត"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"បានចម្លងលេខ​កំណែបង្កើតទៅឃ្លីបបត។"</string>
     <string name="basic_status" msgid="2315371112182658176">"បើកការសន្ទនា"</string>
@@ -916,7 +905,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi ត្រូវបានបិទ"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"មុខងារ​អាទិភាព"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"រូបកំណត់​ម៉ោងរោទ៍"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"បានបើក​មុខងារភ្ញៀវរបស់ Assistant"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"កាមេរ៉ា និង​មីក្រូហ្វូន​ត្រូវបានបិទ"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{ការ​ជូន​ដំណឹង #}other{ការ​ជូនដំណឹង #}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index e10f5d3..afa9df4 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"ಸಿಸ್ಟಂ UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಅನ್ನು ಆನ್ ಮಾಡಬೇಕೇ?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"ನಿಮ್ಮ ಬಳಿ <xliff:g id="PERCENTAGE">%s</xliff:g> ಬ್ಯಾಟರಿ ಉಳಿದಿದೆ. ಬ್ಯಾಟರಿ ಸೇವರ್ ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ, ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆಯನ್ನು ನಿರ್ಬಂಧಿಸುತ್ತದೆ ಮತ್ತು ಅಧಿಸೂಚನೆಗಳನ್ನು ವಿಳಂಬಮಾಡುತ್ತದೆ."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ, ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆಯನ್ನು ನಿರ್ಬಂಧಿಸುತ್ತದೆ ಮತ್ತು ಅಧಿಸೂಚನೆಗಳನ್ನು ವಿಳಂಬಮಾಡುತ್ತದೆ."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> ಉಳಿದಿದೆ"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"USB ಮೂಲಕ ಚಾರ್ಜ್‌ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"ನಿಮ್ಮ ಸಾಧನದೊಂದಿಗೆ ನೀಡಲಾಗಿರುವ ಚಾರ್ಜರ್‌ ಬಳಸಿ"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"ಬ್ಯಾಟರಿ ಸೇವರ್‌ ಆನ್‌ ಮಾಡಬೇಕೇ?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಕುರಿತು"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ಆನ್‌ ಮಾಡಿ"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"ಬ್ಯಾಟರಿ ಸೇವರ್‌ ಆನ್‌ ಮಾಡಿ"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"ಆನ್ ಮಾಡಿ"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"ಬೇಡ"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"ಪರದೆಯನ್ನು ಸ್ವಯಂ-ತಿರುಗಿಸಿ"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ಪ್ರವೇಶಿಸಲು <xliff:g id="APPLICATION">%1$s</xliff:g> ಅನ್ನು ಅನುಮತಿಸುವುದೇ?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ಅನ್ನು ಪ್ರವೇಶಿಸಲು <xliff:g id="APPLICATION">%1$s</xliff:g> ಅನ್ನು ಅನುಮತಿಸುವುದೇ?\nಈ ಆ್ಯಪ್‌ಗೆ ರೆಕಾರ್ಡ್ ಅನುಮತಿಯನ್ನು ನೀಡಲಾಗಿಲ್ಲ, ಆದರೆ ಈ USB ಸಾಧನದ ಮೂಲಕ ಆಡಿಯೊವನ್ನು ಸೆರೆಹಿಡಿಯಬಹುದು."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ಮುಖವನ್ನು ದೃಢೀಕರಿಸಲಾಗಿದೆ"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ದೃಢೀಕರಿಸಲಾಗಿದೆ"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ಪೂರ್ಣಗೊಳಿಸಲು ದೃಢೀಕರಿಸಿ ಅನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"ನಿಮ್ಮ ಮುಖವನ್ನು ಬಳಸಿ ಅನ್‌ಲಾಕ್ ಮಾಡಲಾಗಿದೆ. ಮುಂದುವರಿಯಲು ಒತ್ತಿ."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ದೃಢೀಕರಿಸಲಾಗಿದೆ"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"ಪಿನ್ ಬಳಸಿ"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ಪ್ಯಾಟರ್ನ್ ಬಳಸಿ"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"ಮುಂದಿನ ಪ್ರಯತ್ನದಲ್ಲಿ ನೀವು ತಪ್ಪಾದ ಪ್ಯಾಟರ್ನ್ ನಮೂದಿಸಿದರೆ, ನಿಮ್ಮ ಉದ್ಯೋಗದ ಪ್ರೊಫೈಲ್ ಮತ್ತು ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"ಮುಂದಿನ ಪ್ರಯತ್ನದಲ್ಲಿ ನೀವು ತಪ್ಪಾದ ಪಿನ್ ನಮೂದಿಸಿದರೆ, ನಿಮ್ಮ ಉದ್ಯೋಗದ ಪ್ರೊಫೈಲ್ ಮತ್ತು ಅದರ ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"ಮುಂದಿನ ಪ್ರಯತ್ನದಲ್ಲಿ ನೀವು ತಪ್ಪಾದ ಪಾಸ್‌ವರ್ಡ್ ನಮೂದಿಸಿದರೆ, ನಿಮ್ಮ ಉದ್ಯೋಗದ ಪ್ರೊಫೈಲ್ ಮತ್ತು ಅದರ ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"ಹಲವಾರು ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಈ ಸಾಧನದ ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"ಹಲವಾರು ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಈ ಬಳಕೆದಾರರನ್ನು ಅಳಿಸಲಾಗುವುದು."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"ಹಲವಾರು ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಈ ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್‌ ಮತ್ತು ಅದರ ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"ವಜಾಗೊಳಿಸಿ"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್‌‌ ಅನ್ನು ಸ್ಪರ್ಶಿಸಿ"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಐಕಾನ್"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ಮುಖ ಗುರುತಿಸಲಾಗುತ್ತಿಲ್ಲ ಬದಲಿಗೆ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಬಳಸಿ."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ನಿಧಾನವಾಗಿ ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ಸಮಯದಲ್ಲಿ ಪೂರ್ಣಗೊಳ್ಳುತ್ತದೆ"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ಡಾಕ್ ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ದಲ್ಲಿ ಚಾರ್ಜ್ ಪೂರ್ಣಗೊಳ್ಳುತ್ತದೆ"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ಬಳಕೆದಾರರನ್ನು ಬದಲಿಸಿ"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಿ"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"ಹೊಸ ಬಳಕೆದಾರರು"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ಅತಿಥಿಯನ್ನು ತೆಗೆದುಹಾಕುವುದೇ?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ಈ ಸೆಷನ್‌ನಲ್ಲಿನ ಎಲ್ಲ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ತೆಗೆದುಹಾಕಿ"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"ಮತ್ತೆ ಸುಸ್ವಾಗತ, ಅತಿಥಿ!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"ನಿಮ್ಮ ಸೆಷನ್‌ ಮುಂದುವರಿಸಲು ಇಚ್ಚಿಸುವಿರಾ?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ಪ್ರಾರಂಭಿಸಿ"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"ಹೌದು, ಮುಂದುವರಿಸಿ"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"ಹೊಸ ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸುವುದೇ?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"ನೀವು ಒಬ್ಬ ಹೊಸ ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಿದಾಗ, ಆ ವ್ಯಕ್ತಿಯು ಅವರ ಸ್ಥಳವನ್ನು ಸ್ಥಾಪಿಸಬೇಕಾಗುತ್ತದೆ.\n\nಯಾವುದೇ ಬಳಕೆದಾರರು ಎಲ್ಲಾ ಇತರೆ ಬಳಕೆದಾರರಿಗಾಗಿ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಅಪ್‌ಡೇಟ್‌ ಮಾಡಬಹುದು."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"ಬಳಕೆದಾರರ ಮಿತಿ ತಲುಪಿದೆ"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">ನೀವು <xliff:g id="COUNT">%d</xliff:g> ಬಳಕೆದಾರರವರೆಗೆ ಸೇರಿಸಬಹುದು.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ಬಳಸಲು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"ನಿಮ್ಮ ಕಾರ್ಡ್‌ಗಳನ್ನು ಪಡೆಯುವಾಗ ಸಮಸ್ಯೆ ಉಂಟಾಗಿದೆ, ನಂತರ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ಲಾಕ್ ಸ್ಕ್ರ್ರೀನ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR ಕೋಡ್"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"ಸ್ಕ್ಯಾನ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR ಕೋಡ್ ಸ್ಕ್ಯಾನ್ ಮಾಡಿ"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"ಏರ್‌ಪ್ಲೇನ್ ಮೋಡ್"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"ನಿಮ್ಮ ಮುಂದಿನ <xliff:g id="WHEN">%1$s</xliff:g> ಅಲಾರಮ್ ಅನ್ನು ನೀವು ಆಲಿಸುವುದಿಲ್ಲ"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"ಇನ್ನಷ್ಟು ನೋಡಲು ಸ್ವೈಪ್ ಮಾಡಿ"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ಶಿಫಾರಸುಗಳು ಲೋಡ್ ಆಗುತ್ತಿವೆ"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"ಮಾಧ್ಯಮ"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"ಈ ಮಾಧ್ಯಮ ಸೆಶನ್ ಅನ್ನು ಮರೆಮಾಡಬೇಕೆ?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"ಪ್ರಸ್ತುತ ಮಾಧ್ಯಮ ಸೆಶನ್ ಅನ್ನು ಮರೆಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ವಜಾಗೊಳಿಸಿ"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ಮರೆಮಾಡಿ"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"ಪುನರಾರಂಭಿಸಿ"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> ಅವರ <xliff:g id="SONG_NAME">%1$s</xliff:g> ಹಾಡನ್ನು <xliff:g id="APP_LABEL">%3$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
@@ -808,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ಇಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲು <xliff:g id="DEVICENAME">%1$s</xliff:g> ಸಮೀಪಕ್ಕೆ ಹೋಗಿ"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಆಗುತ್ತಿದೆ"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"ಈ ಫೋನ್‌ನಲ್ಲಿ ಪ್ಲೇ ಆಗುತ್ತಿದೆ"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"ಏನೋ ತಪ್ಪಾಗಿದೆ"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"ಏನೋ ತಪ್ಪಾಗಿದೆ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"ನಿಷ್ಕ್ರಿಯ, ಆ್ಯಪ್ ಪರಿಶೀಲಿಸಿ"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"ಕಂಡುಬಂದಿಲ್ಲ"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"ನಿಯಂತ್ರಣ ಲಭ್ಯವಿಲ್ಲ"</string>
@@ -827,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ಹೊಸ ಸಾಧನವನ್ನು ಜೋಡಿಸಿ"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ಈ ಸೆಶನ್ ಕಾಸ್ಟ್ ಮಾಡಲು, ಆ್ಯಪ್ ಅನ್ನು ತೆರೆಯಿರಿ."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"ಅಪರಿಚಿತ ಆ್ಯಪ್"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ಬಿತ್ತರಿಸುವುದನ್ನು ನಿಲ್ಲಿಸಿ"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"ಬಿಲ್ಡ್ ಸಂಖ್ಯೆ"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"ಬಿಲ್ಡ್ ಸಂಖ್ಯೆಯನ್ನು ಕ್ಲಿಪ್‌ಬೋರ್ಡ್‌ನಲ್ಲಿ ನಕಲಿಸಲಾಗಿದೆ."</string>
     <string name="basic_status" msgid="2315371112182658176">"ಸಂಭಾಷಣೆಯನ್ನು ತೆರೆಯಿರಿ"</string>
@@ -902,7 +891,7 @@
     <string name="fgs_dot_content_description" msgid="2865071539464777240">"ಹೊಸ ಮಾಹಿತಿ"</string>
     <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"ಸಕ್ರಿಯ ಆ್ಯಪ್‌ಗಳು"</string>
     <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ನಿಲ್ಲಿಸಿ"</string>
-    <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"ನಿಲ್ಲಿಸಿದೆ"</string>
+    <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"ನಿಲ್ಲಿಸಲಾಗಿದೆ"</string>
     <string name="clipboard_edit_text_copy" msgid="770856373439969178">"ನಕಲಿಸಿ"</string>
     <string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"ನಕಲಿಸಲಾಗಿದೆ"</string>
     <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> ನಿಂದ"</string>
@@ -916,7 +905,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ವೈ-ಫೈ ಲಭ್ಯವಿಲ್ಲ"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ಆದ್ಯತೆ ಮೋಡ್"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ಅಲಾರಾಂ ಹೊಂದಿಸಲಾಗಿದೆ"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Assistant ಅತಿಥಿ ಮೋಡ್‌ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ಕ್ಯಾಮರಾ ಮತ್ತು ಮೈಕ್ ಆಫ್ ಆಗಿದೆ"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ಅಧಿಸೂಚನೆ}one{# ಅಧಿಸೂಚನೆಗಳು}other{# ಅಧಿಸೂಚನೆಗಳು}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index ba6ef05..8ec281d 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"시스템 UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"절전 모드를 사용 설정하시겠습니까?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"배터리가 <xliff:g id="PERCENTAGE">%s</xliff:g> 남았습니다. 절전 모드는 어두운 테마를 사용 설정하고 백그라운드 활동을 제한하며 알림을 지연시킵니다."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"절전 모드는 어두운 테마를 사용 설정하고 백그라운드 활동을 제한하며 알림을 지연시킵니다."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> 남았습니다."</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"USB로 충전할 수 없습니다."</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"기기와 함께 제공된 충전기를 사용하세요."</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"절전 모드를 사용 설정하시겠습니까?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"절전 모드 정보"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"사용"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"절전 모드 사용 설정"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"사용"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"사용 안함"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"화면 자동 회전"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> 앱이 <xliff:g id="USB_DEVICE">%2$s</xliff:g>에 액세스하도록 허용하시겠습니까?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g>에서 <xliff:g id="USB_DEVICE">%2$s</xliff:g>에 액세스하도록 허용하시겠습니까?\n이 앱에는 녹음 권한이 부여되지 않았지만, 이 USB 기기를 통해 오디오를 녹음할 수 있습니다."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"얼굴이 인증되었습니다."</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"확인함"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"완료하려면 확인을 탭하세요."</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"얼굴 인식으로 잠금 해제했습니다. 계속하려면 누르세요."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"인증됨"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN 사용"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"패턴 사용"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"다음번 시도에서 잘못된 패턴을 입력하면 직장 프로필 및 관련 데이터가 삭제됩니다."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"다음번 시도에서 잘못된 PIN을 입력하면 직장 프로필 및 관련 데이터가 삭제됩니다."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"다음번 시도에서 잘못된 비밀번호를 입력하면 직장 프로필 및 관련 데이터가 삭제됩니다."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"잘못된 시도 횟수가 너무 많습니다. 이 기기의 데이터가 삭제됩니다."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"잘못된 시도 횟수가 너무 많습니다. 이 사용자가 삭제됩니다."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"잘못된 시도 횟수가 너무 많습니다. 이 직장 프로필 및 관련 데이터가 삭제됩니다."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"닫기"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"지문 센서를 터치하세요."</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"지문 아이콘"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"얼굴을 인식할 수 없습니다. 대신 지문을 사용하세요."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 저속 충전 중 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> 후 충전 완료"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 충전 거치대 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> 후 충전 완료"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"사용자 전환"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"사용자 추가"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"신규 사용자"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"게스트를 삭제하시겠습니까?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"이 세션에 있는 모든 앱과 데이터가 삭제됩니다."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"삭제"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"게스트 세션 진행"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"세션을 계속 진행하시겠습니까?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"다시 시작"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"계속 진행"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"신규 사용자를 추가할까요?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"추가된 새로운 사용자는 자신의 공간을 설정해야 합니다.\n\n사용자라면 누구든 다른 사용자를 위해 앱을 업데이트할 수 있습니다."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"사용자 제한 도달"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">사용자를 <xliff:g id="COUNT">%d</xliff:g>명까지 추가할 수 있습니다.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"잠금 해제하여 사용"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"카드를 가져오는 중에 문제가 발생했습니다. 나중에 다시 시도해 보세요."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"잠금 화면 설정"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR 코드"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"탭하여 스캔"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR 코드 스캔"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"직장 프로필"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"비행기 모드"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>에 다음 알람을 들을 수 없습니다."</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"자세히 보려면 스와이프하세요."</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"추천 제어 기능 로드 중"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"미디어"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"이 미디어 세션을 숨기시겠습니까?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"현재 미디어 세션은 숨길 수 없습니다."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"닫기"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"숨기기"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"다시 시작"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"설정"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g>에서 <xliff:g id="ARTIST_NAME">%2$s</xliff:g>의 <xliff:g id="SONG_NAME">%1$s</xliff:g> 재생 중"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"현재 기기에서 재생하려면 <xliff:g id="DEVICENAME">%1$s</xliff:g>에 더 가까이 이동합니다."</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>에서 재생 중"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"휴대전화에서 재생 중"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"문제가 발생했습니다."</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"비활성. 앱을 확인하세요."</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"찾을 수 없음"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"컨트롤을 사용할 수 없음"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"새 기기와 페어링"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"세션을 전송하려면 앱을 열어 주세요"</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"알 수 없는 앱"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"전송 중지"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"빌드 번호"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"빌드 번호가 클립보드에 복사되었습니다."</string>
     <string name="basic_status" msgid="2315371112182658176">"대화 열기"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi를 이용할 수 없습니다."</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"우선순위 모드입니다."</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"알람이 설정되었습니다."</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"어시스턴트 게스트 모드가 사용 설정되었습니다."</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"카메라 및 마이크가 사용 중지되었습니다."</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{알림 #개}other{알림 #개}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index a31ab6d..f213679 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Тутум UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Батареяны үнөмдөгүч режими күйгүзүлсүнбү?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Батареянын деңгээли: <xliff:g id="PERCENTAGE">%s</xliff:g>. Батареяны үнөмдөгүч режими Караңгы теманы күйгүзүп, фондогу аракеттерди чектеп, билдирмелерди кечиктирет."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Батареяны үнөмдөгүч режими Караңгы теманы күйгүзүп, фондогу аракеттерди чектеп, билдирмелерди кечиктирет."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> калды"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"USB аркылуу кубатталбай жатат"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Түзмөгүңүз менен келген кубаттагычты колдонуңуз"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Батареяны үнөмдөө режимин күйгүзөсүзбү?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Батареяны үнөмдөгүч режими жөнүндө маалымат"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Күйгүзүү"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Батареяны үнөмдөгүчтү күйгүзүү"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Күйгүзүү"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Жок, рахмат"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Экранды авто буруу"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосу <xliff:g id="USB_DEVICE">%2$s</xliff:g> түзмөгүн колдоно берсинби?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосу үчүн <xliff:g id="USB_DEVICE">%2$s</xliff:g> түзмөгүнө мүмкүнчүлүк алууга уруксат бересизби?\nБул колдонмонун жаздырууга уруксаты жок, бирок бул USB түзмөгү аркылуу аудиону жаздыра алат."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Жүздүн аныктыгы текшерилди"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Ырасталды"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Бүтүрүү үчүн \"Ырастоо\" баскычын басыңыз"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Жүзүңүз менен ачылды. Улантуу үчүн басыңыз."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Аныктыгы текшерилди"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN кодду колдонуу"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Графикалык ачкычты колдонуу"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Эгер графикалык ачкычты дагы бир жолу туура эмес киргизсеңиз, жумуш профилиңиз жана андагы маалыматтын баары өчөт."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Эгер PIN кодду дагы бир жолу туура эмес киргизсеңиз, жумуш профилиңиз жана андагы маалыматтын баары өчөт."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Эгер сырсөздү дагы бир жолу туура эмес киргизсеңиз, жумуш профилиңиз жана андагы маалыматтын баары өчөт."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Өтө көп жолу жаңылдыңыз. Бул түзмөктөгү дайын-даректер өчүрүлөт."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Өтө көп жолу жаңылдыңыз. Бул колдонуучу өчүрүлөт."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Өтө көп жолу жаңылдыңыз. Бул жумуш профили жана андагы маалымат өчүрүлөт."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Жабуу"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Манжа изинин сенсорун басыңыз"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Манжа изинин сүрөтчөсү"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Жүз таанылбай жатат. Манжа изин колдонуңуз."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Жай кубатталууда • Толгонго чейин <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> калды"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Кубаттоо догу • Толгонго чейин <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> калды"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Колдонуучуну которуу"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Колдонуучу кошуу"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Жаңы колдонуучу"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Конокту алып саласызбы?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Бул сеанстагы бардык колдонмолор жана маалыматтар өчүрүлөт."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Өчүрүү"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Кайтып келишиңиз менен!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Сеансыңызды улантасызбы?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Кайра баштоо"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ооба, уланта берели"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Жаңы колдонуучу кошосузбу?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Жаңы колдонуучу кошулганда, ал өз мейкиндигин түзүп алышы керек.\n\nКолдонмолорду бир колдонуучу жаңыртканда, ал калган бардык колдонуучулар үчүн да жаңырат."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Дагы колдонуучу кошууга болбойт"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> колдонуучуга чейин кошууга болот.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Колдонуу үчүн кулпусун ачыңыз"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Кыйытмаларды алууда ката кетти. Бир аздан кийин кайталап көрүңүз."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Кулпуланган экран жөндөөлөрү"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR коду"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Скандоо үчүн таптап коюңуз"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR кодун скандоо"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Жумуш профили"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Учак режими"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> боло турган кийинки эскертмени укпайсыз"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Дагы көрүү үчүн экранды сүрүп коюңуз"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Сунуштар жүктөлүүдө"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Медиа"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Бул медиа сеансы жашырылсынбы?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Учурдагы медиа сеансын жашыруу мүмкүн эмес."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Жабуу"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Жашыруу"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Улантуу"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Жөндөөлөр"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ыры (аткаруучу: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) <xliff:g id="APP_LABEL">%3$s</xliff:g> колдонмосунан ойнотулуп жатат"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Бул жерде ойнотуу үчүн <xliff:g id="DEVICENAME">%1$s</xliff:g> түзмөгүнө жакындатыңыз"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> аркылуу ойнотулууда"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Ушул телефондо ойнотулууда"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Бир жерден ката кетти"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Жигерсиз. Колдонмону текшериңиз"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Табылган жок"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Башкара албайсыз"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Жаңы түзмөктү жупташтыруу"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Бул сеансты тышкы экранга чыгаруу үчүн колдонмону ачыңыз."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Белгисиз колдонмо"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Тышкы экранга чыгарууну токтотуу"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Курама номери"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Курама номери алмашуу буферине көчүрүлдү."</string>
     <string name="basic_status" msgid="2315371112182658176">"Ачык сүйлөшүү"</string>
@@ -916,7 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi жеткиликсиз"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Маанилүү сүйлөшүүлөр режими"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Ойготкуч коюлду"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Жардамчынын конок режими иштетилди"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камера жана микрофон өчүк"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# билдирме}other{# билдирме}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-land/styles.xml b/packages/SystemUI/res/values-land/styles.xml
index f3d83645..8919198 100644
--- a/packages/SystemUI/res/values-land/styles.xml
+++ b/packages/SystemUI/res/values-land/styles.xml
@@ -18,15 +18,4 @@
     <style name="BrightnessDialogContainer" parent="@style/BaseBrightnessDialogContainer">
         <item name="android:layout_width">360dp</item>
     </style>
-
-    <style name="DockedDividerBackground">
-        <item name="android:layout_width">10dp</item>
-        <item name="android:layout_height">match_parent</item>
-        <item name="android:layout_gravity">center_horizontal</item>
-    </style>
-
-    <style name="DockedDividerMinimizedShadow">
-        <item name="android:layout_width">8dp</item>
-        <item name="android:layout_height">match_parent</item>
-    </style>
 </resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 204e3d9..354adc3 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"ສ່ວນຕິດຕໍ່ຜູ້ໃຊ້ຂອງລະບົບ"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"ເປີດໃຊ້ຕົວປະຢັດແບັດເຕີຣີບໍ?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"ທ່ານມີແບັດເຕີຣີເຫຼືອ <xliff:g id="PERCENTAGE">%s</xliff:g>. ຕົວປະຢັດແບັດເຕີຣີຈະເປີດໃຊ້ຮູບແບບສີສັນມືດ, ຈຳກັດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ ແລະ ເລື່ອນການແຈ້ງເຕືອນອອກໄປ."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"ຕົວປະຢັດແບັດເຕີຣີຈະເປີດໃຊ້ຮູບແບບສີສັນມືດ, ຈຳກັດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ ແລະ ເລື່ອນການແຈ້ງເຕືອນອອກໄປ."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"ຍັງ​ເຫຼືອ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"ບໍ່ສາມາດສາກຜ່ານ USB ໄດ້"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"ກະລຸນາໃຊ້ຕົວສາກທີ່ມາພ້ອມກັບອຸປະກອນຂອງທ່ານ"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"ເປີດໃຊ້ຕົວປະຢັດແບັດເຕີຣີບໍ?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"ກ່ຽວກັບຕົວປະຢັດແບັດເຕີຣີ"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ເປີດ​ໃຊ້"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"ເປີດໃຊ້ຕົວປະຢັດແບັດເຕີຣີ"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"ເປີດໃຊ້"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"ບໍ່, ຂອບໃຈ"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"ໝຸນໜ້າຈໍອັດຕະໂນມັດ"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"ອະນຸຍາດໃຫ້ <xliff:g id="APPLICATION">%1$s</xliff:g> ເຂົ້າເຖິງ <xliff:g id="USB_DEVICE">%2$s</xliff:g> ໄດ້ບໍ?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"ອະນຸຍາດໃຫ້ <xliff:g id="APPLICATION">%1$s</xliff:g> ເຂົ້າເຖິງ <xliff:g id="USB_DEVICE">%2$s</xliff:g> ໄດ້ບໍ?\nແອັບນີ້ບໍ່ໄດ້ຮັບອະນຸາດໃຫ້ບັນທຶກໄດ້ແຕ່ສາມາດບັນທຶກສຽງໄດ້ຜ່ານອຸປະກອນ USB ນີ້."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ພິສູດຢືນຢັນໃບໜ້າແລ້ວ"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ຢືນຢັນແລ້ວ"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ແຕະຢືນຢັນເພື່ອສຳເລັດ"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"ປົດລັອກດ້ວຍໜ້າຂອງທ່ານແລ້ວ. ກົດເພື່ອສືບຕໍ່."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ຮັບຮອງຄວາມຖືກຕ້ອງແລ້ວ"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"ໃຊ້ PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ໃຊ້ຮູບແບບ"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"ຫາກທ່ານໃສ່ຣູບແບບຜິດໃນຄວາມພະຍາຍາມເທື່ອຕໍ່ໄປ, ໂປຣໄຟລ໌ບ່ອນເຣັດວຽກຂອງທ່ານ ແລະ ຂໍ້ມູນຂອງມັນຈະຖືກລຶບອອກ."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"ຫາກທ່ານໃສ່ລະຫັດ PIN ຜິດໃນຄວາມພະຍາຍາມເທື່ອຕໍ່ໄປ, ໂປຣໄຟລ໌ບ່ອນເຣັດວຽກຂອງທ່ານ ແລະ ຂໍ້ມູນຂອງມັນຈະຖືກລຶບອອກ."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"ຫາກທ່ານໃສ່ລະຫັດຜິດໃນຄວາມພະຍາຍາມເທື່ອຕໍ່ໄປ, ໂປຣໄຟລ໌ບ່ອນເຣັດວຽກຂອງທ່ານ ແລະ ຂໍ້ມູນຂອງມັນຈະຖືກລຶບອອກ."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"ພະຍາຍາມປົດລັອກບໍ່ສຳເລັດຫຼາຍເທື່ອເກີນໄປ. ອຸປະກອນນີ້ຈະຖືກລຶບຂໍ້ມູນອອກ."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"ພະຍາຍາມປົດລັອກບໍ່ສຳເລັດຫຼາຍເທື່ອເກີນໄປ. ຜູ້ໃຊ້ນີ້ຈະຖືກລຶບຂໍ້ມູນອອກ."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"ພະຍາຍາມປົດລັອກບໍ່ສຳເລັດຫຼາຍເທື່ອເກີນໄປ. ໂປຣໄຟລ໌ບ່ອນເຣັດວຽກ ແລະ ຂໍ້ມູນຂອງມັນຈະຖືກລຶບອອກ."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"ປິດໄວ້"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ແຕະໃສ່ເຊັນເຊີລາຍນິ້ວມື"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ໄອຄອນລາຍນິ້ວມື"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ບໍ່ສາມາດຈຳແນກໜ້າໄດ້. ກະລຸນາໃຊ້ລາຍນິ້ວມືແທນ."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ກຳລັງສາກໄຟແບບຊ້າ • ຈະເຕັມໃນອີກ <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ກຳລັງສາກໄຟຜ່ານດັອກ • ຈະເຕັມໃນອີກ <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ສະຫຼັບຜູ້ໃຊ້"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"ເພີ່ມຜູ້ໃຊ້"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"ຜູ່ໃຊ້ໃໝ່"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ລຶບ​ແຂກ​ບໍ?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ແອັບຯ​ແລະ​ຂໍ້​ມູນ​ທັງ​ໝົດ​ໃນ​ເຊດ​ຊັນ​ນີ້​ຈະ​ຖືກ​ລຶບ​ອອກ."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ລຶບ​"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"ຍິນ​ດີ​ຕ້ອນ​ຮັບ​ກັບ​ມາ, ຜູ້ຢ້ຽມຢາມ!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"ທ່ານ​ຕ້ອງ​ການ​ສືບ​ຕໍ່​ເຊດ​ຊັນ​ຂອງ​ທ່ານບໍ່?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ເລີ່ມຕົ້ນໃຫມ່"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"​ຕົກ​ລົງ, ດຳ​ເນີນ​ການ​ຕໍ່"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"ເພີ່ມຜູ້ໃຊ້ໃໝ່ບໍ?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"ເມື່ອ​ທ່ານ​ເພີ່ມ​ຜູ້ໃຊ້​ໃໝ່, ຜູ້ໃຊ້​ນັ້ນ​ຈະ​ຕ້ອງ​ຕັ້ງ​ຄ່າ​ພື້ນ​ທີ່​ບ່ອນ​ຈັດ​ເກັບ​ຂໍ້​ມູນ​ຂອງ​ລາວ.\n\nຜູ້ໃຊ້​ທຸກ​ຄົນ​ສາ​ມາດ​ອັບ​ເດດ​ແອັບຂອງ​ຜູ້​ໃຊ້​ຄົນ​ອື່ນ​ທັງ​ໝົດ​ໄດ້."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"ຮອດຂີດຈຳກັດຜູ້ໃຊ້ແລ້ວ"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">ທ່ານສາມາດເພີ່ມໄດ້ສູງສຸດ <xliff:g id="COUNT">%d</xliff:g> ຄົນ.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ປົດລັອກເພື່ອໃຊ້"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"ເກີດບັນຫາໃນການໂຫຼດບັດຂອງທ່ານ, ກະລຸນາລອງໃໝ່ໃນພາຍຫຼັງ"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ການຕັ້ງຄ່າໜ້າຈໍລັອກ"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"ລະຫັດ QR"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"ແຕະເພື່ອສະແກນ"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"ສະແກນລະຫັດ QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"​ໂປຣ​ໄຟລ໌​ບ່ອນ​ເຮັດ​ວຽກ"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"ໂໝດເຮືອ​ບິນ"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"ທ່ານ​ຈະ​ບໍ່​ໄດ້​ຍິນ​ສຽງ​ໂມງ​ປ <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"ປັດເພື່ອເບິ່ງເພີ່ມເຕີມ"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ກຳລັງໂຫຼດຄຳແນະນຳ"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"ມີເດຍ"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"ເຊື່ອງເຊດຊັນມີເດຍນີ້ບໍ?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"ບໍ່ສາມາດເຊື່ອງເຊດຊັນມີເດຍປັດຈຸບັນໄດ້."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ປິດໄວ້"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ເຊື່ອງ"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"ສືບຕໍ່"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"ການຕັ້ງຄ່າ"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ໂດຍ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> ກຳລັງຫຼິ້ນຈາກ <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ກະລຸນາຍ້າຍເຂົ້າໃກ້ <xliff:g id="DEVICENAME">%1$s</xliff:g> ເພື່ອຫຼິ້ນຢູ່ບ່ອນນີ້"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"ກຳລັງຫຼິ້ນຢູ່ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"ກຳລັງຫຼິ້ນຢູ່ໂທລະສັບນີ້"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"ມີບາງຢ່າງຜິດພາດເກີດຂຶ້ນ"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"ບໍ່ເຮັດວຽກ, ກະລຸນາກວດສອບແອັບ"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"ບໍ່ພົບ"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"ບໍ່ສາມາດໃຊ້ການຄວບຄຸມໄດ້"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ຈັບຄູ່ອຸປະກອນໃໝ່"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ເພື່ອສົ່ງສັນຍານເຊດຊັນນີ້, ກະລຸນາເປີດແອັບ."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"ແອັບທີ່ບໍ່ຮູ້ຈັກ"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ຢຸດການສົ່ງສັນຍານ"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"ໝາຍເລກສ້າງ"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"ສຳເນົາໝາຍເລກສ້າງໄປໃສ່ຄລິບບອດແລ້ວ."</string>
     <string name="basic_status" msgid="2315371112182658176">"ເປີດການສົນທະນາ"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ບໍ່ສາມາດໃຊ້ Wi‑Fi ໄດ້"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ໂໝດຄວາມສຳຄັນ"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ຕັ້ງໂມງປຸກແລ້ວ"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"ເປີດການນຳໃຊ້ໂໝດແຂກຜູ້ຊ່ວຍແລ້ວ"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ປິດກ້ອງຖ່າຍຮູບ ແລະ ໄມແລ້ວ"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ການແຈ້ງເຕືອນ}other{# ການແຈ້ງເຕືອນ}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 6bcfa0e..4fb8399 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Sistemos NS"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Įjungti Akumuliatoriaus tausojimo priemonę?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Liko <xliff:g id="PERCENTAGE">%s</xliff:g> akumuliatoriaus energijos. Kai naudojama Akumuliatoriaus tausojimo priemonė, įjungiama Tamsioji tema, apribojama veikla fone ir atidedami pranešimai."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Kai naudojama Akumuliatoriaus tausojimo priemonė, įjungiama Tamsioji tema, apribojama veikla fone ir atidedami pranešimai."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Liko <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Negalima įkrauti naudojant USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Naudokite originalų su įrenginiu pateiktą įkroviklį"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Įjungti Akumuliatoriaus tausojimo priemonę?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Apie Akumuliatoriaus tausojimo priemonę"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Įjungti"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Įjungti Akumuliatoriaus tausojimo priemonę"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Įjungti"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Ne, ačiū"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Automatiškai sukti ekraną"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Leisti „<xliff:g id="APPLICATION">%1$s</xliff:g>“ pasiekti įrenginį (<xliff:g id="USB_DEVICE">%2$s</xliff:g>)?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Leisti „<xliff:g id="APPLICATION">%1$s</xliff:g>“ pasiekti įrenginį (<xliff:g id="USB_DEVICE">%2$s</xliff:g>)?\nŠiai programai nebuvo suteiktas leidimas įrašyti, bet ji gali užfiksuoti garsą per šį USB įrenginį."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Veidas autentifikuotas"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Patvirtinta"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Paliesk. „Patvirtinti“, kad užbaigtumėte"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Atrakinta pagal veidą. Paspauskite, jei norite tęsti."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentifikuota"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Naudoti PIN kodą"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Naudoti atrakinimo piešinį"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Jei kitu bandymu nupiešite netinkamą atrakinimo piešinį, darbo profilis ir jo duomenys bus ištrinti."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Jei kitu bandymu įvesite netinkamą PIN kodą, darbo profilis ir jo duomenys bus ištrinti."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Jei kitu bandymu įvesite netinkamą slaptažodį, darbo profilis ir jo duomenys bus ištrinti."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Per daug netinkamų bandymų. Šio įrenginio duomenys bus ištrinti."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Per daug netinkamų bandymų. Šis naudotojas bus ištrintas."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Per daug netinkamų bandymų. Šis darbo profilis ir jo duomenys bus ištrinti."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Atsisakyti"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Palieskite piršto antspaudo jutiklį"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Piršto antspaudo piktograma"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Veidas neatpažintas. Naudokite kontrolinį kodą."</string>
@@ -330,17 +323,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Lėtai įkraunama • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> iki visiško įkrovimo"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Įkraunama doke • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> iki visiško įkrovimo"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Perjungti naudotoją"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Pridėti naudotoją"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Naujas naudotojas"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Pašalinti svečią?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bus ištrintos visos šios sesijos programos ir duomenys."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Pašalinti"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Sveiki sugrįžę, svety!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Ar norite tęsti sesiją?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Pradėti iš naujo"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Taip, tęsti"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Pridėti naują naudotoją?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Kai pridedate naują naudotoją, šis asmuo turi nustatyti savo erdvę.\n\nBet kuris naudotojas gali atnaujinti visų kitų naudotojų programas."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Pasiekta naudotojų riba"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">Galite pridėti iki <xliff:g id="COUNT">%d</xliff:g> naudotojo.</item>
@@ -468,8 +456,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Atrakinti, kad būtų galima naudoti"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Gaunant korteles kilo problema, bandykite dar kartą vėliau"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Užrakinimo ekrano nustatymai"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR kodas"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Palieskite, kad nuskaitytumėte"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR kodo nuskaitymas"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Darbo profilis"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Lėktuvo režimas"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Negirdėsite kito signalo <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -800,9 +787,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Perbraukite, kad peržiūrėtumėte daugiau"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Įkeliamos rekomendacijos"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Medija"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Slėpti šį medijos seansą?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Dabartinio medijos seanso negalima paslėpti."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Atsisakyti"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Slėpti"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Tęsti"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Nustatymai"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> – „<xliff:g id="SONG_NAME">%1$s</xliff:g>“ leidžiama iš „<xliff:g id="APP_LABEL">%3$s</xliff:g>“"</string>
@@ -820,7 +808,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Perkelkite arčiau „<xliff:g id="DEVICENAME">%1$s</xliff:g>“, kad būtų galima leisti čia"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Leidžiama įrenginyje „<xliff:g id="DEVICENAME">%1$s</xliff:g>“"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Leidžiama šiame telefone"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Kažkas ne taip"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Neaktyvu, patikrinkite progr."</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nerasta"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Valdiklis nepasiekiamas"</string>
@@ -839,6 +828,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Naujo įrenginio susiejimas"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Jei norite perduoti šį seansą, atidarykite programą."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Nežinoma programa"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Sustabdyti perdavimą"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Versijos numeris"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Versijos numeris nukopijuotas į iškarpinę."</string>
     <string name="basic_status" msgid="2315371112182658176">"Atidaryti pokalbį"</string>
@@ -930,8 +920,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"„Wi‑Fi“ ryšys nepasiekiamas"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioriteto režimas"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Signalas nustatytas"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Įgalintas Padėjėjo svečio režimas"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Vaizdo kamera ir mikrofonas išjungti"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# pranešimas}one{# pranešimas}few{# pranešimai}many{# pranešimo}other{# pranešimų}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 286cdec..5265e50 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Sistēmas UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Vai ieslēgt akumulatora enerģijas taupīšanas režīmu?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Atlikušais akumulatora uzlādes līmenis: <xliff:g id="PERCENTAGE">%s</xliff:g>. Akumulatora enerģijas taupīšanas režīmā tiek ieslēgts tumšais motīvs, ierobežotas darbības fonā un aizkavēti paziņojumi."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Akumulatora enerģijas taupīšanas režīmā tiek ieslēgts tumšais motīvs, ierobežotas darbības fonā un aizkavēti paziņojumi."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Atlikuši <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Nevar veikt uzlādi, izmantojot USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Izmantojiet ierīces komplektācijā iekļauto lādētāju"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Vai ieslēgt akumulatora enerģijas taupīšanas režīmu?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Par akumulatora enerģijas taupīšanas režīmu"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Ieslēgt"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Ieslēgt akumulatora enerģijas taupīšanas režīmu"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Ieslēgt"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Nē, paldies"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Automātiska ekrāna pagriešana"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Vai atļaut lietotnei <xliff:g id="APPLICATION">%1$s</xliff:g> piekļūt šai ierīcei: <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Vai atļaut lietotnei <xliff:g id="APPLICATION">%1$s</xliff:g> piekļūt ierīcei “<xliff:g id="USB_DEVICE">%2$s</xliff:g>”?\nŠai lietotnei nav piešķirta ierakstīšanas atļauja, taču tā varētu tvert audio, izmantojot šo USB ierīci."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Seja autentificēta"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Apstiprināts"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Lai pabeigtu, pieskarieties Apstiprināt"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Sākta autorizācija pēc sejas. Nospiediet, lai turpinātu."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentifikācija veikta"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Izmantot PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Izmantot kombināciju"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ja nākamajā mēģinājumā ievadīsiet nepareizu kombināciju, jūsu darba profils un ar to saistītie dati tiks dzēsti."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ja nākamajā mēģinājumā ievadīsiet nepareizu PIN, jūsu darba profils un ar to saistītie dati tiks dzēsti."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ja nākamajā mēģinājumā ievadīsiet nepareizu paroli, jūsu darba profils un ar to saistītie dati tiks dzēsti."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Pārāk daudz neveiksmīgu mēģinājumu. Dati šajā ierīcē tiks dzēsti."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Pārāk daudz neveiksmīgu mēģinājumu. Šis lietotājs tiks dzēsts."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Pārāk daudz neveiksmīgu mēģinājumu. Šis darba profils un ar to saistītie dati tiks dzēsti."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Nerādīt"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Pieskarieties pirksta nospieduma sensoram"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Pirksta nospieduma ikona"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nevar atpazīt seju. Lietojiet pirksta nospiedumu."</string>
@@ -328,17 +321,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Lēnā uzlāde • Laiks līdz pilnai uzlādei: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Notiek uzlāde dokā • Līdz pilnai uzlādei atlicis: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Mainīt lietotāju"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Lietotāja pievienošana"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Jauns lietotājs"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vai noņemt viesi?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tiks dzēstas visas šīs sesijas lietotnes un dati."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Noņemt"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Laipni lūdzam atpakaļ, viesi!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vai vēlaties turpināt savu sesiju?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Sākt no sākuma"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Jā, turpināt"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Vai pievienot jaunu lietotāju?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Kad pievienosiet jaunu lietotāju, viņam būs jāizveido savs profils.\n\nIkviens lietotājs var atjaunināt lietotnes citu lietotāju vietā."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Sasniegts lietotāju ierobežojums"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="zero">Varat pievienot ne vairāk kā <xliff:g id="COUNT">%d</xliff:g> lietotājus.</item>
@@ -465,8 +453,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lai izmantotu, atbloķējiet ekrānu"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Ienesot jūsu kartes, radās problēma. Lūdzu, vēlāk mēģiniet vēlreiz."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Bloķēšanas ekrāna iestatījumi"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"Ātrās atbildes kods"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Pieskarieties, lai skenētu"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR koda skenēšana"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Darba profils"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Lidojuma režīms"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Nākamais signāls (<xliff:g id="WHEN">%1$s</xliff:g>) netiks atskaņots."</string>
@@ -794,9 +781,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Velciet, lai skatītu citus vienumus"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Notiek ieteikumu ielāde"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Multivide"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Vai paslēpt šo multivides sesiju?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Pašreizējo multivides sesiju nevar paslēpt."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Nerādīt"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Paslēpt"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Atsākt"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Iestatījumi"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Tiek atskaņots fails “<xliff:g id="SONG_NAME">%1$s</xliff:g>” (izpildītājs: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) no lietotnes <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string>
@@ -814,7 +802,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Pārvietojieties tuvāk ierīcei “<xliff:g id="DEVICENAME">%1$s</xliff:g>”, lai atskaņotu šeit"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Notiek atskaņošana ierīcē <xliff:g id="DEVICENAME">%1$s</xliff:g>."</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Notiek atskaņošana šajā tālrunī"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Radās problēma"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Neaktīva, pārbaudiet lietotni"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Netika atrasta"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Vadīkla nav pieejama"</string>
@@ -833,6 +822,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Savienošana pārī ar jaunu ierīci"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Lai apraidītu šo sesiju, lūdzu, atveriet lietotni."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Nezināma lietotne"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Apturēt apraidi"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Versijas numurs"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Versijas numurs ir kopēts starpliktuvē."</string>
     <string name="basic_status" msgid="2315371112182658176">"Atvērt sarunu"</string>
@@ -923,8 +913,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi nav pieejams"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritātes režīms"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Signāls ir iestatīts"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Asistenta viesa režīms ir iespējots"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera un mikrofons ir izslēgti"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# paziņojums}zero{# paziņojumu}one{# paziņojums}other{# paziņojumi}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index ffa0e58..bbf7d34 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Кориснички интерфејс на систем"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Да се вклучи „Штедачот на батерија“?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Имате уште <xliff:g id="PERCENTAGE">%s</xliff:g> батерија. „Штедачот на батерија“ ја вклучува „Темната тема“, ја ограничува активноста во заднина и ги одложува известувањата."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"„Штедачот на батерија“ ја вклучува „Темната тема“, ја ограничува активноста во заднина и ги одложува известувањата."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Преостануваат <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Не може да се полни преку USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Користете го полначот што дојде со вашиот уред"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Да се вклучи „Штедачот на батерија“?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"За „Штедачот на батерија“"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Вклучи"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Да се вклучи штедачот на батерија?"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Вклучи"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Не, фала"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Автоматско ротирање на екранот"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Ќе дозволите <xliff:g id="APPLICATION">%1$s</xliff:g> да пристапува до <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Дали дозволувате <xliff:g id="APPLICATION">%1$s</xliff:g> да пристапи до <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nНа апликацијава не ѝ е доделена дозвола за снимање, но може да снима аудио преку овој USB-уред."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Лицето е проверено"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Потврдено"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Допрете „Потврди“ за да се заврши"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Отклучен со вашето лице. Притиснете за да продолжите."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Проверена"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Користи PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Користи шема"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ако внесете погрешна шема при следниот обид, работниот профил и неговите податоци ќе се избришат."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ако внесете погрешен PIN при следниот обид, работниот профил и неговите податоци ќе се избришат."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ако внесете погрешна лозинка при следниот обид, работниот профил и неговите податоци ќе се избришат."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Премногу погрешни обиди. Податоците на уредов ќе се избришат."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Премногу погрешни обиди. Корисникот ќе се избрише."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Премногу погрешни обиди. Работниот профил и неговите податоци ќе се избришат."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Отфрли"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Допрете го сензорот за отпечатоци"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Икона за отпечаток"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Не се препознава ликот. Користете отпечаток."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Се полни бавно • Полна по <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Се полни на док • Полн за <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Промени го корисникот"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Додај корисник"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Нов корисник"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Да се отстрани гостинот?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Сите апликации и податоци во сесијата ќе се избришат."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Отстрани"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Добре дојде пак, гостине!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Дали сакате да продолжите со сесијата?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Почни одново"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Да, продолжи"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Да се додаде нов корисник?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Кога додавате нов корисник, тоа лице треба да го постави својот простор.\n\nСекој корисник може да ажурира апликации за сите други корисници."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Достигнато ограничување на корисник"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">Може да додадете најмногу <xliff:g id="COUNT">%d</xliff:g> корисник.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Отклучете за да користите"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Имаше проблем при преземањето на картичките. Обидете се повторно подоцна"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Поставки за заклучен екран"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-код"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Допрете за скенирање"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Скенирајте QR-код"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Работен профил"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Авионски режим"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Нема да го слушнете следниот аларм <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Повлечете за да видите повеќе"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Се вчитуваат препораки"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Аудиовизуелни содржини"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Да се сокрие аудиовизуелнава сесија?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Аудиовизуелнава сесија не може да се сокрие."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Отфрли"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Сокриј"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Продолжи"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Поставки"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> од <xliff:g id="ARTIST_NAME">%2$s</xliff:g> е пуштено на <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Приближете се до <xliff:g id="DEVICENAME">%1$s</xliff:g> за да пуштите тука"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Пуштено на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Пуштено на овој телефон"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Нешто тргна наопаку"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"Нешто не е во ред. Обидете се повторно."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Неактивна, провери апликација"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Не е најдено"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Контролата не е достапна"</string>
@@ -827,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Спарете нов уред"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"За да ја емитувате сесијава, отворете ја апликацијата."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Непозната апликација"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Сопри со емитување"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Број на верзија"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Бројот на верзијата е копиран во привремената меморија."</string>
     <string name="basic_status" msgid="2315371112182658176">"Започни разговор"</string>
@@ -901,7 +890,7 @@
     </plurals>
     <string name="fgs_dot_content_description" msgid="2865071539464777240">"Нови информации"</string>
     <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Активни апликации"</string>
-    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Крај"</string>
+    <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Запри"</string>
     <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Запрено"</string>
     <string name="clipboard_edit_text_copy" msgid="770856373439969178">"Копирај"</string>
     <string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Копирано"</string>
@@ -916,7 +905,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi е недостапна"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Приоритетен режим"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Алармот е наместен"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Режимот на гостин за „Помошникот“ е овозможен"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камерата и микрофонот се исклучени"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# известување}one{# известување}other{# известувања}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 6aeb7e7..c08c1bc 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"സിസ്റ്റം UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"ബാറ്ററി ലാഭിക്കൽ ഓണാക്കണോ?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"നിങ്ങളുടെ ബാറ്ററിയിൽ <xliff:g id="PERCENTAGE">%s</xliff:g> ചാർജ് ശേഷിക്കുന്നു. ബാറ്ററി ലാഭിക്കൽ, ഡാർക്ക് തീം ഓണാക്കുകയും പശ്ചാത്തല ആക്‌റ്റിവിറ്റി നിയന്ത്രിക്കുകയും അറിയിപ്പുകൾ വെെകിപ്പിക്കുകയും ചെയ്യുന്നു."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"ബാറ്ററി ലാഭിക്കൽ, ഡാർക്ക് തീം ഓണാക്കുകയും പശ്ചാത്തല ആക്‌റ്റിവിറ്റി നിയന്ത്രിക്കുകയും അറിയിപ്പുകൾ വെെകിപ്പിക്കുകയും ചെയ്യുന്നു."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> ശേഷിക്കുന്നു"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"USB വഴി ചാർജ് ചെയ്യാനാകില്ല"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"ഉപകരണത്തിനൊപ്പം ലഭിച്ച ചാർജർ ഉപയോഗിക്കുക"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"ബാറ്ററി ലാഭിക്കൽ ഓണാക്കണോ?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"ബാറ്ററി ലാഭിക്കലിനെ കുറിച്ച്"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ഓൺ ചെയ്യുക"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"ബാറ്ററി ലാഭിക്കൽ ഓണാക്കുക"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"ഓണാക്കുക"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"വേണ്ട"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"സ്‌ക്രീൻ സ്വയമേ തിരിയുക"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ആക്‌സസ് ചെയ്യാൻ <xliff:g id="APPLICATION">%1$s</xliff:g>-നെ അനുവദിക്കണോ?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ആക്‌സസ് ചെയ്യാൻ <xliff:g id="APPLICATION">%1$s</xliff:g> എന്നതിനെ അനുവദിക്കണോ?\nഈ ആപ്പിന് റെക്കോർഡ് അനുമതി നൽകിയിട്ടില്ല, എന്നാൽ ഈ USB ഉപകരണത്തിലൂടെ ഓഡിയോ ക്യാപ്‌ചർ ചെയ്യാനാവും."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"മുഖം പരിശോധിച്ചുറപ്പിച്ചു"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"സ്ഥിരീകരിച്ചു"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"പൂർത്തിയാക്കാൻ സ്ഥിരീകരിക്കുക ടാപ്പ് ചെയ്യൂ"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"മുഖം ഉപയോഗിച്ച് അൺലോക്ക് ചെയ്‌തു. തുടരാൻ അമർത്തുക."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"പരിശോധിച്ചുറപ്പിച്ചു"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"പിൻ ഉപയോഗിക്കുക"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"പാറ്റേൺ ഉപയോഗിക്കുക"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"അടുത്ത തവണയും നിങ്ങൾ തെറ്റായ പാറ്റേൺ നൽകിയാൽ, നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലും അതിന്റെ ഡാറ്റയും ഇല്ലാതാക്കപ്പെടും."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"അടുത്ത തവണയും നിങ്ങൾ തെറ്റായ പിൻ നൽകിയാൽ, നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലും അതിന്റെ ഡാറ്റയും ഇല്ലാതാക്കപ്പെടും."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"അടുത്ത തവണയും നിങ്ങൾ തെറ്റായ പാസ്‌വേഡ് നൽകിയാൽ, നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലും അതിന്റെ ഡാറ്റയും ഇല്ലാതാക്കപ്പെടും."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"ഒരുപാട് തെറ്റായ ശ്രമങ്ങൾ. ഈ ഉപകരണത്തിലെ ഡാറ്റ ഇല്ലാതാക്കപ്പെടും."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"ഒരുപാട് തെറ്റായ ശ്രമങ്ങൾ. ഈ ഉപയോക്താവ് ഇല്ലാതാക്കപ്പെടും."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"ഒരുപാട് തെറ്റായ ശ്രമങ്ങൾ. ഈ ഔദ്യോഗിക പ്രൊഫൈലും അതിന്റെ ഡാറ്റയും ഇല്ലാതാക്കപ്പെടും."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"ഡിസ്മിസ് ചെയ്യുക"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ഫിംഗർപ്രിന്റ് സെൻസർ സ്‌പർശിക്കുക"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ഫിംഗർപ്രിന്റ് ഐക്കൺ"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"മുഖം തിരിച്ചറിയാനായില്ല. പകരം ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കൂ."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • പതുക്കെ ചാർജ് ചെയ്യുന്നു • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>-ൽ പൂർത്തിയാകും"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ചാർജിംഗ് ഡോക്ക് • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>-ൽ പൂർത്തിയാകും"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ഉപയോക്താവ് മാറുക"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"ഉപയോക്താവിനെ ചേര്‍ക്കുക"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"പുതിയ ഉപയോക്താവ്"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"അതിഥിയെ നീക്കംചെയ്യണോ?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ഈ സെഷനിലെ എല്ലാ ആപ്പുകളും ഡാറ്റയും ഇല്ലാതാക്കും."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"നീക്കംചെയ്യുക"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"അതിഥി, വീണ്ടും സ്വാഗതം!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"നിങ്ങളുടെ സെഷൻ തുടരണോ?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"പുനരാംരംഭിക്കുക"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"അതെ, തുടരുക"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"പുതിയ ഉപയോക്താവിനെ ചേർക്കണോ?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"നിങ്ങൾ പുതിയൊരു ഉപയോക്താവിനെ ചേർക്കുമ്പോൾ, ആ വ്യക്തിക്ക് അവരുടെ ഇടം സജ്ജീകരിക്കേണ്ടതുണ്ട്.\n\nമറ്റ് എല്ലാ ഉപയോക്താക്കൾക്കുമായി ഏതൊരു ഉപയോക്താവിനും ആപ്പുകൾ അപ്‌ഡേറ്റ് ചെയ്യാനാവും."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"ഉപയോക്തൃ പരിധി എത്തി"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">നിങ്ങൾക്ക് <xliff:g id="COUNT">%d</xliff:g> ഉപയോക്താക്കളെ വരെ ചേർക്കാനാവും.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ഉപയോഗിക്കാൻ അൺലോക്ക് ചെയ്യുക"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"നിങ്ങളുടെ കാർഡുകൾ ലഭ്യമാക്കുന്നതിൽ ഒരു പ്രശ്‌നമുണ്ടായി, പിന്നീട് വീണ്ടും ശ്രമിക്കുക"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ലോക്ക് സ്ക്രീൻ ക്രമീകരണം"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR കോഡ്"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"സ്‌കാൻ ചെയ്യാൻ ടാപ്പ് ചെയ്യുക"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR കോഡ് സ്‌കാൻ ചെയ്യുക"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"ഔദ്യോഗിക പ്രൊഫൈൽ"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"ഫ്ലൈറ്റ് മോഡ്"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>-നുള്ള നിങ്ങളുടെ അടുത്ത അലാറം കേൾക്കില്ല"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"കൂടുതൽ കാണാൻ സ്വൈപ്പ് ചെയ്യുക"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"നിർദ്ദേശങ്ങൾ ലോഡ് ചെയ്യുന്നു"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"മീഡിയ"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"ഈ മീഡിയ സെഷൻ മറയ്ക്കണോ?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"നിലവിലെ മീഡിയ സെഷൻ മറയ്ക്കാനാകില്ല."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ഡിസ്‌മിസ് ചെയ്യുക"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"മറയ്‌ക്കുക"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"പുനരാരംഭിക്കുക"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"ക്രമീകരണം"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> എന്ന ആർട്ടിസ്റ്റിന്റെ <xliff:g id="SONG_NAME">%1$s</xliff:g> എന്ന ഗാനം <xliff:g id="APP_LABEL">%3$s</xliff:g> ആപ്പിൽ പ്ലേ ചെയ്യുന്നു"</string>
@@ -808,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ഇവിടെ പ്ലേ ചെയ്യാൻ <xliff:g id="DEVICENAME">%1$s</xliff:g> എന്നതിന് അടുത്തേക്ക് നീക്കുക"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> എന്നതിൽ പ്ലേ ചെയ്യുന്നു"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"ഈ ഫോണിൽ പ്ലേ ചെയ്യുന്നു"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"എന്തോ കുഴപ്പമുണ്ടായി"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"എന്തോ കുഴപ്പമുണ്ടായി. വീണ്ടും ശ്രമിക്കുക."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"നിഷ്‌ക്രിയം, ആപ്പ് പരിശോധിക്കൂ"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"കണ്ടെത്തിയില്ല"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"നിയന്ത്രണം ലഭ്യമല്ല"</string>
@@ -827,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"പുതിയ ഉപകരണവുമായി ജോടിയാക്കുക"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ഈ സെഷൻ കാസ്റ്റ് ചെയ്യാൻ, ആപ്പ് തുറക്കുക."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"അജ്ഞാതമായ ആപ്പ്"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"കാസ്റ്റ് ചെയ്യുന്നത് നിർത്തുക"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"ബിൽഡ് നമ്പർ"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"ക്ലിപ്പ്ബോർഡിലേക്ക് ബിൽഡ് നമ്പർ പകർത്തി."</string>
     <string name="basic_status" msgid="2315371112182658176">"സംഭാഷണം തുറക്കുക"</string>
@@ -896,8 +885,8 @@
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ടൈൽ ചേർക്കരുത്"</string>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ഉപയോക്താവിനെ തിരഞ്ഞെടുക്കൂ"</string>
     <plurals name="fgs_manager_footer_label" formatted="false" msgid="9091110396713032871">
-      <item quantity="other">സജീവമായ <xliff:g id="COUNT_1">%s</xliff:g> ആപ്പുകൾ</item>
-      <item quantity="one">സജീവമായ <xliff:g id="COUNT_0">%s</xliff:g> ആപ്പ്</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> സജീവ ആപ്പുകൾ</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> സജീവ ആപ്പ്</item>
     </plurals>
     <string name="fgs_dot_content_description" msgid="2865071539464777240">"പുതിയ വിവരങ്ങൾ"</string>
     <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"സജീവമായ ആപ്പുകൾ"</string>
@@ -916,7 +905,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"വൈഫൈ ലഭ്യമല്ല"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"മുൻഗണനാ മോഡ്"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"അലാറം സജ്ജീകരിച്ചു"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"സഹായി അതിഥി മോഡ് പ്രവർത്തനക്ഷമമാക്കി"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ക്യാമറയും മൈക്കും ഓഫാണ്"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# അറിയിപ്പ്}other{# അറിയിപ്പുകൾ}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 4abfe1b..daea5d8 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Систем UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Батарей хэмнэгчийг асаах уу?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Танд <xliff:g id="PERCENTAGE">%s</xliff:g> батарей үлдсэн байна. Батарей хэмнэгч нь Бараан загварыг асааж, дэвсгэрийн үйл ажиллагааг хязгаарлаж мөн мэдэгдлийг саатуулна."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Батарей хэмнэгч нь Бараан загварыг асааж, дэвсгэрийн үйл ажиллагааг хязгаарлаж мөн мэдэгдлийг саатуулна."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> үлдсэн"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"USB-р цэнэглэх боломжгүй байна"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Төхөөрөмждөө дагалдаж ирсэн цэнэглэгчийг ашиглах"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Батарей хэмнэгчийг асаах уу?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Батарей хэмнэгчийн тухай"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Асаах"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Батарей хэмнэгчийг асаах"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Асаах"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Үгүй, баярлалаа"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Дэлгэцийг автоматаар эргүүлэх"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g>-г <xliff:g id="USB_DEVICE">%2$s</xliff:g>-д хандахыг зөвшөөрөх үү?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g>-д <xliff:g id="USB_DEVICE">%2$s</xliff:g>-д хандахыг зөвшөөрөх үү?\nЭнэ аппад бичих зөвшөөрөл олгогдоогүй ч USB төхөөрөмжөөр дамжуулан аудио бичиж чадсан."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Царайг баталгаажууллаа"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Баталгаажсан"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Дуусгахын тулд баталгаажуулахыг товших"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Таны царайгаар түгжээг тайлсан. Үргэлжлүүлэхийн тулд дарна уу."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Баталгаажуулагдсан"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"ПИН ашиглах"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Хээ ашиглах"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Та дараагийн оролдлогоор буруу хээ оруулбал таны ажлын профайлыг өгөгдөлтэй нь цуг устгах болно."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Та дараагийн оролдлогоор буруу ПИН оруулбал таны ажлын профайлыг өгөгдөлтэй нь цуг устгах болно."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Та дараагийн оролдлогоор буруу нууц үг оруулбал таны ажлын профайлыг өгөгдөлтэй нь цуг устгах болно."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Түгжээг хэт олон удаа буруу оруулсан тул энэ төхөөрөмжийн өгөгдлийг устгах болно."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Түгжээг хэт олон удаа буруу оруулсан тул энэ хэрэглэгчийг устгах болно."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Түгжээг хэт олон удаа буруу оруулсан тул энэ ажлын профайл, түүний өгөгдлийн устгах болно."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Хаах"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Хурууны хээ мэдрэгчид хүрэх"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Хурууны хээний дүрс тэмдэг"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Царай таних боломжгүй. Оронд нь хурууны хээ ашигла"</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Удаан цэнэглэж байна • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>-н дараа дүүрнэ"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Цэнэглэх холбогч • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>-н дараа дүүрнэ"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Хэрэглэгчийг сэлгэх"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Хэрэглэгч нэмэх"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Шинэ хэрэглэгч"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Зочныг хасах уу?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Энэ харилцан үйлдлийн бүх апп болон дата устах болно."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Хасах"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Эргэн тавтай морилно уу!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Та үргэлжлүүлэхийг хүсэж байна уу?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Дахин эхлүүлэх"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Тийм, үргэлжлүүлэх"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Шинэ хэрэглэгч нэмэх үү?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Та шинэ хэрэглэгч нэмбэл тухайн хүн өөрийн профайлыг тохируулах шаардлагатай.\n\nАль ч хэрэглэгч бүх хэрэглэгчийн аппуудыг шинэчлэх боломжтой."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Хэрэглэгчийн хязгаарт хүрсэн"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">Та <xliff:g id="COUNT">%d</xliff:g> хүртэлх хэрэглэгч нэмэх боломжтой.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ашиглахын тулд түгжээг тайлах"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Таны картыг авахад асуудал гарлаа. Дараа дахин оролдоно уу"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Түгжигдсэн дэлгэцийн тохиргоо"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR код"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Скан хийхийн тулд товшино уу"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR код скан хийх"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Ажлын профайл"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Нислэгийн горим"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>-т та дараагийн сэрүүлгээ сонсохгүй"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Илүү ихийг харахын тулд шударна уу"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Зөвлөмжүүдийг ачаалж байна"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Медиа"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Энэ медиа харилцан үйлдлийг нуух уу?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Одоогийн медиа харилцан үйлдлийг нуух боломжгүй."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Хаах"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Нуух"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Үргэлжлүүлэх"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Тохиргоо"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> дээр тоглуулж буй <xliff:g id="ARTIST_NAME">%2$s</xliff:g>-н <xliff:g id="SONG_NAME">%1$s</xliff:g>"</string>
@@ -808,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Энд тоглуулахын тулд <xliff:g id="DEVICENAME">%1$s</xliff:g>-д ойртоно уу"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> дээр тоглуулж байна"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Энэ утсан дээр тоглуулж байна"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Алдаа гарлаа"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"Алдаа гарлаа. Дахин оролдоно уу."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Идэвхгүй байна, аппыг шалгана уу"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Олдсонгүй"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Хяналт боломжгүй байна"</string>
@@ -827,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Шинэ төхөөрөмж хослуулах"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Энэ үйл явдлыг дамжуулахын тулд аппыг нээнэ үү."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Үл мэдэгдэх апп"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Дамжуулахыг зогсоох"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Хийцийн дугаар"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Хийцийн дугаарыг түр санах ойд хуулсан."</string>
     <string name="basic_status" msgid="2315371112182658176">"Харилцан яриаг нээх"</string>
@@ -916,7 +905,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi боломжгүй"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Чухал горим"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Сэрүүлгийг тохируулсан"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Туслахын зочны горимыг идэвхжүүлсэн"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камер болон микрофон унтраалттай байна"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# мэдэгдэл}other{# мэдэгдэл}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 2ec0073..7e499ec 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"सिस्टीम UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"बॅटरी सेव्हर सुरू करायचे आहे का?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"तुमच्याकडे <xliff:g id="PERCENTAGE">%s</xliff:g> बॅटरी शिल्लक आहे. बॅटरी सेव्हर गडद थीम सुरू करते, बॅकग्राउंड ॲक्टिव्हिटी मर्यादित करते, यामुळे सूचना विलंबाने मिळतात."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"बॅटरी सेव्हर गडद थीम सुरू करते, बॅकग्राउंड ॲक्टिव्हिटी मर्यादित करते, यामुळे सूचना विलंबाने मिळतात."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> शिल्लक"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"USB द्वारे चार्ज होऊ शकत नाही"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"तुमच्या डिव्हाइससह आलेल्या चार्जरचा वापर करा"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"बॅटरी सेव्हर सुरू करायचा का?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"बॅटरी सेव्हर बाबत"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"सुरू करा"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"बॅटरी सेव्हर सुरू करा"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"सुरू करा"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"नाही, नको"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"ऑटो-रोटेट स्क्रीन"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> ला <xliff:g id="USB_DEVICE">%2$s</xliff:g> अ‍ॅक्सेस करण्याची अनुमती द्यायची का?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> ला <xliff:g id="USB_DEVICE">%2$s</xliff:g> अ‍ॅक्सेस करण्याची अनुमती द्यायची का?\nया अ‍ॅपला रेकॉर्ड करण्याची परवानगी दिलेली नाही पण या USB डिव्हाइसद्वारे ऑडिओ कॅप्चर केला जाऊ शकतो."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"चेहरा ऑथेंटिकेशन केलेला आहे"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"निश्चित केले"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"पूर्ण करण्यासाठी खात्री करा वर टॅप करा"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"तुमच्या चेहऱ्याने अनलॉक केले. पुढे सुरू ठेवण्यासाठी दाबा."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ऑथेंटिकेशन केलेले"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"पिन वापरा"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"पॅटर्न वापरा"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"तुम्‍ही पुढील प्रयत्‍नात चुकीचा पॅटर्न एंटर केल्यास, तुमची कार्य प्रोफाइल आणि तिचा डेटा हटवला जाईल."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"तुम्‍ही पुढील प्रयत्‍नात चुकीचा पिन एंटर केल्यास, तुमची कार्य प्रोफाइल आणि तिचा डेटा हटवला जाईल."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"तुम्‍ही पुढील प्रयत्‍नात चुकीचा पासवर्ड एंटर केल्यास, तुमची कार्य प्रोफाइल आणि तिचा डेटा हटवला जाईल."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"बरेच चुकीचे प्रयत्‍न. या डिव्‍हाइसचा डेटा हटवला जाईल."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"बरेच चुकीचे प्रयत्‍न. हा वापरकर्ता हटवला जाईल."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"बरेच चुकीचे प्रयत्‍न. ही कार्य प्रोफाइल आणि त्यामधील डेटा हटवला जाईल."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"डिसमिस करा"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"फिंगरप्रिंट सेन्सरला स्पर्श करा"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"फिंगरप्रिंट आयकन"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"चेहरा ओळखू शकत नाही. त्याऐवजी फिंगरप्रिंट वापरा."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • हळू चार्ज होत आहे • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मध्ये पूर्ण होईल"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • चार्जिंग डॉक • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मध्ये पूर्ण होईल"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"वापरकर्ता स्विच करा"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"वापरकर्ता जोडा"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"नवीन वापरकर्ता"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"अतिथी काढायचे?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"या सत्रातील सर्व अ‍ॅप्स आणि डेटा हटवला जाईल."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"काढा"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"अतिथी, तुमचे पुन्‍हा स्‍वागत आहे!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"तुम्ही तुमचे सत्र सुरू ठेवू इच्छिता?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"येथून सुरू करा"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"होय, सुरू ठेवा"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"नवीन वापरकर्ता जोडायचा?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"तुम्ही एक नवीन वापरकर्ता जोडता तेव्हा, त्या व्यक्तीने त्यांचे स्थान सेट करणे आवश्यक असते.\n\nकोणताही वापरकर्ता इतर सर्व वापरकर्त्यांसाठी अ‍ॅप्स अपडेट करू शकतो."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"वापरकर्ता मर्यादा गाठली"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">तुम्ही <xliff:g id="COUNT">%d</xliff:g> वापरकर्त्यांपर्यंत जोडू शकता.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"वापरण्यासाठी अनलॉक करा"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"तुमची कार्ड मिळवताना समस्या आली, कृपया नंतर पुन्हा प्रयत्न करा"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"लॉक स्क्रीन सेटिंग्ज"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR कोड"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"स्कॅन करण्यासाठी टॅप करा"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR कोड स्कॅन करा"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"कार्य प्रोफाईल"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"विमान मोड"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"तुम्ही तुमचा <xliff:g id="WHEN">%1$s</xliff:g> वाजता होणारा पुढील अलार्म ऐकणार नाही"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"अधिक पाहण्यासाठी स्वाइप करा"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"शिफारशी लोड करत आहे"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"मीडिया"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"हे मीडिया सेशन लपवायचे आहे का?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"सध्याचे मीडिया सेशन लपवू शकत नाही."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"डिसमिस करा"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"लपवा"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"पुन्हा सुरू करा"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"सेटिंग्ज"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> मध्ये <xliff:g id="ARTIST_NAME">%2$s</xliff:g> चे <xliff:g id="SONG_NAME">%1$s</xliff:g> प्ले होत आहे"</string>
@@ -808,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"येथे प्ले करण्यासाठी <xliff:g id="DEVICENAME">%1$s</xliff:g> च्या जवळ जा"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> वर प्ले केला जात आहे"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"या फोनवर प्ले होत आहे"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"काहीतरी चूक झाली"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"काहीतरी चूक झाली. पुन्हा प्रयत्न करा."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय, ॲप तपासा"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"आढळले नाही"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"नियंत्रण उपलब्ध नाही"</string>
@@ -827,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नवीन डिव्हाइससोबत पेअर करा"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"हे सेशन कास्ट करण्यासाठी, कृपया ॲप उघडा."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"अज्ञात अ‍ॅप"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"कास्ट करणे थांबवा"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नंबर"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नंबर क्लिपबोर्डवर कॉपी केला."</string>
     <string name="basic_status" msgid="2315371112182658176">"संभाषण उघडा"</string>
@@ -916,7 +905,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"वाय-फाय उपलब्ध नाही"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"प्राधान्य मोड"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"अलार्म सेट केला"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Assistant चा अतिथी मोड सुरू केला"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"कॅमेरा आणि माइक बंद आहेत"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# सूचना}other{# सूचना}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 06270d7..f0e48d4 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"UI Sistem"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Hidupkan Penjimat Bateri?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Anda mempunyai <xliff:g id="PERCENTAGE">%s</xliff:g> baki bateri. Penjimat Bateri menghidupkan Tema gelap, mengehadkan aktiviti latar dan menangguhkan pemberitahuan."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Penjimat Bateri menghidupkan Tema gelap, mengehadkan aktiviti latar dan menangguhkan pemberitahuan."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> yang tinggal"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Tidak dapat mengecas melalui USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Gunakan pengecas yang disertakan dengan peranti anda"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Hidupkan Penjimat Bateri?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Tentang Penjimat Bateri"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Hidupkan"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Hidupkan Penjimat Bateri"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Hidupkan"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Tidak perlu"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Autoputar skrin"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Benarkan <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Benarkan <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nApl ini belum diberikan kebenaran merakam tetapi dapat merakam audio melalui peranti USB ini."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Wajah disahkan"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Disahkan"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ketik Sahkan untuk menyelesaikan"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Dibuka kunci oleh wajah anda. Tekan untuk meneruskan."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Disahkan"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Gunakan PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Gunakan corak"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Jika anda memasukkan corak yang salah pada percubaan seterusnya, profil kerja anda dan data profil itu akan dipadamkan."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Jika anda memasukkan PIN yang salah pada percubaan seterusnya, profil kerja anda dan data profil itu akan dipadamkan."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Jika anda memasukkan kata laluan yang salah pada percubaan seterusnya, profil kerja anda dan data profil itu akan dipadamkan."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Terlalu banyak percubaan yang salah. Data peranti ini akan dipadamkan."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Terlalu banyak percubaan yang salah. Pengguna ini akan dipadamkan."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Terlalu banyak percubaan yang salah. Profil kerja ini dan data profil itu akan dipadamkan."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Ketepikan"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Sentuh penderia cap jari"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikon cap jari"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tidak mengenali wajah. Gunakan cap jari."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mengecas dengan perlahan • Penuh dalam masa <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mengecas dengan Dok • Penuh dalam masa <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Tukar pengguna"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Tambah pengguna"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Pengguna baharu"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Alih keluar tetamu?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua apl dan data dalam sesi ini akan dipadam."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Alih keluar"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Selamat kembali, tetamu!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Adakah anda ingin meneruskan sesi anda?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Mulakan semula"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ya, teruskan"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Tambah pengguna baharu?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Apabila anda menambah pengguna baharu, orang itu perlu menyediakan ruang mereka.\n\nMana-mana pengguna boleh mengemas kini apl untuk semua pengguna lain."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Had pengguna dicapai"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">Anda boleh menambah sehingga <xliff:g id="COUNT">%d</xliff:g> pengguna.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Buka kunci untuk menggunakan"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Terdapat masalah sewaktu mendapatkan kad anda. Sila cuba sebentar lagi"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Tetapan skrin kunci"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"Kod QR"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Ketik untuk membuat imbasan"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Imbas kod QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Profil kerja"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Mod pesawat"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Anda tidak akan mendengar penggera yang seterusnya <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Leret untuk melihat selanjutnya"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Memuatkan cadangan"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Media"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Sembunyikan sesi media ini?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Sesi media semasa tidak dapat disembunyikan."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Tolak"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Sembunyikan"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Sambung semula"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Tetapan"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> oleh <xliff:g id="ARTIST_NAME">%2$s</xliff:g> dimainkan daripada <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Dekatkan dengan <xliff:g id="DEVICENAME">%1$s</xliff:g> untuk bermain di sini"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Dimainkan pada <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Dimainkan pada telefon ini"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Ralat telah berlaku"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"Kesilapan telah berlaku. Cuba lagi."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Tidak aktif, semak apl"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemukan"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Kawalan tidak tersedia"</string>
@@ -827,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Gandingkan peranti baharu"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Untuk menghantar sesi ini, sila buka apl."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Apl yang tidak diketahui"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Berhenti menghantar"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Nombor binaan"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Nombor binaan disalin ke papan keratan."</string>
     <string name="basic_status" msgid="2315371112182658176">"Buka perbualan"</string>
@@ -916,8 +905,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi dimatikan"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Mod keutamaan"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Penggera ditetapkan"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Mod tetamu Assistant didayakan"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera dan mikrofon dimatikan"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# pemberitahuan}other{# pemberitahuan}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 4a4f1a1..2d764e5 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"စနစ်၏ UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"‘ဘက်ထရီ အားထိန်း’ ဖွင့်မလား။"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"သင့်တွင် ဘက်ထရီ <xliff:g id="PERCENTAGE">%s</xliff:g> ကျန်သည်။ ‘ဘက်ထရီ အားထိန်း’ က ‘မှောင်သည့် အပြင်အဆင်’ ဖွင့်ပြီး နောက်ခံလုပ်ဆောင်ချက်ကို ကန့်သတ်ကာ အကြောင်းကြားချက်များကို နှောင့်နှေးစေသည်။"</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"‘ဘက်ထရီ အားထိန်း’ က ‘မှောင်သည့် အပြင်အဆင်’ ဖွင့်ပြီး နောက်ခံလုပ်ဆောင်ချက်ကို ကန့်သတ်ကာ အကြောင်းကြားချက်များကို နှောင့်နှေးစေသည်။"</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> ကျန်ရှိနေ"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"USB ဖြင့် အားသွင်း၍မရပါ"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"သင့်စက်ပစ္စည်းနှင့် အတူပါလာသည့် အားသွင်းကိရိယာကို အသုံးပြုပါ"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"ဘက်ထရီအားထိန်းကို ဖွင့်မလား။"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"\'ဘက်ထရီအားထိန်း\' အကြောင်း"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ဖွင့်ရန်"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"ဘက်ထရီ အားထိန်းကို ဖွင့်ရန်"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"ဖွင့်ရန်"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"မလိုပါ"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"ဖန်သားပြင် အလိုအလျောက်လှည့်ရန်"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> အား ဝင်သုံးရန် <xliff:g id="APPLICATION">%1$s</xliff:g> ကို ခွင့်ပြုပါသလား။"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> အား <xliff:g id="USB_DEVICE">%2$s</xliff:g> ကို သုံးခွင့်ပြုမလား။\nဤအက်ပ်ကို အသံဖမ်းခွင့် ပေးမထားသော်လည်း ၎င်းသည် ဤ USB စက်ပစ္စည်းမှတစ်ဆင့် အသံများကို ဖမ်းယူနိုင်ပါသည်။"</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"မျက်နှာ အထောက်အထားစိစစ်ပြီးပြီ"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"အတည်ပြုပြီးပြီ"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"အပြီးသတ်ရန်အတွက် \'အတည်ပြုရန်\' ကို တို့ပါ"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"သင့်မျက်နှာဖြင့် ဖွင့်သည်။ ရှေ့ဆက်ရန် နှိပ်ပါ။"</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"အထောက်အထားစိစစ်ပြီးပြီ"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"ပင်နံပါတ်သုံးရန်"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ပုံစံကို သုံးရန်"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"မှားယွင်းသည့် ပုံစံကို နောက်တစ်ကြိမ်ထည့်သွင်းပါက သင်၏အလုပ်ပရိုဖိုင်နှင့် ၎င်း၏ ဒေတာများကို ဖျက်လိုက်ပါမည်။"</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"မှားယွင်းသည့် ပင်နံပါတ်ကို နောက်တစ်ကြိမ်ထည့်သွင်းပါက သင်၏အလုပ်ပရိုဖိုင်နှင့် ၎င်း၏ဒေတာများကို ဖျက်လိုက်ပါမည်။"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"မှားယွင်းသည့် စကားဝှက်ကို နောက်တစ်ကြိမ်ထည့်သွင်းပါက သင်၏အလုပ်ပရိုဖိုင်နှင့် ၎င်း၏ ဒေတာများကို ဖျက်လိုက်ပါမည်။"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"မှားယွင်းသည့် အကြိမ်ရေ အလွန်များနေပါပြီ။ ဤစက်၏ ဒေတာကို ဖျက်လိုက်ပါမည်။"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"မှားယွင်းသည့် အကြိမ်ရေ အလွန်များနေပါပြီ။ ဤအသုံးပြုသူကို ဖျက်လိုက်ပါမည်။"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"မှားယွင်းသည့် အကြိမ်ရေ အလွန်များနေပါပြီ။ ဤအလုပ်ပရိုဖိုင်နှင့် ၎င်း၏ ဒေတာကို ဖျက်လိုက်ပါမည်။"</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"ပယ်ရန်"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"လက်ဗွေအာရုံခံကိရိယာကို တို့ပါ"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"လက်ဗွေ သင်္ကေတ"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"မျက်နှာကို မမှတ်မိပါ။ လက်ဗွေကို အစားထိုးသုံးပါ။"</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • နှေးကွေးစွာ အားသွင်းနေသည် • အားပြည့်ရန် <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> လိုသည်"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • အားသွင်းအထိုင် • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> တွင် ပြည့်မည်"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"အသုံးပြုသူကို ပြောင်းလဲရန်"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"အသုံးပြုသူ ထည့်ရန်"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"အသုံးပြုသူ အသစ်"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ဧည့်သည်ကို ဖယ်မလား။"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ဒီချိတ်ဆက်မှု ထဲက အက်ပ်များ အားလုံး နှင့် ဒေတာကို ဖျက်ပစ်မည်။"</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ဖယ်ထုတ်ပါ"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"ဧည့်သည်ကို ပြန်လည် ကြိုဆိုပါသည်။"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"သင်၏ စက်ရှင်ကို ဆက်လုပ်လိုပါသလား။"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ပြန်စပါ"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"ဆက်လုပ်ပါ"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"အသုံးပြုသူအသစ်ကို ထည့်မလား။"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"သင်ထည့်လိုက်သော အသုံးပြုသူအသစ်သည် ၎င်း၏နေရာကို သတ်မှတ်စီစဉ်ရန် လိုအပ်သည်။\n\nမည်သည့်အသုံးပြုသူမဆို ကျန်သူများအားလုံးအတွက် အက်ပ်များကို အပ်ဒိတ်လုပ်ပေးနိုင်သည်။"</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"အသုံးပြုသူ အကန့်အသတ် ပြည့်သွားပါပြီ"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">အသုံးပြုသူ <xliff:g id="COUNT">%d</xliff:g> ဦးအထိ ထည့်နိုင်သည်။</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"သုံးရန် လော့ခ်ဖွင့်ပါ"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"သင်၏ကတ်များ ရယူရာတွင် ပြဿနာရှိနေသည်၊ နောက်မှ ထပ်စမ်းကြည့်ပါ"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"လော့ခ်မျက်နှာပြင် ဆက်တင်များ"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR ကုဒ်"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"စကင်ဖတ်ရန် တို့နိုင်သည်"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR ကုဒ် စကင်ဖတ်ခြင်း"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"အလုပ် ပရိုဖိုင်"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"လေယာဉ်ပျံမုဒ်"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> ၌သင့်နောက်ထပ် နှိုးစက်ကို ကြားမည်မဟုတ်ပါ"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"ပိုကြည့်ရန် ပွတ်ဆွဲပါ"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"အကြံပြုချက်များ ဖွင့်နေသည်"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"မီဒီယာ"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"ဤမီဒီယာစက်ရှင်ကို ဝှက်မလား။"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"လက်ရှိ မီဒီယာစက်ရှင်ကို ဝှက်၍မရပါ။"</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ပယ်ရန်"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ဖျောက်ထားမည်"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"ဆက်လုပ်ရန်"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"ဆက်တင်များ"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> ၏ <xliff:g id="SONG_NAME">%1$s</xliff:g> ကို <xliff:g id="APP_LABEL">%3$s</xliff:g> တွင် ဖွင့်ထားသည်"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ဤနေရာတွင်ဖွင့်ရန် <xliff:g id="DEVICENAME">%1$s</xliff:g> အနီးသို့တိုးပါ"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> တွင် ဖွင့်နေသည်"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"ဤဖုန်းတွင် ဖွင့်နေသည်"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"တစ်ခုခုမှားသွားသည်"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"ရပ်နေသည်၊ အက်ပ်ကို စစ်ဆေးပါ"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"မတွေ့ပါ"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"ထိန်းချုပ်မှု မရနိုင်ပါ"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"စက်အသစ် တွဲချိတ်ရန်"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"အက်ပ်ဖွင့်ပြီး ဤစက်ရှင်ကို ကာစ်လုပ်နိုင်သည်။"</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"အမည်မသိ အက်ပ်"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ကာစ် ရပ်ရန်"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"တည်ဆောက်မှုနံပါတ်"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"တည်ဆောက်မှုနံပါတ်ကို ကလစ်ဘုတ်သို့ မိတ္တူကူးပြီးပါပြီ။"</string>
     <string name="basic_status" msgid="2315371112182658176">"စကားဝိုင်းကို ဖွင့်ရန်"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi မရပါ"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ဦးစားပေးမုဒ်"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"နိုးစက် သတ်မှတ်ထားသည်"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Assistant ဧည့်သည်သုံးခွင့်မုဒ် ဖွင့်ထားသည်"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ကင်မရာနှင့် မိုက် ပိတ်ထားသည်"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{အကြောင်းကြားချက် # ခု}other{အကြောင်းကြားချက် # ခု}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 5ccf528..04e4b94 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"System-UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Vil du slå på batterisparing?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Du har <xliff:g id="PERCENTAGE">%s</xliff:g> batteri igjen. Batterisparing slår på mørkt tema, begrenser bakgrunnsaktivitet og forsinker varsler."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Batterisparing slår på mørkt tema, begrenser bakgrunnsaktivitet og forsinker varsler."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> gjenstår"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Kan ikke lade via USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Bruk laderen som fulgte med enheten"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Vil du slå på batterisparing?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Om Batterisparing"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Slå på"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Slå på batterisparing"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Slå på"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Nei takk"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Rotér skjermen automatisk"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Vil du gi <xliff:g id="APPLICATION">%1$s</xliff:g> tilgang til <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Vil du gi <xliff:g id="APPLICATION">%1$s</xliff:g> tilgang til <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nDenne appen har ikke fått tillatelse til å spille inn, men kan ta opp lyd med denne USB-enheten."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Ansiktet er autentisert"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bekreftet"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Trykk på Bekreft for å fullføre"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Låst opp med ansiktet ditt. Trykk for å fortsette."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentisert"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Bruk PIN-kode"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Bruk mønster"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Hvis du oppgir feil mønster på neste forsøk, slettes jobbprofilen din og tilknyttede data."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Hvis du skriver inn feil PIN-kode på neste forsøk, slettes jobbprofilen din og tilknyttede data."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Hvis du skriver inn feil passord på neste forsøk, slettes jobbprofilen din og tilknyttede data."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"For mange mislykkede forsøk. Dataene på denne enheten blir slettet."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"For mange mislykkede forsøk. Denne brukeren blir slettet."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"For mange mislykkede forsøk. Denne jobbprofilen og tilknyttede data blir slettet."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Avvis"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Trykk på fingeravtrykkssensoren"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikon for fingeravtrykk"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansiktet gjenkjennes ikke. Bruk fingeravtrykk."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Lader sakte • Fulladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ladedokk • Fulladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Bytt bruker"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Legg til brukere"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Ny bruker"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vil du fjerne gjesten?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle appene og all informasjon i denne økten slettes."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Fjern"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Velkommen tilbake, gjest!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vil du fortsette økten?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start på nytt"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ja, fortsett"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Vil du legge til en ny bruker?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Når du legger til en ny bruker, må vedkommende konfigurere sitt eget område.\n\nAlle brukere kan oppdatere apper for alle andre brukere."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Grensen for antall brukere er nådd"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">Du kan legge til opptil <xliff:g id="COUNT">%d</xliff:g> brukere.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lås opp for å bruke"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Det oppsto et problem med henting av kortene. Prøv igjen senere"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Innstillinger for låseskjermen"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-kode"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Trykk for å skanne"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skann QR-koden"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Work-profil"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Flymodus"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Du hører ikke neste innstilte alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Sveip for å se flere"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Laster inn anbefalinger"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Medier"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Vil du skjule denne medieøkten?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Den nåværende medieøkten kan ikke skjules."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Lukk"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Skjul"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Gjenoppta"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Innstillinger"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> av <xliff:g id="ARTIST_NAME">%2$s</xliff:g> spilles av fra <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Flytt deg nærmere <xliff:g id="DEVICENAME">%1$s</xliff:g> for å spille av her"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Spilles av på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Spilles av på denne telefonen"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Noe gikk galt"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Sjekk appen"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Ikke funnet"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrollen er utilgjengelig"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Koble til en ny enhet"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"For å caste denne økten, åpne appen."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Ukjent app"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stopp castingen"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Delversjonsnummer"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Delversjonsnummeret er kopiert til utklippstavlen."</string>
     <string name="basic_status" msgid="2315371112182658176">"Åpen samtale"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi er utilgjengelig"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioriteringsmodus"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmen er stilt inn"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Gjestemodus for assistenten er slått på"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera og mikrofon er av"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# varsel}other{# varsler}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 471bf14..c0d272d 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"सिस्टम UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"ब्याट्री सेभर अन गर्ने हो?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"तपाईंको डिभाइसको ब्याट्रीको चार्ज <xliff:g id="PERCENTAGE">%s</xliff:g> बाँकी छ। ब्याट्री सेभरले अँध्यारो थिम अन गर्छ, ब्याकग्राउन्डमा हुने क्रियाकलाप सीमित पार्छ र सूचनाहरू ढिलो देखाउँछ।"</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"ब्याट्री सेभरले अँध्यारो थिम अन गर्छ, ब्याकग्राउन्डमा हुने क्रियाकलाप सीमित पार्छ र सूचनाहरू ढिलो देखाउँछ।"</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> बाँकी"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"USB मार्फत चार्ज गर्न सकिँदैन"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"तपाईंको यन्त्रसँगै आएको चार्जर प्रयोग गर्नुहोस्‌"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"ब्याट्री सेभर सक्रिय गर्ने हो?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"ब्याट्री सेभरका बारेमा"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"खोल्नुहोस्"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"ब्याट्री सेभर सक्रिय गर्नुहोस्"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"अन गर्नुहोस्"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"पर्दैन"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"स्वत:घुम्ने स्क्रिन"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> लाई <xliff:g id="USB_DEVICE">%2$s</xliff:g> माथि पहुँच राख्ने अनुमति दिने हो?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> लाई <xliff:g id="USB_DEVICE">%2$s</xliff:g> माथि पहुँच राख्न अनुमति दिने हो?\nयो एपलाई रेकर्ड गर्ने अनुमति प्रदान गरिएको छैन तर यसले USB यन्त्रमार्फत अडियो क्याप्चर गर्न सक्छ।"</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"अनुहार प्रमाणीकरण गरियो"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"पुष्टि भयो"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"पूरा गर्नका लागि पुष्टि गर्नुहोस् नामक विकल्पमा ट्याप गर्नुहोस्"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"तपाईंको अनुहार प्रयोग गरी अनलक गरियो। जारी राख्न थिच्नुहोस्।"</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"प्रमाणीकरण गरियो"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN प्रयोग गर्नुहोस्"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ढाँचा प्रयोग गर्नुहोस्"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"तपाईंले अर्को पटक पनि गलत ढाँचा प्रविष्टि गर्नुभयो भने यो कार्य प्रोफाइल र त्यहाँको डेटा मेटाइने छ।"</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"तपाईंले अर्को पटक पनि गलत PIN प्रविष्टि गर्नुभयो भने तपाईंको कार्य प्रोफाइल र त्यहाँको डेटा मेटाइने छ।"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"तपाईंले अर्को पटक पनि गलत पासवर्ड प्रविष्टि गर्नुभयो भने तपाईंको कार्य प्रोफाइल र त्यहाँको डेटा मेटाइने छ।"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"अनलक गर्ने अत्यधिक गलत प्रयासहरू भए। यो डिभाइसको डेटा मेटाइने छ।"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"अनलक गर्ने अत्यधिक गलत प्रयासहरू भए। यो प्रयोगकर्तालाई हटाइने छ।"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"अनलक गर्ने अत्यधिक गलत प्रयासहरू भए। यो कार्यलयको प्रोफाइल र यसको डेटा मेटाइने छ।"</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"हटाउनुहोस्"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"फिंगरप्रिन्ट सेन्सरमा छुनुहोस्‌"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"फिंगरप्रिन्ट जनाउने आइकन"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"अनुहार पहिचान गर्न सकिएन। बरु फिंगरप्रिन्ट प्रयोग गर्नुहोस्।"</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • बिस्तारै चार्ज हुँदै छ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मा पूरै चार्ज हुन्छ"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • डक चार्ज हुँदै छ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मा पूरै चार्ज हुन्छ"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"प्रयोगकर्ता फेर्नुहोस्"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"प्रयोगकर्ता थप्नुहोस्"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"नयाँ प्रयोगकर्ता"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"अतिथि हटाउने हो?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"यो सत्रमा भएका सबै एपहरू र डेटा मेटाइने छ।"</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"हटाउनुहोस्"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"तपाईंलाई फेरि स्वागत छ, अतिथि"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"तपाईं आफ्नो सत्र जारी गर्न चाहनुहुन्छ?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"सुरु गर्नुहोस्"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"हो, जारी राख्नुहोस्"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"नयाँ प्रयोगकर्ता थप्ने हो?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"जब तपाईँले नयाँ प्रयोगकर्ता थप्नुहुन्छ, त्यस प्रयोगकर्ताले आफ्नो स्थान स्थापना गर्न पर्ने छ।\n\nसबै प्रयोगकर्ताले अरू प्रयोगकर्ताका एपहरू अपडेट गर्न सक्छन्।"</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"प्रयोगकर्ताको सीमा पुग्यो"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">तपाईं अधिकतम <xliff:g id="COUNT">%d</xliff:g> प्रयोगहरू मात्र थप्न सक्नुहुन्छ।</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"यो वालेट प्रयोग गर्न डिभाइस अनलक गर्नुहोस्"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"तपाईंका कार्डहरू प्राप्त गर्ने क्रममा समस्या भयो, कृपया पछि फेरि प्रयास गर्नुहोस्"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"लक स्क्रिनसम्बन्धी सेटिङ"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR कोड"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"स्क्यान गर्न ट्याप गर्नुहोस्"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR कोड स्क्यान गर्नुहोस्"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"कार्य प्रोफाइल"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"हवाइजहाज मोड"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"तपाईँले आफ्नो अर्को अलार्म <xliff:g id="WHEN">%1$s</xliff:g> सुन्नुहुने छैन"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"थप हेर्न स्वाइप गर्नुहोस्"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"सिफारिसहरू लोड गर्दै"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"मिडिया"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"यो मिडिया सत्र लुकाउने हो?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"हालको मिडिया सत्र लुकाउन मिल्दैन।"</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"हटाउनुहोस्"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"लुकाउनुहोस्"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"सुचारु गर्नुहोस्"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"सेटिङ"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> को <xliff:g id="SONG_NAME">%1$s</xliff:g> बोलको गीत <xliff:g id="APP_LABEL">%3$s</xliff:g> मा बज्दै छ"</string>
@@ -808,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"तपाईं यहाँ प्ले गर्न चाहनुहुन्छ भने आफ्नो डिभाइसलाई <xliff:g id="DEVICENAME">%1$s</xliff:g> नजिकै लैजानुहोस्"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> मा प्ले गरिँदै छ"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"यो फोनमा प्ले गरिँदै छ"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"केही चिज गडबड भयो"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"केही चिज गडबड भयो। फेरि प्रयास गर्नुहोस्।"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय छ, एप जाँच गर्नु…"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"फेला परेन"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"नियन्त्रण उपलब्ध छैन"</string>
@@ -827,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नयाँ डिभाइस कनेक्ट गर्नुहोस्"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"यो सत्र कास्ट गर्न चाहनुहुन्छ भने कृपया एप खोल्नुहोस्।"</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"अज्ञात एप"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"कास्ट गर्न छाड्नुहोस्"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नम्बर"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नम्बर कपी गरी क्लिपबोर्डमा सारियो।"</string>
     <string name="basic_status" msgid="2315371112182658176">"वार्तालाप खोल्नुहोस्"</string>
@@ -916,7 +905,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi उपलब्ध छैन"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"प्राथमिकता मोड"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"अलार्म सेट गरिएको छ"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"सहायकको अतिथि मोड अन गरिएको छ"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"क्यामेरा र माइक अफ छन्"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# वटा सूचना}other{# वटा सूचनाहरू}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index 4b96d5d..3a638b1 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -67,10 +67,12 @@
 
     <!-- media output dialog-->
     <color name="media_dialog_background">@color/material_dynamic_neutral10</color>
-    <color name="media_dialog_active_item_main_content">@color/material_dynamic_neutral10</color>
-    <color name="media_dialog_inactive_item_main_content">@color/material_dynamic_neutral10</color>
-    <color name="media_dialog_item_status">@color/material_dynamic_neutral10</color>
-    <color name="media_dialog_item_background">@color/material_dynamic_secondary95</color>
+    <color name="media_dialog_item_main_content">@color/material_dynamic_primary90</color>
+    <color name="media_dialog_item_background">@color/material_dynamic_neutral_variant20</color>
+    <color name="media_dialog_connected_item_background">@color/material_dynamic_secondary20</color>
+    <color name="media_dialog_seekbar_progress">@color/material_dynamic_secondary40</color>
+    <color name="media_dialog_button_background">@color/material_dynamic_primary70</color>
+    <color name="media_dialog_solid_button_text">@color/material_dynamic_secondary20</color>
 
     <!-- Biometric dialog colors -->
     <color name="biometric_dialog_gray">#ffcccccc</color>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 047f99f..0fd747e 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Systeem-UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Batterijbesparing aanzetten?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Je hebt nog <xliff:g id="PERCENTAGE">%s</xliff:g> batterij. Batterijbesparing zet het donkere thema aan, beperkt activiteit op de achtergrond en vertraagt meldingen."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Batterijbesparing zet het donkere thema aan, beperkt activiteit op de achtergrond en vertraagt meldingen."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Nog <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Kan niet opladen via USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Gebruik de oplader die bij je apparaat is geleverd"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Batterijbesparing aanzetten?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Over Batterijbesparing"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Aanzetten"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Batterijbesparing aanzetten"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Aanzetten"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Nee"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Scherm automatisch draaien"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> toegang geven tot <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> toegang geven tot <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nDeze app heeft geen opnamerechten gekregen, maar zou audio kunnen vastleggen via dit USB-apparaat."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Gezicht geverifieerd"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bevestigd"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tik op Bevestigen om te voltooien"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Ontgrendeld met je gezicht. Druk om door te gaan."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Geverifieerd"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Pincode gebruiken"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Patroon gebruiken"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Als je bij de volgende poging een onjuist patroon opgeeft, worden je werkprofiel en de bijbehorende gegevens verwijderd."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Als je bij de volgende poging een onjuiste pincode opgeeft, worden je werkprofiel en de bijbehorende gegevens verwijderd."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Als je bij de volgende poging een onjuist wachtwoord opgeeft, worden je werkprofiel en de bijbehorende gegevens verwijderd."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Te veel onjuiste pogingen. De gegevens van dit apparaat worden verwijderd."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Te veel onjuiste pogingen. Deze gebruiker wordt verwijderd."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Te veel onjuiste pogingen. Dit werkprofiel en de bijbehorende gegevens worden verwijderd."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Sluiten"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Raak de vingerafdruksensor aan"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Vingerafdrukpictogram"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Gezicht niet herkend. Gebruik je vingerafdruk."</string>
@@ -270,13 +263,13 @@
     <string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Werk-apps"</string>
     <string name="quick_settings_night_display_label" msgid="8180030659141778180">"Nachtverlichting"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Aan bij zonsondergang"</string>
-    <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Tot zonsopgang"</string>
+    <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Tot zonsopkomst"</string>
     <string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"Aan om <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"Tot <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"Donker thema"</string>
     <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Batterijbesparing"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"Aan bij zonsondergang"</string>
-    <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Tot zonsopgang"</string>
+    <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Tot zonsopkomst"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aan om <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Tot <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at_bedtime" msgid="2274300599408864897">"Aan als het bedtijd is"</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Langzaam opladen • Vol over <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Oplaaddock • Vol over <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Gebruiker wijzigen"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Gebruiker toevoegen"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Nieuwe gebruiker"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Gast verwijderen?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps en gegevens in deze sessie worden verwijderd."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Verwijderen"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welkom terug, gast!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Wil je doorgaan met je sessie?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Opnieuw starten"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ja, doorgaan"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Nieuwe gebruiker toevoegen?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Als je een nieuwe gebruiker toevoegt, moet die persoon zijn eigen profiel instellen.\n\nElke gebruiker kan apps updaten voor alle andere gebruikers."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Gebruikerslimiet bereikt"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">Je kunt maximaal <xliff:g id="COUNT">%d</xliff:g> gebruikers toevoegen.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ontgrendelen om te gebruiken"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Er is een probleem opgetreden bij het ophalen van je kaarten. Probeer het later opnieuw."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Instellingen voor vergrendelscherm"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-code"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Tik om te scannen"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR-code scannen"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Werkprofiel"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Vliegtuigmodus"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Je hoort je volgende wekker niet <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -590,7 +577,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Aan"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Uit"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Niet beschikbaar"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Uit"</string>
+    <string name="tile_disabled" msgid="373212051546573069">"Uitgezet"</string>
     <string name="nav_bar" msgid="4642708685386136807">"Navigatiebalk"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Lay-out"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Extra knoptype links"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe om meer te zien"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Aanbevelingen laden"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Media"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Deze mediasessie verbergen?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"De huidige mediasessie kan niet worden verborgen."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Sluiten"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Verbergen"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Hervatten"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Instellingen"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> van <xliff:g id="ARTIST_NAME">%2$s</xliff:g> wordt afgespeeld via <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Ga dichter bij <xliff:g id="DEVICENAME">%1$s</xliff:g> staan om hier af te spelen"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Afspelen op <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Afspelen op deze telefoon"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Er is iets misgegaan"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"Er is iets misgegaan. Probeer het opnieuw."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactief, check de app"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Niet gevonden"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Beheeroptie niet beschikbaar"</string>
@@ -827,8 +815,9 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Nieuw apparaat koppelen"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Als je deze sessie wilt casten, open je de app."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Onbekende app"</string>
-    <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build-nummer"</string>
-    <string name="build_number_copy_toast" msgid="877720921605503046">"Build-nummer naar klembord gekopieerd."</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Casten stoppen"</string>
+    <string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildnummer"</string>
+    <string name="build_number_copy_toast" msgid="877720921605503046">"Buildnummer naar klembord gekopieerd."</string>
     <string name="basic_status" msgid="2315371112182658176">"Gesprek openen"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Gesprekswidgets"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Tik op een gesprek om het toe te voegen aan je startscherm"</string>
@@ -916,7 +905,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wifi niet beschikbaar"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioriteitsmodus"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Wekker gezet"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Gastmodus voor de Assistent staat aan"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera en microfoon staan uit"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# melding}other{# meldingen}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 0dca918..fb37103 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"ସିଷ୍ଟମ୍ UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"ବ୍ୟାଟେରୀ ସେଭର ଚାଲୁ କରିବେ?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"ଆପଣଙ୍କର <xliff:g id="PERCENTAGE">%s</xliff:g> ବ୍ୟାଟେରୀ ଚାର୍ଜ ବାକି ଅଛି। ବ୍ୟାଟେରୀ ସେଭର ଗାଢ଼ା ଥିମକୁ ଚାଲୁ କରେ, ପୃଷ୍ଠପଟ କାର୍ଯ୍ୟକଳାପକୁ ପ୍ରତିବନ୍ଧିତ କରେ ଏବଂ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ବିଳମ୍ବିତ କରେ।"</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"ବ୍ୟାଟେରୀ ସେଭର ଗାଢ଼ା ଥିମକୁ ଚାଲୁ କରେ, ପୃଷ୍ଠପଟ କାର୍ଯ୍ୟକଳାପକୁ ପ୍ରତିବନ୍ଧିତ କରେ ଏବଂ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ବିଳମ୍ବିତ କରେ।"</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> ବାକି ଅଛି"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"USB ଦ୍ଵାରା ଚାର୍ଜ କରିହେବନାହିଁ"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"ଆପଣଙ୍କ ଡିଭାଇସ୍ ପାଇଁ ଥିବା ଚାର୍ଜର୍‌କୁ ବ୍ୟବହାର କରନ୍ତୁ"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"ବ୍ୟାଟେରୀ ସେଭର୍‌ ଚାଲୁ କରିବେ?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"ବ୍ୟାଟେରୀ ସେଭର୍ ବିଷୟରେ"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ଚାଲୁ‌ କରନ୍ତୁ"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"ବ୍ୟାଟେରୀ ସେଭର୍‌ ଚାଲୁ କରନ୍ତୁ"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"ଚାଲୁ କରନ୍ତୁ"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"ନା, ଧନ୍ୟବାଦ"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"ଅଟୋ-ରୋଟେଟ୍‌ ସ୍କ୍ରିନ୍"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ଆକ୍ସେସ୍‍ କରିବାକୁ <xliff:g id="APPLICATION">%1$s</xliff:g>କୁ ଅନୁମତି ଦେବେ?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ଆକ୍ସେସ୍ କରିବାକୁ <xliff:g id="APPLICATION">%1$s</xliff:g>କୁ ଅନୁମତି ଦେବେ କି?\nଏହି ଆପ୍‌କୁ ରେକର୍ଡ କରିବାକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ କିନ୍ତୁ ଏହି USB ଡିଭାଇସ୍ ଜରିଆରେ ଅଡିଓ କ୍ୟାପ୍ଟର୍ କରିପାରିବ।"</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ମୁହଁ ପ୍ରାମାଣିକତା ହୋଇଛି"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ସୁନିଶ୍ଚିତ କରାଯାଇଛି"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ସମ୍ପୂର୍ଣ୍ଣ କରିବାକୁ ସୁନିଶ୍ଚିତ କରନ୍ତୁରେ ଟାପ୍ କରନ୍ତୁ"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"ଆପଣଙ୍କ ଫେସ ମାଧ୍ୟମରେ ଅନଲକ କରାଯାଇଛି। ଜାରି ରଖିବାକୁ ଦବାନ୍ତୁ।"</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ପ୍ରାମାଣିକତା ହୋଇଛି"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN ବ୍ୟବହାର କରନ୍ତୁ"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ପାଟର୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"ଆପଣ ପରବର୍ତ୍ତୀ ପ୍ରଚେଷ୍ଟାରେ ଏକ ଭୁଲ ପାଟର୍ନ ପ୍ରବେଶ କଲେ, ଆପଣଙ୍କ ୱାର୍କ ପ୍ରୋଫାଇଲ୍ ଏବଂ ଏହାର ଡାଟାକୁ ଡିଲିଟ୍ କରିଦିଆଯିବ।"</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"ଆପଣ ପରବର୍ତ୍ତୀ ପ୍ରଚେଷ୍ଟାରେ ଏକ ଭୁଲ PIN ଲେଖିଲେ, ଆପଣଙ୍କ ୱାର୍କ ପ୍ରୋଫାଇଲ୍ ଏବଂ ଏହାର ଡାଟାକୁ ଡିଲିଟ୍ କରିଦିଆଯିବ।"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"ଆପଣ ପରବର୍ତ୍ତୀ ପ୍ରଚେଷ୍ଟାରେ ଏକ ଭୁଲ ପାସୱାର୍ଡ ଲେଖିଲେ, ଆପଣଙ୍କ ୱାର୍କ ପ୍ରୋଫାଇଲ୍ ଓ ଏହାର ଡାଟାକୁ ଡିଲିଟ୍ କରିଦିଆଯିବ।"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"ଅନେକଗୁଡ଼ିଏ ଭୁଲ ପ୍ରଚେଷ୍ଟା। ଏହି ଡିଭାଇସର ଡାଟା ଡିଲିଟ୍ ହୋଇଯିବ।"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"ଅନେକଗୁଡ଼ିଏ ଭୁଲ ପ୍ରଚେଷ୍ଟା। ଏହି ଉପଯୋଗକର୍ତ୍ତା ଡିଲିଟ୍ ହୋଇଯିବ।"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"ଅନେକଗୁଡ଼ିଏ ଭୁଲ ପ୍ରଚେଷ୍ଟା। ଏହି ୱାର୍କ ପ୍ରୋଫାଇଲ୍ ଏବଂ ଏହାର ଡାଟା ଡିଲିଟ୍ ହୋଇଯିବ।"</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"ଖାରଜ କରନ୍ତୁ"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ଟିପଚିହ୍ନ ସେନସର୍‌କୁ ଛୁଅଁନ୍ତୁ"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ଟିପଚିହ୍ନ ଆଇକନ୍"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ଫେସ୍ ଚିହ୍ନଟ କରିହେବ ନାହିଁ। ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ଧୀରେ ଚାର୍ଜ ହେଉଛି • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>ରେ ସମ୍ପୂର୍ଣ୍ଣ ହେବ"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ଡକରୁ ଚାର୍ଜ ହେଉଛି • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>ରେ ସମ୍ପୂର୍ଣ୍ଣ ହେବ"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ୟୁଜର୍‍ ବଦଳାନ୍ତୁ"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"ଉପଯୋଗକର୍ତ୍ତାଙ୍କୁ ଯୋଗ କରନ୍ତୁ"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"ନୂଆ ଉପଯୋଗକର୍ତ୍ତା"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ଅତିଥିଙ୍କୁ କାଢ଼ିଦେବେ?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ଏହି ସେସନର ସମସ୍ତ ଆପ୍‌ ଓ ଡାଟା ଡିଲିଟ୍‌ ହୋଇଯିବ।"</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"କାଢ଼ିଦିଅନ୍ତୁ"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"ପୁଣି ସ୍ୱାଗତ, ଅତିଥି!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"ଆପଣ ନିଜର ସେସନ୍ ଜାରି ରଖିବାକୁ ଚାହାଁନ୍ତି କି?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ଆରମ୍ଭ କରନ୍ତୁ"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"ହଁ, ଜାରି ରଖନ୍ତୁ"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"ନୂତନ ଉପଯୋଗକର୍ତ୍ତା ଯୋଗ କରିବେ?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"ଆପଣ ଜଣେ ନୂଆ ଉପଯୋଗକର୍ତ୍ତାଙ୍କୁ ଯୋଗ କଲେ,ତାଙ୍କୁ ସ୍ପେସ୍ ସେଟ୍ ଅପ୍ କରିବାକୁ ପଡ଼ିବ। \n \n ଅନ୍ୟ ସମସ୍ତ ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଯେ କୌଣସି ଉପଯୋଗକର୍ତ୍ତା ଆପଗୁଡ଼ିକୁ ଅପଡେଟ୍‌ କରିପାରିବେ।"</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"ଉପଯୋଗକର୍ତ୍ତା ସୀମାରେ ପହଞ୍ଚିଛି"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">କେବଳ <xliff:g id="COUNT">%d</xliff:g> ଉପଯୋଗକର୍ତ୍ତା ହିଁ ତିଆରି କରିହେବ।</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ବ୍ୟବହାର କରିବାକୁ ଅନଲକ୍ କରନ୍ତୁ"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"ଆପଣଙ୍କ କାର୍ଡଗୁଡ଼ିକ ପାଇବାରେ ଏକ ସମସ୍ୟା ହୋଇଥିଲା। ଦୟାକରି ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ସ୍କ୍ରିନ୍ ଲକ୍ ସେଟିଂସ୍"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR କୋଡ"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"ସ୍କାନ କରିବାକୁ ଟାପ କରନ୍ତୁ"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR କୋଡ ସ୍କାନ କରନ୍ତୁ"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"ୱର୍କ ପ୍ରୋଫାଇଲ୍‌"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"ଏରୋପ୍ଲେନ୍‍ ମୋଡ୍"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>ବେଳେ ଆପଣ ନିଜର ପରବର୍ତ୍ତୀ ଆଲାର୍ମ ଶୁଣିପାରିବେ ନାହିଁ"</string>
@@ -645,7 +632,7 @@
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ଦ୍ରୁତ ସେଟିଙ୍ଗ ଏଡିଟର୍।"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> ବିଜ୍ଞପ୍ତି: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"ସେଟିଂସ୍ ଖୋଲନ୍ତୁ।"</string>
-    <string name="accessibility_quick_settings_expand" msgid="2609275052412521467">"ଦ୍ରୁତ ସେଟିଙ୍ଗ ଖୋଲନ୍ତୁ।"</string>
+    <string name="accessibility_quick_settings_expand" msgid="2609275052412521467">"କ୍ଵିକ ସେଟିଂସ ଖୋଲନ୍ତୁ।"</string>
     <string name="accessibility_quick_settings_collapse" msgid="4674876336725041982">"ଦ୍ରୁତ ସେଟିଂସ୍ ବନ୍ଦ କରନ୍ତୁ।"</string>
     <string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> ଭାବରେ ସାଇନ୍‌ ଇନ୍‌ କରିଛନ୍ତି"</string>
     <string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"ଉପଯୋଗକର୍ତ୍ତା ବାଛନ୍ତୁ"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"ଅଧିକ ଦେଖିବାକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ସୁପାରିଶଗୁଡ଼ିକ ଲୋଡ୍ କରାଯାଉଛି"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"ମିଡିଆ"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"ଏହି ମିଡିଆ ସେସନକୁ ଲୁଚାଇବେ?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"ବର୍ତ୍ତମାନର ମିଡିଆ ସେସନକୁ ଲୁଚାଯାଇପାରିବ ନାହିଁ।"</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ଖାରଜ କରନ୍ତୁ"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ଲୁଚାନ୍ତୁ"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"ପୁଣି ଆରମ୍ଭ କରନ୍ତୁ"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"ସେଟିଂସ୍"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g>ରୁ <xliff:g id="ARTIST_NAME">%2$s</xliff:g>ଙ୍କ <xliff:g id="SONG_NAME">%1$s</xliff:g> ଚାଲୁଛି"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ଏଠାରେ ଚଲାଇବା ପାଇଁ <xliff:g id="DEVICENAME">%1$s</xliff:g>ର ପାଖକୁ ମୁଭ କରନ୍ତୁ"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ରେ ଚାଲୁଛି"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"ଏହି ଫୋନରେ ଚାଲୁଛି"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"କିଛି ତ୍ରୁଟି ହୋଇଛି"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"ନିଷ୍କ୍ରିୟ ଅଛି, ଆପ ଯାଞ୍ଚ କରନ୍ତୁ"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"ମିଳିଲା ନାହିଁ"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"ନିୟନ୍ତ୍ରଣ ଉପଲବ୍ଧ ନାହିଁ"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ନୂଆ ଡିଭାଇସକୁ ପେୟାର୍ କରନ୍ତୁ"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ଏହି ସେସନକୁ କାଷ୍ଟ କରିବା ପାଇଁ, ଦୟାକରି ଆପ ଖୋଲନ୍ତୁ।"</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"ଅଜଣା ଆପ"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"କାଷ୍ଟ କରିବା ବନ୍ଦ କରନ୍ତୁ"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"ବିଲ୍ଡ ନମ୍ୱର"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"କ୍ଲିପବୋର୍ଡକୁ କପି କରାଯାଇଥିବା ବିଲ୍ଡ ନମ୍ୱର।"</string>
     <string name="basic_status" msgid="2315371112182658176">"ବାର୍ତ୍ତାଳାପ ଖୋଲନ୍ତୁ"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ୱାଇ-ଫାଇ ଉପଲବ୍ଧ ନାହିଁ"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ପ୍ରାଥମିକତା ମୋଡ"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ଆଲାରାମ ସେଟ"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Assistantର ଅତିଥି ମୋଡ ସକ୍ଷମ କରାଯାଇଛି"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"କ୍ୟାମେରା ଏବଂ ମାଇକ ବନ୍ଦ ଅଛି"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{#ଟି ବିଜ୍ଞପ୍ତି}other{#ଟି ବିଜ୍ଞପ୍ତି}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index faa2062..1a35402 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"ਸਿਸਟਮ UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"ਕੀ ਬੈਟਰੀ ਸੇਵਰ ਚਾਲੂ ਕਰਨਾ ਹੈ?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"ਤੁਹਾਡੇ ਕੋਲ <xliff:g id="PERCENTAGE">%s</xliff:g> ਬੈਟਰੀ ਬਾਕੀ ਬਚੀ ਹੈ। ਬੈਟਰੀ ਸੇਵਰ ਗੂੜ੍ਹੇ ਥੀਮ ਨੂੰ ਚਾਲੂ ਕਰਦਾ ਹੈ, ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਉਂਦਾ ਹੈ ਅਤੇ ਸੂਚਨਾਵਾਂ ਵਿੱਚ ਦੇਰੀ ਕਰਦਾ ਹੈ।"</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"ਬੈਟਰੀ ਸੇਵਰ ਗੂੜ੍ਹੇ ਥੀਮ ਨੂੰ ਚਾਲੂ ਕਰਦਾ ਹੈ, ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਉਂਦਾ ਹੈ ਅਤੇ ਸੂਚਨਾਵਾਂ ਵਿੱਚ ਦੇਰੀ ਕਰਦਾ ਹੈ।"</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> ਬਾਕੀ"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"USB ਰਾਹੀਂ ਚਾਰਜ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"ਆਪਣੇ ਡੀਵਾਈਸ ਨਾਲ ਮਿਲੇ ਚਾਰਜਰ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"ਕੀ ਬੈਟਰੀ ਸੇਵਰ ਚਾਲੂ ਕਰਨਾ ਹੈ?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"ਬੈਟਰੀ ਸੇਵਰ ਬਾਰੇ"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ਚਾਲੂ ਕਰੋ"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"ਬੈਟਰੀ ਸੇਵਰ ਚਾਲੂ ਕਰੋ"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"ਚਾਲੂ ਕਰੋ"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"ਨਹੀਂ ਧੰਨਵਾਦ"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"ਸਕ੍ਰੀਨ ਸਵੈ-ਘੁਮਾਓ"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"ਕੀ <xliff:g id="USB_DEVICE">%2$s</xliff:g> ਤੱਕ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨੂੰ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"ਕੀ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨੂੰ <xliff:g id="USB_DEVICE">%2$s</xliff:g> ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?\nਇਸ ਐਪ ਨੂੰ ਰਿਕਾਰਡ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਦਿੱਤੀ ਗਈ ਪਰ ਇਹ USB ਡੀਵਾਈਸ ਰਾਹੀਂ ਆਡੀਓ ਕੈਪਚਰ ਕਰ ਸਕਦੀ ਹੈ।"</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ਚਿਹਰਾ ਪ੍ਰਮਾਣੀਕਿਰਤ ਹੋਇਆ"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ਪੁਸ਼ਟੀ ਕੀਤੀ ਗਈ"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ਪੂਰਾ ਕਰਨ ਲਈ ਪੁਸ਼ਟੀ ਕਰੋ \'ਤੇ ਟੈਪ ਕਰੋ"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"ਤੁਹਾਡੇ ਚਿਹਰੇ ਵੱਲੋਂ ਅਣਲਾਕ ਕੀਤਾ ਗਿਆ। ਜਾਰੀ ਰੱਖਣ ਲਈ ਦਬਾਓ।"</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ਪ੍ਰਮਾਣਿਤ ਹੋਇਆ"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"ਪਿੰਨ ਵਰਤੋ"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ਪੈਟਰਨ ਵਰਤੋ"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"ਜੇ ਤੁਸੀਂ ਅਗਲੀ ਕੋਸ਼ਿਸ਼ ਵਿੱਚ ਕੋਈ ਗਲਤ ਪੈਟਰਨ ਦਾਖਲ ਕਰਦੇ ਹੋ, ਤਾਂ ਤੁਹਾਡਾ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਅਤੇ ਇਸ ਦਾ ਡਾਟਾ ਮਿਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ।"</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"ਜੇ ਤੁਸੀਂ ਅਗਲੀ ਕੋਸ਼ਿਸ਼ ਵਿੱਚ ਕੋਈ ਗਲਤ ਪਿੰਨ ਦਾਖਲ ਕਰਦੇ ਹੋ, ਤਾਂ ਤੁਹਾਡਾ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਅਤੇ ਇਸ ਦਾ ਡਾਟਾ ਮਿਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ।"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"ਜੇ ਤੁਸੀਂ ਅਗਲੀ ਕੋਸ਼ਿਸ਼ ਵਿੱਚ ਕੋਈ ਗਲਤ ਪਾਸਵਰਡ ਦਾਖਲ ਕਰਦੇ ਹੋ, ਤਾਂ ਤੁਹਾਡਾ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਅਤੇ ਇਸ ਦਾ ਡਾਟਾ ਮਿਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ।"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"ਬਹੁਤ ਸਾਰੀਆਂ ਗਲਤ ਕੋਸ਼ਿਸ਼ਾਂ। ਇਸ ਡੀਵਾਈਸ ਦਾ ਡਾਟਾ ਮਿਟਾਇਆ ਜਾਵੇਗਾ।"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"ਬਹੁਤ ਸਾਰੀਆਂ ਗਲਤ ਕੋਸ਼ਿਸ਼ਾਂ। ਇਸ ਵਰਤੋਂਕਾਰ ਨੂੰ ਮਿਟਾਇਆ ਜਾਵੇਗਾ।"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"ਬਹੁਤ ਸਾਰੀਆਂ ਗਲਤ ਕੋਸ਼ਿਸ਼ਾਂ। ਇਹ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਅਤੇ ਇਸਦਾ ਡਾਟਾ ਮਿਟਾਇਆ ਜਾਵੇਗਾ।"</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"ਖਾਰਜ ਕਰੋ"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਨੂੰ ਸਪੱਰਸ਼ ਕਰੋ"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦਾ ਪ੍ਰਤੀਕ"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ਚਿਹਰਾ ਨਹੀਂ ਪਛਾਣ ਸਕਦੇ। ਇਸਦੀ ਬਜਾਏ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤੋ।"</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ਹੌਲੀ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ਵਿੱਚ ਪੂਰਾ ਚਾਰਜ ਹੋਵੇਗਾ"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ਡੌਕ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ਵਿੱਚ ਪੂਰਾ ਚਾਰਜ ਹੋਵੇਗਾ"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ਵਰਤੋਂਕਾਰ ਸਵਿੱਚ ਕਰੋ"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰੋ"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"ਨਵਾਂ ਵਰਤੋਂਕਾਰ"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ਕੀ ਮਹਿਮਾਨ ਹਟਾਉਣਾ ਹੈ?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ਇਸ ਸੈਸ਼ਨ ਵਿੱਚ ਸਾਰੀਆਂ ਐਪਾਂ ਅਤੇ ਡਾਟਾ ਨੂੰ ਮਿਟਾ ਦਿੱਤਾ ਜਾਏਗਾ।"</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ਹਟਾਓ"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"ਮਹਿਮਾਨ, ਫਿਰ ਤੁਹਾਡਾ ਸੁਆਗਤ ਹੈ!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"ਕੀ ਤੁਸੀਂ ਆਪਣਾ ਸੈਸ਼ਨ ਜਾਰੀ ਰੱਖਣਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ਮੁੜ-ਸ਼ੁਰੂ ਕਰੋ"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"ਹਾਂ, ਜਾਰੀ ਰੱਖੋ"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"ਕੀ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰਨਾ ਹੈ?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"ਜਦੋਂ ਤੁਸੀਂ ਇੱਕ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰਦੇ ਹੋ, ਉਸ ਵਿਅਕਤੀ ਨੂੰ ਆਪਣੀ ਜਗ੍ਹਾ ਸਥਾਪਤ ਕਰਨ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ।\n\nਕੋਈ ਵੀ ਵਰਤੋਂਕਾਰ ਹੋਰ ਸਾਰੇ ਵਰਤੋਂਕਾਰਾਂ ਦੀਆਂ ਐਪਾਂ ਨੂੰ ਅੱਪਡੇਟ ਕਰ ਸਕਦਾ ਹੈ।"</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰਨ ਦੀ ਸੀਮਾ ਪੂਰੀ ਹੋਈ"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">ਤੁਸੀਂ <xliff:g id="COUNT">%d</xliff:g> ਤੱਕ ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰ ਸਕਦੇ ਹੋ।</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ਵਰਤਣ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"ਤੁਹਾਡੇ ਕਾਰਡ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਕੋਈ ਸਮੱਸਿਆ ਆਈ, ਕਿਰਪਾ ਕਰਕੇ ਬਾਅਦ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ਲਾਕ ਸਕ੍ਰੀਨ ਸੈਟਿੰਗਾਂ"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR ਕੋਡ"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"ਸਕੈਨ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR ਕੋਡ ਸਕੈਨ ਕਰੋ"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"ਹਵਾਈ-ਜਹਾਜ਼ ਮੋਡ"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"ਤੁਸੀਂ <xliff:g id="WHEN">%1$s</xliff:g> ਵਜੇ ਆਪਣਾ ਅਗਲਾ ਅਲਾਰਮ ਨਹੀਂ ਸੁਣੋਗੇ"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"ਹੋਰ ਦੇਖਣ ਲਈ ਸਵਾਈਪ ਕਰੋ"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ਸਿਫ਼ਾਰਸ਼ਾਂ ਲੋਡ ਹੋ ਰਹੀਆਂ ਹਨ"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"ਮੀਡੀਆ"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"ਕੀ ਇਹ ਮੀਡੀਆ ਸੈਸ਼ਨ ਲੁਕਾਉਣਾ ਹੈ?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"ਮੌਜੂਦਾ ਮੀਡੀਆ ਸੈਸ਼ਨ ਲੁਕਾਇਆ ਨਹੀਂ ਜਾ ਸਕਦਾ।"</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ਖਾਰਜ ਕਰੋ"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ਲੁਕਾਓ"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"ਮੁੜ-ਚਾਲੂ ਕਰੋ"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"ਸੈਟਿੰਗਾਂ"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> ਤੋਂ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> ਦਾ <xliff:g id="SONG_NAME">%1$s</xliff:g> ਚੱਲ ਰਿਹਾ ਹੈ"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ਇੱਥੇ ਚਲਾਉਣ ਲਈ <xliff:g id="DEVICENAME">%1$s</xliff:g> ਦੇ ਨੇੜੇ ਜਾਓ"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> \'ਤੇ ਚਲਾਇਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"ਇਸ ਫ਼ੋਨ \'ਤੇ ਚਲਾਇਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"ਕੋਈ ਗੜਬੜ ਹੋ ਗਈ"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"ਅਕਿਰਿਆਸ਼ੀਲ, ਐਪ ਦੀ ਜਾਂਚ ਕਰੋ"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"ਨਹੀਂ ਮਿਲਿਆ"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"ਕੰਟਰੋਲ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ਨਵਾਂ ਡੀਵਾਈਸ ਜੋੜਾਬੱਧ ਕਰੋ"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ਇਸ ਸੈਸ਼ਨ ਨੂੰ ਕਾਸਟ ਕਰਨ ਲਈ, ਕਿਰਪਾ ਕਰਕੇ ਐਪ ਖੋਲ੍ਹੋ।"</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"ਅਗਿਆਤ ਐਪ"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ਕਾਸਟ ਕਰਨਾ ਬੰਦ ਕਰੋ"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"ਬਿਲਡ ਨੰਬਰ"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"ਬਿਲਡ ਨੰਬਰ ਨੂੰ ਕਲਿੱਪਬੋਰਡ \'ਤੇ ਕਾਪੀ ਕੀਤਾ ਗਿਆ।"</string>
     <string name="basic_status" msgid="2315371112182658176">"ਗੱਲਬਾਤ ਖੋਲ੍ਹੋ"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ਵਾਈ-ਫਾਈ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ਤਰਜੀਹੀ ਮੋਡ"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ਅਲਾਰਮ ਸੈੱਟ ਹੈ"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Assistant ਮਹਿਮਾਨ ਮੋਡ ਚਾਲੂ ਹੈ"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ਕੈਮਰਾ ਅਤੇ ਮਾਈਕ ਬੰਦ ਹਨ"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ਸੂਚਨਾ}one{# ਸੂਚਨਾ}other{# ਸੂਚਨਾਵਾਂ}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 5d61dfe..b56215d 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"UI systemu"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Włączyć Oszczędzanie baterii?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Masz już tylko <xliff:g id="PERCENTAGE">%s</xliff:g> baterii. Oszczędzanie baterii uruchamia ciemny motyw, ogranicza aktywność w tle i opóźnia powiadomienia."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Oszczędzanie baterii uruchamia ciemny motyw, ogranicza aktywność w tle i opóźnia powiadomienia."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Pozostało <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Nie można naładować przez USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Użyj ładowarki dostarczonej z urządzeniem"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Włączyć Oszczędzanie baterii?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Informacje o Oszczędzaniu baterii"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Włącz"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Włączyć Oszczędzanie baterii?"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Włącz"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Nie, dziękuję"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Autoobracanie ekranu"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Zezwolić aplikacji <xliff:g id="APPLICATION">%1$s</xliff:g> na dostęp do urządzenia <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Zezwolić aplikacji <xliff:g id="APPLICATION">%1$s</xliff:g> na dostęp do urządzenia <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nTa aplikacja nie ma uprawnień do nagrywania, ale może rejestrować dźwięk za pomocą tego urządzenia USB."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Twarz rozpoznana"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potwierdzono"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Aby zakończyć, kliknij Potwierdź"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Odblokowano skanem twarzy. Kliknij, aby kontynuować."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Uwierzytelniono"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Użyj kodu PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Użyj wzoru"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Jeśli następnym razem podasz nieprawidłowy wzór, profil służbowy oraz powiązane z nim dane zostaną usunięte."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Jeśli następnym razem podasz nieprawidłowy kod PIN, profil służbowy oraz powiązane z nim dane zostaną usunięte."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Jeśli następnym razem podasz nieprawidłowe hasło, profil służbowy oraz powiązane z nim dane zostaną usunięte."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Zbyt wiele nieudanych prób. Dane na urządzeniu zostaną usunięte."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Zbyt wiele nieudanych prób. Użytkownik zostanie usunięty."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Zbyt wiele nieudanych prób. Profil służbowy i powiązane z nim dane zostaną usunięte."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Zamknij"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dotknij czytnika linii papilarnych"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona odcisku palca"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nie rozpoznaję twarzy. Użyj odcisku palca."</string>
@@ -330,17 +323,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Wolne ładowanie • Pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ładowanie na stacji dokującej • Pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Przełącz użytkownika"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Dodaj użytkownika"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Nowy użytkownik"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Usunąć gościa?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Wszystkie aplikacje i dane w tej sesji zostaną usunięte."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Usuń"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Witaj ponownie, Gościu!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcesz kontynuować sesję?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Rozpocznij nową"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Tak, kontynuuj"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Dodać nowego użytkownika?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Gdy dodasz nowego użytkownika, musi on skonfigurować swój profil.\n\nKażdy użytkownik może aktualizować aplikacje wszystkich innych użytkowników."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Osiągnięto limit użytkowników"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="few">Możesz dodać maksymalnie <xliff:g id="COUNT">%d</xliff:g> użytkowników.</item>
@@ -468,8 +456,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Odblokuj, aby użyć"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Podczas pobierania kart wystąpił problem. Spróbuj ponownie później."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Ustawienia ekranu blokady"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"Kod QR"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Kliknij, aby zeskanować"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Zeskanuj kod QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Profil służbowy"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Tryb samolotowy"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Nie usłyszysz swojego następnego alarmu <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -800,9 +787,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Przesuń palcem, by zobaczyć więcej"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Wczytuję rekomendacje"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Multimedia"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Ukryć tę sesję multimediów?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Nie można ukryć tej sesji multimediów."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Odrzuć"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ukryj"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Wznów"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Ustawienia"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Aplikacja <xliff:g id="APP_LABEL">%3$s</xliff:g> odtwarza utwór <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>)"</string>
@@ -820,7 +808,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Zbliż do urządzenia <xliff:g id="DEVICENAME">%1$s</xliff:g>, aby na nim odtwarzać"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Odtwarzam na ekranie <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Odtwarzam na tym telefonie"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Coś poszło nie tak"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Nieaktywny, sprawdź aplikację"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nie znaleziono"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Element jest niedostępny"</string>
@@ -839,6 +828,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sparuj nowe urządzenie"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Aby przesłać tę sesję, otwórz aplikację."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Nieznana aplikacja"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zatrzymaj przesyłanie"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Numer kompilacji"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Numer kompilacji został skopiowany do schowka."</string>
     <string name="basic_status" msgid="2315371112182658176">"Otwarta rozmowa"</string>
@@ -930,8 +920,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Sieć Wi‑Fi niedostępna"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Tryb priorytetowy"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm ustawiony"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Tryb gościa w Asystencie włączony"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Aparat i mikrofon są wyłączone"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# powiadomienie}few{# powiadomienia}many{# powiadomień}other{# powiadomienia}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index d9bb15b..219fd7f 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Interface do sistema"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Ativar Economia de bateria?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Você tem <xliff:g id="PERCENTAGE">%s</xliff:g> de bateria. A Economia de bateria ativa o tema escuro, restringe atividades em segundo plano e atrasa notificações."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"A Economia de bateria ativa o tema escuro, restringe atividades em segundo plano e atrasa notificações."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> restantes"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Não é possível carregar via USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Usar o carregador que acompanha o dispositivo"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Ativar \"Economia de bateria\"?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Sobre a Economia de bateria"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Ativar"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Ativar a Economia de bateria"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Ativar"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Agora não"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Giro automático da tela"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Permitir que o app <xliff:g id="APPLICATION">%1$s</xliff:g> acesse <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> acesse <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nEsse app não tem permissão de gravação, mas pode capturar áudio pelo dispositivo USB."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Rosto autenticado"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmada"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toque em \"Confirmar\" para concluir"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Desbloqueado pelo seu rosto. Pressione para continuar."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticado"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Usar PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Usar padrão"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Se você informar um padrão incorreto na próxima tentativa, seu perfil de trabalho e os dados dele serão excluídos."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Se você informar um PIN incorreto na próxima tentativa, seu perfil de trabalho e os dados dele serão excluídos."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Se você informar uma senha incorreta na próxima tentativa, seu perfil de trabalho e os dados dele serão excluídos."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Excesso de tentativas incorretas. Os dados deste dispositivo serão excluídos."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Excesso de tentativas incorretas. O usuário será excluído."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Excesso de tentativas incorretas. Este perfil de trabalho e os dados dele serão excluídos."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Dispensar"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toque no sensor de impressão digital"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ícone de impressão digital"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Não foi possível reconhecer o rosto Use a impressão digital."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carga lenta • Conclusão em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carregando na base • Carga completa em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Trocar usuário"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Adicionar usuário"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Novo usuário"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remover visitante?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todos os apps e dados nesta sessão serão excluídos."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remover"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Você voltou, visitante!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Quer continuar a sessão?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recomeçar"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Sim, continuar"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Adicionar novo usuário?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Quando você adiciona um novo usuário, essa pessoa precisa configurar o próprio espaço.\n\nQualquer usuário pode atualizar apps para os demais usuários."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Limite de usuários atingido"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">É possível adicionar até <xliff:g id="COUNT">%d</xliff:g> usuário.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Ocorreu um problema ao carregar os cards. Tente novamente mais tarde"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Configurações de tela de bloqueio"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"Código QR"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Toque para fazer a leitura"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Ler código QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabalho"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Modo avião"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Você não ouvirá o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Deslize para ver mais"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Carregando recomendações"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Mídia"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Ocultar a sessão de mídia?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Não é possível ocultar a sessão de mídia atual."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dispensar"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Configurações"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Tocando <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> no app <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Aproxime-se do dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g> para abrir a mídia aqui"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Mídia aberta no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Mídia aberta neste smartphone"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Algo deu errado"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"Algo deu errado. Tente novamente."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"O controle está indisponível"</string>
@@ -827,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parear novo dispositivo"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Abra o app para transmitir esta sessão."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"App desconhecido"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Parar transmissão"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da versão"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Número da versão copiado para a área de transferência."</string>
     <string name="basic_status" msgid="2315371112182658176">"Conversa aberta"</string>
@@ -916,7 +905,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi-Fi indisponível"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modo de prioridade"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarme definido"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Modo visitante do Google Assistente ativado"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A câmera e o microfone estão desativados"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}one{# notificação}other{# notificações}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 73ef834..01cfbbb 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"IU do sistema"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Ativar a Poupança de bateria?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Resta-lhe <xliff:g id="PERCENTAGE">%s</xliff:g> de bateria. A Poupança de bateria ativa o tema escuro, restringe a atividade em segundo plano e atrasa as notificações."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"A Poupança de bateria ativa o tema escuro, restringe a atividade em segundo plano e atrasa as notificações."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> restante"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Não é possível carregar através de USB."</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Utilize o carregador fornecido com o dispositivo."</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Pretende ativar a Poupança de bateria?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Acerca da Poupança de bateria"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Ativar"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Ativar a Poupança de bateria"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Ativar"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Não"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Rodar ecrã automaticamente"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Permitir que a app <xliff:g id="APPLICATION">%1$s</xliff:g> aceda ao dispositivo <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> aceda a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nEsta app não recebeu autorização de gravação, mas pode capturar áudio através deste dispositivo USB."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Rosto autenticado"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmado"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toque em Confirmar para concluir."</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Desbloqueado com o rosto. Prima para continuar."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticado"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Utilizar PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Utilizar padrão"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Se introduzir um padrão incorreto na tentativa seguinte, o seu perfil de trabalho e os respetivos dados serão eliminados."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Se introduzir um PIN incorreto na tentativa seguinte, o seu perfil de trabalho e os respetivos dados serão eliminados."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Se introduzir uma palavra-passe incorreta na tentativa seguinte, o seu perfil de trabalho e os respetivos dados serão eliminados."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Demasiadas tentativas incorretas. Os dados deste dispositivo serão eliminados."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Demasiadas tentativas incorretas. Este utilizador será eliminado."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Demasiadas tentativas incorretas. Este perfil de trabalho e os respetivos dados serão eliminados."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Ignorar"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toque no sensor de impressões digitais."</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ícone de impressão digital"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Impos. reconh. rosto. Utilize a impressão digital."</string>
@@ -205,8 +198,8 @@
     <string name="accessibility_clear_all" msgid="970525598287244592">"Limpar todas as notificações."</string>
     <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192">
-      <item quantity="one">Mais <xliff:g id="NUMBER_0">%s</xliff:g> notificação no grupo.</item>
       <item quantity="other">Mais <xliff:g id="NUMBER_1">%s</xliff:g> notificações no grupo.</item>
+      <item quantity="one">Mais <xliff:g id="NUMBER_0">%s</xliff:g> notificação no grupo.</item>
     </plurals>
     <string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"O ecrã está bloqueado na orientação horizontal."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"O ecrã está bloqueado na orientação vertical."</string>
@@ -255,8 +248,8 @@
     <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"A ativar..."</string>
     <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Poup. dados ativada"</string>
     <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="3142308865165871976">
-      <item quantity="one">%d dispositivo</item>
       <item quantity="other">%d dispositivos</item>
+      <item quantity="one">%d dispositivo</item>
     </plurals>
     <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Lanterna"</string>
     <string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Câmara em utilização"</string>
@@ -326,21 +319,16 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • A carregar lentamente • Carga completa em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • A carregar na estação de ancoragem • Carga completa em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Mudar utilizador"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Adicionar utilizador"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Novo utilizador"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remover o convidado?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todas as apps e dados desta sessão serão eliminados."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remover"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bem-vindo de volta, convidado!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Pretende continuar a sessão?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recomeçar"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Sim, continuar"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Adicionar um novo utilizador?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Ao adicionar um novo utilizador, essa pessoa tem de configurar o respetivo espaço.\n\nQualquer utilizador pode atualizar apps para todos os outros utilizadores."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Limite de utilizadores alcançado"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
-      <item quantity="one">Apenas é possível criar um utilizador.</item>
       <item quantity="other">Pode adicionar até <xliff:g id="COUNT">%d</xliff:g> utilizadores.</item>
+      <item quantity="one">Apenas é possível criar um utilizador.</item>
     </plurals>
     <string name="user_remove_user_title" msgid="9124124694835811874">"Remover o utilizador?"</string>
     <string name="user_remove_user_message" msgid="6702834122128031833">"Serão eliminados todos os dados e todas as aplicações deste utilizador."</string>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para utilizar"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Ocorreu um problema ao obter os seus cartões. Tente novamente mais tarde."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Definições do ecrã de bloqueio"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"Código QR"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Toque para ler"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Leia o código QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabalho"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Modo de avião"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Não vai ouvir o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -528,12 +515,12 @@
     <string name="snooze_undo" msgid="2738844148845992103">"Anular"</string>
     <string name="snoozed_for_time" msgid="7586689374860469469">"Suspensa por <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
     <plurals name="snoozeHourOptions" formatted="false" msgid="2066838694120718170">
-      <item quantity="one">%d hora</item>
       <item quantity="other">%d horas</item>
+      <item quantity="one">%d hora</item>
     </plurals>
     <plurals name="snoozeMinuteOptions" formatted="false" msgid="8998483159208055980">
-      <item quantity="one">%d minuto</item>
       <item quantity="other">%d minutos</item>
+      <item quantity="one">%d minuto</item>
     </plurals>
     <string name="battery_detail_switch_title" msgid="6940976502957380405">"Poupança de bateria"</string>
     <string name="keyboard_key_button_template" msgid="8005673627272051429">"Botão <xliff:g id="NAME">%1$s</xliff:g>"</string>
@@ -756,8 +743,8 @@
     <string name="quick_controls_title" msgid="6839108006171302273">"Controlos de dispositivos"</string>
     <string name="controls_providers_title" msgid="6879775889857085056">"Escolha uma app para adicionar controlos"</string>
     <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
-      <item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g> controlo adicionado.</item>
       <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> controlos adicionados.</item>
+      <item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g> controlo adicionado.</item>
     </plurals>
     <string name="controls_removed" msgid="3731789252222856959">"Removido"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Adicionado aos favoritos"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Deslize rapidamente para ver mais."</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"A carregar recomendações…"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Multimédia"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Pretende ocultar esta sessão de multimédia?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Não pode ocultar a sessão de multimédia atual."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ignorar"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Definições"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> em reprodução a partir da app <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Aproxime-se do dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g> para reproduzir aqui"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"A reproduzir no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"A reproduzir neste telemóvel"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Algo correu mal"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"Algo correu mal. Tente novamente."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inativa. Consulte a app."</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado."</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"O controlo está indisponível"</string>
@@ -827,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sincronize o novo dispositivo"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Para transmitir esta sessão, abra a app."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"App desconhecida"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Parar transmissão"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da compilação"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Número da compilação copiado para a área de transferência."</string>
     <string name="basic_status" msgid="2315371112182658176">"Abrir conversa"</string>
@@ -896,8 +885,8 @@
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Não adicion. mosaico"</string>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecione utilizador"</string>
     <plurals name="fgs_manager_footer_label" formatted="false" msgid="9091110396713032871">
-      <item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> app ativa</item>
       <item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> apps ativas</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> app ativa</item>
     </plurals>
     <string name="fgs_dot_content_description" msgid="2865071539464777240">"Novas informações"</string>
     <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apps ativas"</string>
@@ -916,7 +905,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi indisponível"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modo Prioridade"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarme definido"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Modo convidado do Assistente ativado"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A câmara e o microfone estão desativados"</string>
-    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}one{# notificação(ões)}other{# notificações}}"</string>
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}other{# notificações}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index d9bb15b..219fd7f 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Interface do sistema"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Ativar Economia de bateria?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Você tem <xliff:g id="PERCENTAGE">%s</xliff:g> de bateria. A Economia de bateria ativa o tema escuro, restringe atividades em segundo plano e atrasa notificações."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"A Economia de bateria ativa o tema escuro, restringe atividades em segundo plano e atrasa notificações."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> restantes"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Não é possível carregar via USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Usar o carregador que acompanha o dispositivo"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Ativar \"Economia de bateria\"?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Sobre a Economia de bateria"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Ativar"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Ativar a Economia de bateria"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Ativar"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Agora não"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Giro automático da tela"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Permitir que o app <xliff:g id="APPLICATION">%1$s</xliff:g> acesse <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> acesse <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nEsse app não tem permissão de gravação, mas pode capturar áudio pelo dispositivo USB."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Rosto autenticado"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmada"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toque em \"Confirmar\" para concluir"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Desbloqueado pelo seu rosto. Pressione para continuar."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticado"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Usar PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Usar padrão"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Se você informar um padrão incorreto na próxima tentativa, seu perfil de trabalho e os dados dele serão excluídos."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Se você informar um PIN incorreto na próxima tentativa, seu perfil de trabalho e os dados dele serão excluídos."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Se você informar uma senha incorreta na próxima tentativa, seu perfil de trabalho e os dados dele serão excluídos."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Excesso de tentativas incorretas. Os dados deste dispositivo serão excluídos."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Excesso de tentativas incorretas. O usuário será excluído."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Excesso de tentativas incorretas. Este perfil de trabalho e os dados dele serão excluídos."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Dispensar"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toque no sensor de impressão digital"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ícone de impressão digital"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Não foi possível reconhecer o rosto Use a impressão digital."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carga lenta • Conclusão em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carregando na base • Carga completa em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Trocar usuário"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Adicionar usuário"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Novo usuário"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remover visitante?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todos os apps e dados nesta sessão serão excluídos."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remover"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Você voltou, visitante!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Quer continuar a sessão?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recomeçar"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Sim, continuar"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Adicionar novo usuário?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Quando você adiciona um novo usuário, essa pessoa precisa configurar o próprio espaço.\n\nQualquer usuário pode atualizar apps para os demais usuários."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Limite de usuários atingido"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">É possível adicionar até <xliff:g id="COUNT">%d</xliff:g> usuário.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Ocorreu um problema ao carregar os cards. Tente novamente mais tarde"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Configurações de tela de bloqueio"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"Código QR"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Toque para fazer a leitura"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Ler código QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabalho"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Modo avião"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Você não ouvirá o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Deslize para ver mais"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Carregando recomendações"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Mídia"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Ocultar a sessão de mídia?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Não é possível ocultar a sessão de mídia atual."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dispensar"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Configurações"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Tocando <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> no app <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Aproxime-se do dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g> para abrir a mídia aqui"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Mídia aberta no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Mídia aberta neste smartphone"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Algo deu errado"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"Algo deu errado. Tente novamente."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"O controle está indisponível"</string>
@@ -827,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parear novo dispositivo"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Abra o app para transmitir esta sessão."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"App desconhecido"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Parar transmissão"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da versão"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Número da versão copiado para a área de transferência."</string>
     <string name="basic_status" msgid="2315371112182658176">"Conversa aberta"</string>
@@ -916,7 +905,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi-Fi indisponível"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modo de prioridade"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarme definido"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Modo visitante do Google Assistente ativado"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A câmera e o microfone estão desativados"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}one{# notificação}other{# notificações}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index ff409d3..5d789b8 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"UI sistem"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Activați Economisirea bateriei?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Mai aveți <xliff:g id="PERCENTAGE">%s</xliff:g> din baterie. Economisirea bateriei activează Tema întunecată, restricționează activitatea în fundal și amână notificările."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Economisirea bateriei activează Tema întunecată, restricționează activitatea în fundal și amână notificările."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Procent rămas din baterie: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Nu se poate realiza încărcarea prin USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Folosiți încărcătorul livrat împreună cu dispozitivul"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Activați economisirea bateriei?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Despre Economisirea bateriei"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Activați"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Activați economisirea bateriei"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Activați"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Nu, mulțumesc"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Rotire automată a ecranului"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Permiteți <xliff:g id="APPLICATION">%1$s</xliff:g> să acceseze <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Permiteți accesul aplicației <xliff:g id="APPLICATION">%1$s</xliff:g> la <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nPermisiunea de înregistrare nu a fost acordată aplicației, dar aceasta poate să înregistreze conținut audio prin intermediul acestui dispozitiv USB."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Chip autentificat"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmat"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Atingeți Confirmați pentru a finaliza"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"S-a deblocat cu ajutorul feței. Apăsați pentru a continua."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentificat"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Folosiți PIN-ul"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Folosiți modelul"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Dacă la următoarea încercare introduceți un model incorect, profilul de serviciu și datele sale vor fi șterse."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Dacă la următoarea încercare introduceți un cod PIN incorect, profilul de serviciu și datele sale vor fi șterse."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Dacă la următoarea încercare introduceți o parolă incorectă, profilul de serviciu și datele sale vor fi șterse."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Prea multe încercări incorecte. Datele de pe acest dispozitiv vor fi șterse."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Prea multe încercări incorecte. Acest utilizator va fi șters."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Prea multe încercări incorecte. Acest profil de serviciu și datele sale vor fi șterse."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Închideți"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Atingeți senzorul de amprente"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Pictograma amprentă"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Chipul nu a fost recunoscut. Folosiți amprenta."</string>
@@ -328,17 +321,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Se încarcă lent • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> până la încărcarea completă"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Suport de încărcare • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> până la încărcarea completă"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Comutați între utilizatori"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Adăugați un utilizator"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Utilizator nou"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Ștergeți invitatul?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toate aplicațiile și datele din această sesiune vor fi șterse."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ștergeți"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bine ați revenit în sesiunea pentru invitați!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vreți să continuați sesiunea?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Începeți din nou"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Da, continuați"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Adăugați un utilizator nou?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Când adăugați un utilizator nou, acesta trebuie să-și configureze spațiul.\n\nOrice utilizator poate actualiza aplicațiile pentru toți ceilalți utilizatori."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Ați atins limita de utilizatori"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="few">Puteți adăuga maximum <xliff:g id="COUNT">%d</xliff:g> utilizatori.</item>
@@ -465,8 +453,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Deblocați pentru a folosi"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"A apărut o problemă la preluarea cardurilor. Încercați din nou mai târziu"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Setările ecranului de blocare"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"Cod QR"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Atingeți pentru a scana"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Scanați codul QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Profil de serviciu"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Mod Avion"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Nu veți auzi următoarea alarmă <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -794,9 +781,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Glisați pentru a vedea mai multe"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Se încarcă recomandările"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Media"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Ascundeți sesiunea media?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Sesiunea media actuală nu se poate ascunde."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Închideți"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ascunde"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Reia"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Setări"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> de la <xliff:g id="ARTIST_NAME">%2$s</xliff:g> se redă în <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -814,7 +802,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Mergeți mai aproape de <xliff:g id="DEVICENAME">%1$s</xliff:g> ca să redați acolo"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Se redă pe <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Se redă pe acest telefon"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"A apărut o eroare"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactiv, verificați aplicația"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nu s-a găsit"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Comanda este indisponibilă"</string>
@@ -833,6 +822,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Asociați un nou dispozitiv"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Pentru a proiecta această sesiune, deschideți aplicația."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplicație necunoscută"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Nu mai proiectați"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Numărul versiunii"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Numărul versiunii s-a copiat în clipboard."</string>
     <string name="basic_status" msgid="2315371112182658176">"Deschideți conversația"</string>
@@ -923,8 +913,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi indisponibil"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modul Prioritate"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmă setată"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Modul pentru invitați al Asistentului este activat"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera și microfonul sunt dezactivate"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificare}few{# notificări}other{# de notificări}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index a79c247..5a261d0 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Интерфейс системы"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Включить режим энергосбережения?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Уровень заряда батареи: <xliff:g id="PERCENTAGE">%s</xliff:g>. В режиме энергосбережения включается тёмная тема, ограничиваются фоновые процессы и приостанавливается показ уведомлений."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"В режиме энергосбережения включается тёмная тема, ограничиваются фоновые процессы и приостанавливается показ уведомлений."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Осталось: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Невозможно выполнить зарядку через USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Используйте зарядное устройство из комплекта."</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Включить режим энергосбережения?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"О режиме энергосбережения"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Включить"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Включить режим энергосбережения"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Включить"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Нет"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Автоповорот экрана"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Предоставить приложению \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" доступ к устройству \"<xliff:g id="USB_DEVICE">%2$s</xliff:g>\"?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Предоставить приложению \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" доступ к устройству \"<xliff:g id="USB_DEVICE">%2$s</xliff:g>\"?\nПриложению не разрешено вести запись, однако с помощью этого USB-устройства оно может записывать звук."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Лицо распознано"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Подтверждено"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Нажмите \"Подтвердить\""</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Сработало распознавание лица. Нажмите, чтобы продолжить."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Аутентификация выполнена"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN-код"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Использовать графический ключ"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Если вы неправильно введете графический ключ ещё раз, ваш рабочий профиль и его данные будут удалены."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Если вы неправильно введете PIN-код ещё раз, ваш рабочий профиль и его данные будут удалены."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Если вы неправильно введете пароль ещё раз, ваш рабочий профиль и его данные будут удалены."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Слишком много неудачных попыток. С устройства будут удалены все данные."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Слишком много неудачных попыток. Этот пользователь будет удален."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Слишком много неудачных попыток. Этот рабочий профиль и его данные будут удалены."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Закрыть"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Прикоснитесь к сканеру отпечатков пальцев."</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Значок отпечатка пальца"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Не удалось распознать лицо. Используйте отпечаток."</string>
@@ -330,17 +323,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Медленная зарядка • Осталось <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Зарядка от док-станции • Ещё <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Сменить пользователя."</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Добавить пользователя"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Новый пользователь"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Удалить аккаунт гостя?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Все приложения и данные этого профиля будут удалены."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Удалить"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Рады видеть вас снова!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Продолжить сеанс?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Начать заново"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Да, продолжить"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Добавить пользователя?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Когда вы добавите пользователя, ему потребуется настроить профиль.\n\nЛюбой пользователь устройства может обновлять приложения для всех аккаунтов."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Достигнут лимит"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">Можно добавить не более <xliff:g id="COUNT">%d</xliff:g> пользователя.</item>
@@ -468,8 +456,8 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Разблокировать для использования"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Не удалось получить информацию о картах. Повторите попытку позже."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Настройки заблокированного экрана"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-код"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Нажмите, чтобы отсканировать код"</string>
+    <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+    <skip />
     <string name="status_bar_work" msgid="5238641949837091056">"Рабочий профиль"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Режим полета"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Следующий будильник: <xliff:g id="WHEN">%1$s</xliff:g>. Звук отключен."</string>
@@ -800,9 +788,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Проведите по экрану, чтобы увидеть больше"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Загрузка рекомендаций…"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Медиа"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Скрыть этот мультимедийный сеанс?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Этот мультимедийный сеанс невозможно скрыть."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Скрыть"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Скрыть"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Возобновить"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Настройки"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Воспроизводится медиафайл \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" (исполнитель: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) из приложения \"<xliff:g id="APP_LABEL">%3$s</xliff:g>\"."</string>
@@ -820,7 +809,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Для воспроизведения на этом устройстве подойдите ближе к другому (<xliff:g id="DEVICENAME">%1$s</xliff:g>)."</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Воспроизводится на устройстве \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\"."</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Воспроизводится на этом телефоне."</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Произошла ошибка."</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Нет ответа. Проверьте приложение."</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Не найдено."</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Управление недоступно"</string>
@@ -839,6 +829,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Подключить новое устройство"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Чтобы начать трансляцию сеанса, откройте приложение"</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Неизвестное приложение"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Остановить трансляцию"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер сборки"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Номер сборки скопирован в буфер обмена."</string>
     <string name="basic_status" msgid="2315371112182658176">"Открытый чат"</string>
@@ -930,7 +921,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Сеть Wi‑Fi недоступна"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Режим приоритета"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Будильник установлен"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Гостевой режим для Ассистента включен"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камера и микрофон отключены"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# уведомление}one{# уведомление}few{# уведомления}many{# уведомлений}other{# уведомления}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index ffaa4bf..d6c26f2 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"පද්ධති UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"බැටරි සුරැකුම ක්‍රියාත්මක කරන්නද?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"ඔබට බැටරිය <xliff:g id="PERCENTAGE">%s</xliff:g> ඉතිරිව ඇත. බැටරි සුරැකුම අඳුරු තේමාව ක්‍රියාත්මක කරයි, පසුබිම් ක්‍රියාකාරකම සීමා කරයි, සහ දැනුම්දීම් ප්‍රමාද කරයි."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"බැටරි සුරැකුම අඳුරු තේමාව ක්‍රියාත්මක කරයි, පසුබිම් ක්‍රියාකාරකම සීමා කරයි, සහ දැනුම්දීම් ප්‍රමාද කරයි."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> ඉතිරිව තිබේ"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"USB හරහා ආරෝපණය කළ නොහැකිය"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"ඔබේ උපාංගය සමඟ පැමිණි ආරෝපකය භාවිත කරන්න"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"බැටරි සුරැකුම ක්‍රියාත්මක කරන්නද?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"බැටරි සුරැකුම ගැන"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ක්‍රියාත්මක කරන්න"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"බැටරි සුරැකුම ක්‍රියාත්මක කරන්න"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"ක්‍රියාත්මක කරන්න"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"එපා ස්තුතියි"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"ස්වයංක්‍රීයව-භ්‍රමණය වන තිරය"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> හට <xliff:g id="USB_DEVICE">%2$s</xliff:g> වෙත පිවිසීමට ඉඩ දෙන්නද?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> වෙත ප්‍රවේශ වීමට <xliff:g id="USB_DEVICE">%2$s</xliff:g> හට ඉඩ දෙන්නද?\n මෙම යෙදුමට පටිගත කිරීම් අවසරයක් ලබා දී නොමැති නමුත් මෙම USB උපාංගය හරහා ශ්‍රව්‍ය ග්‍රහණය කර ගත හැකිය."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"මුහුණ සත්‍යාපන කළා"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"තහවුරු කළා"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"සම්පූර්ණ කිරීමට තහවුරු කරන්න තට්ටු කර."</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"ඔබගේ මුහුණෙන් අගුලු හරින ලදී. ඉදිරියට යාමට ඔබන්න."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"සත්‍යාපනය විය"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN භාවිත කරන්න"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"රටාව භාවිත කරන්න"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"ඔබ ඊළඟ උත්සාහයේදී වැරදි රටාවක් ඇතුළු කළහොත්, ඔබේ කාර්යාල පැතිකඩ සහ එහි දත්ත මකනු ඇත."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"ඔබ ඊළඟ උත්සාහයේදී වැරදි PIN එකක් ඇතුළු කළහොත්, ඔබේ කාර්යාල පැතිකඩ සහ එහි දත්ත මකනු ඇත."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"ඔබ ඊළඟ උත්සාහයේදී වැරදි මුරපදයක් ඇතුළු කළහොත්, ඔබේ කාර්යාල පැතිකඩ සහ එහි දත්ත මකනු ඇත."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"වැරදි උත්සාහයන් ඉතා වැඩි ගණනකි. මෙම උපාංගයෙහි දත්ත මකනු ඇත."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"වැරදි උත්සාහයන් ඉතා වැඩි ගණනකි. මෙම පරිශීලකයා මකනු ඇත."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"වැරදි උත්සාහයන් ඉතා වැඩි ගණනකි. මෙම කාර්යාල පැතිකඩ සහ එහි දත්ත මකනු ඇත."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"ඉවත ලන්න"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ඇඟිලි සලකුණු සංවේදකය ස්පර්ශ කරන්න"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ඇඟිලි සලකුණු නිරූපකය"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"මුහුණ හැඳිනිය නොහැක. ඒ වෙනුවට ඇඟිලි සලකුණ භාවිත ක."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • සෙමින් ආරෝපණය වෙමින් • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>කින් සම්පූර්ණ වේ"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ආරෝපණ ඩොකය • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>කින් සම්පූර්ණ වේ"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"පරිශීලක මාරුව"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"පරිශීලකයෙක් එක් කරන්න"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"නව පරිශීලකයා"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"අමුත්තාන් ඉවත් කරන්නද?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"මෙම සැසියේ සියළුම යෙදුම් සහ දත්ත මකාවී."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ඉවත් කරන්න"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"නැවත සාදරයෙන් පිළිගනිමු, අමුත්තා!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"ඔබගේ සැසිය දිගටම කරගෙන යෑමට ඔබට අවශ්‍යද?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"යළි මුල සිට අරඹන්න"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"ඔව්, දිගටම කරගෙන යන්න"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"අලුත් පරිශීලකයෙක් එක් කරන්නද?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"ඔබ අලුත් පරිශීලකයෙක් එකතු කරන විට, එම පුද්ගලයා ඔහුගේ වැඩ කරන ඉඩ සකසා ගත යුතුය.\n\nසියළුම අනෙක් පරිශීලකයින් සඳහා ඕනෑම පරිශීලකයෙකුට යාවත්කාලීන කළ හැක."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"පරිශීලක සීමාවට ළඟා විය"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">ඔබට පරිශීලකයින් <xliff:g id="COUNT">%d</xliff:g>ක් දක්වා එක් කළ හැකිය.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"භාවිත කිරීමට අගුලු හරින්න"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"ඔබගේ කාඩ්පත ලබා ගැනීමේ ගැටලුවක් විය, කරුණාකර පසුව නැවත උත්සාහ කරන්න"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"අගුලු තිර සැකසීම්"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR කේතය"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"ස්කෑන් කිරීමට තට්ටු කරන්න"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR කේතය ස්කෑන් කරන්න"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"කාර්යාල පැතිකඩ"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"ගුවන්යානා ප්‍රකාරය"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"ඔබට ඔබේ ඊළඟ එලාමය <xliff:g id="WHEN">%1$s</xliff:g> නොඇසෙනු ඇත"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"තව බැලීමට ස්වයිප් කරන්න"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"නිර්දේශ පූරණය කරමින්"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"මාධ්‍ය"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"මෙම මාධ්‍ය සැසිය සඟවන්නද?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"වත්මන් මාධ්‍ය සැසිය සැඟවිය නොහැකිය."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ඉවත ලන්න"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"සඟවන්න"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"නැවත පටන් ගන්න"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"සැකසීම්"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g>ගේ <xliff:g id="SONG_NAME">%1$s</xliff:g> ගීතය <xliff:g id="APP_LABEL">%3$s</xliff:g> වෙතින් ධාවනය වෙමින් පවතී"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"මෙහි ක්‍රීඩා කිරීමට <xliff:g id="DEVICENAME">%1$s</xliff:g> වෙත වඩා සමීප වන්න"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> හි වාදනය කරමින්"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"මෙම දුරකථනයෙහි වාදනය කරමින්"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"යම් දෙයක් වැරදිණි"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"අක්‍රියයි, යෙදුම පරීක්ෂා කරන්න"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"හමු නොවිණි"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"පාලනය ලබා ගත නොහැකිය"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"නව උපාංගය යුගල කරන්න"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"මෙම සැසිය විකාශය කිරීමට, කරුණාකර යෙදුම විවෘත කරන්න."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"නොදන්නා යෙදුම"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"විකාශය නවතන්න"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"නිමැවුම් අංකය"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"නිමැවුම් අංකය පසුරු පුවරුවට පිටපත් කරන ලදි."</string>
     <string name="basic_status" msgid="2315371112182658176">"සංවාදය විවෘත කරන්න"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi ලබා ගත නොහැකිය"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ප්‍රමුඛතා ප්‍රකාරය"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"සීනුව සකසන ලදි"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"සහායක ආගන්තුක ප්‍රකාරය සබලයි"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"කැමරාව සහ මයික් ක්‍රියාවිරහිතයි"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{දැනුම්දීම් #ක්}one{දැනුම්දීම් #ක්}other{දැනුම්දීම් #ක්}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 2c2a7c8..1738420 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"UI systému"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Chcete zapnúť šetrič batérie?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Zostáva vám <xliff:g id="PERCENTAGE">%s</xliff:g> batérie. Šetrič batérie zapne tmavý motív, obmedzí aktivity na pozadí a odloží upozornenia."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Šetrič batérie zapne tmavý motív, obmedzí aktivity na pozadí a odloží upozornenia."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Zostáva <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Nedá sa nabíjať cez USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Použite nabíjačku dodanú so zariadením"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Zapnúť šetrič batérie?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Šetrič batérie"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Zapnúť"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Zapnúť šetrič batérie"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Zapnúť"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Nie, vďaka"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Automatické otočenie obrazovky"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Povoliť aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g> prístup k zariadeniu <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Povoliť aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g> pristupovať k zariadeniu <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nTejto aplikácii nebolo udelené povolenie na nahrávanie, môže však snímať zvuk cez toto zariadenie USB."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Tvár bola overená"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrdené"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Overenie dokončíte klepnutím na Potvrdiť"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Odomkli ste svojou tvárou. Pokračujte stlačením."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Overené"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Použiť PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Použiť vzor"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ak pri ďalšom pokuse zadáte nesprávny vzor, váš pracovný profil a jeho dáta budú odstránené."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ak pri ďalšom pokuse zadáte nesprávny PIN, váš pracovný profil a jeho dáta budú odstránené."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ak pri ďalšom pokuse zadáte nesprávne heslo, váš pracovný profil a jeho dáta budú odstránené."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Príliš veľa chybných pokusov. Dáta tohto zariadenia budú odstránené."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Príliš veľa chybných pokusov. Tento používateľ bude odstránený."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Príliš veľa chybných pokusov. Tento pracovný profil a jeho dáta budú odstránené."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Zrušiť"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dotknite sa senzora odtlačkov prstov"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona odtlačku prsta"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tvár sa nedá rozpoznať. Použite odtlačok prsta."</string>
@@ -330,17 +323,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Nabíja sa pomaly • Do úplného nabitia zostáva <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Nabíjací dok • Do úplného nabitia zostáva <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Prepnutie používateľa"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Pridať používateľa"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Nový používateľ"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Odstrániť hosťa?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Všetky aplikácie a údaje v tejto relácii budú odstránené."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Odstrániť"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Hosť, vitajte späť!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcete v relácii pokračovať?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Začať odznova"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Áno, pokračovať"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Pridať nového používateľa?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Keď pridáte nového používateľa, musí si nastaviť vlastný priestor.\n\nKtorýkoľvek používateľ môže aktualizovať aplikácie všetkých ostatných používateľov."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Dosiahnutý limit počtu používateľov"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="few">Môžete pridať maximálne <xliff:g id="COUNT">%d</xliff:g> používateľov.</item>
@@ -468,8 +456,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Odomknúť a použiť"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Pri načítavaní kariet sa vyskytol problém. Skúste to neskôr."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Nastavenia uzamknutej obrazovky"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR kód"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Ak chcete skenovať, klepnite"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skenovanie QR kódu"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Pracovný profil"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Režim v lietadle"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Váš budík o <xliff:g id="WHEN">%1$s</xliff:g> sa nespustí"</string>
@@ -800,9 +787,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Potiahnutím zobrazíte ďalšie položky"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Načítavajú sa odporúčania"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Médiá"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Chcete skryť túto reláciu média?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Aktuálna relácia média sa nedá skryť."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Zavrieť"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Skryť"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Pokračovať"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Nastavenia"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> od interpreta <xliff:g id="ARTIST_NAME">%2$s</xliff:g> sa prehráva z aplikácie <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -820,7 +808,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Ak chcete prehrávať v zariadení <xliff:g id="DEVICENAME">%1$s</xliff:g>, priblížte sa k nemu"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Prehráva sa v zariadení <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Prehráva sa v tomto telefóne"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Vyskytol sa problém"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"Niečo sa pokazilo. Skúste to znova."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Neaktívne, preverte aplikáciu"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nenájdené"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Ovládač nie je k dispozícii"</string>
@@ -839,6 +827,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Spárovať nové zariadenie"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Ak chcete túto reláciu prenášať, otvorte aplikáciu."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Neznáma aplikácia"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zastaviť prenos"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Číslo zostavy"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Číslo zostavy bolo skopírované do schránky."</string>
     <string name="basic_status" msgid="2315371112182658176">"Otvorená konverzácia"</string>
@@ -930,7 +919,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi nie je k dispozícii"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Režim priority"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Budík je nastavený"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Režim Asistenta pre hostí je aktivovaný"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera a mikrofón sú vypnuté"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# upozornenie}few{# upozornenia}many{# notifications}other{# upozornení}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 6996d56..ec68ce6 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Sistemski uporabniški vmesnik"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Želite vklopiti varčevanje z energijo baterije?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Preostala napolnjenost baterije: <xliff:g id="PERCENTAGE">%s</xliff:g>. Funkcija varčevanja z energijo baterije vklopi temno temo, omeji dejavnost v ozadju in prikazuje obvestila z zakasnitvijo."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Funkcija varčevanja z energijo baterije vklopi temno temo, omeji dejavnost v ozadju in prikazuje obvestila z zakasnitvijo."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Še <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Ni mogoče polniti prek USB-ja"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Uporabite polnilnik, ki je bil priložen napravi"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Želite vklopiti varčevanje z baterijo?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"O varčevanju z energijo baterije"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Vklopi"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Vklop varčevanja z baterijo"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Vklopi"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Ne, hvala"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Samodejno zasukaj zaslon"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Ali aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> dovolite dostop do dodatka USB <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Ali aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> dovolite dostop do naprave <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nTa aplikacija sicer nima dovoljenja za snemanje, vendar bi lahko zajemala zvok prek te naprave USB."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Pristnost obraza je potrjena"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potrjeno"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Za dokončanje se dotaknite »Potrdite«"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Odklenili ste z obrazom. Pritisnite za nadaljevanje."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Preverjena pristnost"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Uporabi kodo PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Uporabi vzorec"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Če pri naslednjem poskusu vnesete napačen vzorec, bodo delovni profil in podatki v njem izbrisani."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Če pri naslednjem poskusu vnesete napačno kodo PIN, bodo delovni profil in podatki v njem izbrisani."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Če pri naslednjem poskusu vnesete napačno geslo, bodo delovni profil in podatki v njem izbrisani."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Preveč napačnih poskusov. Podatki v napravi bodo izbrisani."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Preveč napačnih poskusov. Uporabnik bo izbrisan."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Preveč napačnih poskusov. Delovni profil in podatki v njem bodo izbrisani."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Opusti"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dotaknite se tipala prstnih odtisov"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona prstnih odtisov"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Obraza ni mogoče prepoznati. Uporabite prstni odtis."</string>
@@ -330,17 +323,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Počasno polnjenje • Napolnjeno čez <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Polnjenje na nosilcu • Polno čez <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Preklop med uporabniki"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Dodajanje uporabnika"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Nov uporabnik"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Želite odstraniti gosta?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Vse aplikacije in podatki v tej seji bodo izbrisani."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Odstrani"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Znova pozdravljeni, gost!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite nadaljevati sejo?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Začni znova"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Da, nadaljuj"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Dodajanje novega uporabnika?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Ko dodate novega uporabnika, mora ta nastaviti svoj prostor.\n\nVsak uporabnik lahko posodobi aplikacije za vse druge uporabnike."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Omejitev uporabnikov je dosežena"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">Dodate lahko do <xliff:g id="COUNT">%d</xliff:g> uporabnika.</item>
@@ -468,8 +456,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Odklenite za uporabo"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Pri pridobivanju kartic je prišlo do težave. Poskusite znova pozneje."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Nastavitve zaklepanja zaslona"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"Koda QR"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Dotaknite se za optično branje"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Optično branje kode QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Profil za Android Work"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Način za letalo"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Naslednjega alarma ob <xliff:g id="WHEN">%1$s</xliff:g> ne boste slišali"</string>
@@ -800,9 +787,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Če si želite ogledati več, povlecite"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Nalaganje priporočil"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Predstavnost"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Želite skriti to sejo predstavnosti?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Trenutne seje predstavnosti ni mogoče skriti."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Opusti"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Skrij"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Nadaljuj"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Nastavitve"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Skladba <xliff:g id="SONG_NAME">%1$s</xliff:g> izvajalca <xliff:g id="ARTIST_NAME">%2$s</xliff:g> se predvaja iz aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string>
@@ -820,7 +808,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Približajte napravi <xliff:g id="DEVICENAME">%1$s</xliff:g> za predvajanje v tej napravi"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Predvajanje v napravi <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Predvajanje v tem telefonu"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Prišlo je do težave"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"Prišlo je do napake. Poskusite znova."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, poglejte aplikacijo"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Ni mogoče najti"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrolnik ni na voljo"</string>
@@ -839,6 +827,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Seznanitev nove naprave"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Če želite predvajati to sejo, odprite aplikacijo."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Neznana aplikacija"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Ustavi predvajanje"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Delovna različica"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Delovna različica je bila kopirana v odložišče."</string>
     <string name="basic_status" msgid="2315371112182658176">"Odprt pogovor"</string>
@@ -930,7 +919,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi ni na voljo."</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prednostni način"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm je nastavljen."</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Način za goste je omogočen za Pomočnika."</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Fotoaparat in mikrofon sta izklopljena."</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# obvestilo}one{# obvestilo}two{# obvestili}few{# obvestila}other{# obvestil}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index bea8d83..c35b8d3 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Ndërfaqja e përdoruesit të sistemit"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Të aktivizohet \"Kursyesi i baterisë\"?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Ke <xliff:g id="PERCENTAGE">%s</xliff:g> bateri të mbetur. \"Kursyesi i baterisë\" aktivizon \"Temën e errët\", kufizon aktivitetet në sfond dhe vonon njoftimet."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"\"Kursyesi i baterisë\" aktivizon \"Temën e errët\", kufizon aktivitetet në sfond dhe vonon njoftimet."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Ka mbetur edhe <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Nuk mund të ngarkohet përmes USB-së"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Përdor karikuesin që ke marrë me pajisjen"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Të aktivizohet \"Kursyesi i baterisë\"?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Rreth \"Kursyesit të baterisë\""</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Aktivizo"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Aktivizo \"Kursyesin e baterisë\""</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Aktivizo"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Jo, faleminderit"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Rrotullimi automatik i ekranit"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Të lejohet <xliff:g id="APPLICATION">%1$s</xliff:g> të ketë qasje te <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Dëshiron të lejosh që <xliff:g id="APPLICATION">%1$s</xliff:g> të ketë qasje te <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nKëtij aplikacioni nuk i është dhënë leje për regjistrim, por mund të regjistrojë audio përmes kësaj pajisjeje USB."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Fytyra u vërtetua"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Konfirmuar"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Trokit \"Konfirmo\" për ta përfunduar"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Shkyçur nga fytyra jote. Shtyp për të vazhduar."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"U vërtetua"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Përdor kodin PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Përdor motivin"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Nëse fut një motiv të pasaktë në tentativën tjetër, profili yt i punës dhe të dhënat e tij do të fshihen."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Nëse fut një kod PIN të pasaktë në tentativën tjetër, profili yt i punës dhe të dhënat e tij do të fshihen."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Nëse fut një fjalëkalim të pasaktë në tentativën tjetër, profili yt i punës dhe të dhënat e tij do të fshihen."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Shumë tentativa të pasakta. Të dhënat e kësaj pajisjeje do të fshihen."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Shumë tentativa të pasakta. Ky përdorues do të fshihet."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Shumë tentativa të pasakta. Ky profil pune dhe të dhënat e tij do të fshihen."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Hiq"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Prek sensorin e gjurmës së gishtit"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona e gjurmës së gishtit"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nuk mund ta dallojë fytyrën. Përdor më mirë gjurmën e gishtit."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Po karikohet ngadalë • Plot për <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Po karikohet në stacion • Plot për <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Ndërro përdorues"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Shto përdorues"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Përdorues i ri"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Të hiqet i ftuari?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Të gjitha aplikacionet dhe të dhënat në këtë sesion do të fshihen."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Hiq"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Mirë se erdhe, i ftuar!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Dëshiron ta vazhdosh sesionin tënd?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Fillo nga e para"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Po, vazhdo"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Të shtohet përdorues i ri?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Kur shton një përdorues të ri, ai person duhet të konfigurojë hapësirën e vet.\n\nÇdo përdorues mund t\'i përditësojë aplikacionet për të gjithë përdoruesit e tjerë."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"U arrit kufiri i përdoruesve"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">Mund të shtosh deri në <xliff:g id="COUNT">%d</xliff:g> përdorues.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Shkyçe për ta përdorur"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Pati një problem me marrjen e kartave të tua. Provo përsëri më vonë"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Cilësimet e ekranit të kyçjes"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"Kodi QR"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Trokit për të skanuar"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skano kodin QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Profili i punës"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Modaliteti i aeroplanit"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Nuk do ta dëgjosh alarmin e radhës në <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Rrëshqit shpejt për të shikuar më shumë"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Po ngarkon rekomandimet"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Media"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Të fshihet kjo seancë media?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Seanca aktuale e medias nuk mund të fshihet."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Hiq"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Fshih"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Vazhdo"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Cilësimet"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> nga <xliff:g id="ARTIST_NAME">%2$s</xliff:g> po luhet nga <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Afrohu te <xliff:g id="DEVICENAME">%1$s</xliff:g> për ta luajtur këtu"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Po luhet në <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Po luhet në këtë telefon"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Ndodhi një gabim"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Joaktive, kontrollo aplikacionin"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nuk u gjet"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrolli është i padisponueshëm"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Çifto pajisjen e re"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Hap aplikacionin për të transmetuar këtë seancë."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplikacion i panjohur"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Ndalo transmetimin"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Numri i ndërtimit"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Numri i ndërtimit u kopjua te kujtesa e fragmenteve"</string>
     <string name="basic_status" msgid="2315371112182658176">"Hap bisedën"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi nuk ofrohet"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modaliteti \"Me përparësi\""</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmi është caktuar"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Modaliteti \"vizitor\" i \"Asistentit\" është aktivizuar"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera dhe mikrofoni janë joaktivë"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# njoftim}other{# njoftime}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index f373eea..ca5d2ec 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"UI система"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Желите ли да укључите Уштеду батерије?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Преостали ниво напуњености батерије је <xliff:g id="PERCENTAGE">%s</xliff:g>. Уштеда батерије укључује Тамну тему, ограничава активности у позадини и одлаже обавештења."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Уштеда батерије укључује Тамну тему, ограничава активности у позадини и одлаже обавештења."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Још <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Пуњење преко USB-а није успело"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Користите пуњач који сте добили уз уређај"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Желите да укључите Уштеду батерије?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"О Уштеди батерије"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Укључи"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Укључи Уштеду батерије"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Укључи"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Не, хвала"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Аутоматско ротирање екрана"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Желите ли да дозволите да <xliff:g id="APPLICATION">%1$s</xliff:g> приступа уређају <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Желите ли да дозволите да <xliff:g id="APPLICATION">%1$s</xliff:g> приступа уређају <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nОва апликација нема дозволу за снимање, али би могла да снима звук помоћу овог USB уређаја."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Лице је потврђено"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Потврђено"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Додирните Потврди да бисте завршили"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Откључали сте лицем. Притисните да бисте наставили."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Идентитет је потврђен"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Користите PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Користите шаблон"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ако унесете нетачан шаблон при следећем покушају, избрисаћемо пословни профил и његове податке."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ако унесете нетачан PIN при следећем покушају, избрисаћемо пословни профил и његове податке."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ако унесете нетачну лозинку при следећем покушају, избрисаћемо пословни профил и његове податке."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Превише нетачних покушаја. Избрисаћемо податке са овог уређаја."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Превише нетачних покушаја. Избрисаћемо овог корисника."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Превише нетачних покушаја. Избрисаћемо овај пословни профил и његове податке."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Одбаци"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Додирните сензор за отисак прста"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Икона отиска прста"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Лице није препознато. Користите отисак прста."</string>
@@ -328,17 +321,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Споро се пуни • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до краја пуњења"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Базна станица за пуњење • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до краја пуњења"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Замени корисника"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Додај корисника"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Нови корисник"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Желите ли да уклоните госта?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Све апликације и подаци у овој сесији ће бити избрисани."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Уклони"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Добро дошли назад, госте!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Желите ли да наставите сесију?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Почни из почетка"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Да, настави"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Додајете новог корисника?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Када додате новог корисника, та особа треба да подеси свој простор.\n\nСваки корисник може да ажурира апликације за све остале кориснике."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Достигнут максимални број корисника"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">Можете да додате највише <xliff:g id="COUNT">%d</xliff:g> корисника.</item>
@@ -465,8 +453,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Откључај ради коришћења"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Дошло је до проблема при преузимању картица. Пробајте поново касније"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Подешавања закључаног екрана"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR кôд"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Додирните да бисте скенирали"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Скенирајте QR кôд"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Пословни профил"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Режим рада у авиону"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Нећете чути следећи аларм у <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -794,9 +781,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Превуците да бисте видели још"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Учитавају се препоруке"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Медији"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Желите ли да сакријете ову сесију медија?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Актуелна сесија медија не може да буде сакривена."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Одбаци"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Сакриј"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Настави"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Подешавања"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> извођача <xliff:g id="ARTIST_NAME">%2$s</xliff:g> се пушта из апликације <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -814,7 +802,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Приближите се уређају <xliff:g id="DEVICENAME">%1$s</xliff:g> да бисте на њему пуштали"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Пушта се на уређају <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Пушта се на овом телефону"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Дошло је до грешке"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно. Видите апликацију"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Није пронађено"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Контрола није доступна"</string>
@@ -833,6 +822,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Упари нови уређај"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Да бисте пребацивали ову сесију, отворите апликацију."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Непозната апликација"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Заустави пребацивање"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Број верзије"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Број верзије је копиран у привремену меморију."</string>
     <string name="basic_status" msgid="2315371112182658176">"Отворите конверзацију"</string>
@@ -923,8 +913,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WiFi није доступан"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Приоритетни режим"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Аларм је подешен"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Омогућен је режим госта у Помоћнику"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камера и микрофон су искључени"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# обавештење}one{# обавештење}few{# обавештења}other{# обавештења}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 638ba9f..9478a92 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Gränssnitt"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Vill du aktivera batterisparläget?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"<xliff:g id="PERCENTAGE">%s</xliff:g> av batteriet återstår. I batterisparläget aktiveras Mörkt tema, bakgrundsaktivitet begränsas och aviseringar skjuts upp."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"I batterisparläget aktiveras Mörkt tema, bakgrundsaktivitet begränsas och aviseringar skjuts upp."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> kvar"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Det går inte att ladda via USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Använd laddaren som följde med enheten."</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Vill du aktivera batterisparläget?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Om batterisparläget"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Aktivera"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Aktivera batterisparläget"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Aktivera"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Nej tack"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Rotera skärmen automatiskt"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Vill du ge <xliff:g id="APPLICATION">%1$s</xliff:g> åtkomst till <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Vill du ge <xliff:g id="APPLICATION">%1$s</xliff:g> åtkomst till <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nAppen har inte fått inspelningsbehörighet men kan spela in ljud via denna USB-enhet."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Ansiktet har autentiserats"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bekräftat"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Slutför genom att trycka på Bekräfta"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Låstes upp med ansiktet. Tryck för att fortsätta."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentiserad"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Använd pinkod"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Använd mönster"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Jobbprofilen och dess data raderas om du ritar fel mönster vid nästa försök."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Jobbprofilen och dess data raderas om du anger fel pinkod vid nästa försök."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Din jobbprofil och dess data raderas om du anger fel lösenord vid nästa försök."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"För många felaktiga försök. Enhetens data raderas."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"För många felaktiga försök. Den här användaren raderas."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"För många felaktiga försök. Den här jobbprofilen och dess data raderas."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Stäng"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Tryck på fingeravtryckssensorn"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikon för fingeravtryck"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansiktet kändes inte igen. Använd fingeravtryck."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laddas långsamt • Fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Dockningsstation • Fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Byt användare"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Lägg till användare"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Ny användare"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vill du ta bort gästen?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alla appar och data i denna session kommer att raderas."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ta bort"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Välkommen tillbaka som gäst!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vill du fortsätta sessionen?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Börja om"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ja, fortsätt"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Lägga till ny användare?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"När du lägger till en ny användare måste den personen konfigurera sitt utrymme.\n\nAlla användare kan uppdatera appar för samtliga användares räkning."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Användargränsen har nåtts"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">Det går att lägga till upp till <xliff:g id="COUNT">%d</xliff:g> användare.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lås upp för att använda"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Det gick inte att hämta dina kort. Försök igen senare."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Inställningar för låsskärm"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-kod"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Tryck för att skanna"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skanna QR-kod"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Jobbprofil"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Flygplansläge"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Nästa alarm, kl. <xliff:g id="WHEN">%1$s</xliff:g>, kommer inte att höras"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Svep om du vill se mer"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Rekommendationer läses in"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Media"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Vill du dölja mediesessionen?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Den aktuella mediesessionen kan inte döljas."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Stäng"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Dölj"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Återuppta"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Inställningar"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> med <xliff:g id="ARTIST_NAME">%2$s</xliff:g> spelas upp från <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Flytta dig närmare <xliff:g id="DEVICENAME">%1$s</xliff:g> om du vill spela här"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Spelas upp på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Spelas upp på denna telefon"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Något gick fel"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv, kolla appen"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Hittades inte"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Styrning är inte tillgänglig"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parkoppla en ny enhet"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Öppna appen om du vill casta den här sessionen."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Okänd app"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Sluta casta"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Versionsnummer"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Versionsnumret har kopierats till urklipp."</string>
     <string name="basic_status" msgid="2315371112182658176">"Öppen konversation"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wifi är inte tillgängligt"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritetsläge"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmet är aktiverat"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Gästläget för assistenten är aktiverat"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kameran och mikrofonen är avstängda"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# avisering}other{# aviseringar}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 931f634..33b985a 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Kiolesura"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Ungependa Kuwasha Kiokoa Betri?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Umebakiza asilimia <xliff:g id="PERCENTAGE">%s</xliff:g> ya betri. Kiokoa Betri kinawasha Mandhari meusi, kinazuia shughuli za chinichini na kuchelewesha arifa."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Kiokoa Betri kinawasha Mandhari meusi, kinazuia shughuli za chinichini na kuchelewesha arifa."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Imebakisha <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Haiwezi kuchaji kupitia USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Tumia chaja ambayo ilikuja na kifaa chako"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Ungependa Kuwasha Kiokoa Betri?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Kuhusu Kiokoa betri"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Washa"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Washa Kiokoa Betri"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Washa"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Hapana"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Skrini ijizungushe kiotomatiki"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Ungependa kuruhusu <xliff:g id="APPLICATION">%1$s</xliff:g> ifikie <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Ungependa kuruhusu <xliff:g id="APPLICATION">%1$s</xliff:g> ifikie <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nProgramu hii haijapewa ruhusa ya kurekodi lakini inaweza kurekodi sauti kupitia kifaa hiki cha USB."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Uso umethibitishwa"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Imethibitishwa"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Gusa Thibitisha ili ukamilishe"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Imefunguliwa kwa kutumia uso wako. Bonyeza ili uendelee."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Umethibitishwa"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Tumia PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Tumia mchoro"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ukiweka mchoro usio sahihi utakapojaribu tena, wasifu wako wa kazini utafutwa pamoja na data yake."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ukiweka PIN isiyo sahihi utakapojaribu tena, wasifu wako wa kazini utafutwa pamoja na data yake."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ukiweka nenosiri lisilo sahihi utakapojaribu tena, wasifu wako wa kazini utafutwa pamoja na data yake."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Umejaribu kufungua mara nyingi mno kwa njia isiyo sahihi. Data iliyo kwenye kifaa hiki itafutwa."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Umejaribu kufungua mara nyingi mno kwa njia isiyo sahihi. Maelezo ya mtumiaji huyu yatafutwa."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Umejaribu kufungua mara nyingi mno kwa njia isiyo sahihi. Wasifu huu wa kazini utafutwa pamoja na data yake."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Ondoa"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Gusa kitambua alama ya kidole"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Aikoni ya alama ya kidole"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Imeshindwa kutambua uso. Tumia alama ya kidole."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Inachaji polepole • Itajaa baada ya <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Kituo cha Kuchaji • Itajaa baada ya <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Badili mtumiaji"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Ongeza mtumiaji"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Mtumiaji mpya"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Ungependa kumwondoa mgeni?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Data na programu zote katika kipindi hiki zitafutwa."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ondoa"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Karibu tena mgeni!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Je, unataka kuendelea na kipindi chako?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Anza upya"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ndiyo, endelea"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Ungependa kuongeza mtumiaji?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Mtumiaji mpya utakayemwongeza atahitaji kuongeza akaunti yake.\n\nMtumiaji yoyote anaweza kusasisha programu kwa niaba ya wengine wote."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Umefikia kima cha juu cha watumiaji"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">Unaruhusiwa kuongeza hadi watumiaji <xliff:g id="COUNT">%d</xliff:g>.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Fungua ili utumie"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Hitilafu imetokea wakati wa kuleta kadi zako, tafadhali jaribu tena baadaye"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Mipangilio ya kufunga skrini"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"Msimbo wa QR"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Gusa ili uchanganue"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Changanua msimbo wa QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Wasifu wa kazini"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Hali ya ndegeni"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Hutasikia kengele yako inayofuata ya saa <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Telezesha kidole ili uone zaidi"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Inapakia mapendekezo"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Maudhui"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Ungependa kuficha kipindi hiki cha maudhui?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Kipindi cha sasa cha maudhui hakiwezi kufichwa."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ondoa"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ficha"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Endelea"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Mipangilio"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ulioimbwa na <xliff:g id="ARTIST_NAME">%2$s</xliff:g> unacheza katika <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Sogeza karibu na <xliff:g id="DEVICENAME">%1$s</xliff:g> ili kucheza hapa"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Inacheza kwenye <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Inacheza kwenye simu hii"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Hitilafu fulani imetokea"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Haitumiki, angalia programu"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Hakipatikani"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Kidhibiti hakipatikani"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Oanisha kifaa kipya"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Ili utume kipindi hiki, tafadhali fungua programu."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Programu isiyojulikana"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Acha kutuma"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Nambari ya muundo"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Nambari ya muundo imewekwa kwenye ubao wa kunakili."</string>
     <string name="basic_status" msgid="2315371112182658176">"Fungua mazungumzo"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi-Fi haipatikani"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Hali ya kipaumbele"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Kengele imewekwa"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Matumizi ya wageni ya Mratibu yamewashwa"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera na maikrofoni zimezimwa"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{Arifa #}other{Arifa #}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index c56ba7b..76780ff 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -36,7 +36,9 @@
     <item name="controls_task_view_width_percentage" translatable="false" format="float" type="dimen">0.45</item>
     <dimen name="controls_task_view_right_margin">8dp</dimen>
 
-    <dimen name="split_shade_header_height">42dp</dimen>
+    <dimen name="status_bar_header_height_keyguard">42dp</dimen>
+
+    <dimen name="lockscreen_shade_max_over_scroll_amount">32dp</dimen>
 
     <!-- Distance that the full shade transition takes in order to complete by tapping on a button
          like "expand". -->
@@ -53,6 +55,14 @@
          the shade (in alpha) -->
     <dimen name="lockscreen_shade_scrim_transition_distance">80dp</dimen>
 
+    <!-- The notifications scrim transition should start when the other scrims' transition is at
+         95%. -->
+    <dimen name="lockscreen_shade_notifications_scrim_transition_delay">76dp</dimen>
+
+    <!-- The notifications scrim transition duration is 66.6% of the duration of the other scrims'
+         transition. -->
+    <dimen name="lockscreen_shade_notifications_scrim_transition_distance">53.28dp</dimen>
+
     <!-- Distance that the full shade transition takes in order for the keyguard content on
          NotificationPanelViewController to fully fade (e.g. Clock & Smartspace) -->
     <dimen name="lockscreen_shade_npvc_keyguard_content_alpha_transition_distance">80dp</dimen>
diff --git a/packages/ConnectivityT/framework-t/aidl-export/android/net/NetworkStats.aidl b/packages/SystemUI/res/values-sw600dp-land/integers.xml
similarity index 71%
rename from packages/ConnectivityT/framework-t/aidl-export/android/net/NetworkStats.aidl
rename to packages/SystemUI/res/values-sw600dp-land/integers.xml
index d06ca65..919d605 100644
--- a/packages/ConnectivityT/framework-t/aidl-export/android/net/NetworkStats.aidl
+++ b/packages/SystemUI/res/values-sw600dp-land/integers.xml
@@ -1,5 +1,6 @@
-/**
- * Copyright (c) 2011, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (c) 2006, 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.
@@ -12,8 +13,8 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
- */
-
-package android.net;
-
-parcelable NetworkStats;
+*/
+-->
+<resources>
+    <integer name="lockscreen_shade_over_scroll_release_duration">500</integer>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index abc69b0..36cc0ad 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -38,4 +38,6 @@
     <!-- Determines whether to allow the nav bar handle to be forced to be opaque. -->
     <bool name="allow_force_nav_bar_handle_opaque">false</bool>
 
+    <bool name="config_use_large_screen_shade_header">true</bool>
+
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 8f6bde5..2264671 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -67,4 +67,6 @@
 
     <!-- The width of large/content heavy dialogs (e.g. Internet, Media output, etc) -->
     <dimen name="large_dialog_width">472dp</dimen>
+
+    <dimen name="large_screen_shade_header_height">42dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-sw720dp-land/dimens.xml b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
index f267088..0512d3c 100644
--- a/packages/SystemUI/res/values-sw720dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
@@ -23,7 +23,9 @@
 
     <dimen name="keyguard_split_shade_top_margin">72dp</dimen>
 
-    <dimen name="split_shade_header_height">56dp</dimen>
+    <dimen name="status_bar_header_height_keyguard">56dp</dimen>
 
-    <dimen name="qs_media_session_height_expanded">184dp</dimen>
+    <dimen name="qs_media_session_height_expanded">251dp</dimen>
+
+    <dimen name="lockscreen_shade_max_over_scroll_amount">42dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml
index 95df594..0705017 100644
--- a/packages/SystemUI/res/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp/dimens.xml
@@ -20,5 +20,7 @@
     <dimen name="status_bar_icon_padding">1dp</dimen>
 
     <dimen name="controls_padding_horizontal">75dp</dimen>
+
+    <dimen name="large_screen_shade_header_height">56dp</dimen>
 </resources>
 
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index e856294f..0d56630 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"சாதனத்தின் UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"பேட்டரி சேமிப்பானை இயக்கவா?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"<xliff:g id="PERCENTAGE">%s</xliff:g> பேட்டரி மீதமுள்ளது. பேட்டரி சேமிப்பான் அம்சம் டார்க் தீமை இயக்கும், அத்துடன் பின்னணிச் செயல்பாடுகளைக் கட்டுப்படுத்தி, அறிவிப்புகளைத் தாமதப்படுத்தும்."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"பேட்டரி சேமிப்பான் அம்சம் டார்க் தீமை இயக்கும், அத்துடன் பின்னணிச் செயல்பாடுகளைக் கட்டுப்படுத்தி, அறிவிப்புகளைத் தாமதப்படுத்தும்."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> உள்ளது"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"USB மூலம், சார்ஜ் செய்ய முடியாது"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"உங்கள் சாதனத்துடன் வழங்கப்பட்ட சார்ஜரைப் பயன்படுத்தவும்"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"பேட்டரி சேமிப்பானை ஆன் செய்யவா?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"பேட்டரி சேமிப்பான்- ஓர் அறிமுகம்"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"இயக்கு"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"பேட்டரி சேமிப்பானை ஆன் செய்"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"இயக்கு"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"வேண்டாம்"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"திரையைத் தானாகச் சுழற்று"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>ஐ அணுக, <xliff:g id="APPLICATION">%1$s</xliff:g> ஆப்ஸை அனுமதிக்கவா?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>ஐப் பயன்படுத்த <xliff:g id="APPLICATION">%1$s</xliff:g>ஐ அனுமதிக்கவா?\nஇந்த ஆப்ஸிற்கு ரெக்கார்டு செய்வதற்கான அனுமதி வழங்கப்படவில்லை, எனினும் இந்த USB சாதனம் மூலம் ஆடியோவைப் பதிவுசெய்யும்."</string>
@@ -90,7 +88,7 @@
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ஸ்க்ரீன் ரெக்கார்டிங் செயலாக்கப்படுகிறது"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"திரை ரெக்கார்டிங் அமர்விற்கான தொடர் அறிவிப்பு"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"ரெக்கார்டிங்கைத் தொடங்கவா?"</string>
-    <string name="screenrecord_description" msgid="1123231719680353736">"ரெக்கார்டு செய்யும்போது, உங்கள் திரையில் தோன்றக்கூடிய அல்லது சாதனத்தில் பிளே ஆகக்கூடிய ஏதேனும் அதிமுக்கியத் தகவலை Android சிஸ்டம் படமெடுக்க முடியும். கடவுச்சொற்கள், பேமெண்ட் தகவல், படங்கள், மெசேஜ்கள், ஆடியோ ஆகியவை இதில் அடங்கும்."</string>
+    <string name="screenrecord_description" msgid="1123231719680353736">"ரெக்கார்டு செய்யும்போது, உங்கள் திரையில் தோன்றக்கூடிய அல்லது சாதனத்தில் பிளே ஆகக்கூடிய பாதுகாக்கப்பட வேண்டிய தகவலை Android சிஸ்டம் படமெடுக்க முடியும். கடவுச்சொற்கள், பேமெண்ட் தகவல், படங்கள், மெசேஜ்கள், ஆடியோ ஆகியவை இதில் அடங்கும்."</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"ஆடியோவை ரெக்கார்டு செய்"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"சாதன ஆடியோ"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"இசை, அழைப்புகள், ரிங்டோன்கள் போன்ற உங்கள் சாதனத்திலிருந்து வரும் ஒலி"</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"முகம் அங்கீகரிக்கப்பட்டது"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"உறுதிப்படுத்தப்பட்டது"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"முடிக்க \'உறுதிப்படுத்துக\' என்பதை தட்டவும்"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"முகத்தை வைத்து அன்லாக் செய்யப்பட்டது. திறக்க அழுத்தவும்."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"அங்கீகரிக்கப்பட்டது"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"பின்னைப் பயன்படுத்து"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"பேட்டர்னைப் பயன்படுத்து"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"அடுத்த முறை தவறான பேட்டர்னை வரைந்தால் உங்கள் பணிக் கணக்கும் அதன் தரவும் நீக்கப்படும்."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"அடுத்த முறை தவறான பின்னை உள்ளிட்டால் உங்கள் பணிக் கணக்கும் அதன் தரவும் நீக்கப்படும்."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"அடுத்த முறை தவறான கடவுச்சொல்லை உள்ளிட்டால் உங்கள் பணிக் கணக்கும் அதன் தரவும் நீக்கப்படும்."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"பலமுறை தவறாக முயன்ற காரணத்தால் இந்தச் சாதனத்தின் தரவு நீக்கப்படும்."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"பலமுறை தவறாக முயன்ற காரணத்தால் இந்தப் பயனர் நீக்கப்படுவார்."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"பலமுறை தவறாக முயன்றதால், இந்தப் பணிக் கணக்கும் அதன் தரவும் நீக்கப்படும்"</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"நிராகரி"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"கைரேகை சென்சாரைத் தொடவும்"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"கைரேகை ஐகான்"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"முகத்தை அடையாளம் காண முடியவில்லை. கைரேகையைப் பயன்படுத்தவும்."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • மெதுவாக சார்ஜாகிறது • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> இல் முழுதும் சார்ஜாகும்"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • டாக் மூலம் சார்ஜாகிறது • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> இல் முழுமையாகச் சார்ஜாகிவிடும்"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"பயனரை மாற்று"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"பயனரைச் சேர்"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"புதியவர்"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"கெஸ்ட்டை அகற்றவா?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"இந்த அமர்வின் எல்லா ஆப்ஸும் தரவும் நீக்கப்படும்."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"அகற்று"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"நல்வரவு!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"உங்கள் அமர்வைத் தொடர விருப்பமா?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"மீண்டும் தொடங்கு"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"தொடரவும்"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"புதியவரைச் சேர்க்கவா?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"புதிய பயனரைச் சேர்க்கும்போது, அவர் தனக்கான இடத்தை அமைக்க வேண்டும்.\n\nஎந்தவொரு பயனரும், மற்ற எல்லா பயனர்களுக்காகவும் ஆப்ஸைப் புதுப்பிக்கலாம்."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"பயனர் வரம்பை அடைந்துவிட்டீர்கள்"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> பயனர்கள் வரை சேர்க்க முடியும்.</item>
@@ -411,10 +399,10 @@
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"முடக்கும்"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"ஆப்ஸ் பின் செய்யப்பட்டது"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"பொருத்தியதை அகற்றும் வரை இதைக் காட்சியில் வைக்கும். அகற்ற, முந்தையது மற்றும் மேலோட்டப் பார்வையைத் தொட்டுப் பிடிக்கவும்."</string>
-    <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"இதற்கான பின்னை அகற்றும் வரை, இந்தப் பயன்முறை செயல்பாட்டிலேயே இருக்கும். அகற்றுவதற்கு, முந்தையது மற்றும் முகப்புப் பொத்தான்களைத் தொட்டுப் பிடிக்கவும்."</string>
+    <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"இதற்கான பின்னை அகற்றும் வரை, இந்தப் பயன்முறை செயல்பாட்டிலேயே இருக்கும். அகற்றுவதற்கு, முந்தையது மற்றும் முகப்பு பட்டன்களைத் தொட்டுப் பிடிக்கவும்."</string>
     <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"பின் செய்திருப்பதை அகற்றும் வரை இதைச் செயல்பாட்டில் வைத்திருக்கும். அதை அகற்றுவதற்கு மேல்நோக்கி ஸ்வைப் செய்து பிடித்திருக்கவும்."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"பொருத்தியதை அகற்றும் வரை இதைக் காட்சியில் வைக்கும். அகற்ற, மேலோட்டப் பார்வையைத் தொட்டுப் பிடிக்கவும்."</string>
-    <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"இதற்கான பின்னை அகற்றும் வரை, இந்தப் பயன்முறை செயல்பாட்டிலேயே இருக்கும். அகற்றுவதற்கு, முகப்புப் பொத்தானைத் தொட்டுப் பிடிக்கவும்."</string>
+    <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"இதற்கான பின்னை அகற்றும் வரை, இந்தப் பயன்முறை செயல்பாட்டிலேயே இருக்கும். அகற்றுவதற்கு, முகப்புப் பட்டனைத் தொட்டுப் பிடிக்கவும்."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"தனிப்பட்ட தரவு அணுகப்படக்கூடும் (தொடர்புகள், மின்னஞ்சலின் உள்ளடக்கம் போன்றவை)."</string>
     <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"பின் செய்யப்பட்டிருக்கும் ஆப்ஸ் பிற ஆப்ஸைத் திறக்கக்கூடும்."</string>
     <string name="screen_pinning_toast" msgid="8177286912533744328">"இந்த ஆப்ஸைப் பின்னிலிருந்து அகற்ற, \'பின்செல்\' மற்றும் \'மேலோட்டப் பார்வை\' பட்டன்களைத் தொட்டுப் பிடித்திருக்கவும்"</string>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"பயன்படுத்துவதற்கு அன்லாக் செய்க"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"உங்கள் கார்டுகளின் விவரங்களைப் பெறுவதில் சிக்கல் ஏற்பட்டது, பிறகு முயலவும்"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"பூட்டுத் திரை அமைப்புகள்"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR குறியீடு"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"ஸ்கேன் செய்யத் தட்டவும்"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR குறியீட்டை ஸ்கேன் செய்தல்"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"பணிக் கணக்கு"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"விமானப் பயன்முறை"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"அடுத்த அலாரத்தை <xliff:g id="WHEN">%1$s</xliff:g> மணிக்கு கேட்க மாட்டீர்கள்"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"மேலும் பார்க்க ஸ்வைப் செய்யவும்"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"பரிந்துரைகளை ஏற்றுகிறது"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"மீடியா"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"இந்த மீடியா அமர்வை மறைக்க வேண்டுமா?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"தற்போதைய மீடியா அமர்வை மறைக்க முடியாது."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"மூடுக"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"மறை"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"தொடர்க"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"அமைப்புகள்"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> இன் <xliff:g id="SONG_NAME">%1$s</xliff:g> பாடல் <xliff:g id="APP_LABEL">%3$s</xliff:g> ஆப்ஸில் பிளேயாகிறது"</string>
@@ -808,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"இங்கு பிளே செய்ய உங்கள் சாதனத்தை <xliff:g id="DEVICENAME">%1$s</xliff:g> சாதனத்திற்கு அருகில் நகர்த்துங்கள்"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> சாதனத்தில் பிளே ஆகிறது"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"இந்த மொபைலில் பிளே ஆகிறது"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"ஏதோ தவறாகிவிட்டது"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"ஏதோ தவறாகிவிட்டது. மீண்டும் முயலவும்."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"செயலில் இல்லை , சரிபார்க்கவும்"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"இல்லை"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"கட்டுப்பாடு இல்லை"</string>
@@ -827,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"புதிய சாதனத்தை இணைத்தல்"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"இந்த அமர்வை அலைபரப்ப ஆப்ஸைத் திறங்கள்."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"அறியப்படாத ஆப்ஸ்"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"அலைபரப்புவதை நிறுத்து"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"பதிப்பு எண்"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"பதிப்பு எண் கிளிப்போர்டுக்கு நகலெடுக்கப்பட்டது."</string>
     <string name="basic_status" msgid="2315371112182658176">"திறந்தநிலை உரையாடல்"</string>
@@ -916,8 +905,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"வைஃபை கிடைக்கவில்லை"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"முன்னுரிமைப் பயன்முறை"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"அலாரம் அமைக்கப்பட்டுள்ளது"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Assistant கெஸ்ட் பயன்முறை இயக்கப்பட்டுள்ளது"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"கேமராவும் மைக்கும் ஆஃப் செய்யப்பட்டுள்ளன"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# அறிவிப்பு}other{# அறிவிப்புகள்}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 6ef8f50..96c1c13 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"సిస్టమ్ UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"బ్యాటరీ సేవర్‌ను ఆన్ చేయాలా?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"మీకు <xliff:g id="PERCENTAGE">%s</xliff:g> బ్యాటరీ మిగిలి ఉంది. బ్యాటరీ సేవర్ ముదురు రంగు రూపాన్ని ఆన్ చేస్తుంది, బ్యాక్‌గ్రౌండ్ యాక్టివిటీని పరిమితం చేస్తుంది, అలాగే నోటిఫికేషన్‌లను ఆలస్యంగా పంపిస్తుంది."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"బ్యాటరీ సేవర్ ముదురు రంగు రూపాన్ని ఆన్ చేస్తుంది, బ్యాక్‌గ్రౌండ్ యాక్టివిటీని పరిమితం చేస్తుంది, అలాగే నోటిఫికేషన్‌లను ఆలస్యంగా పంపిస్తుంది."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> మిగిలి ఉంది"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"USB ద్వారా ఛార్జ్ చేయలేరు"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"మీ పరికరంతో వచ్చిన ఛార్జర్‌ను ఉపయోగించండి"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"బ్యాటరీ సేవర్‌ను ఆన్ చేయాలా?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"బ్యాటరీ సేవర్ గురించి"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ఆన్ చేయి"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"బ్యాటరీ సేవర్‌ను ఆన్ చేయండి"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"ఆన్ చేయండి"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"వద్దు, ధన్యవాదాలు"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"స్క్రీన్ ఆటో-రొటేట్‌"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>ని యాక్సెస్ చేయడానికి <xliff:g id="APPLICATION">%1$s</xliff:g>ని అనుమతించాలా?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>యాక్సెస్ చేయడానికి <xliff:g id="APPLICATION">%1$s</xliff:g>ను అనుమతించాలా?\nఈ యాప్‌నకు రికార్డ్ చేసే అనుమతి మంజూరు చేయబడలేదు, కానీ ఈ USB పరికరం ద్వారా ఆడియోను క్యాప్చర్ చేయగలదు."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ముఖం ప్రామాణీకరించబడింది"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"నిర్ధారించబడింది"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"పూర్తి చేయడానికి \"నిర్ధారించు\" నొక్కండి"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"మీ ముఖం ద్వారా అన్‌లాక్ చేయబడింది. కొనసాగించడానికి నొక్కండి."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ప్రామాణీకరించబడింది"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"పిన్‌ను ఉపయోగించు"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ఆకృతిని ఉపయోగించు"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"మీరు ఒకవేళ తర్వాతి ప్రయత్నంలో తప్పు ఆకృతిని ఎంటర్ చేస్తే, మీ కార్యాలయ ప్రొఫైల్, అలాగే దాని డేటా తొలగించబడతాయి."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"మీరు ఒకవేళ తర్వాతి ప్రయత్నంలో తప్పు పిన్‌ను ఎంటర్ చేస్తే, మీ కార్యాలయ ప్రొఫైల్, అలాగే దాని డేటా తొలగించబడతాయి."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"మీరు ఒకవేళ తర్వాతి ప్రయత్నంలో తప్పు పాస్‌వర్డ్‌ను ఎంటర్ చేస్తే, మీ కార్యాలయ ప్రొఫైల్, అలాగే దాని డేటా తొలగించబడతాయి."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"చాలా ఎక్కువ తప్పు ప్రయత్నాలు చేశారు. ఈ పరికరం యొక్క డేటా తొలగించబడుతుంది."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"చాలా ఎక్కువ తప్పు ప్రయత్నాలు చేశారు. ఈ యూజర్ తొలగించబడతారు."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"చాలా ఎక్కువ తప్పు ప్రయత్నాలు చేశారు. ఈ కార్యాలయ ప్రొఫైల్ మరియు దీని డేటా తొలగించబడతాయి."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"తీసివేయి"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"వేలిముద్ర సెన్సార్‌ను తాకండి"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"వేలిముద్ర చిహ్నం"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ముఖం గుర్తించలేము. బదులుగా వేలిముద్ర ఉపయోగించండి."</string>
@@ -298,7 +291,7 @@
     <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"స్థూలదృష్టిని టోగుల్ చేయి"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"మీరు పేర్కొనే అలారాలు, రిమైండర్‌లు, ఈవెంట్‌లు మరియు కాలర్‌ల నుండి మినహా మరే ఇతర ధ్వనులు మరియు వైబ్రేషన్‌లతో మీకు అంతరాయం కలగదు. మీరు ఇప్పటికీ సంగీతం, వీడియోలు మరియు గేమ్‌లతో సహా మీరు ప్లే చేయడానికి ఎంచుకున్నవి ఏవైనా వింటారు."</string>
     <string name="zen_alarms_introduction" msgid="3987266042682300470">"అలారాలు నుండి మినహా మరే ఇతర ధ్వనులు మరియు వైబ్రేషన్‌లతో మీకు అంతరాయం కలగదు. మీరు ఇప్పటికీ సంగీతం, వీడియోలు మరియు గేమ్‌లతో సహా మీరు ప్లే చేయడానికి ఎంచుకున్నవి ఏవైనా వింటారు."</string>
-    <string name="zen_priority_customize_button" msgid="4119213187257195047">"అనుకూలీకరించు"</string>
+    <string name="zen_priority_customize_button" msgid="4119213187257195047">"అనుకూలంగా మార్చండి"</string>
     <string name="zen_silence_introduction_voice" msgid="853573681302712348">"ఇది అలారాలు, సంగీతం, వీడియోలు మరియు గేమ్‌లతో సహా అన్ని ధ్వనులు మరియు వైబ్రేషన్‌లను బ్లాక్ చేస్తుంది. మీరు ఇప్పటికీ ఫోన్ కాల్స్‌ చేయగలుగుతారు."</string>
     <string name="zen_silence_introduction" msgid="6117517737057344014">"ఇది అలారాలు, సంగీతం, వీడియోలు మరియు గేమ్‌లతో సహా అన్ని ధ్వనులు మరియు వైబ్రేషన్‌లను బ్లాక్ చేస్తుంది."</string>
     <string name="notification_tap_again" msgid="4477318164947497249">"తెరవడానికి మళ్లీ నొక్కండి"</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • నెమ్మదిగా ఛార్జ్ అవుతోంది • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>లో పూర్తి ఛార్జ్"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ఛార్జింగ్ డాక్ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>లో పూర్తిగా ఛార్జ్ అవుతుంది"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"వినియోగదారుని మార్చు"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"యూజర్‌ను జోడించండి"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"కొత్త వినియోగదారు"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"గెస్ట్‌ను తీసివేయాలా?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ఈ సెషన్‌లోని అన్ని యాప్‌లు మరియు డేటా తొలగించబడతాయి."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"తీసివేయి"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"గెస్ట్‌కు తిరిగి స్వాగతం!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"మీరు మీ సెషన్‌ని కొనసాగించాలనుకుంటున్నారా?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"మొదటి నుండి ప్రారంభించు"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"అవును, కొనసాగించు"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"కొత్త యూజర్‌ను జోడించాలా?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"ఒక కొత్త యూజర్‌ను మీరు జోడించినప్పుడు, ఆ వ్యక్తి తన స్పేస్‌ను సెటప్ చేసుకోవాలి.\n\nఏ యూజర్ అయినా మిగతా అందరు యూజర్‌ల కోసం యాప్‌లను అప్‌డేట్ చేయగలరు."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"వినియోగదారు పరిమితిని చేరుకున్నారు"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">మీరు <xliff:g id="COUNT">%d</xliff:g> వినియోగదారుల వరకు జోడించవచ్చు.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ఉపయోగించడానికి అన్‌లాక్ చేయండి"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"మీ కార్డ్‌లను పొందడంలో సమస్య ఉంది, దయచేసి తర్వాత మళ్లీ ట్రై చేయండి"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"లాక్ స్క్రీన్ సెట్టింగ్‌లు"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR కోడ్"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"స్కాన్ చేయడానికి ట్యాప్ చేయండి"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR కోడ్‌ను స్కాన్ చేయండి"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"ఆఫీస్ ప్రొఫైల్‌"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"ఎయిర్‌ప్లేన్ మోడ్"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"మీరు <xliff:g id="WHEN">%1$s</xliff:g> సెట్ చేసిన మీ తర్వాత అలారం మీకు వినిపించదు"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"మరిన్నింటిని చూడటం కోసం స్వైప్ చేయండి"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"సిఫార్సులు లోడ్ అవుతున్నాయి"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"మీడియా"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"ఈ మీడియా సెషన్‌ను దాచాలా?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"ప్రస్తుత మీడియా సెషన్‌ను దాచడం సాధ్యం కాదు."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"విస్మరించు"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"దాచు"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"కొనసాగించండి"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"సెట్టింగ్‌లు"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> పాడిన <xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%3$s</xliff:g> నుండి ప్లే అవుతోంది"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ఇక్కడ ప్లే చేయడానికి <xliff:g id="DEVICENAME">%1$s</xliff:g>కి దగ్గరగా వెళ్లండి"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>లో ప్లే అవుతోంది"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"ఈ ఫోన్‌లో ప్లే అవుతోంది"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"ఏదో తప్పు జరిగింది"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"ఇన్‌యాక్టివ్, యాప్ చెక్ చేయండి"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"కనుగొనబడలేదు"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"కంట్రోల్ అందుబాటులో లేదు"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"కొత్త పరికరాన్ని పెయిర్ చేయండి"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ఈ సెషన్‌ను ప్రసారం చేయడానికి, దయచేసి యాప్‌ను తెరవండి."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"తెలియని యాప్"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ప్రసారాన్ని ఆపివేయండి"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"బిల్డ్ నంబర్"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"బిల్డ్ నంబర్, క్లిప్‌బోర్డ్‌కు కాపీ చేయబడింది."</string>
     <string name="basic_status" msgid="2315371112182658176">"సంభాషణను తెరవండి"</string>
@@ -916,7 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi అందుబాటులో లేదు"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ముఖ్యమైన ఫైల్స్ మోడ్"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"అలారం సెట్ చేశాను"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"అసిస్టెంట్ గెస్ట్ మోడ్ ఎనేబుల్ చేయబడింది"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"కెమెరా, మైక్ ఆఫ్‌లో ఉన్నాయి"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# నోటిఫికేషన్}other{# నోటిఫికేషన్‌లు}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 9072db4..a6ae2bd 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"อินเทอร์เฟซผู้ใช้ของระบบ"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"เปิดโหมดประหยัดแบตเตอรี่ใช่ไหม"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"คุณมีแบตเตอรี่เหลืออยู่ <xliff:g id="PERCENTAGE">%s</xliff:g> โหมดประหยัดแบตเตอรี่จะเปิดธีมมืด จำกัดกิจกรรมในเบื้องหลัง และหน่วงเวลาการแจ้งเตือน"</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"โหมดประหยัดแบตเตอรี่จะเปิดธีมมืด จำกัดกิจกรรมในเบื้องหลัง และหน่วงเวลาการแจ้งเตือน"</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"เหลืออีก <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"ชาร์จผ่าน USB ไม่ได้"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"ใช้ที่ชาร์จที่ให้มาพร้อมกับอุปกรณ์"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"เปิดโหมดประหยัดแบตเตอรี่ใช่ไหม"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"เกี่ยวกับโหมดประหยัดแบตเตอรี่"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"เปิด"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"เปิดโหมดประหยัดแบตเตอรี่"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"เปิด"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"ไม่เป็นไร"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"หมุนหน้าจออัตโนมัติ"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"อนุญาตให้ <xliff:g id="APPLICATION">%1$s</xliff:g> เข้าถึง <xliff:g id="USB_DEVICE">%2$s</xliff:g> ไหม"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"อนุญาตให้ <xliff:g id="APPLICATION">%1$s</xliff:g> เข้าถึง <xliff:g id="USB_DEVICE">%2$s</xliff:g> ไหม\nแอปนี้ไม่ได้รับอนุญาตให้อัดเสียงแต่จะอัดเสียงผ่านอุปกรณ์ USB นี้ได้"</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ตรวจสอบสิทธิ์ใบหน้าแล้ว"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ยืนยันแล้ว"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"แตะยืนยันเพื่อดำเนินการให้เสร็จสมบูรณ์"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"ปลดล็อกโดยใช้ใบหน้าแล้ว กดเพื่อดำเนินการต่อ"</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ตรวจสอบสิทธิ์แล้ว"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"ใช้ PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ใช้รูปแบบ"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"หากคุณป้อนรูปแบบไม่ถูกต้องในความพยายามครั้งถัดไป ระบบจะลบโปรไฟล์งานและข้อมูลในโปรไฟล์"</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"หากคุณป้อน PIN ไม่ถูกต้องในความพยายามครั้งถัดไป ระบบจะลบโปรไฟล์งานและข้อมูลในโปรไฟล์"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"หากคุณป้อนรหัสผ่านไม่ถูกต้องในความพยายามครั้งถัดไป ระบบจะลบโปรไฟล์งานและข้อมูลในโปรไฟล์"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"ใช้ความพยายามหลายครั้งเกินไป ระบบจะลบข้อมูลในอุปกรณ์เครื่องนี้"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"ใช้ความพยายามหลายครั้งเกินไป ระบบจะลบผู้ใช้รายนี้"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"ใช้ความพยายามหลายครั้งเกินไป ระบบจะลบโปรไฟล์งานนี้และข้อมูลในโปรไฟล์"</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"ปิด"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"แตะเซ็นเซอร์ลายนิ้วมือ"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ไอคอนลายนิ้วมือ"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ไม่รู้จักใบหน้า ใช้ลายนิ้วมือแทน"</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • กำลังชาร์จอย่างช้าๆ • จะเต็มในอีก <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • กำลังชาร์จบนแท่นชาร์จ • จะเต็มในอีก <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"สลับผู้ใช้"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"เพิ่มผู้ใช้"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"ผู้ใช้ใหม่"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ต้องการนำผู้ใช้ชั่วคราวออกไหม"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ระบบจะลบแอปและข้อมูลทั้งหมดในเซสชันนี้"</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"นำออก"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"ยินดีต้อนรับผู้เข้าร่วมกลับมาอีกครั้ง"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"คุณต้องการอยู่ในเซสชันต่อไปไหม"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"เริ่มต้นใหม่"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"ใช่ ดำเนินการต่อ"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"ต้องการเพิ่มผู้ใช้ใหม่ใช่ไหม"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"เมื่อคุณเพิ่มผู้ใช้ใหม่ ผู้ใช้ดังกล่าวจะต้องตั้งค่าพื้นที่ของตนเอง\n\nผู้ใช้ทุกคนสามารถอัปเดตแอปสำหรับผู้ใช้รายอื่นทุกคนได้"</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"ถึงขีดจำกัดผู้ใช้แล้ว"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">คุณเพิ่มผู้ใช้ได้สูงสุด <xliff:g id="COUNT">%d</xliff:g> คน</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ปลดล็อกเพื่อใช้"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"เกิดปัญหาในการดึงข้อมูลบัตรของคุณ โปรดลองอีกครั้งในภายหลัง"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"การตั้งค่าหน้าจอล็อก"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"คิวอาร์โค้ด"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"แตะเพื่อสแกน"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"สแกนคิวอาร์โค้ด"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"โปรไฟล์งาน"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"โหมดบนเครื่องบิน"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"คุณจะไม่ได้ยินเสียงปลุกครั้งถัดไปในเวลา <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"เลื่อนเพื่อดูเพิ่มเติม"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"กำลังโหลดคำแนะนำ"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"สื่อ"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"ซ่อนเซสชันสื่อนี้ไหม"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"ซ่อนเซสชันสื่อในปัจจุบันไม่ได้"</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ปิด"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ซ่อน"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"เล่นต่อ"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"การตั้งค่า"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"กำลังเปิดเพลง <xliff:g id="SONG_NAME">%1$s</xliff:g> ของ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> จาก <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ขยับไปใกล้ <xliff:g id="DEVICENAME">%1$s</xliff:g> มากขึ้นเพื่อเล่นที่นี่"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"กำลังเล่นใน <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"กำลังเล่นในโทรศัพท์เครื่องนี้"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"เกิดข้อผิดพลาด"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"เกิดข้อผิดพลาด โปรดลองอีกครั้ง"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"ไม่มีการใช้งาน โปรดตรวจสอบแอป"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"ไม่พบ"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"ใช้การควบคุมไม่ได้"</string>
@@ -827,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"จับคู่อุปกรณ์ใหม่"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"โปรดเปิดแอปหากต้องการแคสต์เซสชันนี้"</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"แอปที่ไม่รู้จัก"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"หยุดแคสต์"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"หมายเลขบิลด์"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"คัดลอกหมายเลขบิลด์ไปยังคลิปบอร์ดแล้ว"</string>
     <string name="basic_status" msgid="2315371112182658176">"เปิดการสนทนา"</string>
@@ -889,7 +878,7 @@
     <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi จะไม่เชื่อมต่ออัตโนมัติในตอนนี้"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"ดูทั้งหมด"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ตัดการเชื่อมต่ออีเทอร์เน็ตเพื่อสลับเครือข่าย"</string>
-    <string name="wifi_scan_notify_message" msgid="3753839537448621794">"เพื่อปรับปรุงประสบการณ์การใช้อุปกรณ์ แอปและบริการต่างๆ จะยังคงสแกนหาเครือข่าย Wi‑Fi ได้ทุกเมื่อแม้ว่า Wi‑Fi จะปิดอยู่ คุณเปลี่ยนตัวเลือกนี้ได้ในการตั้งค่าการสแกนหา Wi-Fi "<annotation id="link">"เปลี่ยน"</annotation></string>
+    <string name="wifi_scan_notify_message" msgid="3753839537448621794">"เพื่อปรับปรุงประสบการณ์การใช้อุปกรณ์ แอปและบริการต่างๆ จะยังคงสแกนหาเครือข่าย Wi‑Fi ได้ทุกเมื่อแม้ว่า Wi‑Fi จะปิดอยู่ คุณเปลี่ยนตัวเลือกนี้ได้ในการตั้งค่าการสแกนหา Wi-Fi "<annotation id="link">"เปลี่ยนการตั้งค่า"</annotation></string>
     <string name="turn_off_airplane_mode" msgid="8425587763226548579">"ปิดโหมดบนเครื่องบิน"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ต้องการเพิ่มชิ้นส่วนต่อไปนี้ในการตั้งค่าด่วน"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"เพิ่มชิ้นส่วน"</string>
@@ -916,7 +905,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ใช้ Wi‑Fi ไม่ได้"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"โหมดลำดับความสำคัญ"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ตั้งปลุกแล้ว"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"เปิดใช้โหมดผู้มาเยือนของ Assistant แล้ว"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"กล้องและไมค์ปิดอยู่"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{การแจ้งเตือน # รายการ}other{การแจ้งเตือน # รายการ}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index b518c603..d6715a3 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"UI ng System"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"I-on ang Pantipid ng Baterya?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"<xliff:g id="PERCENTAGE">%s</xliff:g> na lang ang natitira sa iyong baterya. Ino-on ng Pantipid ng Baterya ang Madilim na tema, pinaghihigpitan nito ang aktibidad sa background, at inaantala nito ang mga notification."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Ino-on ng Pantipid ng Baterya ang Madilim na tema, pinaghihigpitan nito ang aktibidad sa background, at inaantala nito ang mga notification."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> na lang ang natitira"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Hindi makapag-charge sa pamamagitan ng USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Gamitin ang charger na kasama ng iyong device"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"I-on ang Pantipid ng Baterya?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Tungkol sa Pantipid ng Baterya"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"I-on"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"I-on ang Pantipid ng Baterya"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"I-on"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Huwag na lang"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"I-auto rotate ang screen"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Payagan ang <xliff:g id="APPLICATION">%1$s</xliff:g> na ma-access ang <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Payagan ang <xliff:g id="APPLICATION">%1$s</xliff:g> na i-access ang <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nHindi nabigyan ng pahintulot ang app na ito para mag-record pero nakakapag-capture ito ng audio sa pamamagitan ng USB device na ito."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Na-authenticate ang mukha"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Nakumpirma"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"I-tap ang Kumpirmahin para kumpletuhin"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Na-unlock gamit ang mukha mo. Pindutin para magpatuloy."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Na-authenticate"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Gumamit ng PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Gumamit ng pattern"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Kung maling pattern ang mailalagay mo sa susunod na pagsubok, made-delete ang iyong profile sa trabaho at ang data nito."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Kung maling PIN ang mailalagay mo sa susunod na pagsubok, made-delete ang iyong profile sa trabaho at ang data nito."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Kung maling password ang mailalagay mo sa susunod na pagsubok, made-delete ang iyong profile sa trabaho at ang data nito."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Masyadong maraming maling pagsubok. Made-delete ang data ng device na ito."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Masyadong maraming maling pagsubok. Made-delete ang user na ito."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Masyadong maraming maling pagsubok. Made-delete ang profile sa trabaho na ito at ang data nito."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"I-dismiss"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Pindutin ang fingerprint sensor"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Icon ng fingerprint"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Hindi makilala ang mukha. Gumamit ng fingerprint."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mabagal na nagcha-charge • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> na lang para mapuno"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging Dock • Mapupuno sa loob ng <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Magpalit ng user"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Magdagdag ng user"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Bagong user"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Alisin ang bisita?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Ide-delete ang lahat ng app at data sa session na ito."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Alisin"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welcome ulit, bisita!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Gusto mo bang ipagpatuloy ang iyong session?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Magsimulang muli"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Oo, magpatuloy"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Magdagdag ng bagong user?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Kapag nagdagdag ka ng bagong user, kailangang i-set up ng taong iyon ang kanyang espasyo.\n\nAng sinumang user ay maaaring mag-update ng mga app para sa lahat ng iba pang user."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Naabot na ang limitasyon sa user"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">Maaari kang magdagdag ng hanggang <xliff:g id="COUNT">%d</xliff:g> user.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"I-unlock para magamit"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Nagkaproblema sa pagkuha ng iyong mga card, pakisubukan ulit sa ibang pagkakataon"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Mga setting ng lock screen"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR code"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"I-tap para i-scan"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"I-scan ang QR code"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Profile sa trabaho"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Airplane mode"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Hindi mo maririnig ang iyong susunod na alarm ng <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Mag-swipe para tumingin ng higit pa"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Nilo-load ang rekomendasyon"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Media"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Itago ang session ng media na ito?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Hindi maitatago ang kasalukuyang session ng media."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"I-dismiss"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Itago"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Ituloy"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Mga Setting"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Nagpe-play ang <xliff:g id="SONG_NAME">%1$s</xliff:g> ni/ng <xliff:g id="ARTIST_NAME">%2$s</xliff:g> mula sa <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Lumapit sa <xliff:g id="DEVICENAME">%1$s</xliff:g> para mag-play rito"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Nagpe-play sa <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Nagpe-play sa teleponong ito"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Nagkaproblema"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Hindi aktibo, tingnan ang app"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Hindi nahanap"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Hindi available ang kontrol"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Magpares ng bagong device"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Para ma-cast ang session na ito, buksan ang app."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Hindi kilalang app"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Ihinto ang pag-cast"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Numero ng build"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Nakopya sa clipboard ang numero ng build."</string>
     <string name="basic_status" msgid="2315371112182658176">"Buksan ang pag-uusap"</string>
@@ -916,7 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Hindi available ang Wi‑Fi"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Priority mode"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Nakatakda ang alarm"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Naka-enable ang guest mode ng Assistant"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Naka-off ang camera at mikropono"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}one{# notification}other{# na notification}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 0f56057..6cc1703 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Sistem Arayüzü"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Pil Tasarrufu açılsın mı?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"<xliff:g id="PERCENTAGE">%s</xliff:g> piliniz kaldı. Pil Tasarrufu, koyu temayı açıp arka plan etkinliğini kısıtlar ve bildirimleri geciktirir."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Pil Tasarrufu, koyu temayı açıp arka plan etkinliğini kısıtlar ve bildirimleri geciktirir."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> kaldı"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"USB ile şarj edilemiyor"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Cihazınızla birlikte gelen şarj cihazını kullanın"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Pil Tasarrufu açılsın mı?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Pil Tasarrufu hakkında"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Aç"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Pil Tasarrufu\'nu aç"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Aç"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Hayır, teşekkürler"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Ekranı otomatik döndür"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasının <xliff:g id="USB_DEVICE">%2$s</xliff:g> cihazına erişmesine izin verilsin mi?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasının <xliff:g id="USB_DEVICE">%2$s</xliff:g> cihazına erişmesine izin verilsin mi?\nBu uygulamaya kayıt izni verilmemiş ancak bu USB cihazı aracılığıyla sesleri yakalayabilir."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Yüz kimliği doğrulandı"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Onaylandı"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tamamlamak için Onayla\'ya dokunun"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Kilit, yüzünüzle açıldı. Devam etmek için basın."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Kimliği Doğrulandı"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN kullan"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Deseni kullan"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Bir sonraki denemenizde yanlış desen girerseniz iş profiliniz ve verileri silinir."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Bir sonraki denemenizde yanlış PIN girerseniz iş profiliniz ve verileri silinir."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Bir sonraki denemenizde yanlış şifre girerseniz iş profiliniz ve verileri silinir."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Çok fazla sayıda hatalı deneme yapıldı. Bu cihazın verileri silinecek."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Çok fazla sayıda hatalı deneme yapıldı. Bu kullanıcı silinecek."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Çok fazla sayıda hatalı denemede yapıldı. İş profiliniz ve verileri silinecek."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Kapat"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Parmak izi sensörüne dokunun"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Parmak izi simgesi"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Yüz tanınamadı. Bunun yerine parmak izi kullanın."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Yavaş şarj oluyor • Dolmasına <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> kaldı"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Yuvada Şarj Oluyor • Dolmasına <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> kaldı"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Kullanıcı değiştirme"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Kullanıcı ekle"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Yeni kullanıcı"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Misafir oturumu kaldırılsın mı?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu oturumdaki tüm uygulamalar ve veriler silinecek."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Kaldır"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Misafir kullanıcı, tekrar hoşgeldiniz"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Oturumunuza devam etmek istiyor musunuz?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Baştan başla"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Evet, devam et"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Yeni kullanıcı eklensin mi?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Yeni bir kullanıcı eklediğinizde, bu kişinin kendi alanını ayarlaması gerekir.\n\nHerhangi bir kullanıcı, diğer tüm kullanıcılar için uygulamaları güncelleyebilir."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Kullanıcı sınırına ulaşıldı"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">En fazla <xliff:g id="COUNT">%d</xliff:g> kullanıcı ekleyebilirsiniz.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Kullanmak için kilidi aç"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Kartlarınız alınırken bir sorun oluştu. Lütfen daha sonra tekrar deneyin"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Kilit ekranı ayarları"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR kodu"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Taramak için dokunun"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR kodunu tara"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"İş profili"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Uçak modu"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> olarak ayarlanmış bir sonraki alarmınızı duymayacaksınız"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Diğer öğeleri görmek için hızlıca kaydırın"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Öneriler yükleniyor"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Medya"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Bu medya oturumu gizlensin mi?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Geçerli medya oturumu gizlenemez."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Kapat"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Gizle"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Devam ettir"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Ayarlar"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> uygulamasından <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, <xliff:g id="SONG_NAME">%1$s</xliff:g> şarkısı çalıyor"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Burada oynatmak için <xliff:g id="DEVICENAME">%1$s</xliff:g> cihazına yaklaşın"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında oynatılıyor"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Bu telefonda oynatılıyor"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Hata oluştu"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Devre dışı, uygulamaya bakın"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Bulunamadı"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrol kullanılamıyor"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Yeni cihaz eşle"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Bu oturumu yayınlamak için lütfen uygulamayı açın."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Bilinmeyen uygulama"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Yayını durdur"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Derleme numarası"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Derleme numarası panoya kopyalandı."</string>
     <string name="basic_status" msgid="2315371112182658176">"Görüşmeyi aç"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Kablosuz kullanılamıyor"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Öncelik modu"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm kuruldu"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Asistan misafir modu etkinleştirildi"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera ve mikrofon kapalı"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# bildirim}other{# bildirim}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index fa9af2e..1bc89c8 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Інтерфейс системи"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Увімкнути режим енергозбереження?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"У вас залишилося <xliff:g id="PERCENTAGE">%s</xliff:g> заряду акумулятора. У режимі енергозбереження вмикається Темна тема, обмежуються дії у фоновому режимі та затримуються сповіщення."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"У режимі енергозбереження вмикається Темна тема, обмежуються дії у фоновому режимі та затримуються сповіщення."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Залишилося <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Не вдається зарядити через USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Використовуйте зарядний пристрій, який входить у комплект пристрою"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Увімкнути режим енергозбереження?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Про режим енергозбереження"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Увімкнути"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Увімкнути режим енергозбереження"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Увімкнути"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Ні, дякую"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Автообертання екрана"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Надати додатку <xliff:g id="APPLICATION">%1$s</xliff:g> доступ до такого аксесуара: <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Надати додатку <xliff:g id="APPLICATION">%1$s</xliff:g> доступ до <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nЦей додаток не має дозволу на записування звуку, але може фіксувати його через цей USB-пристрій."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Обличчя автентифіковано"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Підтверджено"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Щоб завершити, натисніть \"Підтвердити\""</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Розблоковано: фейсконтроль. Натисніть, щоб продовжити."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Автентифіковано"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Ввести PIN-код"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Намалювати ключ"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Якщо наступного разу ви введете неправильний ключ, ваш робочий профіль і його дані буде видалено."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Якщо наступного разу ви введете неправильний PIN-код, ваш робочий профіль і його дані буде видалено."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Якщо наступного разу ви введете неправильний пароль, ваш робочий профіль і його дані буде видалено."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Забагато невдалих спроб. Дані на цьому пристрої буде видалено."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Забагато невдалих спроб. Цього користувача буде видалено."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Забагато невдалих спроб. Цей робочий профіль і його дані буде видалено."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Закрити"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Торкніться сканера відбитків пальців"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Значок відбитка пальця"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Обличчя не розпізнано. Скористайтеся відбитком пальця."</string>
@@ -330,17 +323,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Повільне заряджання • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до повного заряду"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Док-станція для заряджання • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до повного заряду"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Змінити користувача"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Додати користувача"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Новий користувач"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Видалити гостя?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усі додатки й дані з цього сеансу буде видалено."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Вийти"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"З поверненням!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Продовжити сеанс?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Почати знову"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Так, продовжити"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Додати нового користувача?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Користувач має налаштувати свій профіль після створення.\n\nБудь-який користувач пристрою може оновлювати додатки для решти користувачів."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Ви досягли ліміту користувачів"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">Можна додати до <xliff:g id="COUNT">%d</xliff:g> користувача.</item>
@@ -468,8 +456,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Розблокувати, щоб використовувати"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Не вдалось отримати ваші картки. Повторіть спробу пізніше."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Параметри блокування екрана"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-код"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Натисніть, щоб сканувати"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Сканувати QR-код"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Робочий профіль"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Режим польоту"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Наступний сигнал о <xliff:g id="WHEN">%1$s</xliff:g> не пролунає"</string>
@@ -800,9 +787,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Гортайте, щоб переглянути інші"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Завантаження рекомендацій"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Медіа"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Приховати цей медіасеанс?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Поточний медіасеанс не можна приховати."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Закрити"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Приховати"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Відновити"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Налаштування"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Пісня \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\", яку виконує <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, грає в додатку <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -820,7 +808,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Наблизьтеся до пристрою <xliff:g id="DEVICENAME">%1$s</xliff:g>, щоб відтворити медіафайли на ньому"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Відтворюється на пристрої <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Відтворюється на цьому телефоні"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Сталася помилка"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, перейдіть у додаток"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Не знайдено"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Елемент керування недоступний"</string>
@@ -839,6 +828,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Підключити новий пристрій"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Щоб транслювати цей сеанс, відкрийте додаток."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Невідомий додаток"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Припинити трансляцію"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер складання"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Номер складання скопійовано в буфер обміну."</string>
     <string name="basic_status" msgid="2315371112182658176">"Відкрита розмова"</string>
@@ -930,8 +920,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Мережа Wi-Fi недоступна"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Режим пріоритету"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Будильник установлено"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Увімкнено режим гостя Асистента"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камеру й мікрофон вимкнено"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# сповіщення}one{# сповіщення}few{# сповіщення}many{# сповіщень}other{# сповіщення}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 3576021..5c1d4d6 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"‏سسٹم UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"بیٹری سیور آن کریں؟"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"آپ کے پاس <xliff:g id="PERCENTAGE">%s</xliff:g> بیٹری باقی ہے۔ بیٹری سیور گہری تھیم کو آن، پس منظر کی سرگرمی کو محدود اور اطلاعات میں تاخیر کرتی ہے۔"</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"بیٹری سیور گہری تھیم کو آن، پس منظر کی سرگرمی کو محدود اور اطلاعات میں تاخیر کرتی ہے۔"</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> باقی ہے"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"‏USB کے ذریعے چارج نہیں کر سکتے"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"اپنے آلہ کے ساتھ ملنے والے چارجر کا استعمال کریں"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"بیٹری سیور آن کریں؟"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"بیٹری سیور کے بارے میں"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"آن کریں"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"بیٹری سیور آن کریں"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"آن کریں"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"نہیں شکریہ"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"سکرین کو خودکار طور پر گھمائیں"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> کو <xliff:g id="USB_DEVICE">%2$s</xliff:g> تک رسائی حاصل کرنے کی اجازت دیں؟"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"‏<xliff:g id="APPLICATION">%1$s</xliff:g> کو <xliff:g id="USB_DEVICE">%2$s</xliff:g> تک رسائی دیں؟\nاس ایپ کو ریکارڈ کی اجازت عطا نہیں کی گئی ہے مگر اس USB آلہ سے کیپچر کر سکتے ہیں۔"</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"چہرے کی تصدیق ہو گئی"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"تصدیق شدہ"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"مکمل کرنے کیلئے \'تصدیق کریں\' تھپتھپائیں"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"آپ کے چہرے سے غیر مقفل کیا گیا جاری رکھنے کے لیے دبائیں"</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"تصدیق کردہ"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"‏PIN استعمال کریں"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"پیٹرن کا استعمال کریں"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"اگر آپ نے اگلی کوشش میں غلط پیٹرن درج کیا تو آپ کی دفتری پروفائل اور اس کا ڈیٹا حذف کر دیا جائے گا۔"</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"‏اگر آپ نے اگلی کوشش میں غلط PIN درج کیا تو آپ کی دفتری پروفائل اور اس کا ڈیٹا حذف کر دیا جائے گا۔"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"اگر آپ نے اگلی کوشش میں غلط پاس ورڈ درج کیا تو آپ کی دفتری پروفائل اور اس کا ڈیٹا حذف کر دیا جائے گا۔"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"بہت زیادہ غلط کوششیں۔ اس آلے کا ڈیٹا حذف کر دیا جائے گا۔"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"بہت زیادہ غلط کوششیں۔ اس صارف کو حذف کر دیا جائے گا۔"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"بہت زیادہ غلط کوششیں۔ یہ دفتری پروفائل اور اس کا ڈیٹا حذف کر دیا جائے گا۔"</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"برخاست کریں"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"فنگر پرنٹ سینسر پر ٹچ کریں"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"فنگر پرنٹ آئیکن"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"چہرے کی شناخت نہیں ہو سکی۔ اس کے بجائے فنگر پرنٹ استعمال کریں۔"</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • آہستہ چارج ہو رہا ہے • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> میں مکمل"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ڈاک چارج ہو رہا ہے • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> میں مکمل"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"صارف سوئچ کریں"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"صارف کو شامل کریں"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"نیا صارف"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"مہمان کو ہٹائیں؟"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"اس سیشن میں موجود سبھی ایپس اور ڈیٹا کو حذف کر دیا جائے گا۔"</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ہٹائیں"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"مہمان، پھر سے خوش آمدید!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"کیا آپ اپنا سیشن جاری رکھنا چاہتے ہیں؟"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"دوبارہ شروع کریں"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"ہاں، جاری رکھیں"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"نیا صارف شامل کریں؟"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"جب آپ ایک نیا صارف شامل کرتے ہیں تو اس شخص کو اپنی جگہ کو ترتیب دینے کی ضرورت ہوتی ہے۔\n\nکوئی بھی صارف دیگر سبھی صارفین کیلئے ایپس کو اپ ڈیٹ کر سکتا ہے۔"</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"صارف کی حد مکمل ہو گئی"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">صرف <xliff:g id="COUNT">%d</xliff:g> صارفین بنائے جا سکتے ہیں۔</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"استعمال کرنے کے لیے غیر مقفل کریں"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"آپ کے کارڈز حاصل کرنے میں ایک مسئلہ درپیش تھا، براہ کرم بعد میں دوبارہ کوشش کریں"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"مقفل اسکرین کی ترتیبات"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"‏QR کوڈ"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"اسکین کرنے کے لیے تھپتھپائیں"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"‏QR کوڈ اسکین کریں"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"دفتری پروفائل"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"ہوائی جہاز وضع"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"آپ کو <xliff:g id="WHEN">%1$s</xliff:g> بجے اپنا اگلا الارم سنائی نہیں دے گا"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"مزید دیکھنے کیلئے سوائپ کریں"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"تجاویز لوڈ ہو رہی ہیں"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"میڈیا"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"اس میڈیا سیشن کو چھپائیں؟"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"میڈیا کے موجودہ سیشن کو چھپایا نہیں جا سکتا۔"</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"برخاست کریں"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"چھپائیں"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"دوبارہ شروع کریں"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"ترتیبات"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> سے <xliff:g id="ARTIST_NAME">%2$s</xliff:g> کا <xliff:g id="SONG_NAME">%1$s</xliff:g> چل رہا ہے"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"یہاں چلانے کے ليے <xliff:g id="DEVICENAME">%1$s</xliff:g> کے قریب جائیں"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> پر چل رہا ہے"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"اس فون پر چل رہا ہے"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"کچھ غلط ہو گیا"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"غیر فعال، ایپ چیک کریں"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"نہیں ملا"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"کنٹرول دستیاب نہیں ہے"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"نئے آلہ کا جوڑا بنائیں"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"اس سیشن کو کاسٹ کرنے کیلئے، براہ کرم ایپ کھولیں۔"</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"نامعلوم ایپ"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"کاسٹ کرنا بند کریں"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"بلڈ نمبر"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"بلڈ نمبر کلپ بورڈ میں کاپی ہو گیا۔"</string>
     <string name="basic_status" msgid="2315371112182658176">"گفتگو کھولیں"</string>
@@ -916,7 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"‏Wi-Fi دستیاب نہیں ہے"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ترجیحی وضع"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"الارم سیٹ ہوگیا"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"اسسٹنٹ مہمان وضع فعال ہے"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"کیمرا اور مائیک آف ہیں"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# اطلاع}other{# اطلاعات}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 0cead71..95111c7 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Tizim interfeysi"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Quvvat tejash funksiyasi yoqilsinmi?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"<xliff:g id="PERCENTAGE">%s</xliff:g> batareya quvvati qoldi. Quvvat tejash funksiyasi Tungi mavzuni yoqadi va fondagi faollikni cheklaydi. Buning natijasida bildirishnomalar kechikishi mumkin."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Quvvat tejash funksiyasi Tungi mavzuni yoqadi va fondagi faollikni cheklaydi. Buning natijasida bildirishnomalar kechikishi mumkin."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> qoldi"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"USB orqali quvvatlash imkonsiz"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Qurilmangiz bilan kelgan quvvatlash moslamasidan foydalaning"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Quvvat tejash yoqilsinmi?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Quvvat tejash funksiyasi haqida"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Yoqish"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Quvvat tejash funksiyasini yoqing"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Yoqish"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Kerak emas"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Ekranning avtomatik burilishi"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasiga <xliff:g id="USB_DEVICE">%2$s</xliff:g> qurilmasidan foydalanishga ruxsat berilsinmi?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasiga <xliff:g id="USB_DEVICE">%2$s</xliff:g> qurilmasidan foydalanish uchun ruxsat berilsinmi?\nBu ilovaga yozib olish ruxsati berilmagan, lekin shu USB orqali ovozlarni yozib olishi mumkin."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Yuzingiz aniqlandi"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Tasdiqlangan"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tasdiqlash uchun tegining"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Yuz bilan ochildi. Davom etish uchun bosing."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Tasdiqlandi"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN kod kiritish"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Grafik kalitdan foydalanish"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Agar grafik kalitni xato kiritsangiz, ish profili va undagi maʼlumotlar oʻchirib tashlanadi."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Agar PIN kodni xato kiritsangiz, ish profili va undagi maʼlumotlar oʻchirib tashlanadi."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Agar parolni xato kiritsangiz, ish profili va undagi maʼlumotlar oʻchirib tashlanadi."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Juda koʻp marta muvaffaqiyatsiz urindingiz. Bu qurilmadagi maʼlumotlar oʻchirib tashlanadi."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Juda koʻp marta muvaffaqiyatsiz urindingiz. Bu foydalanuvchi oʻchirib tashlanadi."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Juda koʻp marta muvaffaqiyatsiz urindingiz. Bu ish profili va undagi maʼlumotlar oʻchirib tashlanadi."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Yopish"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Barmoq izi skaneriga tegining"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Barmoq izi belgisi"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Bu yuz notanish. Barmoq izi orqali urining."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Sekin quvvat olmoqda • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> qoldi"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Dok-stansiya • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> qoldi"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Foydalanuvchini almashtirish"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Foydalanuvchi"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Yangi foydalanuvchi"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Mehmon olib tashlansinmi?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Ushbu seansdagi barcha ilovalar va ma’lumotlar o‘chirib tashlanadi."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Olib tashlash"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Xush kelibsiz, mehmon!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Seansni davom ettirmoqchimisiz?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Boshidan boshlansin"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ha, davom ettirilsin"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Foydalanuvchi qo‘shilsinmi?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Yangi profil qo‘shilgach, uni sozlash lozim.\n\nQurilmaning istalgan foydalanuvchisi ilovalarni barcha hisoblar uchun yangilashi mumkin."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Limitga yetib keldi"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> tagacha foydalanuvchi qo‘shish mumkin.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Foydalanish uchun qulfdan chiqarish"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Bildirgilarni yuklashda xatolik yuz berdi, keyinroq qaytadan urining"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Qulflangan ekran sozlamalari"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR kod"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Skanerlash uchun bosing"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR kodni skanerlash"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Ish profili"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Parvoz rejimi"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Keyingi signal (<xliff:g id="WHEN">%1$s</xliff:g>) chalinmaydi"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Batafsil axborot olish uchun suring"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Tavsiyalar yuklanmoqda"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Media"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Bu media seansi berkitilsinmi?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Joriy media seansi berkitilmadi."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Yopish"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Berkitish"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Davom etish"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Sozlamalar"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> ilovasida ijro etilmoqda: <xliff:g id="SONG_NAME">%1$s</xliff:g> – <xliff:g id="ARTIST_NAME">%2$s</xliff:g>"</string>
@@ -808,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Bu yerda ijro qilish uchun <xliff:g id="DEVICENAME">%1$s</xliff:g>qurilmasiga yaqinlashtiring"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> qurilmasida ijro qilinmoqda"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Bu telefonda ijro etilmoqda"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Xatolik yuz berdi"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"Xatolik yuz berdi. Qayta urining."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Nofaol. Ilovani tekshiring"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Topilmadi"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Boshqarish imkonsiz"</string>
@@ -827,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Yangi qurilmani ulash"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Bu seansni translatsiya qilish uchun ilovani oching."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Notanish ilova"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Toʻxtatish"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Nashr raqami"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Nashr raqami vaqtinchalik xotiraga nusxalandi."</string>
     <string name="basic_status" msgid="2315371112182658176">"Suhbatni ochish"</string>
@@ -916,7 +905,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi ishlamayapti"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Imtiyozli rejim"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Signal oʻrnatildi"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Assistentli mehmon rejimi yoqildi"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera va mikrofon yoqilmagan"</string>
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ta bildirishnoma}other{# ta bildirishnoma}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index a5609eb8..499495f 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Giao diện người dùng hệ thống"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Bật Trình tiết kiệm pin?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Bạn còn <xliff:g id="PERCENTAGE">%s</xliff:g> pin. Trình tiết kiệm pin sẽ bật Giao diện tối, giới hạn hoạt động trong nền và trì hoãn thông báo."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Trình tiết kiệm pin sẽ bật Giao diện tối, giới hạn hoạt động trong nền và trì hoãn thông báo."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Còn lại <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Không thể sạc qua USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Sử dụng bộ sạc đi kèm với thiết bị"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Bật trình tiết kiệm pin?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Giới thiệu về Trình tiết kiệm pin"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Bật"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Bật trình tiết kiệm pin"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Bật"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Không, cảm ơn"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Tự động xoay màn hình"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Cho phép <xliff:g id="APPLICATION">%1$s</xliff:g> truy cập <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Cho phép <xliff:g id="APPLICATION">%1$s</xliff:g> truy cập vào <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nỨng dụng này chưa được cấp quyền ghi âm nhưng vẫn có thể ghi âm thông qua thiết bị USB này."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Đã xác thực khuôn mặt"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Ðã xác nhận"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Nhấn vào Xác nhận để hoàn tất"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Đã mở khoá bằng khuôn mặt bạn. Hãy nhấn để tiếp tục."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Đã xác thực"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Dùng mã PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Dùng hình mở khóa"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Nếu bạn nhập hình mở khóa không chính xác vào lần thử tiếp theo, thì hồ sơ công việc của bạn và dữ liệu của hồ sơ công việc sẽ bị xóa."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Nếu bạn nhập mã PIN không chính xác vào lần thử tiếp theo, thì hồ sơ công việc của bạn và dữ liệu của hồ sơ công việc sẽ bị xóa."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Nếu bạn nhập mật khẩu không chính xác vào lần thử tiếp theo, thì hồ sơ công việc của bạn và dữ liệu của hồ sơ công việc sẽ bị xóa."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Dữ liệu trên thiết bị này sẽ bị xóa do có quá nhiều lần nhập sai khóa thiết bị."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Người dùng này sẽ bị xóa do có quá nhiều lần nhập sai khóa người dùng."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Hồ sơ công việc này và dữ liệu của hồ sơ công việc sẽ bị xóa do có quá nhiều lần nhập sai khóa công việc."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Đóng"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Chạm vào cảm biến vân tay"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Biểu tượng vân tay"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Không thể nhận dạng khuôn mặt. Hãy dùng vân tay."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Đang sạc chậm • Sẽ đầy sau <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Đế sạc • Sạc đầy sau <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Chuyển đổi người dùng"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Thêm người dùng"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Người dùng mới"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Xóa phiên khách?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tất cả ứng dụng và dữ liệu trong phiên này sẽ bị xóa."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Xóa"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Chào mừng bạn trở lại!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Bạn có muốn tiếp tục phiên của mình không?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Bắt đầu lại"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Có, tiếp tục"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Thêm người dùng mới?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Khi bạn thêm người dùng mới, họ cần thiết lập không gian của mình.\n\nMọi người dùng đều có thể cập nhật ứng dụng cho tất cả người dùng khác."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Đã đạt đến giới hạn người dùng"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">Bạn có thể thêm tối đa <xliff:g id="COUNT">%d</xliff:g> người dùng.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Mở khóa để sử dụng"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Đã xảy ra sự cố khi tải thẻ của bạn. Vui lòng thử lại sau"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Cài đặt màn hình khóa"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"Mã QR"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Nhấn để quét"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Quét mã QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Hồ sơ công việc"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Chế độ máy bay"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Bạn sẽ không nghe thấy báo thức tiếp theo lúc <xliff:g id="WHEN">%1$s</xliff:g> của mình"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Vuốt để xem thêm"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Đang tải các đề xuất"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Nội dung nghe nhìn"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Ẩn phiên phát nội dung nghe nhìn này?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Không thể ẩn phiên phát nội dung nghe nhìn hiện tại."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Đóng"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ẩn"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Tiếp tục"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Cài đặt"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Đang phát <xliff:g id="SONG_NAME">%1$s</xliff:g> của <xliff:g id="ARTIST_NAME">%2$s</xliff:g> trên <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Di chuyển đến gần <xliff:g id="DEVICENAME">%1$s</xliff:g> hơn để phát tại đây"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Đang phát trên <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Đang phát trên điện thoại này"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Đã xảy ra lỗi"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"Không hoạt động, hãy kiểm tra ứng dụng"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Không tìm thấy"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Không có chức năng điều khiển"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Ghép nối thiết bị mới"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Vui lòng mở ứng dụng để truyền phiên này."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Ứng dụng không xác định"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Dừng truyền"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Số bản dựng"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Đã sao chép số bản dựng vào bảng nhớ tạm."</string>
     <string name="basic_status" msgid="2315371112182658176">"Mở cuộc trò chuyện"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Không có Wi‑Fi"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Chế độ ưu tiên"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Đã đặt chuông báo"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Đã bật chế độ khách cho Trợ lý"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Máy ảnh và micrô đang tắt"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# thông báo}other{# thông báo}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 0610b59..3c459f6 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"系统界面"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"要开启省电模式吗?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"您的电池还剩 <xliff:g id="PERCENTAGE">%s</xliff:g> 的电量。省电模式会开启深色主题,限制后台活动并将通知延迟。"</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"省电模式会开启深色主题,限制后台活动并将通知延迟。"</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"剩余<xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"无法通过 USB 充电"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"使用设备随附的充电器"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"要开启省电模式吗?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"关于省电模式"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"开启"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"开启省电模式"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"开启"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"不用了"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"自动旋转屏幕"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"要允许<xliff:g id="APPLICATION">%1$s</xliff:g>访问<xliff:g id="USB_DEVICE">%2$s</xliff:g>吗?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"是否允许<xliff:g id="APPLICATION">%1$s</xliff:g>访问<xliff:g id="USB_DEVICE">%2$s</xliff:g>?\n此应用未获得录音权限,但能通过此 USB 设备录制音频。"</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"面孔身份验证成功"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"已确认"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"点按“确认”即可完成"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"已通过面孔识别解锁。点按即可继续。"</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"已经过身份验证"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"使用 PIN 码"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"使用图案"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"如果您下次绘制的解锁图案仍然有误,您的工作资料及其相关数据将会被删除。"</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"如果您下次输入的 PIN 码仍然有误,您的工作资料及其相关数据将会被删除。"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"如果您下次输入的密码仍然有误,您的工作资料及其相关数据将会被删除。"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"错误次数过多。系统将删除此设备上的数据。"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"错误次数过多。系统将删除此用户。"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"错误次数过多。系统将删除此工作资料和相关数据。"</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"关闭"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"请触摸指纹传感器"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"指纹图标"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"无法识别人脸。请改用指纹。"</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 正在慢速充电 • 将于 <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>后充满"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 正在基座上充电 • 将于 <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>后充满"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切换用户"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"添加用户"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"新用户"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"要移除访客吗?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"此会话中的所有应用和数据都将被删除。"</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"移除"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"访客,欢迎回来!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"要继续您的会话吗?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"重新开始"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"是,继续"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"要添加新用户吗?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"当您添加新用户时,该用户必须设置自己的空间。\n\n任何用户均可为其他所有用户更新应用。"</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"已达到用户数上限"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">您最多可以添加 <xliff:g id="COUNT">%d</xliff:g> 位用户。</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"解锁设备即可使用"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"获取您的卡片时出现问题,请稍后重试"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"锁定屏幕设置"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"二维码"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"点按即可扫描"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"扫描二维码"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"工作资料"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"飞行模式"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"您在<xliff:g id="WHEN">%1$s</xliff:g>将不会听到下次闹钟响铃"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"滑动可查看更多结构"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"正在加载推荐内容"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"媒体"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"要隐藏此媒体会话吗?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"无法隐藏当前的媒体会话。"</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"关闭"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"隐藏"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"继续播放"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"设置"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"正在通过<xliff:g id="APP_LABEL">%3$s</xliff:g>播放<xliff:g id="ARTIST_NAME">%2$s</xliff:g>的《<xliff:g id="SONG_NAME">%1$s</xliff:g>》"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"若要在此设备上播放,请靠近“<xliff:g id="DEVICENAME">%1$s</xliff:g>”"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"正在“<xliff:g id="DEVICENAME">%1$s</xliff:g>”上播放"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"正在此手机上播放"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"出了点问题"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"无效,请检查应用"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"未找到"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"控件不可用"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"与新设备配对"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"如需投射此会话,请打开相关应用。"</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"未知应用"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"停止投射"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"版本号"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"已将版本号复制到剪贴板。"</string>
     <string name="basic_status" msgid="2315371112182658176">"开放式对话"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WLAN 已关闭"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"优先模式"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"闹钟已设置"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Google 助理访客模式已启用"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"摄像头和麦克风已关闭"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# 条通知}other{# 条通知}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 8600859..ee97575 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"系統使用者介面"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"要開啟「省電模式」嗎?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"剩餘 <xliff:g id="PERCENTAGE">%s</xliff:g> 電量。「省電模式」會開啟深色主題背景、限制背景活動,並延遲顯示通知。"</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"「省電模式」會開啟深色主題背景、限制背景活動,並延遲顯示通知。"</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"剩餘 <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"無法透過 USB 充電"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"使用裝置隨附的充電器"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"要開啟省電模式嗎?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"關於「省電模式」"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"開啟"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"開啟省電模式"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"開啟"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"不用了,謝謝"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"自動旋轉螢幕"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"要允許「<xliff:g id="APPLICATION">%1$s</xliff:g>」存取「<xliff:g id="USB_DEVICE">%2$s</xliff:g>」嗎?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"要允許「<xliff:g id="APPLICATION">%1$s</xliff:g>」存取「<xliff:g id="USB_DEVICE">%2$s</xliff:g>」嗎?\n此應用程式尚未獲授予錄音權限,但可透過此 USB 裝置記錄音訊。"</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"臉孔已經驗證"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"已確認"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"輕按 [確定] 以完成"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"您已使用面孔解鎖。按下即可繼續操作。"</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"驗證咗"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"使用 PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"使用圖案"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"如果您下次畫出錯誤的上鎖圖案,系統將會刪除工作設定檔和相關資料。"</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"如果您下次輸入錯誤的 PIN,系統將會刪除工作設定檔和相關資料。"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"如果您下次輸入錯誤的密碼,系統將會刪除工作設定檔和相關資料。"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"錯誤次數太多,系統將會刪除此裝置上的資料。"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"錯誤次數太多,系統將會刪除此使用者。"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"錯誤次數太多,系統將會刪除此工作設定檔和相關資料。"</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"關閉"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"請輕觸指紋感應器"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"指紋圖示"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"無法辨識面孔,請改用指紋完成驗證。"</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 慢速充電中 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>後充滿電"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 正在插座上充電 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>後充滿電"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切換使用者"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"加入使用者"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"新使用者"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"移除訪客?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會被刪除。"</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"移除"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"訪客您好,歡迎回來!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"您要繼續您的工作階段嗎?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"重新開始"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"是的,請繼續"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"新增使用者?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"新增的使用者需要自行設定個人空間。\n\n任何使用者均可為所有其他使用者更新應用程式。"</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"已達到使用者上限"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">您可以加入多達 <xliff:g id="COUNT">%d</xliff:g> 個使用者。</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"解鎖即可使用"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"擷取資訊卡時發生問題,請稍後再試。"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"上鎖畫面設定"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR 碼"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"輕按即可掃瞄"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"掃瞄 QR 碼"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"工作設定檔"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"飛行模式"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"您不會<xliff:g id="WHEN">%1$s</xliff:g>聽到鬧鐘"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"滑動以查看更多"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"正在載入建議"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"媒體"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"要隱藏此媒體工作階段嗎?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"無法隱藏目前的媒體工作階段。"</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"關閉"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"隱藏"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"繼續播放"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"設定"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"正在透過 <xliff:g id="APP_LABEL">%3$s</xliff:g> 播放 <xliff:g id="ARTIST_NAME">%2$s</xliff:g> 的《<xliff:g id="SONG_NAME">%1$s</xliff:g>》"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"如要在此裝置上播放,請靠近「<xliff:g id="DEVICENAME">%1$s</xliff:g>」"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"正在「<xliff:g id="DEVICENAME">%1$s</xliff:g>」上播放"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"正在此手機上播放"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"發生錯誤"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"已停用,請檢查應用程式"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"找不到"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"無法使用控制功能"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"配對新裝置"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"如要投放此工作階段,請開啟應用程式。"</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"不明應用程式"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"停止投放"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"版本號碼"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"版本號碼已複製到剪貼簿。"</string>
     <string name="basic_status" msgid="2315371112182658176">"開啟對話"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi 已關閉"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"優先模式"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"已設定鬧鐘"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"已啟用「Google 助理」訪客模式"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"相機和麥克風已關閉"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# 則通知}other{# 則通知}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 0206a9e..5257afe 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"系統 UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"要開啟省電模式嗎?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"電池電量還剩 <xliff:g id="PERCENTAGE">%s</xliff:g>。省電模式會開啟深色主題、限制背景活動,並延遲顯示通知。"</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"省電模式會開啟深色主題、限制背景活動,並延遲顯示通知。"</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"僅剩 <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"無法透過 USB 充電"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"使用裝置隨附的充電器"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"要開啟省電模式嗎?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"關於省電模式"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"開啟"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"開啟省電模式"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"開啟"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"不用了,謝謝"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"自動旋轉螢幕"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"要允許「<xliff:g id="APPLICATION">%1$s</xliff:g>」存取「<xliff:g id="USB_DEVICE">%2$s</xliff:g>」嗎?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"要允許「<xliff:g id="APPLICATION">%1$s</xliff:g>」存取「<xliff:g id="USB_DEVICE">%2$s</xliff:g>」嗎?\n這個應用程式未取得錄製權限,但可以透過這部 USB 裝置錄製音訊。"</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"臉孔驗證成功"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"確認完畢"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"輕觸 [確認] 完成驗證設定"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"你已用自己的臉解鎖裝置,按下即可繼續操作。"</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"已通過驗證"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"使用 PIN 碼"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"使用解鎖圖案"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"如果下次輸入的解鎖圖案仍不正確,系統將刪除你的工作資料夾和相關資料。"</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"如果下次輸入的 PIN 碼仍不正確,系統將刪除你的工作資料夾和相關資料。"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"如果下次輸入的密碼仍不正確,系統將刪除你的工作資料夾和相關資料。"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"錯誤次數過多,系統將刪除這部裝置中的資料。"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"錯誤次數過多,系統將刪除這位使用者。"</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"錯誤次數過多,系統將刪除這個工作資料夾和相關資料。"</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"關閉"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"請輕觸指紋感應器"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"指紋圖示"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"無法辨識臉孔,請改用指紋完成驗證。"</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 慢速充電中 • 將於 <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>後充飽"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 正在座架上充電 • 將於 <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>後充飽"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切換使用者"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"新增使用者"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"新使用者"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"移除訪客?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會遭到刪除。"</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"移除"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"訪客你好,歡迎回來!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"你要繼續這個工作階段嗎?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"重新開始"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"是,繼續"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"要新增使用者嗎?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"新增的使用者需要自行設定個人空間。\n\n任何使用者皆可為其他所有使用者更新應用程式。"</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"已達使用者數量上限"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="other">最多可新增 <xliff:g id="COUNT">%d</xliff:g> 位使用者。</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"解鎖即可使用"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"擷取卡片時發生問題,請稍後再試"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"螢幕鎖定設定"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR 圖碼"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"輕觸即可掃描"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"掃描 QR 圖碼"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"工作資料夾"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"飛航模式"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"你不會聽到下一個<xliff:g id="WHEN">%1$s</xliff:g> 的鬧鐘"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"滑動即可查看其他結構"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"正在載入建議控制項"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"媒體"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"要隱藏這個媒體工作階段嗎?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"無法隱藏目前的媒體工作階段。"</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"關閉"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"隱藏"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"繼續播放"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"設定"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"系統正透過「<xliff:g id="APP_LABEL">%3$s</xliff:g>」播放<xliff:g id="ARTIST_NAME">%2$s</xliff:g>的〈<xliff:g id="SONG_NAME">%1$s</xliff:g>〉"</string>
@@ -808,7 +796,8 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"如要在這部裝置上播放,請移到更靠近「<xliff:g id="DEVICENAME">%1$s</xliff:g>」的位置"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"正在「<xliff:g id="DEVICENAME">%1$s</xliff:g>」上播放"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"正在這支手機上播放"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"發生錯誤"</string>
+    <!-- no translation found for media_transfer_failed (7955354964610603723) -->
+    <skip />
     <string name="controls_error_timeout" msgid="794197289772728958">"無效,請查看應用程式"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"找不到控制項"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"無法使用控制項"</string>
@@ -827,6 +816,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"配對新裝置"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"如要投放這個工作階段,請開啟應用程式。"</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"不明的應用程式"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"停止投放"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"版本號碼"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"已將版本號碼複製到剪貼簿。"</string>
     <string name="basic_status" msgid="2315371112182658176">"開放式對話"</string>
@@ -916,8 +906,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi 已關閉"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"優先模式"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"鬧鐘設定成功"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"已啟用 Google 助理訪客模式"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"已關閉相機和麥克風"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# 則通知}other{# 則通知}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 98e7fc4..1a0f74bc 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -20,19 +20,17 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"Uhlelo lwe-UI"</string>
-    <!-- no translation found for battery_low_title (5319680173344341779) -->
-    <skip />
-    <!-- no translation found for battery_low_description (3282977755476423966) -->
-    <skip />
-    <!-- no translation found for battery_low_intro (5148725009653088790) -->
-    <skip />
+    <string name="battery_low_title" msgid="5319680173344341779">"Vula Isilondolozi Sebhethri?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Usele ngo-<xliff:g id="PERCENTAGE">%s</xliff:g> kwibhethri. Isilondolozi Sebhethri sivula itimu Emnyama, sikhawulela umsebenzi wangemuva, futhi sibambezele izaziso."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Isilondolozi Sebhethri sivula itimu Emnyama, sikhawulela umsebenzi wangemuva, futhi sibambezele izaziso."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> okusele"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Ayikwazi ukushaja nge-USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Sebenzisa ishaja eze nedivayisi yakho"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Vula isilondolozi sebhethri?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Mayelana nesilondolozi sebhethri"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Vula"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Vula isilondolozi sebhethri"</string>
+    <string name="battery_saver_start_action" msgid="8353766979886287140">"Vula"</string>
+    <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Cha ngiyabonga"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Ukuzulazula kweskrini okuzenzakalelayo"</string>
     <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Vumela i-<xliff:g id="APPLICATION">%1$s</xliff:g> ukufinyelela i-<xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Vumela i-<xliff:g id="APPLICATION">%1$s</xliff:g> ukuthi ifinyelele ku-<xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nLolu hlelo lokusebenza alunikeziwe imvume yokurekhoda kodwa lingathatha umsindo ngale divayisi ye-USB."</string>
@@ -133,8 +131,7 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Ubuso bufakazelwe ubuqiniso"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Kuqinisekisiwe"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Thepha okuthi Qinisekisa ukuze uqedele"</string>
-    <!-- no translation found for biometric_dialog_tap_confirm_with_face (1597899891472340950) -->
-    <skip />
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Ivulwe ngobuso bakho. Cindezela ukuze uqhubeke."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Kugunyaziwe"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Sebenzisa iphinikhodi"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Sebenzisa iphethini"</string>
@@ -154,10 +151,6 @@
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Uma ufaka iphethini engalungile kumzamo olandelayo, iphrofayela yakho yomsebenzi nedatha yayo izosuswa."</string>
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Uma ufaka iphinikhodi engalungile kumzamo olandelayo, iphrofayela yakho yomsebenzi nedatha yayo izosuswa."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Uma ufake iphasiwedi engalungile kumzamo olandelayo, iphrofayela yakho yomsebenzi nedatha yayo izosuswa."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Imizamo eminingi kakhulu engalungile. Le datha yedivayisi izosuswa."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Imizamo eminingi kakhulu engalungile. Lo msebenzisi uzosuswa."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Imizamo eminingi kakhulu engalungile. Le phrofayela yomsebenzi nedatha yayo kuzosuswa."</string>
-    <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Cashisa"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Thinta inzwa yesigxivizo zeminwe"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Isithonjana sezigxivizo zeminwe"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ayibazi ubuso. Sebenzisa izigxivizo zeminwe kunalokho."</string>
@@ -326,17 +319,12 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ishaja kancane • Izogcwala ngo-<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ukushaja Idokhi • Izogcwala ngo-<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Shintsha umsebenzisi"</string>
-    <string name="user_add_user" msgid="4336657383006913022">"Engeza umsebenzisi"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"Umsebenzisi omusha"</string>
-    <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Susa isivakashi?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Zonke izinhlelo zokusebenza nedatha kulesi sikhathi zizosuswa."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Susa"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Siyakwamukela futhi, sivakashi!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Ingabe ufuna ukuqhubeka ngesikhathi sakho?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Qala phansi"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Yebo, qhubeka"</string>
-    <string name="user_add_user_title" msgid="4172327541504825032">"Engeza umsebenzisi omusha?"</string>
-    <string name="user_add_user_message_short" msgid="2599370307878014791">"Uma ungeza umsebenzisi omusha, loyo muntu udinga ukusetha isikhala sakhe.\n\nNoma yimuphi umsebenzisi angabuyekeza izinhlelo zokusebenza kubo bonke abasebenzisi."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Kufinyelelwe kumkhawulo womsebenzisi"</string>
     <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
       <item quantity="one">Ungangeza kufikela kubasebenzisi abangu-<xliff:g id="COUNT">%d</xliff:g>.</item>
@@ -462,8 +450,7 @@
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Vula ukuze usebenzise"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Kube khona inkinga yokuthola amakhadi akho, sicela uzame futhi ngemuva kwesikhathi"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Amasethingi okukhiya isikrini"</string>
-    <string name="qr_code_scanner_title" msgid="5660820608548306581">"Ikhodi ye-QR"</string>
-    <string name="qr_code_scanner_description" msgid="7937603775306661863">"Thepha ukuze uskene"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skena ikhodi ye-QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Iphrofayela yomsebenzi"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Imodi yendiza"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Ngeke uzwe i-alamu yakho elandelayo ngo-<xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -788,9 +775,10 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swayipha ukuze ubone okuningi"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Ilayisha izincomo"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Imidiya"</string>
-    <string name="controls_media_close_session" msgid="1193000643003066508">"Fihla le seshini yemidiya?"</string>
+    <!-- no translation found for controls_media_close_session (4780485355795635052) -->
+    <skip />
     <string name="controls_media_active_session" msgid="3146882316024153337">"Iseshini yamanje yemidiya ayikwazi ukufihlwa."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Cashisa"</string>
+    <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Fihla"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Qalisa kabusha"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Izilungiselelo"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"I-<xliff:g id="SONG_NAME">%1$s</xliff:g> ka-<xliff:g id="ARTIST_NAME">%2$s</xliff:g> idlala kusuka ku-<xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
@@ -808,7 +796,7 @@
     <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Sondela eduze ne-<xliff:g id="DEVICENAME">%1$s</xliff:g> ukuze udlale lapha"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Idlala ku-<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Okudlala kule foni"</string>
-    <string name="media_transfer_failed" msgid="2640354446629980227">"Kukhona okungahambanga kahle"</string>
+    <string name="media_transfer_failed" msgid="7955354964610603723">"Kukhona okungahambanga kahle. Zama futhi."</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Akusebenzi, hlola uhlelo lokusebenza"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Ayitholakali"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Ukulawula akutholakali"</string>
@@ -827,6 +815,7 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Bhangqa idivayisi entsha"</string>
     <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Ukuze usakaze le seshini, sicela uvule i-app."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"I-app engaziwa"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Misa ukusakaza"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Yakha inombolo"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Yakha inombolo ekopishelwe kubhodi yokunamathisela."</string>
     <string name="basic_status" msgid="2315371112182658176">"Vula ingxoxo"</string>
@@ -916,8 +905,6 @@
     <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"I-Wi-Fi ayitholakali"</string>
     <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Imodi ebalulekile"</string>
     <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"I-alamu isethiwe"</string>
-    <string name="dream_overlay_status_bar_assistant_guest_mode_enabled" msgid="3715897096012469615">"Imodi yesivakashi somsizi inikwe amandla"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Ikhamera nemakrofoni kuvaliwe"</string>
-    <!-- no translation found for dream_overlay_status_bar_notification_indicator (8091389255691081711) -->
-    <skip />
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{Isaziso esingu-#}one{Izaziso ezingu-#}other{Izaziso ezingu-#}}"</string>
 </resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 1edaaad..49fc848 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -176,10 +176,12 @@
 
     <!-- media output dialog-->
     <color name="media_dialog_background" android:lstar="98">@color/material_dynamic_neutral90</color>
-    <color name="media_dialog_active_item_main_content">@color/material_dynamic_primary10</color>
-    <color name="media_dialog_inactive_item_main_content">@color/material_dynamic_primary40</color>
-    <color name="media_dialog_item_status">@color/material_dynamic_primary10</color>
+    <color name="media_dialog_item_main_content">@color/material_dynamic_primary20</color>
     <color name="media_dialog_item_background">@color/material_dynamic_secondary95</color>
+    <color name="media_dialog_connected_item_background">@color/material_dynamic_primary90</color>
+    <color name="media_dialog_seekbar_progress">@color/material_dynamic_secondary40</color>
+    <color name="media_dialog_button_background">@color/material_dynamic_primary40</color>
+    <color name="media_dialog_solid_button_text">@color/material_dynamic_neutral95</color>
 
     <!-- controls -->
     <color name="control_primary_text">#E6FFFFFF</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index a0a8768..d5331e8 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -556,6 +556,9 @@
     <!-- Whether to use the split 2-column notification shade -->
     <bool name="config_use_split_notification_shade">false</bool>
 
+    <!-- Whether we use large screen shade header which takes only one row compared to QS header -->
+    <bool name="config_use_large_screen_shade_header">false</bool>
+
     <!-- Whether notification header should never show section headers. -->
     <bool name="config_notification_never_show_section_headers">false</bool>
 
@@ -707,4 +710,18 @@
     <integer name="complicationFadeInMs">500</integer>
 
     <integer name="complicationRestoreMs">1000</integer>
+
+    <!-- Icons that don't show in a collapsed non-keyguard statusbar -->
+    <string-array name="config_collapsed_statusbar_icon_blocklist" translatable="false">
+        <item>@*android:string/status_bar_volume</item>
+        <item>@*android:string/status_bar_alarm_clock</item>
+        <item>@*android:string/status_bar_call_strength</item>
+    </string-array>
+
+    <!-- Icons that don't show in a collapsed statusbar on keyguard -->
+    <string-array name="config_keyguard_statusbar_icon_blocklist" translatable="false">
+        <item>@*android:string/status_bar_volume</item>
+        <item>@*android:string/status_bar_alarm_clock</item>
+        <item>@*android:string/status_bar_call_strength</item>
+    </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 512f916..f39b5ef 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -368,10 +368,12 @@
     <dimen name="match_parent">-1px</dimen>
 
     <!-- Height of status bar in split shade mode - visible only on large screens -->
-    <dimen name="split_shade_header_height">@*android:dimen/quick_qs_offset_height</dimen>
-    <dimen name="split_shade_header_min_height">@dimen/qs_header_row_min_height</dimen>
+    <dimen name="large_screen_shade_header_height">@*android:dimen/quick_qs_offset_height</dimen>
+    <dimen name="large_screen_shade_header_min_height">@dimen/qs_header_row_min_height</dimen>
 
-    <!-- The top margin of the panel that holds the list of notifications. -->
+    <!-- The top margin of the panel that holds the list of notifications.
+         On phones it's always 0dp but it's overridden in Car UI
+    -->
     <dimen name="notification_panel_margin_top">0dp</dimen>
 
     <!-- The minimum content height for the split shade NSSL.
@@ -941,6 +943,9 @@
     <!--  Three privacy items. This value must not be exceeded  -->
     <dimen name="ongoing_appops_chip_max_width">76dp</dimen>
     <dimen name="ongoing_appops_dot_diameter">6dp</dimen>
+    <dimen name="ongoing_appops_chip_min_animation_width">10dp</dimen>
+    <dimen name="ongoing_appops_chip_animation_in_status_bar_translation_x">15dp</dimen>
+    <dimen name="ongoing_appops_chip_animation_out_status_bar_translation_x">7dp</dimen>
     <!--  Total minimum padding to enforce to ensure that the dot can always show  -->
     <dimen name="ongoing_appops_dot_min_padding">20dp</dimen>
 
@@ -956,10 +961,7 @@
 
     <!-- Size of media cards in the QSPanel carousel -->
     <dimen name="qs_media_padding">16dp</dimen>
-    <dimen name="qs_media_album_size_small">72dp</dimen>
-    <dimen name="qs_media_album_size">84dp</dimen>
     <dimen name="qs_media_album_radius">14dp</dimen>
-    <dimen name="qs_media_album_device_padding">26dp</dimen>
     <dimen name="qs_media_info_margin">12dp</dimen>
     <dimen name="qs_media_info_spacing">8dp</dimen>
     <dimen name="qs_media_icon_size">20dp</dimen>
@@ -971,10 +973,7 @@
     <dimen name="qs_seamless_icon_size">12dp</dimen>
     <dimen name="qs_media_disabled_seekbar_height">1dp</dimen>
     <dimen name="qs_media_enabled_seekbar_height">2dp</dimen>
-    <dimen name="qs_media_enabled_seekbar_vertical_padding">28dp</dimen>
-    <dimen name="qs_media_disabled_seekbar_vertical_padding">29dp</dimen>
 
-    <!-- Sizes for alternate session-based layout -->
     <dimen name="qs_media_session_enabled_seekbar_vertical_padding">15dp</dimen>
     <dimen name="qs_media_session_disabled_seekbar_vertical_padding">16dp</dimen>
     <dimen name="qs_media_session_height_expanded">184dp</dimen>
@@ -1005,6 +1004,9 @@
     <!-- Media tap-to-transfer chip for receiver device -->
     <dimen name="media_ttt_chip_size_receiver">100dp</dimen>
     <dimen name="media_ttt_icon_size_receiver">95dp</dimen>
+    <!-- Since the generic icon isn't circular, we need to scale it down so it still fits within
+         the circular chip. -->
+    <dimen name="media_ttt_generic_icon_size_receiver">70dp</dimen>
 
     <!-- Window magnification -->
     <dimen name="magnification_border_drag_size">35dp</dimen>
@@ -1138,6 +1140,12 @@
          the shade (in alpha) -->
     <dimen name="lockscreen_shade_scrim_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
 
+    <!-- Distance that it takes in order for the notifications scrim fade in to start. -->
+    <dimen name="lockscreen_shade_notifications_scrim_transition_delay">0dp</dimen>
+
+    <!-- Distance that it takes for the notifications scrim to fully fade if after it started. -->
+    <dimen name="lockscreen_shade_notifications_scrim_transition_distance">@dimen/lockscreen_shade_scrim_transition_distance</dimen>
+
     <!-- Distance that the full shade transition takes in order for the keyguard content on
          NotificationPanelViewController to fully fade (e.g. Clock & Smartspace) -->
     <dimen name="lockscreen_shade_npvc_keyguard_content_alpha_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
@@ -1166,9 +1174,8 @@
          the shade -->
     <dimen name="lockscreen_shade_media_transition_distance">120dp</dimen>
 
-    <!-- Maximum overshoot for the topPadding of notifications when transitioning to the full
-         shade -->
-    <dimen name="lockscreen_shade_notification_movement">24dp</dimen>
+    <!-- Maximum over scroll amount for the shade when transition to the full shade. -->
+    <dimen name="lockscreen_shade_max_over_scroll_amount">24dp</dimen>
 
     <!-- Maximum overshoot for the pulse expansion -->
     <dimen name="pulse_expansion_max_top_overshoot">32dp</dimen>
@@ -1367,9 +1374,6 @@
     <dimen name="dream_overlay_status_icon_margin">8dp</dimen>
     <dimen name="dream_overlay_status_bar_icon_size">
         @*android:dimen/status_bar_system_icon_size</dimen>
-    <!-- Height of the area at the top of the dream overlay to allow dragging down the notifications
-         shade. -->
-    <dimen name="dream_overlay_notifications_drag_area_height">100dp</dimen>
     <dimen name="dream_overlay_camera_mic_off_indicator_size">8dp</dimen>
     <dimen name="dream_overlay_notification_indicator_size">6dp</dimen>
 
@@ -1379,6 +1383,7 @@
     <dimen name="dream_overlay_complication_weather_text_size">18sp</dimen>
     <dimen name="dream_overlay_complication_preview_text_size">36sp</dimen>
     <dimen name="dream_overlay_complication_preview_icon_padding">28dp</dimen>
+    <dimen name="dream_overlay_complication_shadow_padding">2dp</dimen>
 
     <!-- The position of the end guide, which dream overlay complications can align their start with
          if their end is aligned with the parent end. Represented as the percentage over from the
diff --git a/packages/SystemUI/res/values/integers.xml b/packages/SystemUI/res/values/integers.xml
index f0f7a19..3164ed1 100644
--- a/packages/SystemUI/res/values/integers.xml
+++ b/packages/SystemUI/res/values/integers.xml
@@ -25,4 +25,7 @@
          See com.android.systemui.volume.VolumeDialogImpl.
          Value 21 corresponds to RIGHT|CENTER_VERTICAL. -->
     <integer name="volume_dialog_gravity">21</integer>
+
+    <!-- The time it takes for the over scroll release animation to complete, in milli seconds.  -->
+    <integer name="lockscreen_shade_over_scroll_release_duration">0</integer>
 </resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 9f2f1c1..d3b76d9 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -368,15 +368,6 @@
     <!-- Content of a dialog shown when the user only has one attempt left to provide the correct password before the work profile is removed. [CHAR LIMIT=NONE] -->
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile">If you enter an incorrect password on the next attempt, your work profile and its data will be deleted.</string>
 
-    <!-- Content of a dialog shown when the user has failed to provide the device lock too many times and the device is wiped. [CHAR LIMIT=NONE] -->
-    <string name="biometric_dialog_failed_attempts_now_wiping_device">Too many incorrect attempts. This device\u2019s data will be deleted.</string>
-    <!-- Content of a dialog shown when the user has failed to provide the user lock too many times and the user is removed. [CHAR LIMIT=NONE] -->
-    <string name="biometric_dialog_failed_attempts_now_wiping_user">Too many incorrect attempts. This user will be deleted.</string>
-    <!-- Content of a dialog shown when the user has failed to provide the work lock too many times and the work profile is removed. [CHAR LIMIT=NONE] -->
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile">Too many incorrect attempts. This work profile and its data will be deleted.</string>
-    <!-- Button label to dismiss the dialog telling the user the device, user, or work profile has been wiped. [CHAR LIMIT=40] -->
-    <string name="biometric_dialog_now_wiping_dialog_dismiss">Dismiss</string>
-
     <!-- Message shown when the system-provided fingerprint dialog is shown, asking for authentication -->
     <string name="fingerprint_dialog_touch_sensor">Touch the fingerprint sensor</string>
     <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -831,15 +822,6 @@
 
     <!-- Accessibility label for the button that opens the quick contact of the user. -->
 
-    <!-- Label for the adding a new user in the user switcher [CHAR LIMIT=35] -->
-    <string name="user_add_user">Add user</string>
-
-    <!-- Name for a freshly added user [CHAR LIMIT=30] -->
-    <string name="user_new_user_name">New user</string>
-
-    <!-- Title of the confirmation dialog when exiting guest session [CHAR LIMIT=NONE] -->
-    <string name="guest_exit_guest_dialog_title">Remove guest?</string>
-
     <!-- Message of the confirmation dialog when exiting guest session [CHAR LIMIT=NONE] -->
     <string name="guest_exit_guest_dialog_message">All apps and data in this session will be deleted.</string>
 
@@ -858,12 +840,6 @@
     <!-- Notification when resuming an existing guest session: Action that continues with the current session [CHAR LIMIT=35] -->
     <string name="guest_wipe_session_dontwipe">Yes, continue</string>
 
-    <!-- Title for add user confirmation dialog [CHAR LIMIT=30] -->
-    <string name="user_add_user_title" msgid="2108112641783146007">Add new user?</string>
-
-    <!-- Message for add user confirmation dialog - short version. [CHAR LIMIT=none] -->
-    <string name="user_add_user_message_short" msgid="1511354412249044381">When you add a new user, that person needs to set up their space.\n\nAny user can update apps for all other users. </string>
-
     <!-- Title for the dialog that lets users know that the maximum allowed number of users on the device has been reached. [CHAR LIMIT=35]-->
     <string name="user_limit_reached_title">User limit reached</string>
 
@@ -1193,10 +1169,7 @@
     <string name="wallet_lockscreen_settings_label">Lock screen settings</string>
 
     <!-- QR Code Scanner label, title [CHAR LIMIT=32] -->
-    <string name="qr_code_scanner_title">QR code</string>
-
-    <!-- QR Code Scanner description [CHAR LIMIT=NONE] -->
-    <string name="qr_code_scanner_description">Tap to scan</string>
+    <string name="qr_code_scanner_title">Scan QR code</string>
 
     <!-- Name of the work status bar icon. -->
     <string name="status_bar_work">Work profile</string>
@@ -2143,11 +2116,11 @@
     <!-- Title for media controls [CHAR_LIMIT=50] -->
     <string name="controls_media_title">Media</string>
     <!-- Explanation for closing controls associated with a specific media session [CHAR_LIMIT=50] -->
-    <string name="controls_media_close_session">Hide this media session?</string>
+    <string name="controls_media_close_session">Hide this media control for <xliff:g id="app_name" example="YouTube Music">%1$s</xliff:g>?</string>
     <!-- Explanation that controls associated with a specific media session are active [CHAR_LIMIT=50] -->
     <string name="controls_media_active_session">The current media session cannot be hidden.</string>
     <!-- Label for a button that will hide media controls [CHAR_LIMIT=30] -->
-    <string name="controls_media_dismiss_button">Dismiss</string>
+    <string name="controls_media_dismiss_button">Hide</string>
     <!-- Label for button to resume media playback [CHAR_LIMIT=NONE] -->
     <string name="controls_media_resume">Resume</string>
     <!-- Label for button to go to media control settings screen [CHAR_LIMIT=30] -->
@@ -2187,7 +2160,7 @@
     <!-- Text informing the user that their media is now playing on this device. [CHAR LIMIT=50] -->
     <string name="media_transfer_playing_this_device">Playing on this phone</string>
     <!-- Text informing the user that the media transfer has failed because something went wrong. [CHAR LIMIT=50] -->
-    <string name="media_transfer_failed">Something went wrong</string>
+    <string name="media_transfer_failed">Something went wrong. Try again.</string>
 
     <!-- Error message indicating that a control timed out while waiting for an update [CHAR_LIMIT=30] -->
     <string name="controls_error_timeout">Inactive, check app</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 3ae21e0..4776587 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -486,7 +486,7 @@
 
     <style name="MediaOutputItemInactiveTitle">
         <item name="android:textSize">16sp</item>
-        <item name="android:textColor">@color/media_dialog_inactive_item_main_content</item>
+        <item name="android:textColor">@color/media_dialog_item_main_content</item>
     </style>
 
     <style name="TunerSettings" parent="@android:style/Theme.DeviceDefault.Settings">
@@ -616,7 +616,6 @@
            parent="@android:style/Widget.Material.Button.Borderless.Small">
         <item name="android:background">@drawable/qs_media_light_source</item>
         <item name="android:tint">?android:attr/textColorPrimary</item>
-        <item name="android:stateListAnimator">@anim/media_button_state_list_animator</item>
         <item name="android:paddingTop">12dp</item>
         <item name="android:paddingStart">12dp</item>
         <item name="android:paddingEnd">12dp</item>
@@ -629,8 +628,12 @@
         <item name="android:backgroundTint">@color/media_player_solid_button_bg</item>
     </style>
 
+    <style name="MediaPlayer.SessionAction.Secondary" parent="MediaPlayer.SessionAction">
+        <item name="android:stateListAnimator">@anim/media_button_state_list_animator</item>
+    </style>
+
     <style name="MediaPlayer.OutlineButton">
-        <item name="android:background">@drawable/qs_media_button_background</item>
+        <item name="android:background">@drawable/qs_media_outline_button</item>
         <item name="android:textColor">?android:attr/textColorPrimary</item>
         <item name="android:backgroundTint">@color/media_player_outline_button_bg</item>
         <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
diff --git a/packages/SystemUI/res/xml/combined_qs_header_scene.xml b/packages/SystemUI/res/xml/combined_qs_header_scene.xml
index 91607d2..0e83326 100644
--- a/packages/SystemUI/res/xml/combined_qs_header_scene.xml
+++ b/packages/SystemUI/res/xml/combined_qs_header_scene.xml
@@ -43,9 +43,9 @@
     </Transition>
 
     <Transition
-        android:id="@+id/split_header_transition"
-        app:constraintSetStart="@id/split_header_constraint"
-        app:constraintSetEnd="@id/split_header_constraint"/>
+        android:id="@+id/large_screen_header_transition"
+        app:constraintSetStart="@id/large_screen_header_constraint"
+        app:constraintSetEnd="@id/large_screen_header_constraint"/>
 
     <!--
         Placeholder ConstraintSet. They are populated in the controller for this class.
@@ -56,6 +56,6 @@
 
     <ConstraintSet android:id="@id/qs_header_constraint"/>
 
-    <ConstraintSet android:id="@id/split_header_constraint" />
+    <ConstraintSet android:id="@id/large_screen_header_constraint" />
 
 </MotionScene>
diff --git a/packages/SystemUI/res/xml/split_header.xml b/packages/SystemUI/res/xml/large_screen_shade_header.xml
similarity index 94%
rename from packages/SystemUI/res/xml/split_header.xml
rename to packages/SystemUI/res/xml/large_screen_shade_header.xml
index 03401b3..8909051 100644
--- a/packages/SystemUI/res/xml/split_header.xml
+++ b/packages/SystemUI/res/xml/large_screen_shade_header.xml
@@ -18,7 +18,7 @@
 <ConstraintSet
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/split_header_constraint">
+    android:id="@+id/large_screen_header_constraint">
 
     <Constraint
         android:id="@+id/clock">
@@ -58,7 +58,7 @@
         <Layout
             android:layout_width="wrap_content"
             android:layout_height="0dp"
-            app:layout_constraintHeight_min="@dimen/split_shade_header_min_height"
+            app:layout_constraintHeight_min="@dimen/large_screen_shade_header_min_height"
             app:layout_constraintStart_toEndOf="@id/statusIcons"
             app:layout_constraintEnd_toStartOf="@id/privacy_container"
             app:layout_constraintTop_toTopOf="@id/clock"
diff --git a/packages/SystemUI/res/xml/media_collapsed.xml b/packages/SystemUI/res/xml/media_collapsed.xml
deleted file mode 100644
index 12e446f..0000000
--- a/packages/SystemUI/res/xml/media_collapsed.xml
+++ /dev/null
@@ -1,176 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2020 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
-  -->
-<ConstraintSet
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto">
-    <Constraint
-        android:id="@+id/icon"
-        android:layout_width="@dimen/qs_media_icon_size"
-        android:layout_height="@dimen/qs_media_icon_size"
-        android:translationY="@dimen/qs_media_icon_offset"
-        android:translationX="@dimen/qs_media_icon_offset"
-        app:layout_constraintEnd_toEndOf="@id/album_art"
-        app:layout_constraintBottom_toBottomOf="@id/album_art"
-        />
-
-    <Constraint
-        android:id="@+id/media_seamless"
-        android:layout_width="wrap_content"
-        android:layout_height="48dp"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintStart_toEndOf="@id/center_vertical_guideline"
-        app:layout_constraintBottom_toTopOf="@id/center_horizontal_guideline"
-        app:layout_constraintHorizontal_chainStyle="spread_inside"
-        app:layout_constraintHorizontal_bias="1"
-        app:layout_constrainedWidth="true"
-        app:layout_constraintWidth_min="48dp"
-        app:layout_constraintHeight_min="48dp"
-        android:layout_marginStart="@dimen/qs_center_guideline_padding"
-        />
-
-    <Constraint
-        android:id="@+id/album_art"
-        android:layout_width="@dimen/qs_media_album_size_small"
-        android:layout_height="@dimen/qs_media_album_size_small"
-        android:layout_marginTop="@dimen/qs_media_padding"
-        android:layout_marginStart="@dimen/qs_media_padding"
-        android:layout_marginBottom="@dimen/qs_media_padding"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintBottom_toBottomOf="parent"
-        />
-
-    <!-- Song name -->
-    <Constraint
-        android:id="@+id/header_title"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="@dimen/qs_media_info_margin"
-        android:layout_marginEnd="@dimen/qs_center_guideline_padding"
-        app:layout_constrainedWidth="true"
-        app:layout_constraintBottom_toTopOf="@id/center_horizontal_guideline"
-        app:layout_constraintStart_toEndOf="@id/album_art"
-        app:layout_constraintEnd_toStartOf="@id/center_vertical_guideline"
-        app:layout_constraintHorizontal_bias="0"/>
-
-    <!-- Artist name -->
-    <Constraint
-        android:id="@+id/header_artist"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        app:layout_constrainedWidth="true"
-        android:layout_marginTop="@dimen/qs_media_info_spacing"
-        app:layout_constraintTop_toBottomOf="@id/center_horizontal_guideline"
-        app:layout_constraintStart_toStartOf="@id/header_title"
-        app:layout_constraintEnd_toStartOf="@id/media_action_barrier"
-        app:layout_constraintHorizontal_bias="0"/>
-
-    <!-- Seek Bar -->
-    <Constraint
-        android:id="@+id/media_progress_bar"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:alpha="0.0"
-        app:layout_constraintTop_toBottomOf="@id/album_art"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        android:visibility="gone"
-        />
-
-    <Constraint
-        android:id="@+id/notification_media_progress_time"
-        android:alpha="0.0"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        app:layout_constraintTop_toBottomOf="@id/album_art"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        android:visibility="gone"
-        />
-
-    <Constraint
-        android:id="@+id/action0"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:layout_marginStart="@dimen/qs_media_padding"
-        android:layout_marginEnd="@dimen/qs_media_action_spacing"
-        android:visibility="gone"
-        app:layout_constraintHorizontal_chainStyle="packed"
-        app:layout_constraintTop_toBottomOf="@id/center_horizontal_guideline"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintLeft_toLeftOf="parent"
-        app:layout_constraintRight_toLeftOf="@id/action1"
-        app:layout_constraintHorizontal_bias="1"
-        >
-    </Constraint>
-
-    <Constraint
-        android:id="@+id/action1"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:layout_marginStart="@dimen/qs_media_action_spacing"
-        android:layout_marginEnd="@dimen/qs_media_action_spacing"
-        app:layout_constraintTop_toBottomOf="@id/center_horizontal_guideline"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintLeft_toRightOf="@id/action0"
-        app:layout_constraintRight_toLeftOf="@id/action2"
-        >
-    </Constraint>
-
-    <Constraint
-        android:id="@+id/action2"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:layout_marginStart="@dimen/qs_media_action_spacing"
-        android:layout_marginEnd="@dimen/qs_media_action_spacing"
-        app:layout_constraintTop_toBottomOf="@id/center_horizontal_guideline"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintLeft_toRightOf="@id/action1"
-        app:layout_constraintRight_toLeftOf="@id/action3"
-        >
-    </Constraint>
-
-    <Constraint
-        android:id="@+id/action3"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:layout_marginStart="@dimen/qs_media_action_spacing"
-        android:layout_marginEnd="@dimen/qs_media_action_spacing"
-        app:layout_constraintTop_toBottomOf="@id/center_horizontal_guideline"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintLeft_toRightOf="@id/action2"
-        app:layout_constraintRight_toLeftOf="@id/action4"
-        >
-    </Constraint>
-
-    <Constraint
-        android:id="@+id/action4"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:layout_marginStart="@dimen/qs_media_action_spacing"
-        android:layout_marginEnd="@dimen/qs_media_padding"
-        android:visibility="gone"
-        app:layout_constraintHorizontal_chainStyle="packed"
-        app:layout_constraintTop_toBottomOf="@id/center_horizontal_guideline"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintLeft_toRightOf="@id/action3"
-        app:layout_constraintRight_toRightOf="parent"
-        app:layout_constraintHorizontal_bias="0"
-        >
-    </Constraint>
-</ConstraintSet>
diff --git a/packages/SystemUI/res/xml/media_expanded.xml b/packages/SystemUI/res/xml/media_expanded.xml
deleted file mode 100644
index 6b83aae..0000000
--- a/packages/SystemUI/res/xml/media_expanded.xml
+++ /dev/null
@@ -1,174 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2020 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
-  -->
-<ConstraintSet
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto">
-    <Constraint
-        android:id="@+id/icon"
-        android:layout_width="@dimen/qs_media_icon_size"
-        android:layout_height="@dimen/qs_media_icon_size"
-        android:translationY="@dimen/qs_media_icon_offset"
-        android:translationX="@dimen/qs_media_icon_offset"
-        app:layout_constraintEnd_toEndOf="@id/album_art"
-        app:layout_constraintBottom_toBottomOf="@id/album_art"
-    />
-
-    <Constraint
-        android:id="@+id/media_seamless"
-        android:layout_width="wrap_content"
-        android:layout_height="48dp"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintStart_toEndOf="@id/center_vertical_guideline"
-        app:layout_constraintHorizontal_chainStyle="spread_inside"
-        app:layout_constraintHorizontal_bias="1"
-        app:layout_constrainedWidth="true"
-        app:layout_constraintWidth_min="48dp"
-        app:layout_constraintHeight_min="48dp"
-        android:paddingTop="@dimen/qs_media_padding"
-        android:paddingEnd="@dimen/qs_media_padding"
-        android:layout_marginStart="@dimen/qs_center_guideline_padding"
-        android:layout_marginBottom="4dp" />
-
-    <Constraint
-        android:id="@+id/album_art"
-        android:layout_width="@dimen/qs_media_album_size"
-        android:layout_height="@dimen/qs_media_album_size"
-        android:layout_marginTop="@dimen/qs_media_padding"
-        android:layout_marginStart="@dimen/qs_media_padding"
-        android:layout_marginBottom="0dp"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        />
-
-    <!-- Song name -->
-    <Constraint
-        android:id="@+id/header_title"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="26dp"
-        android:layout_marginStart="@dimen/qs_media_info_margin"
-        android:layout_marginEnd="@dimen/qs_media_padding"
-        app:layout_constrainedWidth="true"
-        app:layout_constraintTop_toTopOf="@+id/album_art"
-        app:layout_constraintStart_toEndOf="@id/album_art"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0"/>
-
-    <!-- Artist name -->
-    <Constraint
-        android:id="@+id/header_artist"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginEnd="@dimen/qs_media_padding"
-        android:layout_marginBottom="@dimen/qs_media_info_margin"
-        app:layout_constrainedWidth="true"
-        android:layout_marginTop="1dp"
-        app:layout_constraintTop_toBottomOf="@id/header_title"
-        app:layout_constraintStart_toStartOf="@id/header_title"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="0"/>
-
-    <!-- Seek Bar -->
-    <Constraint
-        android:id="@+id/media_progress_bar"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="34dp"
-        app:layout_constraintTop_toBottomOf="@id/center_horizontal_guideline"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        />
-
-    <Constraint
-        android:id="@+id/notification_media_progress_time"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginEnd="@dimen/qs_media_padding"
-        android:layout_marginStart="@dimen/qs_media_padding"
-        app:layout_constraintTop_toBottomOf="@id/media_progress_bar"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        />
-
-    <Constraint
-        android:id="@+id/action0"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:layout_marginStart="@dimen/qs_media_padding"
-        android:layout_marginEnd="@dimen/qs_media_action_spacing"
-        android:layout_marginBottom="@dimen/qs_media_action_margin"
-        app:layout_constraintHorizontal_chainStyle="packed"
-        app:layout_constraintLeft_toLeftOf="parent"
-        app:layout_constraintRight_toLeftOf="@id/action1"
-        app:layout_constraintTop_toBottomOf="@id/media_progress_bar"
-        app:layout_constraintBottom_toBottomOf="parent">
-    </Constraint>
-
-    <Constraint
-        android:id="@+id/action1"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:layout_marginStart="@dimen/qs_media_action_spacing"
-        android:layout_marginEnd="@dimen/qs_media_action_spacing"
-        android:layout_marginBottom="@dimen/qs_media_action_margin"
-        app:layout_constraintLeft_toRightOf="@id/action0"
-        app:layout_constraintRight_toLeftOf="@id/action2"
-        app:layout_constraintTop_toBottomOf="@id/media_progress_bar"
-        app:layout_constraintBottom_toBottomOf="parent">
-    </Constraint>
-
-    <Constraint
-        android:id="@+id/action2"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:layout_marginStart="@dimen/qs_media_action_spacing"
-        android:layout_marginEnd="@dimen/qs_media_action_spacing"
-        android:layout_marginBottom="@dimen/qs_media_action_margin"
-        app:layout_constraintLeft_toRightOf="@id/action1"
-        app:layout_constraintRight_toLeftOf="@id/action3"
-        app:layout_constraintTop_toBottomOf="@id/media_progress_bar"
-        app:layout_constraintBottom_toBottomOf="parent">
-    </Constraint>
-
-    <Constraint
-        android:id="@+id/action3"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:layout_marginStart="@dimen/qs_media_action_spacing"
-        android:layout_marginEnd="@dimen/qs_media_action_spacing"
-        android:layout_marginBottom="@dimen/qs_media_action_margin"
-        app:layout_constraintLeft_toRightOf="@id/action2"
-        app:layout_constraintRight_toLeftOf="@id/action4"
-        app:layout_constraintTop_toBottomOf="@id/media_progress_bar"
-        app:layout_constraintBottom_toBottomOf="parent">
-    </Constraint>
-
-    <Constraint
-        android:id="@+id/action4"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:layout_marginStart="@dimen/qs_media_action_spacing"
-        android:layout_marginEnd="@dimen/qs_media_padding"
-        android:layout_marginBottom="@dimen/qs_media_action_margin"
-        app:layout_constraintHorizontal_chainStyle="packed"
-        app:layout_constraintLeft_toRightOf="@id/action3"
-        app:layout_constraintRight_toRightOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/media_progress_bar"
-        app:layout_constraintBottom_toBottomOf="parent">
-    </Constraint>
-</ConstraintSet>
diff --git a/packages/SystemUI/res/xml/media_session_expanded.xml b/packages/SystemUI/res/xml/media_session_expanded.xml
index 10da704..bec4e7a 100644
--- a/packages/SystemUI/res/xml/media_session_expanded.xml
+++ b/packages/SystemUI/res/xml/media_session_expanded.xml
@@ -31,25 +31,24 @@
         android:id="@+id/header_title"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginTop="20dp"
         android:layout_marginStart="@dimen/qs_media_padding"
         android:layout_marginEnd="@dimen/qs_media_padding"
         app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
         app:layout_constrainedWidth="true"
-        app:layout_constraintTop_toBottomOf="@id/icon"
         app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintBottom_toTopOf="@id/header_artist"
         app:layout_constraintHorizontal_bias="0" />
     <Constraint
         android:id="@+id/header_artist"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginEnd="@dimen/qs_media_padding"
+        android:layout_marginBottom="@dimen/qs_media_padding"
         android:layout_marginTop="0dp"
         app:layout_constrainedWidth="true"
         app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
-        app:layout_constraintBottom_toTopOf="@id/media_action_barrier"
-        app:layout_constraintTop_toBottomOf="@id/header_title"
         app:layout_constraintStart_toStartOf="@id/header_title"
+        app:layout_constraintBottom_toTopOf="@id/media_action_barrier_top"
         app:layout_constraintVertical_bias="0"
         app:layout_constraintHorizontal_bias="0" />
 
@@ -59,10 +58,9 @@
         android:layout_height="48dp"
         android:layout_marginStart="@dimen/qs_media_padding"
         android:layout_marginEnd="@dimen/qs_media_padding"
-        android:layout_marginBottom="0dp"
+        android:layout_marginBottom="@dimen/qs_media_padding"
         app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/media_seamless"
-        app:layout_constraintBottom_toBottomOf="@id/header_artist" />
+        app:layout_constraintBottom_toTopOf="@id/media_action_barrier_top" />
 
     <!--
     The bottom row of action buttons should remain in the same order when RTL, so their constraints
@@ -76,7 +74,6 @@
         app:layout_constraintLeft_toLeftOf="parent"
         app:layout_constraintRight_toLeftOf="@id/media_progress_bar"
         app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/header_artist"
         app:layout_constraintHorizontal_chainStyle="spread" />
 
     <Constraint
@@ -86,7 +83,6 @@
         app:layout_constraintLeft_toRightOf="@id/actionPrev"
         app:layout_constraintRight_toLeftOf="@id/actionNext"
         app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/header_artist"
         app:layout_constraintHorizontal_weight="1" />
 
     <Constraint
@@ -95,8 +91,7 @@
         android:layout_height="48dp"
         app:layout_constraintLeft_toRightOf="@id/media_progress_bar"
         app:layout_constraintRight_toLeftOf="@id/action0"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/header_artist" />
+        app:layout_constraintBottom_toBottomOf="parent" />
 
     <Constraint
         android:id="@+id/action0"
@@ -104,8 +99,7 @@
         android:layout_height="48dp"
         app:layout_constraintLeft_toRightOf="@id/actionNext"
         app:layout_constraintRight_toLeftOf="@id/action1"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/header_artist" />
+        app:layout_constraintBottom_toBottomOf="parent" />
 
     <Constraint
         android:id="@+id/action1"
@@ -113,8 +107,7 @@
         android:layout_height="48dp"
         app:layout_constraintLeft_toRightOf="@id/action0"
         app:layout_constraintRight_toLeftOf="@id/action2"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/header_artist" />
+        app:layout_constraintBottom_toBottomOf="parent" />
 
     <Constraint
         android:id="@+id/action2"
@@ -122,8 +115,7 @@
         android:layout_height="48dp"
         app:layout_constraintLeft_toRightOf="@id/action1"
         app:layout_constraintRight_toLeftOf="@id/action3"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/header_artist" />
+        app:layout_constraintBottom_toBottomOf="parent"/>
 
     <Constraint
         android:id="@+id/action3"
@@ -131,8 +123,7 @@
         android:layout_height="48dp"
         app:layout_constraintLeft_toRightOf="@id/action2"
         app:layout_constraintRight_toLeftOf="@id/action4"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/header_artist" />
+        app:layout_constraintBottom_toBottomOf="parent"/>
 
     <Constraint
         android:id="@+id/action4"
@@ -140,6 +131,5 @@
         android:layout_height="48dp"
         app:layout_constraintLeft_toRightOf="@id/action3"
         app:layout_constraintRight_toRightOf="parent"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/header_artist" />
+        app:layout_constraintBottom_toBottomOf="parent" />
 </ConstraintSet>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt b/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt
index 6ad9161..19a5309 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt
@@ -24,6 +24,7 @@
 
 interface Flag<T> {
     val id: Int
+    val teamfood: Boolean
 }
 
 interface ParcelableFlag<T> : Flag<T>, Parcelable {
@@ -44,7 +45,8 @@
 
 data class BooleanFlag @JvmOverloads constructor(
     override val id: Int,
-    override val default: Boolean = false
+    override val default: Boolean = false,
+    override val teamfood: Boolean = false
 ) : ParcelableFlag<Boolean> {
 
     companion object {
@@ -66,20 +68,25 @@
     }
 }
 
-data class ResourceBooleanFlag constructor(
+data class ResourceBooleanFlag @JvmOverloads constructor(
     override val id: Int,
-    @BoolRes override val resourceId: Int
+    @BoolRes override val resourceId: Int,
+    override val teamfood: Boolean = false
 ) : ResourceFlag<Boolean>
 
-data class SysPropBooleanFlag constructor(
+data class SysPropBooleanFlag @JvmOverloads constructor(
     override val id: Int,
     override val name: String,
     override val default: Boolean = false
-) : SysPropFlag<Boolean>
+) : SysPropFlag<Boolean> {
+    // TODO(b/223379190): Teamfood not supported for sysprop flags yet.
+    override val teamfood: Boolean = false
+}
 
 data class StringFlag @JvmOverloads constructor(
     override val id: Int,
-    override val default: String = ""
+    override val default: String = "",
+    override val teamfood: Boolean = false
 ) : ParcelableFlag<String> {
     companion object {
         @JvmField
@@ -100,14 +107,16 @@
     }
 }
 
-data class ResourceStringFlag constructor(
+data class ResourceStringFlag @JvmOverloads constructor(
     override val id: Int,
-    @StringRes override val resourceId: Int
+    @StringRes override val resourceId: Int,
+    override val teamfood: Boolean = false
 ) : ResourceFlag<String>
 
 data class IntFlag @JvmOverloads constructor(
     override val id: Int,
-    override val default: Int = 0
+    override val default: Int = 0,
+    override val teamfood: Boolean = false
 ) : ParcelableFlag<Int> {
 
     companion object {
@@ -129,14 +138,16 @@
     }
 }
 
-data class ResourceIntFlag constructor(
+data class ResourceIntFlag @JvmOverloads constructor(
     override val id: Int,
-    @IntegerRes override val resourceId: Int
+    @IntegerRes override val resourceId: Int,
+    override val teamfood: Boolean = false
 ) : ResourceFlag<Int>
 
 data class LongFlag @JvmOverloads constructor(
     override val id: Int,
-    override val default: Long = 0
+    override val default: Long = 0,
+    override val teamfood: Boolean = false
 ) : ParcelableFlag<Long> {
 
     companion object {
@@ -160,7 +171,8 @@
 
 data class FloatFlag @JvmOverloads constructor(
     override val id: Int,
-    override val default: Float = 0f
+    override val default: Float = 0f,
+    override val teamfood: Boolean = false
 ) : ParcelableFlag<Float> {
 
     companion object {
@@ -182,14 +194,16 @@
     }
 }
 
-data class ResourceFloatFlag constructor(
+data class ResourceFloatFlag @JvmOverloads constructor(
     override val id: Int,
-    override val resourceId: Int
+    override val resourceId: Int,
+    override val teamfood: Boolean = false
 ) : ResourceFlag<Int>
 
 data class DoubleFlag @JvmOverloads constructor(
     override val id: Int,
-    override val default: Double = 0.0
+    override val default: Double = 0.0,
+    override val teamfood: Boolean = false
 ) : ParcelableFlag<Double> {
 
     companion object {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt b/packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt
index 149f6e8..26e40e1 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt
@@ -64,7 +64,7 @@
         intent.setPackage(RECEIVING_PACKAGE)
 
         return CallbackToFutureAdapter.getFuture {
-            completer: CallbackToFutureAdapter.Completer<Any?> ->
+            completer: CallbackToFutureAdapter.Completer<Collection<Flag<*>>> ->
                 context.sendOrderedBroadcast(intent, null,
                     object : BroadcastReceiver() {
                         override fun onReceive(context: Context, intent: Intent) {
@@ -79,7 +79,7 @@
                         }
                     }, null, Activity.RESULT_OK, "extra data", null)
             "QueryingFlags"
-        } as ListenableFuture<Collection<Flag<*>>>
+        }
     }
 
     /**
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
index db62f88..e38d2ba 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
@@ -17,36 +17,22 @@
 package com.android.systemui.shared.system;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 
 import android.app.ActivityOptions;
 import android.content.Context;
 import android.os.Handler;
 
-import com.android.systemui.shared.recents.model.Task;
-
 /**
  * Wrapper around internal ActivityOptions creation.
  */
 public abstract class ActivityOptionsCompat {
 
     /**
+     * @Deprecated
      * @return ActivityOptions for starting a task in split screen as the primary window.
      */
     public static ActivityOptions makeSplitScreenOptions(boolean dockTopLeft) {
-        return makeSplitScreenOptions(dockTopLeft, true);
-    }
-
-    /**
-     * @return ActivityOptions for starting a task in split screen.
-     */
-    public static ActivityOptions makeSplitScreenOptions(boolean dockTopLeft, boolean isPrimary) {
-        final ActivityOptions options = ActivityOptions.makeBasic();
-        options.setLaunchWindowingMode(isPrimary
-                ? WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
-                : WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
-        return options;
+        return ActivityOptions.makeBasic();
     }
 
     /**
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index c9a659a..9cf482f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -32,6 +32,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.util.ArrayMap;
+import android.util.IntArray;
 import android.util.SparseArray;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
@@ -269,6 +270,7 @@
             SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) {
         final ArrayList<RemoteAnimationTargetCompat> out = new ArrayList<>();
         final SparseArray<RemoteAnimationTargetCompat> childTaskTargets = new SparseArray<>();
+        final IntArray excludedParentTaskIds = new IntArray();
         for (int i = 0; i < info.getChanges().size(); i++) {
             final TransitionInfo.Change change = info.getChanges().get(i);
             final boolean changeIsWallpaper =
@@ -282,22 +284,40 @@
             }
             final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
             if (taskInfo != null) {
-                if (taskInfo.parentTaskId != -1) {
-                    // Cache child task targets to override its parent target later and exclude
-                    // child task while wrapping up animate targets. Otherwise the child task might
-                    // get transformed twice with the flow like RecentsView#redrawLiveTile.
-                    childTaskTargets.put(taskInfo.parentTaskId, targetCompat);
+                // Skip wrapping excluded parent task animate target since it will animate its child
+                // tasks instead.
+                if (excludedParentTaskIds.binarySearch(taskInfo.taskId) != -1) {
                     continue;
                 }
 
-                final RemoteAnimationTargetCompat childTaskTarget =
-                        childTaskTargets.get(taskInfo.taskId);
+                // Check if there's a matching child task target in cache.
+                RemoteAnimationTargetCompat childTaskTarget = childTaskTargets.get(taskInfo.taskId);
                 if (childTaskTarget != null) {
-                    // Launcher monitors leaf tasks to perform animation, hence override the parent
-                    // task target with child task info so Launcher can locate and animate root
-                    // surface directly with leaf task information.
+                    // Launcher monitors leaf task ids to perform animation, override the target
+                    // with its child task information so Launcher can animate this parent surface
+                    // directly with leaf task information.
                     targetCompat.taskInfo = childTaskTarget.taskInfo;
                     targetCompat.taskId = childTaskTarget.taskId;
+                    childTaskTargets.remove(taskInfo.taskId);
+                }
+
+                // Check if it has a parent task, cache its information for later use.
+                if (taskInfo.parentTaskId != -1
+                        && excludedParentTaskIds.binarySearch(taskInfo.parentTaskId) == -1) {
+                    if (!childTaskTargets.contains(taskInfo.parentTaskId)) {
+                        // Cache the target amd skip wrapping it info the final animation targets.
+                        // Otherwise, the child task might get transformed multiple-times with the
+                        // flow like RecentsView#redrawLiveTile.
+                        childTaskTargets.put(taskInfo.parentTaskId, targetCompat);
+                        continue;
+                    }
+
+                    // There is another child task target cached with the same parent task id.
+                    // Which means the parent having multiple child tasks in transition. Stop
+                    // propagate child task info.
+                    childTaskTarget = childTaskTargets.removeReturnOld(taskInfo.parentTaskId);
+                    out.add(childTaskTarget);
+                    excludedParentTaskIds.add(taskInfo.parentTaskId);
                 }
             }
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index b61827a..51001a7 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -331,13 +331,12 @@
             }
             if (mWrapped != null) mWrapped.finish(toHome, sendUserLeaveHint);
             final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-            final WindowContainerTransaction wct;
+            final WindowContainerTransaction wct = new WindowContainerTransaction();
 
             if (!toHome && mPausingTasks != null && mOpeningLeashes == null) {
                 // The gesture went back to opening the app rather than continuing with
                 // recents, so end the transition by moving the app back to the top (and also
                 // re-showing it's task).
-                wct = new WindowContainerTransaction();
                 for (int i = mPausingTasks.size() - 1; i >= 0; --i) {
                     // reverse order so that index 0 ends up on top
                     wct.reorder(mPausingTasks.get(i), true /* onTop */);
@@ -347,8 +346,14 @@
                     wct.restoreTransientOrder(mRecentsTask);
                 }
             } else {
-                wct = null;
-                if (mPipTask != null && mPipTransaction != null) {
+                if (!sendUserLeaveHint) {
+                    for (int i = 0; i < mPausingTasks.size(); ++i) {
+                        // This means recents is not *actually* finishing, so of course we gotta
+                        // do special stuff in WMCore to accommodate.
+                        wct.setDoNotPip(mPausingTasks.get(i));
+                    }
+                }
+                if (mPipTask != null && mPipTransaction != null && sendUserLeaveHint) {
                     t.show(mInfo.getChange(mPipTask).getLeash());
                     PictureInPictureSurfaceTransaction.apply(mPipTransaction,
                             mInfo.getChange(mPipTask).getLeash(), t);
@@ -363,7 +368,7 @@
                 t.remove(mLeashMap.valueAt(i));
             }
             try {
-                mFinishCB.onTransitionFinished(wct, t);
+                mFinishCB.onTransitionFinished(wct.isEmpty() ? null : wct, t);
             } catch (RemoteException e) {
                 Log.e("RemoteTransitionCompat", "Failed to call animation finish callback", e);
                 t.apply();
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
index 85d5de0..32299f5 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
@@ -78,10 +78,6 @@
     public static final int WINDOWING_MODE_MULTI_WINDOW =
             WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 
-    public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY =
-            WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-    public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY =
-            WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
     public static final int WINDOWING_MODE_FREEFORM = WindowConfiguration.WINDOWING_MODE_FREEFORM;
 
     public static final int ITYPE_EXTRA_NAVIGATION_BAR = InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
index 15593ea..9e5aeb8 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.unfold
 
+import android.app.ActivityManager
 import android.content.ContentResolver
 import android.content.Context
 import android.hardware.SensorManager
@@ -51,6 +52,7 @@
             @BindsInstance config: UnfoldTransitionConfig,
             @BindsInstance screenStatusProvider: ScreenStatusProvider,
             @BindsInstance deviceStateManager: DeviceStateManager,
+            @BindsInstance activityManager: ActivityManager,
             @BindsInstance sensorManager: SensorManager,
             @BindsInstance @Main handler: Handler,
             @BindsInstance @Main executor: Executor,
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
index 8e4ff9b..cc56007c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
@@ -17,6 +17,7 @@
 
 package com.android.systemui.unfold
 
+import android.app.ActivityManager
 import android.content.Context
 import android.hardware.SensorManager
 import android.hardware.devicestate.DeviceStateManager
@@ -39,6 +40,7 @@
     config: UnfoldTransitionConfig,
     screenStatusProvider: ScreenStatusProvider,
     deviceStateManager: DeviceStateManager,
+    activityManager: ActivityManager,
     sensorManager: SensorManager,
     mainHandler: Handler,
     mainExecutor: Executor,
@@ -51,6 +53,7 @@
             config,
             screenStatusProvider,
             deviceStateManager,
+            activityManager,
             sensorManager,
             mainHandler,
             mainExecutor,
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
index 5266f09..3daae75 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
@@ -33,7 +33,7 @@
 import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdatesListener
 
 /** Maps fold updates to unfold transition progress using DynamicAnimation. */
-internal class PhysicsBasedUnfoldTransitionProgressProvider(
+class PhysicsBasedUnfoldTransitionProgressProvider(
     private val foldStateProvider: FoldStateProvider
 ) : UnfoldTransitionProgressProvider, FoldUpdatesListener, DynamicAnimation.OnAnimationEndListener {
 
@@ -97,7 +97,17 @@
             FOLD_UPDATE_START_CLOSING -> {
                 // The transition might be already running as the device might start closing several
                 // times before reaching an end state.
-                if (!isTransitionRunning) {
+                if (isTransitionRunning) {
+                    // If we are cancelling the animation, reset that so we can resume it normally.
+                    // The animation could be 'cancelled' when the user stops folding/unfolding
+                    // for some period of time or fully unfolds the device. In this case,
+                    // it is forced to run to the end ignoring all further hinge angle events.
+                    // By resetting this flag we allow reacting to hinge angle events again, so
+                    // the transition continues running.
+                    if (isAnimatedCancelRunning) {
+                        isAnimatedCancelRunning = false
+                    }
+                } else {
                     startTransition(startValue = 1f)
                 }
             }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
index 24ecf87..eb1181d9 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
@@ -16,6 +16,8 @@
 package com.android.systemui.unfold.updates
 
 import android.annotation.FloatRange
+import android.app.ActivityManager
+import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME
 import android.content.Context
 import android.hardware.devicestate.DeviceStateManager
 import android.os.Handler
@@ -39,6 +41,7 @@
     private val hingeAngleProvider: HingeAngleProvider,
     private val screenStatusProvider: ScreenStatusProvider,
     private val deviceStateManager: DeviceStateManager,
+    private val activityManager: ActivityManager,
     @Main private val mainExecutor: Executor,
     @Main private val handler: Handler
 ) : FoldStateProvider {
@@ -92,10 +95,12 @@
         }
 
         val isClosing = angle < lastHingeAngle
+        val closingThreshold = getClosingThreshold()
+        val closingThresholdMet = closingThreshold == null || angle < closingThreshold
         val isFullyOpened = FULLY_OPEN_DEGREES - angle < FULLY_OPEN_THRESHOLD_DEGREES
         val closingEventDispatched = lastFoldUpdate == FOLD_UPDATE_START_CLOSING
 
-        if (isClosing && !closingEventDispatched && !isFullyOpened) {
+        if (isClosing && closingThresholdMet && !closingEventDispatched && !isFullyOpened) {
             notifyFoldUpdate(FOLD_UPDATE_START_CLOSING)
         }
 
@@ -113,6 +118,33 @@
         outputListeners.forEach { it.onHingeAngleUpdate(angle) }
     }
 
+    /**
+     * Fold animation should be started only after the threshold returned here.
+     *
+     * This has been introduced because the fold animation might be distracting/unwanted on top of
+     * apps that support table-top/HALF_FOLDED mode. Only for launcher, there is no threshold.
+     */
+    private fun getClosingThreshold(): Int? {
+        val activityType =
+            activityManager
+                .getRunningTasks(/* maxNum= */ 1)
+                ?.getOrNull(0)
+                ?.configuration
+                ?.windowConfiguration
+                ?.activityType
+                ?: return null
+
+        if (DEBUG) {
+            Log.d(TAG, "activityType=" + activityType)
+        }
+
+        return if (activityType == ACTIVITY_TYPE_HOME) {
+            null
+        } else {
+            START_CLOSING_ON_APPS_THRESHOLD_DEGREES
+        }
+    }
+
     private inner class FoldStateListener(context: Context) :
         DeviceStateManager.FoldStateListener(
             context,
@@ -199,7 +231,10 @@
  * Time after which [FOLD_UPDATE_FINISH_HALF_OPEN] is emitted following a
  * [FOLD_UPDATE_START_CLOSING] or [FOLD_UPDATE_START_OPENING] event, if an end state is not reached.
  */
-@VisibleForTesting const val HALF_OPENED_TIMEOUT_MILLIS = 1000L
+@VisibleForTesting const val HALF_OPENED_TIMEOUT_MILLIS = 600L
 
 /** Threshold after which we consider the device fully unfolded. */
 @VisibleForTesting const val FULLY_OPEN_THRESHOLD_DEGREES = 15f
+
+/** Fold animation on top of apps only when the angle exceeds this threshold. */
+@VisibleForTesting const val START_CLOSING_ON_APPS_THRESHOLD_DEGREES = 60
diff --git a/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
index adfc872..2560284 100644
--- a/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
+++ b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
@@ -19,11 +19,12 @@
 import android.content.Context
 import android.os.Handler
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.flags.FeatureFlagsDebug.ALL_FLAGS
 import com.android.systemui.util.settings.SettingsUtilModule
 import dagger.Binds
 import dagger.Module
 import dagger.Provides
-import java.util.function.Supplier
+import javax.inject.Named
 
 @Module(includes = [
     SettingsUtilModule::class
@@ -42,6 +43,7 @@
 
         @JvmStatic
         @Provides
-        fun providesFlagCollector(): Supplier<Map<Int, Flag<*>>>? = null
+        @Named(ALL_FLAGS)
+        fun providesAllFlags(): Map<Int, Flag<*>> = Flags.collectFlags()
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/BouncerPanelExpansionCalculator.kt b/packages/SystemUI/src/com/android/keyguard/BouncerPanelExpansionCalculator.kt
new file mode 100644
index 0000000..497d81f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/BouncerPanelExpansionCalculator.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.keyguard
+
+import android.util.MathUtils
+
+object BouncerPanelExpansionCalculator {
+    /**
+     *  Scale the alpha/position of the host view.
+     */
+    @JvmStatic
+    fun getHostViewScaledExpansion(fraction: Float): Float {
+        return when {
+                    fraction >= 0.9f -> 1f
+                    fraction < 0.6 -> 0f
+                    else -> (fraction - 0.6f) / 0.3f
+                }
+    }
+
+    /**
+     *  Scale the alpha/tint of the back scrim.
+     */
+    @JvmStatic
+    fun getBackScrimScaledExpansion(fraction: Float): Float {
+        return MathUtils.constrain((fraction - 0.9f) / 0.1f, 0f, 1f)
+    }
+
+    /**
+     *  This will scale the alpha/position of the clock.
+     */
+    @JvmStatic
+    fun getKeyguardClockScaledExpansion(fraction: Float): Float {
+        return MathUtils.constrain((fraction - 0.7f) / 0.3f, 0f, 1f)
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
index ffd1546..458d22e 100644
--- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
@@ -96,7 +96,7 @@
      **/
     public void reloadColors() {
         int color = Utils.getColorAttrDefaultColor(getContext(),
-                android.R.attr.textColorPrimaryInverse);
+                com.android.internal.R.attr.textColorOnAccent);
         setTextColor(color);
         setBackground(getContext()
                 .getDrawable(com.android.systemui.R.drawable.kg_emergency_button_background));
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index d02b875..b18abf3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -76,8 +76,7 @@
     // Cause a VIRTUAL_KEY vibration
     public void doHapticKeyClick() {
         performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
-                HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
-                | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
+                HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
     }
 
     public void setKeyDownListener(KeyDownListener keyDownListener) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
index b691096..8c3e066 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
@@ -37,7 +37,6 @@
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
 import com.android.systemui.util.ViewController;
 
 import java.io.File;
@@ -64,6 +63,7 @@
 
     private ActivityStarter.OnDismissAction mDismissAction;
     private Runnable mCancelAction;
+    private int mTranslationY;
 
     private final KeyguardUpdateMonitorCallback mUpdateCallback =
             new KeyguardUpdateMonitorCallback() {
@@ -322,12 +322,14 @@
 
     /**
      * Fades and translates in/out the security screen.
+     * Fades in as expansion approaches 0.
+     * Animation duration is between 0.33f and 0.67f of panel expansion fraction.
      * @param fraction amount of the screen that should show.
      */
     public void setExpansion(float fraction) {
-        float alpha = MathUtils.map(KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1, 1, 0, fraction);
-        mView.setAlpha(MathUtils.constrain(alpha, 0f, 1f));
-        mView.setTranslationY(fraction * mView.getHeight());
+        float scaledFraction = BouncerPanelExpansionCalculator.getHostViewScaledExpansion(fraction);
+        mView.setAlpha(MathUtils.constrain(1 - scaledFraction, 0f, 1f));
+        mView.setTranslationY(scaledFraction * mTranslationY);
     }
 
     /**
@@ -490,6 +492,8 @@
             gravity = resources.getInteger(R.integer.keyguard_host_view_gravity);
         }
 
+        mTranslationY = resources
+                .getDimensionPixelSize(R.dimen.keyguard_host_view_translation_y);
         // Android SysUI uses a FrameLayout as the top-level, but Auto uses RelativeLayout.
         // We're just changing the gravity here though (which can't be applied to RelativeLayout),
         // so only attempt the update if mView is inside a FrameLayout.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
index 75579b0..5ab2fd0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
@@ -57,7 +57,7 @@
     private ColorStateList mDefaultColorState;
     private CharSequence mMessage;
     private ColorStateList mNextMessageColorState = ColorStateList.valueOf(DEFAULT_COLOR);
-    private boolean mBouncerVisible;
+    private boolean mBouncerShowing;
     private boolean mAltBouncerShowing;
     /**
      * Container that wraps the KeyguardMessageArea - may be null if current view hierarchy doesn't
@@ -177,7 +177,7 @@
 
     void update() {
         CharSequence status = mMessage;
-        setVisibility(TextUtils.isEmpty(status) || (!mBouncerVisible && !mAltBouncerShowing)
+        setVisibility(TextUtils.isEmpty(status) || (!mBouncerShowing && !mAltBouncerShowing)
                 ? INVISIBLE : VISIBLE);
         setText(status);
         ColorStateList colorState = mDefaultColorState;
@@ -192,8 +192,14 @@
         setTextColor(colorState);
     }
 
-    public void setBouncerVisible(boolean bouncerVisible) {
-        mBouncerVisible = bouncerVisible;
+    /**
+     * Set whether the bouncer is fully showing
+     */
+    public void setBouncerShowing(boolean bouncerShowing) {
+        if (mBouncerShowing != bouncerShowing) {
+            mBouncerShowing = bouncerShowing;
+            update();
+        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
index 05318bb..81cc3a9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
@@ -39,12 +39,6 @@
         public void onStartedWakingUp() {
             mView.setSelected(true);
         }
-
-        @Override
-        public void onKeyguardBouncerChanged(boolean bouncer) {
-            mView.setBouncerVisible(bouncer);
-            mView.update();
-        }
     };
 
     private ConfigurationListener mConfigurationListener = new ConfigurationListener() {
@@ -94,6 +88,13 @@
         mView.setAltBouncerShowing(showing);
     }
 
+    /**
+     * Set bouncer is fully showing
+     */
+    public void setBouncerShowing(boolean showing) {
+        mView.setBouncerShowing(showing);
+    }
+
     public void setMessage(CharSequence s) {
         mView.setMessage(s);
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index 1efda7e..77044ed 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -188,14 +188,13 @@
 
         enableClipping(false);
         setTranslationY(0);
-        AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */, 280 /* duration */,
-                mDisappearYTranslation, mDisappearAnimationUtils.getInterpolator(),
-                getAnimationListener(InteractionJankMonitor.CUJ_LOCKSCREEN_PIN_DISAPPEAR));
         DisappearAnimationUtils disappearAnimationUtils = needsSlowUnlockTransition
                         ? mDisappearAnimationUtilsLocked
                         : mDisappearAnimationUtils;
-        disappearAnimationUtils.startAnimation2d(mViews,
-                () -> {
+        disappearAnimationUtils.createAnimation(
+                this, 0, 200, mDisappearYTranslation, false,
+                mDisappearAnimationUtils.getInterpolator(), () -> {
+                    getAnimationListener(InteractionJankMonitor.CUJ_LOCKSCREEN_PIN_DISAPPEAR);
                     enableClipping(true);
                     if (finishRunnable != null) {
                         finishRunnable.run();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
index 28f21af..0529cdbc 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
@@ -183,7 +183,7 @@
     @Override
     void resetState() {
         mPasswordEntry.setTextOperationUser(UserHandle.of(KeyguardUpdateMonitor.getCurrentUser()));
-        mMessageAreaController.setMessage(R.string.keyguard_enter_your_password);
+        mMessageAreaController.setMessage("");
         final boolean wasDisabled = mPasswordEntry.isEnabled();
         mView.setPasswordEntryEnabled(true);
         mView.setPasswordEntryInputEnabled(true);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index 7635f919..41f9240 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -358,7 +358,7 @@
     }
 
     private void displayDefaultSecurityMessage() {
-        mMessageAreaController.setMessage(R.string.keyguard_enter_your_pattern);
+        mMessageAreaController.setMessage("");
     }
 
     private void handleAttemptLockout(long elapsedRealtimeDeadline) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
index cc7e4f7..f7423ed 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
@@ -132,7 +132,6 @@
     @Override
     void resetState() {
         mView.setPasswordEntryEnabled(true);
-        mMessageAreaController.setMessage(R.string.keyguard_enter_your_pin);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
index 160d82a..9f4585f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
@@ -76,6 +76,12 @@
     }
 
     @Override
+    void resetState() {
+        super.resetState();
+        mMessageAreaController.setMessage("");
+    }
+
+    @Override
     public boolean startDisappearAnimation(Runnable finishRunnable) {
         return mView.startDisappearAnimation(
                 mKeyguardUpdateMonitor.needsSlowUnlockTransition(), finishRunnable);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 362fbed..3103219 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -152,6 +152,7 @@
     private SwipeListener mSwipeListener;
     private ViewMode mViewMode = new DefaultViewMode();
     private @Mode int mCurrentMode = MODE_DEFAULT;
+    private int mWidth = -1;
 
     private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback =
             new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {
@@ -306,8 +307,6 @@
     void onResume(SecurityMode securityMode, boolean faceAuthEnabled) {
         mSecurityViewFlipper.setWindowInsetsAnimationCallback(mWindowInsetsAnimationCallback);
         updateBiometricRetry(securityMode, faceAuthEnabled);
-
-        setupViewMode();
     }
 
     void initMode(@Mode int mode, GlobalSettings globalSettings, FalsingManager falsingManager,
@@ -649,9 +648,11 @@
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
 
-        // After a layout pass, we need to re-place the inner bouncer, as our bounds may have
-        // changed.
-        mViewMode.updateSecurityViewLocation();
+        int width = right - left;
+        if (changed && mWidth != width) {
+            mWidth = width;
+            mViewMode.updateSecurityViewLocation();
+        }
     }
 
     @Override
@@ -1041,11 +1042,13 @@
 
         /**
          * Moves the bouncer to align with a tap (most likely in the shade), so the bouncer
-         * appears on the same side as a touch. Will not update the user-preference.
+         * appears on the same side as a touch.
          */
         @Override
         public void updatePositionByTouchX(float x) {
-            updateSecurityViewLocation(x <= mView.getWidth() / 2f, /* animate= */false);
+            boolean isTouchOnLeft = x <= mView.getWidth() / 2f;
+            updateSideSetting(isTouchOnLeft);
+            updateSecurityViewLocation(isTouchOnLeft, /* animate= */false);
         }
 
         boolean isLeftAligned() {
@@ -1054,6 +1057,13 @@
                 == Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT;
         }
 
+        private void updateSideSetting(boolean leftAligned) {
+            mGlobalSettings.putInt(
+                    Settings.Global.ONE_HANDED_KEYGUARD_SIDE,
+                    leftAligned ? Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT
+                    : Settings.Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT);
+        }
+
         /**
          * Determine if a tap on this view is on the other side. If so, will animate positions
          * and record the preference to always show on this side.
@@ -1067,10 +1077,7 @@
                     || (!currentlyLeftAligned && (x < mView.getWidth() / 2f))) {
 
                 boolean willBeLeftAligned = !currentlyLeftAligned;
-                mGlobalSettings.putInt(
-                        Settings.Global.ONE_HANDED_KEYGUARD_SIDE,
-                        willBeLeftAligned ? Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT
-                        : Settings.Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT);
+                updateSideSetting(willBeLeftAligned);
 
                 int keyguardState = willBeLeftAligned
                         ? SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__SWITCH_LEFT
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 57997d8..1a325d3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -233,6 +233,13 @@
                     mSecurityViewFlipperController.reloadColors();
                 }
             };
+    private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
+            new KeyguardUpdateMonitorCallback() {
+        @Override
+        public void onDevicePolicyManagerStateChanged() {
+            showPrimarySecurityScreen(false);
+        }
+    };
 
     private KeyguardSecurityContainerController(KeyguardSecurityContainer view,
             AdminSecondaryLockScreenController.Factory adminSecondaryLockScreenControllerFactory,
@@ -279,6 +286,7 @@
 
     @Override
     protected void onViewAttached() {
+        mUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
         mView.setSwipeListener(mSwipeListener);
         mView.addMotionEventListener(mGlobalTouchListener);
         mConfigurationController.addCallback(mConfigurationListener);
@@ -286,6 +294,7 @@
 
     @Override
     protected void onViewDetached() {
+        mUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
         mConfigurationController.removeCallback(mConfigurationListener);
         mView.removeMotionEventListener(mGlobalTouchListener);
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 31f466f..087817f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -113,6 +113,22 @@
         }
     }
 
+    /** Sets a translationY value on every child view except for the media view. */
+    public void setChildrenTranslationYExcludingMediaView(float translationY) {
+        setChildrenTranslationYExcluding(translationY, Set.of(mMediaHostContainer));
+    }
+
+    /** Sets a translationY value on every view except for the views in the provided set. */
+    private void setChildrenTranslationYExcluding(float translationY, Set<View> excludedViews) {
+        for (int i = 0; i < mStatusViewContainer.getChildCount(); i++) {
+            final View child = mStatusViewContainer.getChildAt(i);
+
+            if (!excludedViews.contains(child)) {
+                child.setTranslationY(translationY);
+            }
+        }
+    }
+
     public float getChildrenAlphaExcludingSmartSpace() {
         return mChildrenAlphaExcludingSmartSpace;
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index af3da9f..14c9cb2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -137,6 +137,13 @@
     }
 
     /**
+     * Sets a translationY on the views on the keyguard, except on the media view.
+     */
+    public void setTranslationYExcludingMedia(float translationY) {
+        mView.setChildrenTranslationYExcludingMediaView(translationY);
+    }
+
+    /**
      * Set keyguard status view alpha.
      */
     public void setAlpha(float alpha) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 1ef6dea..fcabbbc 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -326,7 +326,6 @@
     private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
     private final Executor mBackgroundExecutor;
     private SensorPrivacyManager mSensorPrivacyManager;
-    private int mFaceAuthUserId;
 
     /**
      * Short delay before restarting fingerprint authentication after a successful try. This should
@@ -1030,8 +1029,8 @@
         boolean cameraPrivacyEnabled = false;
         if (mSensorPrivacyManager != null) {
             cameraPrivacyEnabled = mSensorPrivacyManager
-                    .isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA,
-                    mFaceAuthUserId);
+                    .isSensorPrivacyEnabled(SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE,
+                    SensorPrivacyManager.Sensors.CAMERA);
         }
 
         if (msgId == FaceManager.FACE_ERROR_CANCELED
@@ -1487,6 +1486,10 @@
                 @Override
                 public void onAuthenticationFailed() {
                     handleFingerprintAuthFailed();
+
+                    // TODO(b/225231929): Refactor as needed, add tests, etc.
+                    mTrustManager.reportUserRequestedUnlock(
+                            KeyguardUpdateMonitor.getCurrentUser(), true);
                 }
 
                 @Override
@@ -1498,17 +1501,23 @@
 
                 @Override
                 public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
+                    Trace.beginSection("KeyguardUpdateMonitor#onAuthenticationHelp");
                     handleFingerprintHelp(helpMsgId, helpString.toString());
+                    Trace.endSection();
                 }
 
                 @Override
                 public void onAuthenticationError(int errMsgId, CharSequence errString) {
+                    Trace.beginSection("KeyguardUpdateMonitor#onAuthenticationError");
                     handleFingerprintError(errMsgId, errString.toString());
+                    Trace.endSection();
                 }
 
                 @Override
                 public void onAuthenticationAcquired(int acquireInfo) {
+                    Trace.beginSection("KeyguardUpdateMonitor#onAuthenticationAcquired");
                     handleFingerprintAcquired(acquireInfo);
+                    Trace.endSection();
                 }
 
                 @Override
@@ -2259,7 +2268,8 @@
         }
 
         if (shouldTriggerActiveUnlock()) {
-            mTrustManager.reportUserRequestedUnlock(KeyguardUpdateMonitor.getCurrentUser());
+            // TODO(b/225231929): Refactor surrounding code to reflect calling of new method
+            mTrustManager.reportUserMayRequestUnlock(KeyguardUpdateMonitor.getCurrentUser());
         }
     }
 
@@ -2599,7 +2609,6 @@
             // This would need to be updated for multi-sensor devices
             final boolean supportsFaceDetection = !mFaceSensorProperties.isEmpty()
                     && mFaceSensorProperties.get(0).supportsFaceDetection;
-            mFaceAuthUserId = userId;
             if (isEncryptedOrLockdown(userId) && supportsFaceDetection) {
                 mFaceManager.detectFace(mFaceCancelSignal, mFaceDetectionCallback, userId);
             } else {
@@ -2714,12 +2723,20 @@
     }
 
     /**
-     * Handle {@link #MSG_DPM_STATE_CHANGED}
+     * Handle {@link #MSG_DPM_STATE_CHANGED} which can change primary authentication methods to
+     * pin/pattern/password/none.
      */
     private void handleDevicePolicyManagerStateChanged(int userId) {
         Assert.isMainThread();
         updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
         updateSecondaryLockscreenRequirement(userId);
+
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onDevicePolicyManagerStateChanged();
+            }
+        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index ad2053c..9373ea8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -300,6 +300,11 @@
     public void onSecondaryLockscreenRequirementChanged(int userId) { }
 
     /**
+     * Called when device policy manager state changes.
+     */
+    public void onDevicePolicyManagerStateChanged() { }
+
+    /**
      * Called when notifying user to unlock in order to use NFC.
      */
     public void onRequireUnlockForNfc() { }
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 370686a..a4a0105f 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -211,6 +211,18 @@
         mDownDetected = false;
         updateBurnInOffsets();
         updateVisibility();
+
+        mAccessibilityManager.addTouchExplorationStateChangeListener(
+                mTouchExplorationStateChangeListener);
+        updateAccessibility();
+    }
+
+    private void updateAccessibility() {
+        if (mAccessibilityManager.isTouchExplorationEnabled()) {
+            mView.setOnClickListener(mA11yClickListener);
+        } else {
+            mView.setOnClickListener(null);
+        }
     }
 
     @Override
@@ -225,6 +237,9 @@
             mCancelDelayedUpdateVisibilityRunnable.run();
             mCancelDelayedUpdateVisibilityRunnable = null;
         }
+
+        mAccessibilityManager.removeTouchExplorationStateChangeListener(
+                mTouchExplorationStateChangeListener);
     }
 
     public float getTop() {
@@ -250,7 +265,6 @@
             return;
         }
 
-        boolean wasShowingUnlock = mShowUnlockIcon;
         boolean wasShowingFpIcon = mUdfpsEnrolled && !mShowUnlockIcon && !mShowLockIcon
                 && !mShowAodUnlockedIcon && !mShowAodLockIcon;
         mShowLockIcon = !mCanDismissLockScreen && !mUserUnlockedWithBiometric && isLockScreen()
@@ -558,7 +572,7 @@
         switch(event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN:
             case MotionEvent.ACTION_HOVER_ENTER:
-                if (!mDownDetected) {
+                if (!mDownDetected && mAccessibilityManager.isTouchExplorationEnabled()) {
                     mVibrator.vibrate(
                             Process.myUid(),
                             getContext().getOpPackageName(),
@@ -685,6 +699,14 @@
         mView.setAlpha(alpha);
     }
 
+    private void updateUdfpsConfig() {
+        // must be called from the main thread since it may update the views
+        mExecutor.execute(() -> {
+            updateIsUdfpsEnrolled();
+            updateConfiguration();
+        });
+    }
+
     private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() {
         @Override
         public void onAllAuthenticatorsRegistered() {
@@ -697,11 +719,8 @@
         }
     };
 
-    private void updateUdfpsConfig() {
-        // must be called from the main thread since it may update the views
-        mExecutor.execute(() -> {
-            updateIsUdfpsEnrolled();
-            updateConfiguration();
-        });
-    }
+    private final View.OnClickListener mA11yClickListener = v -> onLongPress();
+
+    private final AccessibilityManager.TouchExplorationStateChangeListener
+            mTouchExplorationStateChangeListener = enabled -> updateAccessibility();
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
index e0d0fc2..7b98f27 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
@@ -19,6 +19,8 @@
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
 import android.graphics.drawable.VectorDrawable;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
@@ -37,8 +39,14 @@
     public NumPadButton(Context context, AttributeSet attrs) {
         super(context, attrs);
 
-        mAnimator = new NumPadAnimator(context, getBackground().mutate(),
-                attrs.getStyleAttribute());
+        Drawable background = getBackground();
+        if (background instanceof GradientDrawable) {
+            mAnimator = new NumPadAnimator(context, background.mutate(),
+                    attrs.getStyleAttribute());
+        } else {
+            mAnimator = null;
+        }
+
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index 88a0bce..f771c97 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -18,6 +18,8 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.util.AttributeSet;
@@ -129,8 +131,13 @@
 
         setContentDescription(mDigitText.getText().toString());
 
-        mAnimator = new NumPadAnimator(context, getBackground().mutate(),
-                R.style.NumPadKey, mDigitText);
+        Drawable background = getBackground();
+        if (background instanceof GradientDrawable) {
+            mAnimator = new NumPadAnimator(context, background.mutate(),
+                    R.style.NumPadKey, mDigitText);
+        } else {
+            mAnimator = null;
+        }
     }
 
     @Override
@@ -212,7 +219,6 @@
     // Cause a VIRTUAL_KEY vibration
     public void doHapticKeyClick() {
         performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
-                HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
-                | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
+                HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
index 5bd620e..7af6f66 100644
--- a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
@@ -16,6 +16,7 @@
 
 import android.app.PendingIntent;
 import android.content.Intent;
+import android.os.UserHandle;
 import android.view.View;
 
 import androidx.annotation.Nullable;
@@ -100,6 +101,15 @@
     }
 
     @Override
+    public void startActivity(Intent intent, boolean dismissShade,
+            @Nullable ActivityLaunchAnimator.Controller animationController,
+            boolean showOverLockscreenWhenLocked, UserHandle userHandle) {
+        mActualStarterOptionalLazy.get().ifPresent(
+                starter -> starter.startActivity(intent, dismissShade, animationController,
+                    showOverLockscreenWhenLocked, userHandle));
+    }
+
+    @Override
     public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade) {
         mActualStarterOptionalLazy.get().ifPresent(
                 starter -> starter.startActivity(intent, onlyProvisioned, dismissShade));
diff --git a/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
index 56046d9..ccb5b11 100644
--- a/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
+++ b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
@@ -79,6 +79,8 @@
     override fun onAttachedToWindow() {
         super.onAttachedToWindow()
         updateCutout()
+        updateProtectionBoundingPath()
+        onUpdate()
     }
 
     fun onDisplayChanged(displayId: Int) {
@@ -93,6 +95,7 @@
         if (displayId == display.displayId) {
             updateCutout()
             updateProtectionBoundingPath()
+            onUpdate()
         }
     }
 
@@ -100,8 +103,13 @@
         displayRotation = rotation
         updateCutout()
         updateProtectionBoundingPath()
+        onUpdate()
     }
 
+    // Called after the cutout and protection bounding path change. Subclasses
+    // should make any changes that need to happen based on the change.
+    open fun onUpdate() = Unit
+
     @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
     public override fun onDraw(canvas: Canvas) {
         super.onDraw(canvas)
diff --git a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
index b5b6b13..9a6020f 100644
--- a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
@@ -128,7 +128,7 @@
                 UserSwitcherController userSwitcherController,
                 UiEventLogger uiEventLogger,
                 int userId) {
-            super(context);
+            super(context, false /* dismissOnDeviceLock */);
 
             setTitle(context.getString(R.string.guest_wipe_session_title));
             setMessage(context.getString(R.string.guest_wipe_session_message));
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt b/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
index 4b86862..22c6937 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
@@ -101,10 +101,10 @@
 
     override fun onAttachedToWindow() {
         super.onAttachedToWindow()
+        parent.requestTransparentRegion(this)
         if (!DEBUG_COLOR) {
-            parent.requestTransparentRegion(this)
+            viewRootImpl.setDisplayDecoration(true)
         }
-        viewRootImpl.setDisplayDecoration(true)
 
         if (useInvertedAlphaColor) {
             paint.set(clearPaint)
@@ -114,17 +114,24 @@
         }
     }
 
+    override fun onUpdate() {
+        parent.requestTransparentRegion(this)
+    }
+
     override fun onDraw(canvas: Canvas) {
         // If updating onDraw, also update gatherTransparentRegion
         if (useInvertedAlphaColor) {
             canvas.drawColor(bgColor)
         }
+
+        // We may clear the color(if useInvertedAlphaColor is true) of the rounded corner rects
+        // before drawing rounded corners. If the cutout happens to be inside one of these rects, it
+        // will be cleared, so we have to draw rounded corners before cutout.
+        drawRoundedCorners(canvas)
         // Cutouts are drawn in DisplayCutoutBaseView.onDraw()
         super.onDraw(canvas)
-        drawRoundedCorners(canvas)
 
         debugTransparentRegionPaint?.let {
-            calculateTransparentRect()
             canvas.drawRect(transparentRect, it)
         }
     }
@@ -132,7 +139,16 @@
     override fun gatherTransparentRegion(region: Region?): Boolean {
         region?.let {
             calculateTransparentRect()
-            region.op(transparentRect, Region.Op.INTERSECT)
+            if (DEBUG_COLOR) {
+                // Since we're going to draw a rectangle where the layer would
+                // normally be transparent, treat the transparent region as
+                // empty. We still want this method to be called, though, so
+                // that it calculates the transparent rect at the right time
+                // to match !DEBUG_COLOR.
+                region.setEmpty()
+            } else {
+                region.op(transparentRect, Region.Op.INTERSECT)
+            }
         }
         // Always return false - views underneath this should always be visible.
         return false
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index ae41cae..2f5292c 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -37,13 +37,11 @@
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.content.res.TypedArray;
 import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.PixelFormat;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.hardware.display.DisplayManager;
@@ -53,14 +51,12 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings.Secure;
-import android.util.DisplayMetrics;
-import android.util.DisplayUtils;
 import android.util.Log;
+import android.util.Size;
 import android.view.DisplayCutout;
 import android.view.DisplayCutout.BoundsPosition;
 import android.view.Gravity;
 import android.view.LayoutInflater;
-import android.view.RoundedCorners;
 import android.view.View;
 import android.view.View.OnLayoutChangeListener;
 import android.view.ViewGroup;
@@ -81,6 +77,7 @@
 import com.android.systemui.decor.DecorProviderKt;
 import com.android.systemui.decor.OverlayWindow;
 import com.android.systemui.decor.PrivacyDotDecorProviderFactory;
+import com.android.systemui.decor.RoundedCornerResDelegate;
 import com.android.systemui.qs.SettingObserver;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.events.PrivacyDotViewController;
@@ -139,11 +136,7 @@
     // corners. for now it is only supposed when reading the intrinsic size from the drawables with
     // mIsRoundedCornerMultipleRadius is set
     @VisibleForTesting
-    protected Point mRoundedDefault = new Point(0, 0);
-    @VisibleForTesting
-    protected Point mRoundedDefaultTop = new Point(0, 0);
-    @VisibleForTesting
-    protected Point mRoundedDefaultBottom = new Point(0, 0);
+    protected RoundedCornerResDelegate mRoundedCornerResDelegate;
     @VisibleForTesting
     protected OverlayWindow[] mOverlays = null;
     @Nullable
@@ -152,17 +145,12 @@
     ViewGroup mScreenDecorHwcWindow;
     @VisibleForTesting
     ScreenDecorHwcLayer mScreenDecorHwcLayer;
-    private float mDensity;
     private WindowManager mWindowManager;
     private int mRotation;
     private SettingObserver mColorInversionSetting;
     private DelayableExecutor mExecutor;
     private Handler mHandler;
     boolean mPendingRotationChange;
-    private boolean mIsRoundedCornerMultipleRadius;
-    private Drawable mRoundedCornerDrawable;
-    private Drawable mRoundedCornerDrawableTop;
-    private Drawable mRoundedCornerDrawableBottom;
     @VisibleForTesting
     String mDisplayUniqueId;
     private int mTintColor = Color.BLACK;
@@ -302,7 +290,8 @@
     private void startOnScreenDecorationsThread() {
         mRotation = mContext.getDisplay().getRotation();
         mDisplayUniqueId = mContext.getDisplay().getUniqueId();
-        mIsRoundedCornerMultipleRadius = isRoundedCornerMultipleRadius(mContext, mDisplayUniqueId);
+        mRoundedCornerResDelegate = new RoundedCornerResDelegate(mContext.getResources(),
+                mDisplayUniqueId);
         mWindowManager = mContext.getSystemService(WindowManager.class);
         mDisplayManager = mContext.getSystemService(DisplayManager.class);
         mHwcScreenDecorationSupport = mContext.getDisplay().getDisplayDecorationSupport();
@@ -359,8 +348,7 @@
                 final String newUniqueId = mContext.getDisplay().getUniqueId();
                 if (!Objects.equals(newUniqueId, mDisplayUniqueId)) {
                     mDisplayUniqueId = newUniqueId;
-                    mIsRoundedCornerMultipleRadius =
-                            isRoundedCornerMultipleRadius(mContext, mDisplayUniqueId);
+                    mRoundedCornerResDelegate.reloadAll(newUniqueId);
                     final DisplayDecorationSupport newScreenDecorationSupport =
                             mContext.getDisplay().getDisplayDecorationSupport();
                     // When the value of mSupportHwcScreenDecoration is changed, re-setup the whole
@@ -457,9 +445,6 @@
             if (mIsRegistered) {
                 return;
             }
-            DisplayMetrics metrics = new DisplayMetrics();
-            mContext.getDisplay().getMetrics(metrics);
-            mDensity = metrics.density;
 
             mMainExecutor.execute(() -> mTunerService.addTunable(this, SIZE));
 
@@ -606,8 +591,8 @@
         mScreenDecorHwcWindow.addView(mScreenDecorHwcLayer, new FrameLayout.LayoutParams(
                 MATCH_PARENT, MATCH_PARENT, Gravity.TOP | Gravity.START));
         mWindowManager.addView(mScreenDecorHwcWindow, getHwcWindowLayoutParams());
-        updateRoundedCornerSize(mRoundedDefault, mRoundedDefaultTop, mRoundedDefaultBottom);
-        updateRoundedCornerImageView();
+        updateHwLayerRoundedCornerSize();
+        updateHwLayerRoundedCornerDrawable();
         mScreenDecorHwcWindow.getViewTreeObserver().addOnPreDrawListener(
                 new ValidatingPreDrawListener(mScreenDecorHwcWindow));
     }
@@ -640,7 +625,9 @@
         // update rounded corner view rotation
         updateRoundedCornerView(pos, R.id.left, cutout);
         updateRoundedCornerView(pos, R.id.right, cutout);
-        updateRoundedCornerSize(mRoundedDefault, mRoundedDefaultTop, mRoundedDefaultBottom);
+        updateRoundedCornerSize(
+                mRoundedCornerResDelegate.getTopRoundedSize(),
+                mRoundedCornerResDelegate.getBottomRoundedSize());
         updateRoundedCornerImageView();
 
         // update cutout view rotation
@@ -844,7 +831,6 @@
     public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
         pw.println("ScreenDecorations state:");
         pw.println("  DEBUG_DISABLE_SCREEN_DECORATIONS:" + DEBUG_DISABLE_SCREEN_DECORATIONS);
-        pw.println("  mIsRoundedCornerMultipleRadius:" + mIsRoundedCornerMultipleRadius);
         pw.println("  mIsPrivacyDotEnabled:" + isPrivacyDotEnabled());
         pw.println("  mPendingRotationChange:" + mPendingRotationChange);
         if (mHwcScreenDecorationSupport != null) {
@@ -862,16 +848,12 @@
         } else {
             pw.println("  mScreenDecorHwcLayer: null");
         }
-        pw.println("  mRoundedDefault(x,y)=(" + mRoundedDefault.x + "," + mRoundedDefault.y + ")");
-        pw.println("  mRoundedDefaultTop(x,y)=(" + mRoundedDefaultTop.x + "," + mRoundedDefaultTop.y
-                + ")");
-        pw.println("  mRoundedDefaultBottom(x,y)=(" + mRoundedDefaultBottom.x + ","
-                + mRoundedDefaultBottom.y + ")");
         pw.println("  mOverlays(left,top,right,bottom)=("
                 + (mOverlays != null && mOverlays[BOUNDS_POSITION_LEFT] != null) + ","
                 + (mOverlays != null && mOverlays[BOUNDS_POSITION_TOP] != null) + ","
                 + (mOverlays != null && mOverlays[BOUNDS_POSITION_RIGHT] != null) + ","
                 + (mOverlays != null && mOverlays[BOUNDS_POSITION_BOTTOM] != null) + ")");
+        mRoundedCornerResDelegate.dump(fd, pw, args);
     }
 
     private void updateOrientation() {
@@ -912,119 +894,18 @@
         // upgrading all of the configs to contain (width, height) pairs. Instead assume that a
         // device configured using the single integer config value is okay with drawing the corners
         // as a square
-        final int newRoundedDefault = RoundedCorners.getRoundedCornerRadius(
-                mContext.getResources(), mDisplayUniqueId);
-        final int newRoundedDefaultTop = RoundedCorners.getRoundedCornerTopRadius(
-                mContext.getResources(), mDisplayUniqueId);
-        final int newRoundedDefaultBottom = RoundedCorners.getRoundedCornerBottomRadius(
-                mContext.getResources(), mDisplayUniqueId);
+        final Size oldRoundedDefaultTop = mRoundedCornerResDelegate.getTopRoundedSize();
+        final Size oldRoundedDefaultBottom = mRoundedCornerResDelegate.getBottomRoundedSize();
+        mRoundedCornerResDelegate.reloadAll(mDisplayUniqueId);
+        final Size newRoundedDefaultTop = mRoundedCornerResDelegate.getTopRoundedSize();
+        final Size newRoundedDefaultBottom = mRoundedCornerResDelegate.getBottomRoundedSize();
 
-        final boolean changed = mRoundedDefault.x != newRoundedDefault
-                        || mRoundedDefaultTop.x != newRoundedDefaultTop
-                        || mRoundedDefaultBottom.x != newRoundedDefaultBottom;
-
-        if (changed) {
-            // If config_roundedCornerMultipleRadius set as true, ScreenDecorations respect the
-            // (width, height) size of drawable/rounded.xml instead of rounded_corner_radius
-            if (mIsRoundedCornerMultipleRadius) {
-                mRoundedDefault.set(mRoundedCornerDrawable.getIntrinsicWidth(),
-                        mRoundedCornerDrawable.getIntrinsicHeight());
-                mRoundedDefaultTop.set(mRoundedCornerDrawableTop.getIntrinsicWidth(),
-                        mRoundedCornerDrawableTop.getIntrinsicHeight());
-                mRoundedDefaultBottom.set(mRoundedCornerDrawableBottom.getIntrinsicWidth(),
-                        mRoundedCornerDrawableBottom.getIntrinsicHeight());
-            } else {
-                mRoundedDefault.set(newRoundedDefault, newRoundedDefault);
-                mRoundedDefaultTop.set(newRoundedDefaultTop, newRoundedDefaultTop);
-                mRoundedDefaultBottom.set(newRoundedDefaultBottom, newRoundedDefaultBottom);
-            }
+        if (oldRoundedDefaultTop.getWidth() != newRoundedDefaultTop.getWidth()
+                || oldRoundedDefaultBottom.getWidth() != newRoundedDefaultBottom.getWidth()) {
             onTuningChanged(SIZE, null);
         }
     }
 
-    /**
-     * Gets whether the rounded corners are multiple radii for current display.
-     *
-     * Loads the default config {@link R.bool#config_roundedCornerMultipleRadius} if
-     * {@link com.android.internal.R.array#config_displayUniqueIdArray} is not set.
-     */
-    private static boolean isRoundedCornerMultipleRadius(Context context, String displayUniqueId) {
-        final Resources res = context.getResources();
-        final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
-        final TypedArray array = res.obtainTypedArray(
-                R.array.config_roundedCornerMultipleRadiusArray);
-        boolean isMultipleRadius;
-        if (index >= 0 && index < array.length()) {
-            isMultipleRadius = array.getBoolean(index, false);
-        } else {
-            isMultipleRadius = res.getBoolean(R.bool.config_roundedCornerMultipleRadius);
-        }
-        array.recycle();
-        return isMultipleRadius;
-    }
-
-    /**
-     * Gets the rounded corner drawable for current display.
-     *
-     * Loads the default config {@link R.drawable#rounded} if
-     * {@link com.android.internal.R.array#config_displayUniqueIdArray} is not set.
-     */
-    private static Drawable getRoundedCornerDrawable(Context context, String displayUniqueId) {
-        final Resources res = context.getResources();
-        final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
-        final TypedArray array = res.obtainTypedArray(R.array.config_roundedCornerDrawableArray);
-        Drawable drawable;
-        if (index >= 0 && index < array.length()) {
-            drawable = array.getDrawable(index);
-        } else {
-            drawable = context.getDrawable(R.drawable.rounded);
-        }
-        array.recycle();
-        return drawable;
-    }
-
-    /**
-     * Gets the rounded corner top drawable for current display.
-     *
-     * Loads the default config {@link R.drawable#rounded_corner_top} if
-     * {@link com.android.internal.R.array#config_displayUniqueIdArray} is not set.
-     */
-    private static Drawable getRoundedCornerTopDrawable(Context context, String displayUniqueId) {
-        final Resources res = context.getResources();
-        final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
-        final TypedArray array = res.obtainTypedArray(R.array.config_roundedCornerTopDrawableArray);
-        Drawable drawable;
-        if (index >= 0 && index < array.length()) {
-            drawable = array.getDrawable(index);
-        } else {
-            drawable = context.getDrawable(R.drawable.rounded_corner_top);
-        }
-        array.recycle();
-        return drawable;
-    }
-
-    /**
-     * Gets the rounded corner bottom drawable for current display.
-     *
-     * Loads the default config {@link R.drawable#rounded_corner_bottom} if
-     * {@link com.android.internal.R.array#config_displayUniqueIdArray} is not set.
-     */
-    private static Drawable getRoundedCornerBottomDrawable(
-            Context context, String displayUniqueId) {
-        final Resources res = context.getResources();
-        final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
-        final TypedArray array = res.obtainTypedArray(
-                R.array.config_roundedCornerBottomDrawableArray);
-        Drawable drawable;
-        if (index >= 0 && index < array.length()) {
-            drawable = array.getDrawable(index);
-        } else {
-            drawable = context.getDrawable(R.drawable.rounded_corner_bottom);
-        }
-        array.recycle();
-        return drawable;
-    }
-
     private void updateRoundedCornerView(@BoundsPosition int pos, int id,
             @Nullable DisplayCutout cutout) {
         final View rounded = mOverlays[pos].getRootView().findViewById(id);
@@ -1085,10 +966,9 @@
         }
     }
     private boolean hasRoundedCorners() {
-        return mRoundedDefault.x > 0
-                || mRoundedDefaultBottom.x > 0
-                || mRoundedDefaultTop.x > 0
-                || mIsRoundedCornerMultipleRadius;
+        return mRoundedCornerResDelegate.getBottomRoundedSize().getWidth() > 0
+                || mRoundedCornerResDelegate.getTopRoundedSize().getWidth() > 0
+                || mRoundedCornerResDelegate.isMultipleRadius();
     }
 
     private boolean isDefaultShownOverlayPos(@BoundsPosition int pos,
@@ -1154,33 +1034,28 @@
         mExecutor.execute(() -> {
             if (mOverlays == null) return;
             if (SIZE.equals(key)) {
-                Point size = mRoundedDefault;
-                Point sizeTop = mRoundedDefaultTop;
-                Point sizeBottom = mRoundedDefaultBottom;
                 if (newValue != null) {
                     try {
-                        int s = (int) (Integer.parseInt(newValue) * mDensity);
-                        size = new Point(s, s);
+                        mRoundedCornerResDelegate.updateTuningSizeFactor(
+                                Integer.parseInt(newValue));
                     } catch (Exception e) {
                     }
                 }
-                updateRoundedCornerSize(size, sizeTop, sizeBottom);
+                updateRoundedCornerSize(
+                        mRoundedCornerResDelegate.getTopRoundedSize(),
+                        mRoundedCornerResDelegate.getBottomRoundedSize());
             }
         });
     }
 
     private void updateRoundedCornerDrawable() {
-        mRoundedCornerDrawable = getRoundedCornerDrawable(mContext, mDisplayUniqueId);
-        mRoundedCornerDrawableTop = getRoundedCornerTopDrawable(mContext, mDisplayUniqueId);
-        mRoundedCornerDrawableBottom = getRoundedCornerBottomDrawable(mContext, mDisplayUniqueId);
+        mRoundedCornerResDelegate.reloadAll(mDisplayUniqueId);
         updateRoundedCornerImageView();
     }
 
     private void updateRoundedCornerImageView() {
-        final Drawable top = mRoundedCornerDrawableTop != null
-                ? mRoundedCornerDrawableTop : mRoundedCornerDrawable;
-        final Drawable bottom = mRoundedCornerDrawableBottom != null
-                ? mRoundedCornerDrawableBottom : mRoundedCornerDrawable;
+        final Drawable top = mRoundedCornerResDelegate.getTopRoundedDrawable();
+        final Drawable bottom = mRoundedCornerResDelegate.getBottomRoundedDrawable();
 
         if (mScreenDecorHwcLayer != null) {
             mScreenDecorHwcLayer.updateRoundedCornerDrawable(top, bottom);
@@ -1205,6 +1080,20 @@
         }
     }
 
+    private void updateHwLayerRoundedCornerDrawable() {
+        if (mScreenDecorHwcLayer == null) {
+            return;
+        }
+
+        final Drawable topDrawable = mRoundedCornerResDelegate.getTopRoundedDrawable();
+        final Drawable bottomDrawable = mRoundedCornerResDelegate.getBottomRoundedDrawable();
+
+        if (topDrawable == null || bottomDrawable == null) {
+            return;
+        }
+        mScreenDecorHwcLayer.updateRoundedCornerDrawable(topDrawable, bottomDrawable);
+    }
+
     @VisibleForTesting
     boolean isTopRoundedCorner(@BoundsPosition int pos, int id) {
         switch (pos) {
@@ -1224,19 +1113,21 @@
         }
     }
 
-    private void updateRoundedCornerSize(
-            Point sizeDefault,
-            Point sizeTop,
-            Point sizeBottom) {
-        if (sizeTop.x == 0) {
-            sizeTop = sizeDefault;
-        }
-        if (sizeBottom.x == 0) {
-            sizeBottom = sizeDefault;
+    private void updateHwLayerRoundedCornerSize() {
+        if (mScreenDecorHwcLayer == null) {
+            return;
         }
 
+        final int topWidth = mRoundedCornerResDelegate.getTopRoundedSize().getWidth();
+        final int bottomWidth = mRoundedCornerResDelegate.getBottomRoundedSize().getWidth();
+
+        mScreenDecorHwcLayer.updateRoundedCornerSize(topWidth, bottomWidth);
+    }
+
+    private void updateRoundedCornerSize(Size sizeTop, Size sizeBottom) {
+
         if (mScreenDecorHwcLayer != null) {
-            mScreenDecorHwcLayer.updateRoundedCornerSize(sizeTop.x, sizeBottom.x);
+            mScreenDecorHwcLayer.updateRoundedCornerSize(sizeTop.getWidth(), sizeBottom.getWidth());
             return;
         }
 
@@ -1256,10 +1147,10 @@
     }
 
     @VisibleForTesting
-    protected void setSize(View view, Point pixelSize) {
+    protected void setSize(View view, Size pixelSize) {
         LayoutParams params = view.getLayoutParams();
-        params.width = pixelSize.x;
-        params.height = pixelSize.y;
+        params.width = pixelSize.getWidth();
+        params.height = pixelSize.getHeight();
         view.setLayoutParams(params);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 3a6165c..031e378 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -27,6 +27,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
 import android.os.Bundle;
+import android.os.Looper;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemProperties;
@@ -105,6 +106,10 @@
         mBootCompleteCache = mSysUIComponent.provideBootCacheImpl();
         log.traceEnd();
 
+        // Enable Looper trace points.
+        // This allows us to see Handler callbacks on traces.
+        Looper.getMainLooper().setTraceTag(Trace.TRACE_TAG_APP);
+
         // Set the application theme that is inherited by all services. Note that setting the
         // application theme in the manifest does only work for activities. Keep this in sync with
         // the theme set there.
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 7e1a026..807ff21 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -254,8 +254,8 @@
 
         mMirrorViewGeometryVsyncCallback =
                 l -> {
-                    if (isWindowVisible() && mMirrorSurface != null) {
-                        calculateSourceBounds(mMagnificationFrame, mScale);
+                    if (isWindowVisible() && mMirrorSurface != null && calculateSourceBounds(
+                            mMagnificationFrame, mScale)) {
                         // The final destination for the magnification surface should be at 0,0
                         // since the ViewRootImpl's position will change
                         mTmpRect.set(0, 0, mMagnificationFrame.width(),
@@ -350,6 +350,7 @@
             mMirrorWindowControl.destroyControl();
         }
         mMirrorViewBounds.setEmpty();
+        mSourceBounds.setEmpty();
         updateSystemUIStateIfNeeded();
         mContext.unregisterComponentCallbacks(this);
     }
@@ -728,8 +729,12 @@
     /**
      * Calculates the desired source bounds. This will be the area under from the center of  the
      * displayFrame, factoring in scale.
+     *
+     * @return {@code true} if the source bounds is changed.
      */
-    private void calculateSourceBounds(Rect displayFrame, float scale) {
+    private boolean calculateSourceBounds(Rect displayFrame, float scale) {
+        final Rect oldSourceBounds = mTmpRect;
+        oldSourceBounds.set(mSourceBounds);
         int halfWidth = displayFrame.width() / 2;
         int halfHeight = displayFrame.height() / 2;
         int left = displayFrame.left + (halfWidth - (int) (halfWidth / scale));
@@ -757,6 +762,7 @@
             mSourceBounds.offsetTo(mSourceBounds.left,
                     mWindowBounds.height() - mSourceBounds.height());
         }
+        return !mSourceBounds.equals(oldSourceBounds);
     }
 
     private void calculateMagnificationFrameBoundary() {
@@ -1079,7 +1085,7 @@
         pw.println("      mMagnificationFrame:"
                 + (isWindowVisible() ? mMagnificationFrame : "empty"));
         pw.println("      mSourceBounds:"
-                 + (isWindowVisible() ? mSourceBounds : "empty"));
+                 + (mSourceBounds.isEmpty() ? "empty" : mSourceBounds));
         pw.println("      mSystemGestureTop:" + mSystemGestureTop);
         pw.println("      mMagnificationFrameOffsetX:" + mMagnificationFrameOffsetX);
         pw.println("      mMagnificationFrameOffsetY:" + mMagnificationFrameOffsetY);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index 76d4aa8..55da8da 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -47,6 +47,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.R;
+import com.android.systemui.util.LargeScreenUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -814,7 +815,7 @@
     }
 
     private boolean isLargeDisplay() {
-        return com.android.systemui.util.Utils.shouldUseSplitNotificationShade(getResources());
+        return LargeScreenUtils.shouldUseSplitNotificationShade(getResources());
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 64c2d2e..c100a07 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -726,8 +726,8 @@
 
         boolean isCameraPrivacyEnabled = false;
         if (error == BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE
-                && mSensorPrivacyManager.isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA,
-                mCurrentDialogArgs.argi1 /* userId */)) {
+                && mSensorPrivacyManager.isSensorPrivacyEnabled(
+                SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE, SensorPrivacyManager.Sensors.CAMERA)) {
             isCameraPrivacyEnabled = true;
         }
         // TODO(b/141025588): Create separate methods for handling hard and soft errors.
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
index 57ca0f4..ed84a37 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
@@ -20,7 +20,7 @@
 import static android.app.admin.DevicePolicyResources.Strings.SystemUi.BIOMETRIC_DIALOG_WORK_PASSWORD_LAST_ATTEMPT;
 import static android.app.admin.DevicePolicyResources.Strings.SystemUi.BIOMETRIC_DIALOG_WORK_PATTERN_LAST_ATTEMPT;
 import static android.app.admin.DevicePolicyResources.Strings.SystemUi.BIOMETRIC_DIALOG_WORK_PIN_LAST_ATTEMPT;
-import static android.app.admin.DevicePolicyResources.Strings.UNDEFINED;
+import static android.app.admin.DevicePolicyResources.UNDEFINED;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -390,7 +390,9 @@
     private void showNowWipingDialog() {
         final AlertDialog alertDialog = new AlertDialog.Builder(mContext)
                 .setMessage(getNowWipingMessage(getUserTypeForWipe()))
-                .setPositiveButton(R.string.biometric_dialog_now_wiping_dialog_dismiss, null)
+                .setPositiveButton(
+                        com.android.settingslib.R.string.failed_attempts_now_wiping_dialog_dismiss,
+                        null /* OnClickListener */)
                 .setOnDismissListener(
                         dialog -> mContainerView.animateAway(AuthDialogCallback.DISMISSED_ERROR))
                 .create();
@@ -442,7 +444,7 @@
 
     private String getLastAttemptBeforeWipeProfileMessage(
             @Utils.CredentialType int credentialType) {
-        return mDevicePolicyManager.getString(
+        return mDevicePolicyManager.getResources().getString(
                 getLastAttemptBeforeWipeProfileUpdatableStringId(credentialType),
                 () -> getLastAttemptBeforeWipeProfileDefaultMessage(credentialType));
     }
@@ -495,7 +497,7 @@
     }
 
     private String getNowWipingMessage(@UserType int userType) {
-        return mDevicePolicyManager.getString(
+        return mDevicePolicyManager.getResources().getString(
                 getNowWipingUpdatableStringId(userType),
                 () -> getNowWipingDefaultMessage(userType));
     }
@@ -513,13 +515,13 @@
         int resId;
         switch (userType) {
             case USER_TYPE_PRIMARY:
-                resId = R.string.biometric_dialog_failed_attempts_now_wiping_device;
+                resId = com.android.settingslib.R.string.failed_attempts_now_wiping_device;
                 break;
             case USER_TYPE_MANAGED_PROFILE:
-                resId = R.string.biometric_dialog_failed_attempts_now_wiping_profile;
+                resId = com.android.settingslib.R.string.failed_attempts_now_wiping_profile;
                 break;
             case USER_TYPE_SECONDARY:
-                resId = R.string.biometric_dialog_failed_attempts_now_wiping_user;
+                resId = com.android.settingslib.R.string.failed_attempts_now_wiping_user;
                 break;
             default:
                 throw new IllegalArgumentException("Unrecognized user type:" + userType);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index a27b9cd..b811c51 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -116,7 +116,7 @@
     }
 
     fun showRipple(biometricSourceType: BiometricSourceType?) {
-        if (!keyguardUpdateMonitor.isKeyguardVisible ||
+        if (!(keyguardUpdateMonitor.isKeyguardVisible || keyguardUpdateMonitor.isDreaming) ||
             keyguardUpdateMonitor.userNeedsStrongAuth()) {
             return
         }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt
index 4c00735..085bcfa 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt
@@ -33,6 +33,8 @@
 import android.hardware.fingerprint.ISidefpsController
 import android.os.Handler
 import android.util.Log
+import android.view.View.AccessibilityDelegate
+import android.view.accessibility.AccessibilityEvent
 import android.view.Display
 import android.view.Gravity
 import android.view.LayoutInflater
@@ -181,6 +183,23 @@
         }
         lottie.addOverlayDynamicColor(context)
 
+        /**
+         * Intercepts TYPE_WINDOW_STATE_CHANGED accessibility event, preventing Talkback from
+         * speaking @string/accessibility_fingerprint_label twice when sensor location indicator
+         * is in focus
+         */
+        view.setAccessibilityDelegate(object : AccessibilityDelegate() {
+            override fun dispatchPopulateAccessibilityEvent(
+                host: View,
+                event: AccessibilityEvent
+            ): Boolean {
+                return if (event.getEventType() === AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
+                    true
+                } else {
+                    super.dispatchPopulateAccessibilityEvent(host, event)
+                }
+            }
+        })
         return view
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index bf42db5..975e0c5 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -49,7 +49,6 @@
 import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.VelocityTracker;
-import android.view.View;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
 
@@ -92,7 +91,7 @@
  * Note that the current architecture is designed so that a single {@link UdfpsController}
  * controls/manages all UDFPS sensors. In other words, a single controller is registered with
  * {@link com.android.server.biometrics.sensors.fingerprint.FingerprintService}, and interfaces such
- * as {@link FingerprintManager#onPointerDown(int, int, int, float, float)} or
+ * as {@link FingerprintManager#onPointerDown(long, int, int, int, float, float)} or
  * {@link IUdfpsOverlayController#showUdfpsOverlay} should all have
  * {@code sensorId} parameters.
  */
@@ -193,7 +192,7 @@
 
     public class UdfpsOverlayController extends IUdfpsOverlayController.Stub {
         @Override
-        public void showUdfpsOverlay(int sensorId, int reason,
+        public void showUdfpsOverlay(long requestId, int sensorId, int reason,
                 @NonNull IUdfpsOverlayControllerCallback callback) {
             mFgExecutor.execute(
                     () -> UdfpsController.this.showUdfpsOverlay(new UdfpsControllerOverlay(
@@ -203,8 +202,10 @@
                             mKeyguardUpdateMonitor, mDialogManager, mDumpManager,
                             mLockscreenShadeTransitionController, mConfigurationController,
                             mSystemClock, mKeyguardStateController,
-                            mUnlockedScreenOffAnimationController, mSensorProps, mHbmProvider,
-                            reason, callback, UdfpsController.this::onTouch,
+                            mUnlockedScreenOffAnimationController, mSensorProps,
+                            mHbmProvider, requestId, reason, callback,
+                            (view, event, fromUdfpsView) ->
+                                   onTouch(requestId, event, fromUdfpsView),
                             mActivityLaunchAnimator)));
         }
 
@@ -318,7 +319,8 @@
         if (mOverlay == null || mOverlay.isHiding()) {
             return false;
         }
-        return onTouch(mOverlay.getOverlayView(), event, false);
+        // TODO(b/225068271): may not be correct but no way to get the id yet
+        return onTouch(mOverlay.getRequestId(), event, false);
     }
 
     /**
@@ -342,8 +344,18 @@
                 && getSensorLocation().contains(x, y);
     }
 
-    private boolean onTouch(@NonNull View view, @NonNull MotionEvent event, boolean fromUdfpsView) {
-        UdfpsView udfpsView = (UdfpsView) view;
+    private boolean onTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView) {
+        if (mOverlay == null) {
+            Log.w(TAG, "ignoring onTouch with null overlay");
+            return false;
+        }
+        if (!mOverlay.matchesRequestId(requestId)) {
+            Log.w(TAG, "ignoring stale touch event: " + requestId + " current: "
+                    + mOverlay.getRequestId());
+            return false;
+        }
+
+        final UdfpsView udfpsView = mOverlay.getOverlayView();
         final boolean isIlluminationRequested = udfpsView.isIlluminationRequested();
         boolean handled = false;
         switch (event.getActionMasked()) {
@@ -453,7 +465,7 @@
                                     // Do nothing to stay in portrait mode.
                             }
 
-                            onFingerDown(x, y, minor, major);
+                            onFingerDown(requestId, x, y, minor, major);
                             Log.v(TAG, "onTouch | finger down: " + touchInfo);
                             mTouchLogTime = mSystemClock.elapsedRealtime();
                             mPowerManager.userActivity(mSystemClock.uptimeMillis(),
@@ -465,7 +477,7 @@
                         }
                     } else {
                         Log.v(TAG, "onTouch | finger outside");
-                        onFingerUp(udfpsView);
+                        onFingerUp(requestId, udfpsView);
                     }
                 }
                 Trace.endSection();
@@ -482,7 +494,7 @@
                 }
                 Log.v(TAG, "onTouch | finger up");
                 mAttemptedToDismissKeyguard = false;
-                onFingerUp(udfpsView);
+                onFingerUp(requestId, udfpsView);
                 mFalsingManager.isFalseTouch(UDFPS_AUTHENTICATION);
                 Trace.endSection();
                 break;
@@ -584,16 +596,18 @@
     }
 
     /**
-     * Play haptic to signal udfps scanning started.
+     * If a11y touchExplorationEnabled, play haptic to signal UDFPS scanning started.
      */
     @VisibleForTesting
     public void playStartHaptic() {
-        mVibrator.vibrate(
-                Process.myUid(),
-                mContext.getOpPackageName(),
-                EFFECT_CLICK,
-                "udfps-onStart-click",
-                VIBRATION_ATTRIBUTES);
+        if (mAccessibilityManager.isTouchExplorationEnabled()) {
+            mVibrator.vibrate(
+                    Process.myUid(),
+                    mContext.getOpPackageName(),
+                    EFFECT_CLICK,
+                    "udfps-onStart-click",
+                    VIBRATION_ATTRIBUTES);
+        }
     }
 
     @Nullable
@@ -677,7 +691,7 @@
             // Reset the controller back to its starting state.
             final UdfpsView oldView = mOverlay.getOverlayView();
             if (oldView != null) {
-                onFingerUp(oldView);
+                onFingerUp(mOverlay.getRequestId(), oldView);
             }
             final boolean removed = mOverlay.hide();
             if (mKeyguardViewManager.isShowingAlternateAuth()) {
@@ -708,6 +722,8 @@
             return;
         }
 
+        // TODO(b/225068271): this may not be correct but there isn't a way to track it
+        final long requestId = mOverlay != null ? mOverlay.getRequestId() : -1;
         mAodInterruptRunnable = () -> {
             mIsAodInterruptActive = true;
             // Since the sensor that triggers the AOD interrupt doesn't provide
@@ -717,10 +733,10 @@
             mCancelAodTimeoutAction = mFgExecutor.executeDelayed(this::onCancelUdfps,
                     AOD_INTERRUPT_TIMEOUT_MILLIS);
             // using a hard-coded value for major and minor until it is available from the sensor
-            onFingerDown(screenX, screenY, minor, major);
+            onFingerDown(requestId, screenX, screenY, minor, major);
         };
 
-        if (mScreenOn && mAodInterruptRunnable != null) {
+        if (mScreenOn) {
             mAodInterruptRunnable.run();
             mAodInterruptRunnable = null;
         }
@@ -753,7 +769,7 @@
      */
     void onCancelUdfps() {
         if (mOverlay != null && mOverlay.getOverlayView() != null) {
-            onFingerUp(mOverlay.getOverlayView());
+            onFingerUp(mOverlay.getRequestId(), mOverlay.getOverlayView());
         }
         if (!mIsAodInterruptActive) {
             return;
@@ -769,12 +785,17 @@
         return mOnFingerDown;
     }
 
-    private void onFingerDown(int x, int y, float minor, float major) {
+    private void onFingerDown(long requestId, int x, int y, float minor, float major) {
         mExecution.assertIsMainThread();
         if (mOverlay == null) {
             Log.w(TAG, "Null request in onFingerDown");
             return;
         }
+        if (!mOverlay.matchesRequestId(requestId)) {
+            Log.w(TAG, "Mismatched fingerDown: " + requestId
+                    + " current: " + mOverlay.getRequestId());
+            return;
+        }
 
         if (mOverlay.getAnimationViewController() instanceof UdfpsKeyguardViewController
                 && !mStatusBarStateController.isDozing()) {
@@ -789,14 +810,14 @@
             }
         }
         mOnFingerDown = true;
-        mFingerprintManager.onPointerDown(mSensorProps.sensorId, x, y, minor, major);
+        mFingerprintManager.onPointerDown(requestId, mSensorProps.sensorId, x, y, minor, major);
         Trace.endAsyncSection("UdfpsController.e2e.onPointerDown", 0);
 
         final UdfpsView view = mOverlay.getOverlayView();
         if (view != null) {
             Trace.beginAsyncSection("UdfpsController.e2e.startIllumination", 0);
             view.startIllumination(() -> {
-                mFingerprintManager.onUiReady(mSensorProps.sensorId);
+                mFingerprintManager.onUiReady(requestId, mSensorProps.sensorId);
                 mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE);
                 Trace.endAsyncSection("UdfpsController.e2e.startIllumination", 0);
             });
@@ -807,12 +828,12 @@
         }
     }
 
-    private void onFingerUp(@NonNull UdfpsView view) {
+    private void onFingerUp(long requestId, @NonNull UdfpsView view) {
         mExecution.assertIsMainThread();
         mActivePointerId = -1;
         mAcquiredReceived = false;
         if (mOnFingerDown) {
-            mFingerprintManager.onPointerUp(mSensorProps.sensorId);
+            mFingerprintManager.onPointerUp(requestId, mSensorProps.sensorId);
             for (Callback cb : mCallbacks) {
                 cb.onFingerUp();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index 086894d..ee43e93 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -80,6 +80,7 @@
     private val unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController,
     private val sensorProps: FingerprintSensorPropertiesInternal,
     private var hbmProvider: UdfpsHbmProvider,
+    val requestId: Long,
     @ShowReason val requestReason: Int,
     private val controllerCallback: IUdfpsOverlayControllerCallback,
     private val onTouch: (View, MotionEvent, Boolean) -> Boolean,
@@ -276,6 +277,9 @@
         }
     }
 
+    /** Checks if the id is relevant for this overlay. */
+    fun matchesRequestId(id: Long): Boolean = requestId == -1L || requestId == id
+
     private fun WindowManager.LayoutParams.updateForLocation(
         location: SensorLocationInternal,
         animation: UdfpsAnimationViewController<*>?
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
index bbb75c3..0ff5805 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
@@ -60,6 +60,8 @@
  * Use only for IntentFilters with actions and optionally categories. It does not support,
  * permissions, schemes, data types, data authorities or priority different than 0.
  * Cannot be used for getting sticky broadcasts (either as return of registering or as re-delivery).
+ * Broadcast handling may be asynchronous *without* calling goAsync(), as it's running within sysui
+ * and doesn't need to worry about being killed.
  */
 open class BroadcastDispatcher constructor (
     private val context: Context,
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
index 508262d..835025b 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.charging;
 
+import static com.android.systemui.charging.WirelessChargingLayout.UNKNOWN_BATTERY_LEVEL;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
@@ -76,6 +78,16 @@
     }
 
     /**
+     * Creates a charging animation object using mostly default values for non-dozing and unknown
+     * battery level without charging number shown.
+     */
+    public static WirelessChargingAnimation makeChargingAnimationWithNoBatteryLevel(
+            @NonNull Context context, UiEventLogger uiEventLogger) {
+        return makeWirelessChargingAnimation(context, null,
+                UNKNOWN_BATTERY_LEVEL, UNKNOWN_BATTERY_LEVEL, null, false, uiEventLogger);
+    }
+
+    /**
      * Show the view for the specified duration.
      */
     public void show(long delay) {
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index 0f937d1..804576a 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -190,6 +190,13 @@
             }
         });
 
+        mTextPreview.getViewTreeObserver().addOnPreDrawListener(() -> {
+            int availableHeight = mTextPreview.getHeight()
+                    - (mTextPreview.getPaddingTop() + mTextPreview.getPaddingBottom());
+            mTextPreview.setMaxLines(availableHeight / mTextPreview.getLineHeight());
+            return true;
+        });
+
         mDismissButton.setOnClickListener(view -> animateOut());
 
         mEditChip.setIcon(Icon.createWithResource(mContext, R.drawable.ic_screenshot_edit), true);
@@ -240,7 +247,10 @@
                 SELF_PERMISSION, null);
         monitorOutsideTouches();
 
-        mContext.sendBroadcast(new Intent(COPY_OVERLAY_ACTION), SELF_PERMISSION);
+        Intent copyIntent = new Intent(COPY_OVERLAY_ACTION);
+        // Set package name so the system knows it's safe
+        copyIntent.setPackage(mContext.getPackageName());
+        mContext.sendBroadcast(copyIntent, SELF_PERMISSION);
     }
 
     void setClipData(ClipData clipData, String clipSource) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
index 40662536..f9115b2 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
@@ -17,10 +17,13 @@
 package com.android.systemui.controls.management
 
 import android.content.ComponentName
+import android.content.res.Configuration
+import android.content.res.Resources
 import android.graphics.Rect
 import android.os.Bundle
 import android.service.controls.Control
 import android.service.controls.DeviceTypes
+import android.util.TypedValue
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
@@ -32,7 +35,6 @@
 import androidx.core.view.AccessibilityDelegateCompat
 import androidx.core.view.ViewCompat
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
-import androidx.recyclerview.widget.GridLayoutManager
 import androidx.recyclerview.widget.RecyclerView
 import com.android.systemui.R
 import com.android.systemui.controls.ControlInterface
@@ -56,11 +58,32 @@
         const val TYPE_ZONE = 0
         const val TYPE_CONTROL = 1
         const val TYPE_DIVIDER = 2
-    }
 
-    val spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
-        override fun getSpanSize(position: Int): Int {
-            return if (getItemViewType(position) != TYPE_CONTROL) 2 else 1
+        /**
+         * For low-dp width screens that also employ an increased font scale, adjust the
+         * number of columns. This helps prevent text truncation on these devices.
+         *
+         */
+        @JvmStatic
+        fun findMaxColumns(res: Resources): Int {
+            var maxColumns = res.getInteger(R.integer.controls_max_columns)
+            val maxColumnsAdjustWidth =
+                    res.getInteger(R.integer.controls_max_columns_adjust_below_width_dp)
+
+            val outValue = TypedValue()
+            res.getValue(R.dimen.controls_max_columns_adjust_above_font_scale, outValue, true)
+            val maxColumnsAdjustFontScale = outValue.getFloat()
+
+            val config = res.configuration
+            val isPortrait = config.orientation == Configuration.ORIENTATION_PORTRAIT
+            if (isPortrait &&
+                    config.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED &&
+                    config.screenWidthDp <= maxColumnsAdjustWidth &&
+                    config.fontScale >= maxColumnsAdjustFontScale) {
+                maxColumns--
+            }
+
+            return maxColumns
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
index 6f94943..f611c3e 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
@@ -195,10 +195,11 @@
         val margin = resources
                 .getDimensionPixelSize(R.dimen.controls_card_margin)
         val itemDecorator = MarginItemDecorator(margin, margin)
+        val spanCount = ControlAdapter.findMaxColumns(resources)
 
         recyclerView.apply {
             this.adapter = adapter
-            layoutManager = object : GridLayoutManager(recyclerView.context, 2) {
+            layoutManager = object : GridLayoutManager(recyclerView.context, spanCount) {
 
                 // This will remove from the announcement the row corresponding to the divider,
                 // as it's not something that should be announced.
@@ -210,7 +211,12 @@
                     return if (initial > 0) initial - 1 else initial
                 }
             }.apply {
-                spanSizeLookup = adapter.spanSizeLookup
+                spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
+                    override fun getSpanSize(position: Int): Int {
+                        return if (adapter?.getItemViewType(position)
+                                != ControlAdapter.TYPE_CONTROL) spanCount else 1
+                    }
+                }
             }
             addItemDecoration(itemDecorator)
         }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
index cb67454..747bcbe 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
@@ -60,11 +60,17 @@
             val margin = itemView.context.resources
                 .getDimensionPixelSize(R.dimen.controls_card_margin)
             val itemDecorator = MarginItemDecorator(margin, margin)
+            val spanCount = ControlAdapter.findMaxColumns(itemView.resources)
 
             recyclerView.apply {
                 this.adapter = controlAdapter
-                layoutManager = GridLayoutManager(recyclerView.context, 2).apply {
-                    spanSizeLookup = controlAdapter.spanSizeLookup
+                layoutManager = GridLayoutManager(recyclerView.context, spanCount).apply {
+                    spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
+                        override fun getSpanSize(position: Int): Int {
+                            return if (adapter?.getItemViewType(position)
+                                    != ControlAdapter.TYPE_CONTROL) spanCount else 1
+                        }
+                    }
                 }
                 addItemDecoration(itemDecorator)
             }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
index 46a03e8..49f7584 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
@@ -77,8 +77,8 @@
         initBroadcastReceiver()
     }
 
-    override fun onResume() {
-        super.onResume()
+    override fun onStart() {
+        super.onStart()
 
         parent = requireViewById<ViewGroup>(R.id.global_actions_controls)
         parent.alpha = 0f
@@ -91,8 +91,8 @@
         finish()
     }
 
-    override fun onPause() {
-        super.onPause()
+    override fun onStop() {
+        super.onStop()
 
         uiController.hide()
     }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 59c291c..1268250 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -25,12 +25,10 @@
 import android.content.Context
 import android.content.Intent
 import android.content.SharedPreferences
-import android.content.res.Configuration
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.LayerDrawable
 import android.service.controls.Control
 import android.util.Log
-import android.util.TypedValue
 import android.view.ContextThemeWrapper
 import android.view.LayoutInflater
 import android.view.View
@@ -51,6 +49,7 @@
 import com.android.systemui.controls.controller.ControlInfo
 import com.android.systemui.controls.controller.ControlsController
 import com.android.systemui.controls.controller.StructureInfo
+import com.android.systemui.controls.management.ControlAdapter
 import com.android.systemui.controls.management.ControlsEditingActivity
 import com.android.systemui.controls.management.ControlsFavoritingActivity
 import com.android.systemui.controls.management.ControlsListingController
@@ -386,7 +385,7 @@
             visibility = View.VISIBLE
         }
 
-        val maxColumns = findMaxColumns()
+        val maxColumns = ControlAdapter.findMaxColumns(activityContext.resources)
 
         val listView = parent.requireViewById(R.id.global_actions_controls_list) as ViewGroup
         var lastRow: ViewGroup = createRow(inflater, listView)
@@ -432,32 +431,6 @@
         }
     }
 
-    /**
-     * For low-dp width screens that also employ an increased font scale, adjust the
-     * number of columns. This helps prevent text truncation on these devices.
-     */
-    private fun findMaxColumns(): Int {
-        val res = activityContext.resources
-        var maxColumns = res.getInteger(R.integer.controls_max_columns)
-        val maxColumnsAdjustWidth =
-            res.getInteger(R.integer.controls_max_columns_adjust_below_width_dp)
-
-        val outValue = TypedValue()
-        res.getValue(R.dimen.controls_max_columns_adjust_above_font_scale, outValue, true)
-        val maxColumnsAdjustFontScale = outValue.getFloat()
-
-        val config = res.configuration
-        val isPortrait = config.orientation == Configuration.ORIENTATION_PORTRAIT
-        if (isPortrait &&
-            config.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED &&
-            config.screenWidthDp <= maxColumnsAdjustWidth &&
-            config.fontScale >= maxColumnsAdjustFontScale) {
-            maxColumns--
-        }
-
-        return maxColumns
-    }
-
     override fun getPreferredStructure(structures: List<StructureInfo>): StructureInfo {
         if (structures.isEmpty()) return EMPTY_STRUCTURE
 
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index f78929f..a9f34085 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -35,6 +35,7 @@
 import com.android.systemui.recents.Recents
 import com.android.systemui.shortcut.ShortcutKeyDispatcher
 import com.android.systemui.statusbar.notification.InstantAppNotifier
+import com.android.systemui.statusbar.phone.KeyguardLiftController
 import com.android.systemui.theme.ThemeOverlayController
 import com.android.systemui.toast.ToastUI
 import com.android.systemui.usb.StorageNotification
@@ -198,4 +199,10 @@
     @IntoMap
     @ClassKey(WMShell::class)
     abstract fun bindWMShell(sysui: WMShell): CoreStartable
+
+    /** Inject into KeyguardLiftController.  */
+    @Binds
+    @IntoMap
+    @ClassKey(KeyguardLiftController::class)
+    abstract fun bindKeyguardLiftController(sysui: KeyguardLiftController): CoreStartable
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 166c265..59fcf87 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -43,6 +43,7 @@
 import com.android.systemui.log.dagger.LogModule;
 import com.android.systemui.lowlightclock.LowLightClockController;
 import com.android.systemui.model.SysUiState;
+import com.android.systemui.navigationbar.NavigationBarComponent;
 import com.android.systemui.plugins.BcSmartspaceDataPlugin;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.recents.Recents;
@@ -132,6 +133,7 @@
         },
         subcomponents = {
             CentralSurfacesComponent.class,
+            NavigationBarComponent.class,
             NotificationRowComponent.class,
             DozeComponent.class,
             ExpandableNotificationRowComponent.class,
diff --git a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt
new file mode 100644
index 0000000..c817f89
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt
@@ -0,0 +1,201 @@
+/*
+ * 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.systemui.decor
+
+import android.annotation.ArrayRes
+import android.annotation.DrawableRes
+import android.content.res.Resources
+import android.graphics.drawable.Drawable
+import android.util.DisplayUtils
+import android.util.Size
+import android.view.RoundedCorners
+import com.android.systemui.Dumpable
+import com.android.systemui.R
+import java.io.FileDescriptor
+import java.io.PrintWriter
+
+class RoundedCornerResDelegate(
+    private val res: Resources,
+    private var displayUniqueId: String?
+) : Dumpable {
+
+    private val density: Float
+        get() = res.displayMetrics.density
+
+    var isMultipleRadius: Boolean = false
+        private set
+
+    private var roundedDrawable: Drawable? = null
+
+    var topRoundedDrawable: Drawable? = null
+        private set
+
+    var bottomRoundedDrawable: Drawable? = null
+        private set
+
+    private var roundedSize = Size(0, 0)
+
+    var topRoundedSize = Size(0, 0)
+        private set
+
+    var bottomRoundedSize = Size(0, 0)
+        private set
+
+    init {
+        reloadDrawables()
+        reloadMeasures()
+    }
+
+    fun reloadAll(newDisplayUniqueId: String?) {
+        displayUniqueId = newDisplayUniqueId
+        reloadDrawables()
+        reloadMeasures()
+    }
+
+    private fun reloadDrawables() {
+        val configIdx = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId)
+        isMultipleRadius = getIsMultipleRadius(configIdx)
+
+        roundedDrawable = getDrawable(
+                displayConfigIndex = configIdx,
+                arrayResId = R.array.config_roundedCornerDrawableArray,
+                backupDrawableId = R.drawable.rounded
+        )
+        topRoundedDrawable = getDrawable(
+                displayConfigIndex = configIdx,
+                arrayResId = R.array.config_roundedCornerTopDrawableArray,
+                backupDrawableId = R.drawable.rounded_corner_top
+        ) ?: roundedDrawable
+        bottomRoundedDrawable = getDrawable(
+                displayConfigIndex = configIdx,
+                arrayResId = R.array.config_roundedCornerBottomDrawableArray,
+                backupDrawableId = R.drawable.rounded_corner_bottom
+        ) ?: roundedDrawable
+
+        // If config_roundedCornerMultipleRadius set as true, ScreenDecorations respect the
+        // (width, height) size of drawable/rounded.xml instead of rounded_corner_radius
+        if (isMultipleRadius) {
+            roundedSize = Size(
+                    roundedDrawable?.intrinsicWidth ?: 0,
+                    roundedDrawable?.intrinsicHeight ?: 0)
+            topRoundedDrawable?.let {
+                topRoundedSize = Size(it.intrinsicWidth, it.intrinsicHeight)
+            }
+            bottomRoundedDrawable?.let {
+                bottomRoundedSize = Size(it.intrinsicWidth, it.intrinsicHeight)
+            }
+        } else {
+            val defaultRadius = RoundedCorners.getRoundedCornerRadius(res, displayUniqueId)
+            val topRadius = RoundedCorners.getRoundedCornerTopRadius(res, displayUniqueId)
+            val bottomRadius = RoundedCorners.getRoundedCornerBottomRadius(res, displayUniqueId)
+            roundedSize = Size(defaultRadius, defaultRadius)
+            topRoundedSize = Size(topRadius, topRadius)
+            bottomRoundedSize = Size(bottomRadius, bottomRadius)
+        }
+
+        if (topRoundedSize.width == 0) {
+            topRoundedSize = roundedSize
+        }
+        if (bottomRoundedSize.width == 0) {
+            bottomRoundedSize = roundedSize
+        }
+    }
+
+    private fun reloadMeasures(roundedSizeFactor: Int? = null) {
+        // If config_roundedCornerMultipleRadius set as true, ScreenDecorations respect the
+        // (width, height) size of drawable/rounded.xml instead of rounded_corner_radius
+        if (isMultipleRadius) {
+            roundedSize = Size(
+                    roundedDrawable?.intrinsicWidth ?: 0,
+                    roundedDrawable?.intrinsicHeight ?: 0)
+            topRoundedDrawable?.let {
+                topRoundedSize = Size(it.intrinsicWidth, it.intrinsicHeight)
+            }
+            bottomRoundedDrawable?.let {
+                bottomRoundedSize = Size(it.intrinsicWidth, it.intrinsicHeight)
+            }
+        } else {
+            val defaultRadius = RoundedCorners.getRoundedCornerRadius(res, displayUniqueId)
+            val topRadius = RoundedCorners.getRoundedCornerTopRadius(res, displayUniqueId)
+            val bottomRadius = RoundedCorners.getRoundedCornerBottomRadius(res, displayUniqueId)
+            roundedSize = Size(defaultRadius, defaultRadius)
+            topRoundedSize = Size(topRadius, topRadius)
+            bottomRoundedSize = Size(bottomRadius, bottomRadius)
+        }
+
+        roundedSizeFactor ?.let {
+            val length: Int = (it * density).toInt()
+            roundedSize = Size(length, length)
+        }
+
+        if (topRoundedSize.width == 0) {
+            topRoundedSize = roundedSize
+        }
+        if (bottomRoundedSize.width == 0) {
+            bottomRoundedSize = roundedSize
+        }
+    }
+
+    fun updateTuningSizeFactor(factor: Int) {
+        reloadMeasures(factor)
+    }
+
+    /**
+     * Gets whether the rounded corners are multiple radii for current display.
+     *
+     * Loads the default config {@link R.bool#config_roundedCornerMultipleRadius} if
+     * {@link com.android.internal.R.array#config_displayUniqueIdArray} is not set.
+     */
+    private fun getIsMultipleRadius(displayConfigIndex: Int): Boolean {
+        val isMultipleRadius: Boolean
+        res.obtainTypedArray(R.array.config_roundedCornerMultipleRadiusArray).let { array ->
+            isMultipleRadius = if (displayConfigIndex >= 0 && displayConfigIndex < array.length()) {
+                array.getBoolean(displayConfigIndex, false)
+            } else {
+                res.getBoolean(R.bool.config_roundedCornerMultipleRadius)
+            }
+            array.recycle()
+        }
+        return isMultipleRadius
+    }
+
+    private fun getDrawable(
+        displayConfigIndex: Int,
+        @ArrayRes arrayResId: Int,
+        @DrawableRes backupDrawableId: Int
+    ): Drawable? {
+        val drawable: Drawable?
+        res.obtainTypedArray(arrayResId).let { array ->
+            drawable = if (displayConfigIndex >= 0 && displayConfigIndex < array.length()) {
+                array.getDrawable(displayConfigIndex)
+            } else {
+                res.getDrawable(backupDrawableId, null)
+            }
+            array.recycle()
+        }
+        return drawable
+    }
+
+    override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
+        pw.println("RoundedCornerResDelegate state:")
+        pw.println("  isMultipleRadius:$isMultipleRadius")
+        pw.println("  roundedSize(w,h)=(${roundedSize.width},${roundedSize.height})")
+        pw.println("  topRoundedSize(w,h)=(${topRoundedSize.width},${topRoundedSize.height})")
+        pw.println("  bottomRoundedSize(w,h)=(${bottomRoundedSize.width}," +
+                "${bottomRoundedSize.height})")
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index 0a2e69f..8e1d645 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -319,9 +319,10 @@
     /**
      * Appends the doze state that was suppressed to the doze event log
      * @param suppressedState The {@link DozeMachine.State} that was suppressed
+     * @param reason what suppressed always on
      */
-    public void traceAlwaysOnSuppressed(DozeMachine.State suppressedState) {
-        mLogger.logAlwaysOnSuppressed(suppressedState);
+    public void traceAlwaysOnSuppressed(DozeMachine.State suppressedState, String reason) {
+        mLogger.logAlwaysOnSuppressed(suppressedState, reason);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
index f3f6be2..4c81563 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
@@ -267,11 +267,12 @@
         })
     }
 
-    fun logAlwaysOnSuppressed(state: DozeMachine.State) {
+    fun logAlwaysOnSuppressed(state: DozeMachine.State, reason: String) {
         buffer.log(TAG, INFO, {
             str1 = state.name
+            str2 = reason
         }, {
-            "Always-on state suppressed, suppressed state=$str1"
+            "Always-on state suppressed, suppressed state=$str1 reason=$str2"
         })
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index ae01f0a..5779bb3 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -358,8 +358,13 @@
             return State.FINISH;
         }
         if (mDozeHost.isAlwaysOnSuppressed() && requestedState.isAlwaysOn()) {
-            Log.i(TAG, "Doze is suppressed. Suppressing state: " + requestedState);
-            mDozeLog.traceAlwaysOnSuppressed(requestedState);
+            Log.i(TAG, "Doze is suppressed by an app. Suppressing state: " + requestedState);
+            mDozeLog.traceAlwaysOnSuppressed(requestedState, "app");
+            return State.DOZE;
+        }
+        if (mDozeHost.isPowerSaveActive() && requestedState.isAlwaysOn()) {
+            Log.i(TAG, "Doze is suppressed by battery saver. Suppressing state: " + requestedState);
+            mDozeLog.traceAlwaysOnSuppressed(requestedState, "batterySaver");
             return State.DOZE;
         }
         if ((mState == State.DOZE_AOD_PAUSED || mState == State.DOZE_AOD_PAUSING
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index b8b4092..dfb27ef 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -89,6 +89,7 @@
     private boolean mPaused = false;
     private boolean mScreenOff = false;
     private int mLastSensorValue = -1;
+    private DozeMachine.State mState = DozeMachine.State.UNINITIALIZED;
 
     /**
      * Debug value used for emulating various display brightness buckets:
@@ -135,6 +136,7 @@
 
     @Override
     public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
+        mState = newState;
         switch (newState) {
             case INITIALIZED:
                 resetBrightnessToDefault();
@@ -262,8 +264,9 @@
      */
     private int clampToDimBrightnessForScreenOff(int brightness) {
         final boolean screenTurningOff =
-                mDozeParameters.shouldClampToDimBrightness()
-                        || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_GOING_TO_SLEEP;
+                (mDozeParameters.shouldClampToDimBrightness()
+                        || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_GOING_TO_SLEEP)
+                && mState == DozeMachine.State.INITIALIZED;
         if (screenTurningOff
                 && mWakefulnessLifecycle.getLastSleepReason() == GO_TO_SLEEP_REASON_TIMEOUT) {
             return Math.max(
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 19b0ea1..b06bf89 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -136,6 +136,8 @@
     @Override
     public void setDozeScreenState(int state) {
         super.setDozeScreenState(state);
-        mDozeMachine.onScreenState(state);
+        if (mDozeMachine != null) {
+            mDozeMachine.onScreenState(state);
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java
index 31d43b5..89f50ad 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java
@@ -166,6 +166,8 @@
     private DozeHost.Callback mHostCallback = new DozeHost.Callback() {
         @Override
         public void onPowerSaveChanged(boolean active) {
+            // handles suppression changes, while DozeMachine#transitionPolicy handles gating
+            // transitions to DOZE_AOD
             DozeMachine.State nextState = null;
             if (mDozeHost.isPowerSaveActive()) {
                 nextState = DozeMachine.State.DOZE;
@@ -182,6 +184,8 @@
 
         @Override
         public void onAlwaysOnSuppressedChanged(boolean suppressed) {
+            // handles suppression changes, while DozeMachine#transitionPolicy handles gating
+            // transitions to DOZE_AOD
             final DozeMachine.State nextState;
             if (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT) && !suppressed) {
                 nextState = DozeMachine.State.DOZE_AOD;
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index 69f15e6..330bd6c 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -23,12 +23,13 @@
 import android.view.View;
 import android.view.ViewGroup;
 
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.R;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dreams.complication.ComplicationHostViewController;
 import com.android.systemui.dreams.dagger.DreamOverlayComponent;
 import com.android.systemui.dreams.dagger.DreamOverlayModule;
+import com.android.systemui.statusbar.BlurUtils;
+import com.android.systemui.statusbar.phone.KeyguardBouncer;
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.util.ViewController;
 
 import javax.inject.Inject;
@@ -39,10 +40,9 @@
  */
 @DreamOverlayComponent.DreamOverlayScope
 public class DreamOverlayContainerViewController extends ViewController<DreamOverlayContainerView> {
-    // The height of the area at the top of the dream overlay to allow dragging down the
-    // notifications shade.
-    private final int mDreamOverlayNotificationsDragAreaHeight;
     private final DreamOverlayStatusBarViewController mStatusBarViewController;
+    private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+    private final BlurUtils mBlurUtils;
 
     private final ComplicationHostViewController mComplicationHostViewController;
 
@@ -65,12 +65,57 @@
 
     private long mJitterStartTimeMillis;
 
+    private boolean mBouncerAnimating;
+
+    private final KeyguardBouncer.BouncerExpansionCallback mBouncerExpansionCallback =
+            new KeyguardBouncer.BouncerExpansionCallback() {
+
+                @Override
+                public void onStartingToShow() {
+                    mBouncerAnimating = true;
+                }
+
+                @Override
+                public void onStartingToHide() {
+                    mBouncerAnimating = true;
+                }
+
+                @Override
+                public void onFullyHidden() {
+                    mBouncerAnimating = false;
+                }
+
+                @Override
+                public void onFullyShown() {
+                    mBouncerAnimating = false;
+                }
+
+                @Override
+                public void onExpansionChanged(float bouncerHideAmount) {
+                    if (!mBouncerAnimating) return;
+                    final int blurRadius =
+                            (int) mBlurUtils.blurRadiusOfRatio(1 - bouncerHideAmount);
+                    updateTransitionState(blurRadius, bouncerHideAmount);
+                }
+
+                @Override
+                public void onVisibilityChanged(boolean isVisible) {
+                    // The bouncer may be hidden abruptly without triggering onExpansionChanged.
+                    // In this case, we should reset the transition state.
+                    if (!isVisible) {
+                        updateTransitionState(0, 1f);
+                    }
+                }
+            };
+
     @Inject
     public DreamOverlayContainerViewController(
             DreamOverlayContainerView containerView,
             ComplicationHostViewController complicationHostViewController,
             @Named(DreamOverlayModule.DREAM_OVERLAY_CONTENT_VIEW) ViewGroup contentView,
             DreamOverlayStatusBarViewController statusBarViewController,
+            StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+            BlurUtils blurUtils,
             @Main Handler handler,
             @Named(DreamOverlayModule.MAX_BURN_IN_OFFSET) int maxBurnInOffset,
             @Named(DreamOverlayModule.BURN_IN_PROTECTION_UPDATE_INTERVAL) long
@@ -79,9 +124,8 @@
         super(containerView);
         mDreamOverlayContentView = contentView;
         mStatusBarViewController = statusBarViewController;
-        mDreamOverlayNotificationsDragAreaHeight =
-                mView.getResources().getDimensionPixelSize(
-                        R.dimen.dream_overlay_notifications_drag_area_height);
+        mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+        mBlurUtils = blurUtils;
 
         mComplicationHostViewController = complicationHostViewController;
         final View view = mComplicationHostViewController.getView();
@@ -106,22 +150,25 @@
     protected void onViewAttached() {
         mJitterStartTimeMillis = System.currentTimeMillis();
         mHandler.postDelayed(this::updateBurnInOffsets, mBurnInProtectionUpdateInterval);
+        final KeyguardBouncer bouncer = mStatusBarKeyguardViewManager.getBouncer();
+        if (bouncer != null) {
+            bouncer.addBouncerExpansionCallback(mBouncerExpansionCallback);
+        }
     }
 
     @Override
     protected void onViewDetached() {
         mHandler.removeCallbacks(this::updateBurnInOffsets);
+        final KeyguardBouncer bouncer = mStatusBarKeyguardViewManager.getBouncer();
+        if (bouncer != null) {
+            bouncer.removeBouncerExpansionCallback(mBouncerExpansionCallback);
+        }
     }
 
     View getContainerView() {
         return mView;
     }
 
-    @VisibleForTesting
-    int getDreamOverlayNotificationsDragAreaHeight() {
-        return mDreamOverlayNotificationsDragAreaHeight;
-    }
-
     private void updateBurnInOffsets() {
         int burnInOffset = mMaxBurnInOffset;
 
@@ -144,4 +191,9 @@
 
         mHandler.postDelayed(this::updateBurnInOffsets, mBurnInProtectionUpdateInterval);
     }
+
+    private void updateTransitionState(int blurRadiusPixels, float alpha) {
+        mBlurUtils.applyBlur(mView.getViewRootImpl(), blurRadiusPixels, false);
+        mView.setAlpha(alpha);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayNotificationCountProvider.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayNotificationCountProvider.java
new file mode 100644
index 0000000..aaa34ed
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayNotificationCountProvider.java
@@ -0,0 +1,116 @@
+/*
+ * 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.systemui.dreams;
+
+import android.annotation.NonNull;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
+import com.android.systemui.statusbar.policy.CallbackController;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.inject.Inject;
+
+/***
+ * {@link DreamOverlayNotificationCountProvider} provides the current notification count to
+ * registered callbacks.
+ */
+@SysUISingleton
+public class DreamOverlayNotificationCountProvider
+        implements CallbackController<DreamOverlayNotificationCountProvider.Callback> {
+    private final Set<String> mNotificationKeys = new HashSet<>();
+    private final List<Callback> mCallbacks = new ArrayList<>();
+
+    private final NotificationHandler mNotificationHandler = new NotificationHandler() {
+        @Override
+        public void onNotificationPosted(
+                StatusBarNotification sbn, NotificationListenerService.RankingMap rankingMap) {
+            mNotificationKeys.add(sbn.getKey());
+            reportNotificationCountChanged();
+        }
+
+        @Override
+        public void onNotificationRemoved(
+                StatusBarNotification sbn, NotificationListenerService.RankingMap rankingMap) {
+            mNotificationKeys.remove(sbn.getKey());
+            reportNotificationCountChanged();
+        }
+
+        @Override
+        public void onNotificationRemoved(
+                StatusBarNotification sbn,
+                NotificationListenerService.RankingMap rankingMap,
+                int reason) {
+            mNotificationKeys.remove(sbn.getKey());
+            reportNotificationCountChanged();
+        }
+
+        @Override
+        public void onNotificationRankingUpdate(NotificationListenerService.RankingMap rankingMap) {
+        }
+
+        @Override
+        public void onNotificationsInitialized() {
+        }
+    };
+
+    @Inject
+    public DreamOverlayNotificationCountProvider(
+            NotificationListener notificationListener) {
+        notificationListener.addNotificationHandler(mNotificationHandler);
+        Arrays.stream(notificationListener.getActiveNotifications())
+                .forEach(sbn -> mNotificationKeys.add(sbn.getKey()));
+    }
+
+    @Override
+    public void addCallback(@NonNull Callback callback) {
+        if (!mCallbacks.contains(callback)) {
+            mCallbacks.add(callback);
+            callback.onNotificationCountChanged(mNotificationKeys.size());
+        }
+    }
+
+    @Override
+    public void removeCallback(@NonNull Callback callback) {
+        mCallbacks.remove(callback);
+    }
+
+    private void reportNotificationCountChanged() {
+        final int notificationCount = mNotificationKeys.size();
+        mCallbacks.forEach(callback -> callback.onNotificationCountChanged(notificationCount));
+    }
+
+    /**
+     * A callback to be registered with {@link DreamOverlayNotificationCountProvider} to receive
+     * changes to the current notification count.
+     */
+    public interface Callback {
+        /**
+         * Called when the notification count has changed.
+         * @param count The current notification count.
+         */
+        void onNotificationCountChanged(int count);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index dfbb0c7..db225cf 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -26,10 +26,13 @@
 import android.view.WindowManager;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
 import androidx.lifecycle.Lifecycle;
 import androidx.lifecycle.LifecycleRegistry;
 import androidx.lifecycle.ViewModelStore;
 
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
 import com.android.internal.policy.PhoneWindow;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
@@ -61,6 +64,7 @@
     private final DreamOverlayContainerViewController mDreamOverlayContainerViewController;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final DreamPreviewComplication mPreviewComplication;
+    private final UiEventLogger mUiEventLogger;
 
     // A reference to the {@link Window} used to hold the dream overlay.
     private Window mWindow;
@@ -97,6 +101,25 @@
 
     private DreamOverlayStateController mStateController;
 
+    @VisibleForTesting
+    public enum DreamOverlayEvent implements UiEventLogger.UiEventEnum {
+        @UiEvent(doc = "The dream overlay has entered start.")
+        DREAM_OVERLAY_ENTER_START(989),
+        @UiEvent(doc = "The dream overlay has completed start.")
+        DREAM_OVERLAY_COMPLETE_START(990);
+
+        private final int mId;
+
+        DreamOverlayEvent(int id) {
+            mId = id;
+        }
+
+        @Override
+        public int getId() {
+            return mId;
+        }
+    }
+
     @Inject
     public DreamOverlayService(
             Context context,
@@ -104,13 +127,15 @@
             DreamOverlayComponent.Factory dreamOverlayComponentFactory,
             DreamOverlayStateController stateController,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
-            DreamPreviewComplication previewComplication) {
+            DreamPreviewComplication previewComplication,
+            UiEventLogger uiEventLogger) {
         mContext = context;
         mExecutor = executor;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mKeyguardUpdateMonitor.registerCallback(mKeyguardCallback);
         mStateController = stateController;
         mPreviewComplication = previewComplication;
+        mUiEventLogger = uiEventLogger;
 
         final DreamOverlayComponent component =
                 dreamOverlayComponentFactory.create(mViewModelStore, mHost);
@@ -143,6 +168,7 @@
 
     @Override
     public void onStartDream(@NonNull WindowManager.LayoutParams layoutParams) {
+        mUiEventLogger.log(DreamOverlayEvent.DREAM_OVERLAY_ENTER_START);
         setCurrentState(Lifecycle.State.STARTED);
         mExecutor.execute(() -> {
             if (mDestroyed) {
@@ -159,6 +185,7 @@
             addOverlayWindowLocked(layoutParams);
             setCurrentState(Lifecycle.State.RESUMED);
             mStateController.setOverlayActive(true);
+            mUiEventLogger.log(DreamOverlayEvent.DREAM_OVERLAY_COMPLETE_START);
         });
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
index d2ab611..59a17ba 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
@@ -88,10 +88,6 @@
                 fetchStatusIconForResId(R.id.dream_overlay_priority_mode));
     }
 
-    void showIcon(@StatusIconType int iconType, boolean show) {
-        showIcon(iconType, show, null);
-    }
-
     void showIcon(@StatusIconType int iconType, boolean show, @Nullable String contentDescription) {
         View icon = mStatusIcons.get(iconType);
         if (icon == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
index a25a742..d4909c78 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.dreams;
 
+import android.annotation.Nullable;
 import android.app.AlarmManager;
 import android.content.res.Resources;
 import android.hardware.SensorPrivacyManager;
@@ -26,16 +27,12 @@
 import android.net.NetworkRequest;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.service.notification.NotificationListenerService.RankingMap;
-import android.service.notification.StatusBarNotification;
 import android.text.format.DateFormat;
 import android.util.PluralsMessageFormatter;
 
 import com.android.systemui.R;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dreams.dagger.DreamOverlayComponent;
-import com.android.systemui.statusbar.NotificationListener;
-import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
 import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
 import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.ZenModeController;
@@ -45,6 +42,7 @@
 
 import java.util.Locale;
 import java.util.Map;
+import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
 
@@ -60,8 +58,11 @@
     private final Resources mResources;
     private final DateFormatUtil mDateFormatUtil;
     private final IndividualSensorPrivacyController mSensorPrivacyController;
-    private final NotificationListener mNotificationListener;
+    private final DreamOverlayNotificationCountProvider mDreamOverlayNotificationCountProvider;
     private final ZenModeController mZenModeController;
+    private final Executor mMainExecutor;
+
+    private boolean mIsAttached;
 
     private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder()
             .clearCapabilities()
@@ -91,35 +92,6 @@
     private final NextAlarmController.NextAlarmChangeCallback mNextAlarmCallback =
             nextAlarm -> updateAlarmStatusIcon();
 
-    private final NotificationHandler mNotificationHandler = new NotificationHandler() {
-        @Override
-        public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
-            updateNotificationsStatusIcon();
-        }
-
-        @Override
-        public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) {
-            updateNotificationsStatusIcon();
-        }
-
-        @Override
-        public void onNotificationRemoved(
-                StatusBarNotification sbn,
-                RankingMap rankingMap,
-                int reason) {
-            updateNotificationsStatusIcon();
-        }
-
-        @Override
-        public void onNotificationRankingUpdate(RankingMap rankingMap) {
-        }
-
-        @Override
-        public void onNotificationsInitialized() {
-            updateNotificationsStatusIcon();
-        }
-    };
-
     private final ZenModeController.Callback mZenModeCallback = new ZenModeController.Callback() {
         @Override
         public void onZenChanged(int zen) {
@@ -127,37 +99,43 @@
         }
     };
 
+    private final DreamOverlayNotificationCountProvider.Callback mNotificationCountCallback =
+            notificationCount -> showIcon(
+                    DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS,
+                    notificationCount > 0,
+                    notificationCount > 0
+                            ? buildNotificationsContentDescription(notificationCount)
+                            : null);
+
     @Inject
     public DreamOverlayStatusBarViewController(
             DreamOverlayStatusBarView view,
             @Main Resources resources,
+            @Main Executor mainExecutor,
             ConnectivityManager connectivityManager,
             TouchInsetManager.TouchInsetSession touchInsetSession,
             AlarmManager alarmManager,
             NextAlarmController nextAlarmController,
             DateFormatUtil dateFormatUtil,
             IndividualSensorPrivacyController sensorPrivacyController,
-            NotificationListener notificationListener,
+            DreamOverlayNotificationCountProvider dreamOverlayNotificationCountProvider,
             ZenModeController zenModeController) {
         super(view);
         mResources = resources;
+        mMainExecutor = mainExecutor;
         mConnectivityManager = connectivityManager;
         mTouchInsetSession = touchInsetSession;
         mAlarmManager = alarmManager;
         mNextAlarmController = nextAlarmController;
         mDateFormatUtil = dateFormatUtil;
         mSensorPrivacyController = sensorPrivacyController;
-        mNotificationListener = notificationListener;
+        mDreamOverlayNotificationCountProvider = dreamOverlayNotificationCountProvider;
         mZenModeController = zenModeController;
-
-        // Handlers can be added to NotificationListener, but apparently they can't be removed. So
-        // add the handler here in the constructor rather than in onViewAttached to avoid confusion.
-        mNotificationListener.addNotificationHandler(mNotificationHandler);
     }
 
     @Override
     protected void onViewAttached() {
-        updateNotificationsStatusIcon();
+        mIsAttached = true;
 
         mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback);
         updateWifiUnavailableStatusIcon();
@@ -171,6 +149,7 @@
         mZenModeController.addCallback(mZenModeCallback);
         updatePriorityModeStatusIcon();
 
+        mDreamOverlayNotificationCountProvider.addCallback(mNotificationCountCallback);
         mTouchInsetSession.addViewToTracking(mView);
     }
 
@@ -180,7 +159,10 @@
         mSensorPrivacyController.removeCallback(mSensorCallback);
         mNextAlarmController.removeCallback(mNextAlarmCallback);
         mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
+        mDreamOverlayNotificationCountProvider.removeCallback(mNotificationCountCallback);
         mTouchInsetSession.clear();
+
+        mIsAttached = false;
     }
 
     private void updateWifiUnavailableStatusIcon() {
@@ -189,14 +171,14 @@
                         mConnectivityManager.getActiveNetwork());
         final boolean available = capabilities != null
                 && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
-        mView.showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, !available);
+        showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, !available);
     }
 
     private void updateAlarmStatusIcon() {
         final AlarmManager.AlarmClockInfo alarm =
                 mAlarmManager.getNextAlarmClock(UserHandle.USER_CURRENT);
         final boolean hasAlarm = alarm != null && alarm.getTriggerTime() > 0;
-        mView.showIcon(
+        showIcon(
                 DreamOverlayStatusBarView.STATUS_ICON_ALARM_SET,
                 hasAlarm,
                 hasAlarm ? buildAlarmContentDescription(alarm) : null);
@@ -215,29 +197,11 @@
                 .isSensorBlocked(SensorPrivacyManager.Sensors.MICROPHONE);
         final boolean cameraBlocked = mSensorPrivacyController
                 .isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA);
-        mView.showIcon(
+        showIcon(
                 DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED,
                 micBlocked && cameraBlocked);
     }
 
-    private void updateNotificationsStatusIcon() {
-        if (mView == null) {
-            // It is possible for this method to be called before the view is attached, which makes
-            // null-checking necessary.
-            return;
-        }
-
-        final StatusBarNotification[] notifications =
-                mNotificationListener.getActiveNotifications();
-        final int notificationCount = notifications != null ? notifications.length : 0;
-        mView.showIcon(
-                DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS,
-                notificationCount > 0,
-                notificationCount > 0
-                        ? buildNotificationsContentDescription(notificationCount)
-                        : null);
-    }
-
     private String buildNotificationsContentDescription(int notificationCount) {
         return PluralsMessageFormatter.format(
                 mResources,
@@ -246,8 +210,23 @@
     }
 
     private void updatePriorityModeStatusIcon() {
-        mView.showIcon(
+        showIcon(
                 DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON,
                 mZenModeController.getZen() != Settings.Global.ZEN_MODE_OFF);
     }
+
+    private void showIcon(@DreamOverlayStatusBarView.StatusIconType int iconType, boolean show) {
+        showIcon(iconType, show, null);
+    }
+
+    private void showIcon(
+            @DreamOverlayStatusBarView.StatusIconType int iconType,
+            boolean show,
+            @Nullable String contentDescription) {
+        mMainExecutor.execute(() -> {
+            if (mIsAttached) {
+                mView.showIcon(iconType, show, contentDescription);
+            }
+        });
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java
index aa43383..4065a25 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java
@@ -540,13 +540,15 @@
     /**
      * Removes a complication by {@link ComplicationId}.
      */
-    public void removeComplication(ComplicationId id) {
-        if (!mEntries.containsKey(id)) {
+    public boolean removeComplication(ComplicationId id) {
+        final ViewEntry entry = mEntries.remove(id);
+
+        if (entry == null) {
             Log.e(TAG, "could not find id:" + id);
-            return;
+            return false;
         }
 
-        final ViewEntry entry = mEntries.get(id);
         entry.remove();
+        return true;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockDateComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockDateComplication.java
index 6861c74..1ca06b2 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockDateComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockDateComplication.java
@@ -16,32 +16,32 @@
 
 package com.android.systemui.dreams.complication;
 
-import static com.android.systemui.dreams.complication.dagger.DreamClockDateComplicationComponent.DreamClockDateComplicationModule.DREAM_CLOCK_DATE_COMPLICATION_LAYOUT_PARAMS;
-import static com.android.systemui.dreams.complication.dagger.DreamClockDateComplicationComponent.DreamClockDateComplicationModule.DREAM_CLOCK_DATE_COMPLICATION_VIEW;
+import static com.android.systemui.dreams.complication.dagger.DreamClockDateComplicationModule.DREAM_CLOCK_DATE_COMPLICATION_LAYOUT_PARAMS;
+import static com.android.systemui.dreams.complication.dagger.DreamClockDateComplicationModule.DREAM_CLOCK_DATE_COMPLICATION_VIEW;
 
 import android.content.Context;
 import android.view.View;
 
 import com.android.systemui.CoreStartable;
 import com.android.systemui.dreams.DreamOverlayStateController;
-import com.android.systemui.dreams.complication.dagger.DreamClockDateComplicationComponent;
 
 import javax.inject.Inject;
 import javax.inject.Named;
+import javax.inject.Provider;
 
 /**
  * Clock Date Complication that produce Clock Date view holder.
  */
 public class DreamClockDateComplication implements Complication {
-    DreamClockDateComplicationComponent.Factory mComponentFactory;
+    private final Provider<DreamClockDateViewHolder> mDreamClockDateViewHolderProvider;
 
     /**
      * Default constructor for {@link DreamClockDateComplication}.
      */
     @Inject
     public DreamClockDateComplication(
-            DreamClockDateComplicationComponent.Factory componentFactory) {
-        mComponentFactory = componentFactory;
+            Provider<DreamClockDateViewHolder> dreamClockDateViewHolderProvider) {
+        mDreamClockDateViewHolderProvider = dreamClockDateViewHolderProvider;
     }
 
     @Override
@@ -54,11 +54,11 @@
      */
     @Override
     public ViewHolder createView(ComplicationViewModel model) {
-        return mComponentFactory.create().getViewHolder();
+        return mDreamClockDateViewHolderProvider.get();
     }
 
     /**
-     * {@link CoreStartable} responsbile for registering {@link DreamClockDateComplication} with
+     * {@link CoreStartable} responsible for registering {@link DreamClockDateComplication} with
      * SystemUI.
      */
     public static class Registrant extends CoreStartable {
@@ -84,7 +84,7 @@
     }
 
     /**
-     * ViewHolder to contain value/logic associated with a Clock Date Complication View.
+     * {@link ViewHolder} to contain value/logic associated with {@link DreamClockDateComplication}.
      */
     public static class DreamClockDateViewHolder implements ViewHolder {
         private final View mView;
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java
index 936767a..7f67ecd 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java
@@ -16,32 +16,32 @@
 
 package com.android.systemui.dreams.complication;
 
-import static com.android.systemui.dreams.complication.dagger.DreamClockTimeComplicationComponent.DreamClockTimeComplicationModule.DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS;
-import static com.android.systemui.dreams.complication.dagger.DreamClockTimeComplicationComponent.DreamClockTimeComplicationModule.DREAM_CLOCK_TIME_COMPLICATION_VIEW;
+import static com.android.systemui.dreams.complication.dagger.DreamClockTimeComplicationModule.DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS;
+import static com.android.systemui.dreams.complication.dagger.DreamClockTimeComplicationModule.DREAM_CLOCK_TIME_COMPLICATION_VIEW;
 
 import android.content.Context;
 import android.view.View;
 
 import com.android.systemui.CoreStartable;
 import com.android.systemui.dreams.DreamOverlayStateController;
-import com.android.systemui.dreams.complication.dagger.DreamClockTimeComplicationComponent;
 
 import javax.inject.Inject;
 import javax.inject.Named;
+import javax.inject.Provider;
 
 /**
  * Clock Time Complication that produce Clock Time view holder.
  */
 public class DreamClockTimeComplication implements Complication {
-    DreamClockTimeComplicationComponent.Factory mComponentFactory;
+    private final Provider<DreamClockTimeViewHolder> mDreamClockTimeViewHolderProvider;
 
     /**
      * Default constructor for {@link DreamClockTimeComplication}.
      */
     @Inject
     public DreamClockTimeComplication(
-            DreamClockTimeComplicationComponent.Factory componentFactory) {
-        mComponentFactory = componentFactory;
+            Provider<DreamClockTimeViewHolder> dreamClockTimeViewHolderProvider) {
+        mDreamClockTimeViewHolderProvider = dreamClockTimeViewHolderProvider;
     }
 
     @Override
@@ -54,11 +54,11 @@
      */
     @Override
     public ViewHolder createView(ComplicationViewModel model) {
-        return mComponentFactory.create().getViewHolder();
+        return mDreamClockTimeViewHolderProvider.get();
     }
 
     /**
-     * {@link CoreStartable} responsbile for registering {@link DreamClockTimeComplication} with
+     * {@link CoreStartable} responsible for registering {@link DreamClockTimeComplication} with
      * SystemUI.
      */
     public static class Registrant extends CoreStartable {
@@ -84,7 +84,7 @@
     }
 
     /**
-     * ViewHolder to contain value/logic associated with a Clock Time Complication View.
+     * {@link ViewHolder} to contain value/logic associated with {@link DreamClockTimeComplication}.
      */
     public static class DreamClockTimeViewHolder implements ViewHolder {
         private final View mView;
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationComponent.java
deleted file mode 100644
index dd7f10c..0000000
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationComponent.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * 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.systemui.dreams.complication.dagger;
-
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.android.internal.util.Preconditions;
-import com.android.systemui.R;
-import com.android.systemui.dreams.complication.ComplicationLayoutParams;
-import com.android.systemui.dreams.complication.DreamClockDateComplication.DreamClockDateViewHolder;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
-import javax.inject.Named;
-import javax.inject.Scope;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.Subcomponent;
-
-/**
- * {@link DreamClockDateComplicationComponent} is responsible for generating dependencies
- * surrounding the
- * Clock Date {@link com.android.systemui.dreams.complication.Complication}, such as the layout
- * details.
- */
-@Subcomponent(modules = {
-        DreamClockDateComplicationComponent.DreamClockDateComplicationModule.class,
-})
-@DreamClockDateComplicationComponent.DreamClockDateComplicationScope
-public interface DreamClockDateComplicationComponent {
-    /**
-     * Creates {@link DreamClockDateViewHolder}.
-     */
-    DreamClockDateViewHolder getViewHolder();
-
-    @Documented
-    @Retention(RUNTIME)
-    @Scope
-    @interface DreamClockDateComplicationScope {
-    }
-
-    /**
-     * Generates {@link DreamClockDateComplicationComponent}.
-     */
-    @Subcomponent.Factory
-    interface Factory {
-        DreamClockDateComplicationComponent create();
-    }
-
-    /**
-     * Scoped values for {@link DreamClockDateComplicationComponent}.
-     */
-    @Module
-    interface DreamClockDateComplicationModule {
-        String DREAM_CLOCK_DATE_COMPLICATION_VIEW = "clock_date_complication_view";
-        String DREAM_CLOCK_DATE_COMPLICATION_LAYOUT_PARAMS =
-                "clock_date_complication_layout_params";
-        // Order weight of insert into parent container
-        int INSERT_ORDER_WEIGHT = 2;
-
-        /**
-         * Provides the complication view.
-         */
-        @Provides
-        @DreamClockDateComplicationScope
-        @Named(DREAM_CLOCK_DATE_COMPLICATION_VIEW)
-        static View provideComplicationView(LayoutInflater layoutInflater) {
-            return Preconditions.checkNotNull(
-                    layoutInflater.inflate(R.layout.dream_overlay_complication_clock_date,
-                            null, false),
-                    "R.layout.dream_overlay_complication_clock_date did not properly inflated");
-        }
-
-        /**
-         * Provides the layout parameters for the complication view.
-         */
-        @Provides
-        @DreamClockDateComplicationScope
-        @Named(DREAM_CLOCK_DATE_COMPLICATION_LAYOUT_PARAMS)
-        static ComplicationLayoutParams provideLayoutParams() {
-            return new ComplicationLayoutParams(0,
-                    ViewGroup.LayoutParams.WRAP_CONTENT,
-                    ComplicationLayoutParams.POSITION_BOTTOM
-                            | ComplicationLayoutParams.POSITION_START,
-                    ComplicationLayoutParams.DIRECTION_END,
-                    INSERT_ORDER_WEIGHT);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationModule.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationModule.java
new file mode 100644
index 0000000..eb2fc5d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationModule.java
@@ -0,0 +1,71 @@
+/*
+ * 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.systemui.dreams.complication.dagger;
+
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.internal.util.Preconditions;
+import com.android.systemui.R;
+import com.android.systemui.dreams.complication.ComplicationLayoutParams;
+import com.android.systemui.dreams.complication.DreamClockDateComplication;
+
+import javax.inject.Named;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Module for providing {@link DreamClockDateComplication}.
+ */
+@Module
+public interface DreamClockDateComplicationModule {
+    String DREAM_CLOCK_DATE_COMPLICATION_VIEW = "clock_date_complication_view";
+    String DREAM_CLOCK_DATE_COMPLICATION_LAYOUT_PARAMS =
+            "clock_date_complication_layout_params";
+    // Order weight of insert into parent container
+    //TODO(b/217199227): move to a single location.
+    int INSERT_ORDER_WEIGHT = 2;
+
+    /**
+     * Provides the complication view.
+     */
+    @Provides
+    @Named(DREAM_CLOCK_DATE_COMPLICATION_VIEW)
+    static View provideComplicationView(LayoutInflater layoutInflater) {
+        return Preconditions.checkNotNull(
+                layoutInflater.inflate(R.layout.dream_overlay_complication_clock_date,
+                        null, false),
+                "R.layout.dream_overlay_complication_clock_date did not properly inflated");
+    }
+
+    /**
+     * Provides the layout parameters for the complication view.
+     */
+    @Provides
+    @Named(DREAM_CLOCK_DATE_COMPLICATION_LAYOUT_PARAMS)
+    static ComplicationLayoutParams provideLayoutParams() {
+        return new ComplicationLayoutParams(0,
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ComplicationLayoutParams.POSITION_BOTTOM
+                        | ComplicationLayoutParams.POSITION_START,
+                ComplicationLayoutParams.DIRECTION_END,
+                INSERT_ORDER_WEIGHT);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationComponent.java
deleted file mode 100644
index de11b61..0000000
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationComponent.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * 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.systemui.dreams.complication.dagger;
-
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextClock;
-
-import com.android.internal.util.Preconditions;
-import com.android.systemui.R;
-import com.android.systemui.dreams.complication.ComplicationLayoutParams;
-import com.android.systemui.dreams.complication.DreamClockTimeComplication.DreamClockTimeViewHolder;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
-import javax.inject.Named;
-import javax.inject.Scope;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.Subcomponent;
-
-/**
- * {@link DreamClockTimeComplicationComponent} is responsible for generating dependencies
- * surrounding the
- * Clock Time {@link com.android.systemui.dreams.complication.Complication}, such as the layout
- * details.
- */
-@Subcomponent(modules = {
-        DreamClockTimeComplicationComponent.DreamClockTimeComplicationModule.class,
-})
-@DreamClockTimeComplicationComponent.DreamClockTimeComplicationScope
-public interface DreamClockTimeComplicationComponent {
-    /**
-     * Creates {@link DreamClockTimeViewHolder}.
-     */
-    DreamClockTimeViewHolder getViewHolder();
-
-    @Documented
-    @Retention(RUNTIME)
-    @Scope
-    @interface DreamClockTimeComplicationScope {
-    }
-
-    /**
-     * Generates {@link DreamClockTimeComplicationComponent}.
-     */
-    @Subcomponent.Factory
-    interface Factory {
-        DreamClockTimeComplicationComponent create();
-    }
-
-    /**
-     * Scoped values for {@link DreamClockTimeComplicationComponent}.
-     */
-    @Module
-    interface DreamClockTimeComplicationModule {
-        String DREAM_CLOCK_TIME_COMPLICATION_VIEW = "clock_time_complication_view";
-        String DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS =
-                "clock_time_complication_layout_params";
-        // Order weight of insert into parent container
-        int INSERT_ORDER_WEIGHT = 0;
-        String TAG_WEIGHT = "'wght' ";
-        int WEIGHT = 200;
-
-        /**
-         * Provides the complication view.
-         */
-        @Provides
-        @DreamClockTimeComplicationScope
-        @Named(DREAM_CLOCK_TIME_COMPLICATION_VIEW)
-        static View provideComplicationView(LayoutInflater layoutInflater) {
-            final TextClock view = Preconditions.checkNotNull((TextClock)
-                            layoutInflater.inflate(R.layout.dream_overlay_complication_clock_time,
-                                    null, false),
-                    "R.layout.dream_overlay_complication_clock_time did not properly inflated");
-            view.setFontVariationSettings(TAG_WEIGHT + WEIGHT);
-            return view;
-        }
-
-        /**
-         * Provides the layout parameters for the complication view.
-         */
-        @Provides
-        @DreamClockTimeComplicationScope
-        @Named(DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS)
-        static ComplicationLayoutParams provideLayoutParams() {
-            return new ComplicationLayoutParams(0,
-                    ViewGroup.LayoutParams.WRAP_CONTENT,
-                    ComplicationLayoutParams.POSITION_BOTTOM
-                            | ComplicationLayoutParams.POSITION_START,
-                    ComplicationLayoutParams.DIRECTION_UP,
-                    INSERT_ORDER_WEIGHT);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationModule.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationModule.java
new file mode 100644
index 0000000..3ad7d3d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationModule.java
@@ -0,0 +1,76 @@
+/*
+ * 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.systemui.dreams.complication.dagger;
+
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextClock;
+
+import com.android.internal.util.Preconditions;
+import com.android.systemui.R;
+import com.android.systemui.dreams.complication.ComplicationLayoutParams;
+import com.android.systemui.dreams.complication.DreamClockTimeComplication;
+
+import javax.inject.Named;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Module for providing {@link DreamClockTimeComplication}.
+ */
+@Module
+public interface DreamClockTimeComplicationModule {
+    String DREAM_CLOCK_TIME_COMPLICATION_VIEW = "clock_time_complication_view";
+    String DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS =
+            "clock_time_complication_layout_params";
+    // Order weight of insert into parent container
+    //TODO(b/217199227): move to a single location.
+    int INSERT_ORDER_WEIGHT = 0;
+    String TAG_WEIGHT = "'wght' ";
+    int WEIGHT = 200;
+
+    /**
+     * Provides the complication view.
+     */
+    @Provides
+    @Named(DREAM_CLOCK_TIME_COMPLICATION_VIEW)
+    static View provideComplicationView(LayoutInflater layoutInflater) {
+        final TextClock view = Preconditions.checkNotNull((TextClock)
+                        layoutInflater.inflate(R.layout.dream_overlay_complication_clock_time,
+                                null, false),
+                "R.layout.dream_overlay_complication_clock_time did not properly inflated");
+        view.setFontVariationSettings(TAG_WEIGHT + WEIGHT);
+        return view;
+    }
+
+    /**
+     * Provides the layout parameters for the complication view.
+     */
+    @Provides
+    @Named(DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS)
+    static ComplicationLayoutParams provideLayoutParams() {
+        return new ComplicationLayoutParams(0,
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ComplicationLayoutParams.POSITION_BOTTOM
+                        | ComplicationLayoutParams.POSITION_START,
+                ComplicationLayoutParams.DIRECTION_UP,
+                INSERT_ORDER_WEIGHT);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java
index 8e4fb37..62a4140c 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java
@@ -24,10 +24,12 @@
  * Module for all components with corresponding dream layer complications registered in
  * {@link SystemUIBinder}.
  */
-@Module(subcomponents = {
-        DreamClockTimeComplicationComponent.class,
-        DreamClockDateComplicationComponent.class,
-        DreamWeatherComplicationComponent.class,
-})
+@Module(includes = {
+                DreamClockDateComplicationModule.class,
+                DreamClockTimeComplicationModule.class,
+        },
+        subcomponents = {
+                DreamWeatherComplicationComponent.class,
+        })
 public interface RegisteredComplicationsModule {
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamsSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamsSmartspaceController.kt
index 4e228a1..9b99c52 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamsSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamsSmartspaceController.kt
@@ -160,9 +160,8 @@
             return
         }
 
-        // TODO(b/217559844): Replace with "dream" session when available.
         val newSession = smartspaceManager.createSmartspaceSession(
-                SmartspaceConfig.Builder(context, "lockscreen").build())
+                SmartspaceConfig.Builder(context, "dream").build())
         Log.d(TAG, "Starting smartspace session for dream")
         newSession.addOnTargetsAvailableListener(uiExecutor, sessionListener)
         this.session = newSession
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
index e140f6b..1b62ec4 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
@@ -31,8 +31,8 @@
 import android.view.VelocityTracker;
 
 import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
+import com.android.systemui.statusbar.phone.KeyguardBouncer;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.wm.shell.animation.FlingAnimationUtils;
 
@@ -82,6 +82,8 @@
 
     private Boolean mCapture;
 
+    private boolean mBouncerInitiallyShowing;
+
     private TouchSession mTouchSession;
 
     private ValueAnimatorCreator mValueAnimatorCreator;
@@ -89,7 +91,7 @@
     private VelocityTrackerFactory mVelocityTrackerFactory;
 
     private final GestureDetector.OnGestureListener mOnGestureListener =
-            new  GestureDetector.SimpleOnGestureListener() {
+            new GestureDetector.SimpleOnGestureListener() {
                 @Override
                 public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
                         float distanceY) {
@@ -97,6 +99,7 @@
                         // If the user scrolling favors a vertical direction, begin capturing
                         // scrolls.
                         mCapture = Math.abs(distanceY) > Math.abs(distanceX);
+                        mBouncerInitiallyShowing = mCentralSurfaces.isBouncerShowing();
 
                         if (mCapture) {
                             // Since the user is dragging the bouncer up, set scrimmed to false.
@@ -115,7 +118,7 @@
                     // (0).
                     final float screenTravelPercentage =
                             Math.abs((e1.getY() - e2.getY()) / mCentralSurfaces.getDisplayHeight());
-                    setPanelExpansion(mCentralSurfaces.isBouncerShowing()
+                    setPanelExpansion(mBouncerInitiallyShowing
                             ? screenTravelPercentage : 1 - screenTravelPercentage);
                     return true;
                 }
@@ -134,9 +137,9 @@
             NotificationShadeWindowController notificationShadeWindowController,
             ValueAnimatorCreator valueAnimatorCreator,
             VelocityTrackerFactory velocityTrackerFactory,
-            @Named(SWIPE_TO_BOUNCER_FLING_ANIMATION_UTILS_CLOSING)
-                    FlingAnimationUtils flingAnimationUtils,
             @Named(SWIPE_TO_BOUNCER_FLING_ANIMATION_UTILS_OPENING)
+                    FlingAnimationUtils flingAnimationUtils,
+            @Named(SWIPE_TO_BOUNCER_FLING_ANIMATION_UTILS_CLOSING)
                     FlingAnimationUtils flingAnimationUtilsClosing,
             @Named(SWIPE_TO_BOUNCER_START_REGION) float swipeRegionPercentage) {
         mDisplayMetrics = displayMetrics;
@@ -154,13 +157,16 @@
     public void getTouchInitiationRegion(Region region) {
         if (mCentralSurfaces.isBouncerShowing()) {
             region.op(new Rect(0, 0, mDisplayMetrics.widthPixels,
-                    Math.round(mDisplayMetrics.heightPixels * mBouncerZoneScreenPercentage)),
+                            Math.round(
+                                    mDisplayMetrics.heightPixels * mBouncerZoneScreenPercentage)),
                     Region.Op.UNION);
         } else {
             region.op(new Rect(0,
-                    Math.round(mDisplayMetrics.heightPixels * (1 - mBouncerZoneScreenPercentage)),
-                    mDisplayMetrics.widthPixels,
-                    mDisplayMetrics.heightPixels),
+                            Math.round(
+                                    mDisplayMetrics.heightPixels
+                                            * (1 - mBouncerZoneScreenPercentage)),
+                            mDisplayMetrics.widthPixels,
+                            mDisplayMetrics.heightPixels),
                     Region.Op.UNION);
         }
     }
@@ -171,18 +177,18 @@
         mTouchSession = session;
         mVelocityTracker.clear();
         mNotificationShadeWindowController.setForcePluginOpen(true, this);
+
+        session.registerCallback(() -> {
+            mVelocityTracker.recycle();
+            mCapture = null;
+            mNotificationShadeWindowController.setForcePluginOpen(false, this);
+        });
+
         session.registerGestureListener(mOnGestureListener);
         session.registerInputListener(ev -> onMotionEvent(ev));
 
     }
 
-    @Override
-    public void onSessionEnd(TouchSession session) {
-        mVelocityTracker.recycle();
-        mCapture = null;
-        mNotificationShadeWindowController.setForcePluginOpen(false, this);
-    }
-
     private void onMotionEvent(InputEvent event) {
         if (!(event instanceof MotionEvent)) {
             Log.e(TAG, "non MotionEvent received:" + event);
@@ -191,7 +197,7 @@
 
         final MotionEvent motionEvent = (MotionEvent) event;
 
-        switch(motionEvent.getAction()) {
+        switch (motionEvent.getAction()) {
             case MotionEvent.ACTION_CANCEL:
             case MotionEvent.ACTION_UP:
                 mTouchSession.pop();
@@ -210,9 +216,8 @@
                 final float velocityVector =
                         (float) Math.hypot(horizontalVelocity, verticalVelocity);
 
-
                 final float expansion = flingRevealsOverlay(verticalVelocity, velocityVector)
-                            ? KeyguardBouncer.EXPANSION_HIDDEN : KeyguardBouncer.EXPANSION_VISIBLE;
+                        ? KeyguardBouncer.EXPANSION_HIDDEN : KeyguardBouncer.EXPANSION_VISIBLE;
                 flingToExpansion(verticalVelocity, expansion);
 
                 if (expansion == KeyguardBouncer.EXPANSION_HIDDEN) {
@@ -236,8 +241,8 @@
     }
 
     protected boolean flingRevealsOverlay(float velocity, float velocityVector) {
-        // Fully expand if the user has expanded the bouncer less than halfway or final velocity was
-        // positive, indicating an downward direction.
+        // Fully expand the space above the bouncer, if the user has expanded the bouncer less
+        // than halfway or final velocity was positive, indicating a downward direction.
         if (Math.abs(velocityVector) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
             return mCurrentExpansion > FLING_PERCENTAGE_THRESHOLD;
         } else {
@@ -246,17 +251,20 @@
     }
 
     protected void flingToExpansion(float velocity, float expansion) {
+        // The animation utils deal in pixel units, rather than expansion height.
         final float viewHeight = mCentralSurfaces.getDisplayHeight();
         final float currentHeight = viewHeight * mCurrentExpansion;
         final float targetHeight = viewHeight * expansion;
 
         final ValueAnimator animator = createExpansionAnimator(expansion);
         if (expansion == KeyguardBouncer.EXPANSION_HIDDEN) {
-            // The animation utils deal in pixel units, rather than expansion height.
-            mFlingAnimationUtils.apply(animator, currentHeight, targetHeight, velocity, viewHeight);
+            // Hides the bouncer, i.e., fully expands the space above the bouncer.
+            mFlingAnimationUtilsClosing.apply(animator, currentHeight, targetHeight, velocity,
+                    viewHeight);
         } else {
-            mFlingAnimationUtilsClosing.apply(
-                    animator, mCurrentExpansion, currentHeight, targetHeight, viewHeight);
+            // Shows the bouncer, i.e., fully collapses the space above the bouncer.
+            mFlingAnimationUtils.apply(
+                    animator, currentHeight, targetHeight, velocity, viewHeight);
         }
 
         animator.start();
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamTouchHandler.java
index 20008d5..8288fcf 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamTouchHandler.java
@@ -96,11 +96,4 @@
      * @param session
      */
     void onSessionStart(TouchSession session);
-
-    /**
-     * Invoked when a session has ended. This will be invoked for every session completion, even
-     * those that are removed through {@link TouchSession#pop()}.
-     * @param session
-     */
-    default void onSessionEnd(TouchSession session) { }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/HideComplicationTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/HideComplicationTouchHandler.java
index d4ba2d8..4965c9d 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/HideComplicationTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/HideComplicationTouchHandler.java
@@ -127,11 +127,4 @@
             }
         });
     }
-
-    @Override
-    public void onSessionEnd(TouchSession session) {
-        if (DEBUG) {
-            Log.d(TAG, "onSessionEnd");
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
index 0c5f7eb..3335c8d 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
@@ -50,9 +50,9 @@
 import java.util.Objects;
 import java.util.TreeMap;
 import java.util.function.Consumer;
-import java.util.function.Supplier;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 
 /**
  * Concrete implementation of the a Flag manager that returns default values for debug builds
@@ -66,12 +66,13 @@
 @SysUISingleton
 public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
     private static final String TAG = "SysUIFlags";
+    static final String ALL_FLAGS = "all_flags";
 
     private final FlagManager mFlagManager;
     private final SecureSettings mSecureSettings;
     private final Resources mResources;
     private final SystemPropertiesHelper mSystemProperties;
-    private final Supplier<Map<Integer, Flag<?>>> mFlagsCollector;
+    private final Map<Integer, Flag<?>> mAllFlags;
     private final Map<Integer, Boolean> mBooleanFlagCache = new TreeMap<>();
     private final Map<Integer, String> mStringFlagCache = new TreeMap<>();
     private final IStatusBarService mBarService;
@@ -84,13 +85,13 @@
             SystemPropertiesHelper systemProperties,
             @Main Resources resources,
             DumpManager dumpManager,
-            @Nullable Supplier<Map<Integer, Flag<?>>> flagsCollector,
+            @Named(ALL_FLAGS) Map<Integer, Flag<?>> allFlags,
             IStatusBarService barService) {
         mFlagManager = flagManager;
         mSecureSettings = secureSettings;
         mResources = resources;
         mSystemProperties = systemProperties;
-        mFlagsCollector = flagsCollector != null ? flagsCollector : Flags::collectFlags;
+        mAllFlags = allFlags;
         IntentFilter filter = new IntentFilter();
         filter.addAction(ACTION_SET_FLAG);
         filter.addAction(ACTION_GET_FLAGS);
@@ -107,7 +108,7 @@
         int id = flag.getId();
         if (!mBooleanFlagCache.containsKey(id)) {
             mBooleanFlagCache.put(id,
-                    readFlagValue(id, flag.getDefault(), BooleanFlagSerializer.INSTANCE));
+                    readFlagValue(id, flag.getDefault()));
         }
 
         return mBooleanFlagCache.get(id);
@@ -118,8 +119,7 @@
         int id = flag.getId();
         if (!mBooleanFlagCache.containsKey(id)) {
             mBooleanFlagCache.put(id,
-                    readFlagValue(id, mResources.getBoolean(flag.getResourceId()),
-                            BooleanFlagSerializer.INSTANCE));
+                    readFlagValue(id, mResources.getBoolean(flag.getResourceId())));
         }
 
         return mBooleanFlagCache.get(id);
@@ -129,8 +129,13 @@
     public boolean isEnabled(@NonNull SysPropBooleanFlag flag) {
         int id = flag.getId();
         if (!mBooleanFlagCache.containsKey(id)) {
+            // Use #readFlagValue to get the default. That will allow it to fall through to
+            // teamfood if need be.
             mBooleanFlagCache.put(
-                    id, mSystemProperties.getBoolean(flag.getName(), flag.getDefault()));
+                    id,
+                    mSystemProperties.getBoolean(
+                            flag.getName(),
+                            readFlagValue(id, flag.getDefault())));
         }
 
         return mBooleanFlagCache.get(id);
@@ -161,6 +166,19 @@
         return mStringFlagCache.get(id);
     }
 
+    /** Specific override for Boolean flags that checks against the teamfood list.*/
+    private boolean readFlagValue(int id, boolean defaultValue) {
+        Boolean result = readFlagValueInternal(id, BooleanFlagSerializer.INSTANCE);
+        // Only check for teamfood if the default is false.
+        if (!defaultValue && result == null && id != Flags.TEAMFOOD.getId()) {
+            if (mAllFlags.containsKey(id) && mAllFlags.get(id).getTeamfood()) {
+                return isEnabled(Flags.TEAMFOOD);
+            }
+        }
+
+        return result == null ? defaultValue : result;
+    }
+
     @NonNull
     private <T> T readFlagValue(int id, @NonNull T defaultValue, FlagSerializer<T> serializer) {
         requireNonNull(defaultValue, "defaultValue");
@@ -266,8 +284,7 @@
             if (ACTION_SET_FLAG.equals(action)) {
                 handleSetFlag(intent.getExtras());
             } else if (ACTION_GET_FLAGS.equals(action)) {
-                Map<Integer, Flag<?>> knownFlagMap = mFlagsCollector.get();
-                ArrayList<Flag<?>> flags = new ArrayList<>(knownFlagMap.values());
+                ArrayList<Flag<?>> flags = new ArrayList<>(mAllFlags.values());
 
                 // Convert all flags to parcelable flags.
                 ArrayList<ParcelableFlag<?>> pFlags = new ArrayList<>();
@@ -296,12 +313,11 @@
                 return;
             }
 
-            Map<Integer, Flag<?>> flagMap = mFlagsCollector.get();
-            if (!flagMap.containsKey(id)) {
+            if (!mAllFlags.containsKey(id)) {
                 Log.w(TAG, "Tried to set unknown id: " + id);
                 return;
             }
-            Flag<?> flag = flagMap.get(id);
+            Flag<?> flag = mAllFlags.get(id);
 
             if (!extras.containsKey(EXTRA_VALUE)) {
                 eraseFlag(flag);
@@ -338,13 +354,16 @@
         @Nullable
         private ParcelableFlag<?> toParcelableFlag(Flag<?> f) {
             if (f instanceof BooleanFlag) {
-                return new BooleanFlag(f.getId(), isEnabled((BooleanFlag) f));
+                return new BooleanFlag(f.getId(), isEnabled((BooleanFlag) f), f.getTeamfood());
             }
             if (f instanceof ResourceBooleanFlag) {
-                return new BooleanFlag(f.getId(), isEnabled((ResourceBooleanFlag) f));
+                return new BooleanFlag(
+                        f.getId(), isEnabled((ResourceBooleanFlag) f), f.getTeamfood());
             }
             if (f instanceof SysPropBooleanFlag) {
-                return new BooleanFlag(f.getId(), isEnabled((SysPropBooleanFlag) f));
+                // TODO(b/223379190): Teamfood not supported for sysprop flags yet.
+                return new BooleanFlag(
+                        f.getId(), isEnabled((SysPropBooleanFlag) f), false);
             }
 
             // TODO: add support for other flag types.
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index b590412..9356b16 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.flags;
 
+import com.android.internal.annotations.Keep;
 import com.android.systemui.R;
 
 import java.lang.reflect.Field;
@@ -144,8 +145,7 @@
     /***************************************/
     // 900 - media
     public static final BooleanFlag MEDIA_TAP_TO_TRANSFER = new BooleanFlag(900, true);
-    public static final BooleanFlag MEDIA_SESSION_ACTIONS = new BooleanFlag(901, true);
-    public static final BooleanFlag MEDIA_SESSION_LAYOUT = new BooleanFlag(902, true);
+    public static final BooleanFlag MEDIA_SESSION_ACTIONS = new BooleanFlag(901, false);
     public static final BooleanFlag MEDIA_NEARBY_DEVICES = new BooleanFlag(903, true);
     public static final BooleanFlag MEDIA_MUTE_AWAIT = new BooleanFlag(904, true);
 
@@ -154,6 +154,7 @@
             new BooleanFlag(1000, true);
 
     // 1100 - windowing
+    @Keep
     public static final SysPropBooleanFlag WM_ENABLE_SHELL_TRANSITIONS =
             new SysPropBooleanFlag(1100, "persist.wm.debug.shell_transit", false);
 
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index af553c7..acb080a 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -1067,13 +1067,7 @@
             // Add a little delay before executing, to give the dialog a chance to go away before
             // switching user
             mHandler.postDelayed(() -> {
-                try {
-                    int currentUserId = getCurrentUser().id;
-                    mIActivityManager.switchUser(UserHandle.USER_SYSTEM);
-                    mIActivityManager.stopUser(currentUserId, true /*force*/, null);
-                } catch (RemoteException re) {
-                    Log.e(TAG, "Couldn't logout user " + re);
-                }
+                mDevicePolicyManager.logoutUser();
             }, mDialogPressDelay);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index c01d2c3..758609a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -20,6 +20,7 @@
 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
 
 import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_TRANSITION_FROM_AOD;
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_UNLOCK_ANIMATION;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
@@ -123,11 +124,11 @@
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.phone.BiometricUnlockController;
+import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.NotificationPanelViewController;
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -1237,14 +1238,52 @@
     }
 
     /**
-     * Locks the keyguard if {@link #mPendingLock} is true, unless we're playing the screen off
-     * animation.
+     * Locks the keyguard if {@link #mPendingLock} is true, and there are no reasons to further
+     * delay the pending lock.
      *
-     * If we are, we will lock the keyguard either when the screen off animation ends, or in
-     * {@link #onStartedWakingUp} if the animation is cancelled.
+     * If you do delay handling the pending lock, you must ensure that this method is ALWAYS called
+     * again when the condition causing the delay changes. Otherwise, the device may remain unlocked
+     * indefinitely.
      */
     public void maybeHandlePendingLock() {
-        if (mPendingLock && !mScreenOffAnimationController.isKeyguardShowDelayed()) {
+        if (mPendingLock) {
+
+            // The screen off animation is playing, so if we lock now, the foreground app will
+            // vanish and the keyguard will jump-cut in. Delay it, until either:
+            //   - The screen off animation ends. We will call maybeHandlePendingLock from
+            //     the end action in UnlockedScreenOffAnimationController#animateInKeyguard.
+            //   - The screen off animation is cancelled by the device waking back up. We will call
+            //     maybeHandlePendingLock from KeyguardViewMediator#onStartedWakingUp.
+            if (mScreenOffAnimationController.isKeyguardShowDelayed()) {
+                if (DEBUG) {
+                    Log.d(TAG, "#maybeHandlePendingLock: not handling because the screen off "
+                            + "animation's isKeyguardShowDelayed() returned true. This should be "
+                            + "handled soon by #onStartedWakingUp, or by the end actions of the "
+                            + "screen off animation.");
+                }
+
+                return;
+            }
+
+            // The device was re-locked while in the process of unlocking. If we lock now, callbacks
+            // in the unlock sequence might end up re-unlocking the device. Delay the lock until the
+            // keyguard is done going away. We'll call maybeHandlePendingLock again in
+            // StatusBar#finishKeyguardFadingAway, which is always responsible for setting
+            // isKeyguardGoingAway to false.
+            if (mKeyguardStateController.isKeyguardGoingAway()) {
+                if (DEBUG) {
+                    Log.d(TAG, "#maybeHandlePendingLock: not handling because the keyguard is "
+                            + "going away. This should be handled shortly by "
+                            + "StatusBar#finishKeyguardFadingAway.");
+                }
+
+                return;
+            }
+
+            if (DEBUG) {
+                Log.d(TAG, "#maybeHandlePendingLock: handling pending lock; locking keyguard.");
+            }
+
             doKeyguardLocked(null);
             mPendingLock = false;
         }
@@ -1557,6 +1596,7 @@
     public void setOccluded(boolean isOccluded, boolean animate) {
         Trace.beginSection("KeyguardViewMediator#setOccluded");
         if (DEBUG) Log.d(TAG, "setOccluded " + isOccluded);
+        mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_TRANSITION_FROM_AOD);
         mHandler.removeMessages(SET_OCCLUDED);
         Message msg = mHandler.obtainMessage(SET_OCCLUDED, isOccluded ? 1 : 0, animate ? 1 : 0);
         mHandler.sendMessage(msg);
@@ -1667,16 +1707,11 @@
             return;
         }
 
-        // If the keyguard is already showing, don't bother unless it was in the process of going
-        // away. If it was going away, keyguard state may be out of sync and we should make sure to
-        // re-show it explicitly. Check flags in both files to account for the hiding animation
-        // which results in a delay and discrepancy between flags.
-        if ((mShowing && mKeyguardViewControllerLazy.get().isShowing())
-                && !mKeyguardStateController.isKeyguardGoingAway()) {
-            if (DEBUG) {
-                Log.d(TAG, "doKeyguard: not showing "
-                        + "because it is already showing and not going away");
-            }
+        // if the keyguard is already showing, don't bother. check flags in both files
+        // to account for the hiding animation which results in a delay and discrepancy
+        // between flags
+        if (mShowing && mKeyguardViewControllerLazy.get().isShowing()) {
+            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");
             resetStateLocked();
             return;
         }
@@ -1706,14 +1741,6 @@
                 if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");
                 return;
             }
-
-            if (mLockPatternUtils.checkVoldPassword(KeyguardUpdateMonitor.getCurrentUser())) {
-                if (DEBUG) Log.d(TAG, "Not showing lock screen since just decrypted");
-                // Without this, settings is not enabled until the lock screen first appears
-                setShowingLocked(false);
-                hideLocked();
-                return;
-            }
         }
 
         if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
@@ -2191,14 +2218,7 @@
             mKeyguardExitAnimationRunner = null;
             mScreenOnCoordinator.setWakeAndUnlocking(false);
             mPendingLock = false;
-
-            // If we're asked to re-show while the keyguard is going away, force callbacks to ensure
-            // that state is re-set correctly. Otherwise, we might short circuit since mShowing is
-            // true during the keyguard going away process, despite having partially set some state
-            // to unlocked.
-            setShowingLocked(
-                    true, mKeyguardStateController.isKeyguardGoingAway() /* forceCallbacks */);
-
+            setShowingLocked(true);
             mKeyguardViewControllerLazy.get().show(options);
             resetKeyguardDonePendingLocked();
             mHideAnimationRun = false;
@@ -2353,7 +2373,8 @@
                 // Hack level over 9000: To speed up wake-and-unlock sequence, force it to report
                 // the next draw from here, so we don't have to wait for window manager to signal
                 // this to our ViewRootImpl.
-                mKeyguardViewControllerLazy.get().getViewRootImpl().setReportNextDraw();
+                mKeyguardViewControllerLazy.get().getViewRootImpl().setReportNextDraw(
+                        false /* syncBuffer */);
                 mScreenOnCoordinator.setWakeAndUnlocking(false);
             }
 
@@ -2368,28 +2389,14 @@
                             @Override
                             public void onAnimationFinished() throws RemoteException {
                                 try {
-                                    // WindowManager always needs to know that this animation
-                                    // finished so it does not wait the 10s until timeout.
                                     finishedCallback.onAnimationFinished();
                                 } catch (RemoteException e) {
                                     Slog.w(TAG, "Failed to call onAnimationFinished", e);
                                 }
-
-                                // If we're not interactive, it means the device is going back to
-                                // sleep. This happens if the power button is pressed during the
-                                // activity launch. If we're going back to sleep, we should *not*
-                                // run keyguard exit finished callbacks and hide the keyguard, since
-                                // we are in the process of locking again and this might result in
-                                // the device staying unlocked when it shouldn't.
-                                // We need to directly query isInteractive rather than mGoingToSleep
-                                // because mGoingToSleep is set in onStartedGoingToSleep, which is
-                                // dispatched asynchronously.
-                                if (mPM.isInteractive()) {
-                                    onKeyguardExitFinished();
-                                    mKeyguardViewControllerLazy.get().hide(0 /* startTime */,
-                                            0 /* fadeoutDuration */);
-                                    mInteractionJankMonitor.end(CUJ_LOCKSCREEN_UNLOCK_ANIMATION);
-                                }
+                                onKeyguardExitFinished();
+                                mKeyguardViewControllerLazy.get().hide(0 /* startTime */,
+                                        0 /* fadeoutDuration */);
+                                mInteractionJankMonitor.end(CUJ_LOCKSCREEN_UNLOCK_ANIMATION);
                             }
 
                             @Override
@@ -2813,6 +2820,7 @@
             RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
             RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback) {
         Trace.beginSection("KeyguardViewMediator#startKeyguardExitAnimation");
+        mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_TRANSITION_FROM_AOD);
         Message msg = mHandler.obtainMessage(START_KEYGUARD_EXIT_ANIM,
                 new StartKeyguardExitAnimParams(transit, startTime, fadeoutDuration, apps,
                         wallpapers, nonApps, finishedCallback));
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
index b337183..e6b650b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
@@ -94,7 +94,7 @@
         // Blank out the activity. When it is on-screen it will look like a Recents thumbnail with
         // redaction switched on.
         final DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
-        String contentDescription = dpm.getString(
+        String contentDescription = dpm.getResources().getString(
                 WORK_LOCK_ACCESSIBILITY, () -> getString(R.string.accessibility_desc_work_lock));
         final View blankView = new View(this);
         blankView.setContentDescription(contentDescription);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index c69f947..71dfa74 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -16,10 +16,8 @@
 
 package com.android.systemui.keyguard.dagger;
 
-import android.annotation.Nullable;
 import android.app.trust.TrustManager;
 import android.content.Context;
-import android.content.pm.PackageManager;
 import android.os.PowerManager;
 
 import com.android.internal.jank.InteractionJankMonitor;
@@ -44,18 +42,14 @@
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.phone.KeyguardLiftController;
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.util.DeviceConfigProxy;
-import com.android.systemui.util.sensors.AsyncSensorManager;
 
 import java.util.concurrent.Executor;
 
@@ -133,20 +127,4 @@
                 notificationShadeWindowController,
                 activityLaunchAnimator);
     }
-
-    @SysUISingleton
-    @Provides
-    @Nullable
-    static KeyguardLiftController provideKeyguardLiftController(
-            Context context,
-            StatusBarStateController statusBarStateController,
-            AsyncSensorManager asyncSensorManager,
-            KeyguardUpdateMonitor keyguardUpdateMonitor,
-            DumpManager dumpManager) {
-        if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
-            return null;
-        }
-        return new KeyguardLiftController(statusBarStateController, asyncSensorManager,
-                keyguardUpdateMonitor, dumpManager);
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
index c3f4ce9..237b505 100644
--- a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
@@ -30,7 +30,7 @@
 import com.android.systemui.statusbar.notification.stack.MediaContainerView
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.util.Utils
+import com.android.systemui.util.LargeScreenUtils
 import javax.inject.Inject
 import javax.inject.Named
 
@@ -45,8 +45,7 @@
     private val statusBarStateController: SysuiStatusBarStateController,
     private val notifLockscreenUserManager: NotificationLockscreenUserManager,
     private val context: Context,
-    configurationController: ConfigurationController,
-    private val mediaFlags: MediaFlags
+    configurationController: ConfigurationController
 ) {
 
     init {
@@ -62,11 +61,7 @@
         })
 
         // First let's set the desired state that we want for this host
-        mediaHost.expansion = if (mediaFlags.useMediaSessionLayout()) {
-            MediaHostState.EXPANDED
-        } else {
-            MediaHostState.COLLAPSED
-        }
+        mediaHost.expansion = MediaHostState.EXPANDED
         mediaHost.showsOnlyActiveMedia = true
         mediaHost.falsingProtectionNeeded = true
 
@@ -76,7 +71,7 @@
     }
 
     private fun updateResources() {
-        useSplitShade = Utils.shouldUseSplitNotificationShade(context.resources)
+        useSplitShade = LargeScreenUtils.shouldUseSplitNotificationShade(context.resources)
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index 83ad027..20029fe 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -419,15 +419,8 @@
                 .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
         if (existingPlayer == null) {
             var newPlayer = mediaControlPanelFactory.get()
-            if (mediaFlags.useMediaSessionLayout()) {
-                newPlayer.attachPlayer(
-                        PlayerSessionViewHolder.create(LayoutInflater.from(context), mediaContent),
-                        MediaViewController.TYPE.PLAYER_SESSION)
-            } else {
-                newPlayer.attachPlayer(
-                        PlayerViewHolder.create(LayoutInflater.from(context), mediaContent),
-                        MediaViewController.TYPE.PLAYER)
-            }
+            newPlayer.attachPlayer(MediaViewHolder.create(
+                    LayoutInflater.from(context), mediaContent))
             newPlayer.mediaViewController.sizeChangedListener = this::updateCarouselDimensions
             val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                     ViewGroup.LayoutParams.WRAP_CONTENT)
@@ -522,7 +515,7 @@
 
     private fun recreatePlayers() {
         bgColor = getBackgroundColor()
-        pageIndicator.tintList = ColorStateList.valueOf(getForegroundColor())
+        pageIndicator.tintList = ColorStateList.valueOf(R.color.material_dynamic_neutral_variant80)
 
         MediaPlayerData.mediaData().forEach { (key, data, isSsMediaRec) ->
             if (isSsMediaRec) {
@@ -543,14 +536,6 @@
         return context.getColor(R.color.material_dynamic_secondary95)
     }
 
-    private fun getForegroundColor(): Int {
-        return if (mediaFlags.useMediaSessionLayout()) {
-            context.getColor(R.color.material_dynamic_neutral_variant80)
-        } else {
-            context.getColor(R.color.material_dynamic_secondary10)
-        }
-    }
-
     private fun updatePageIndicator() {
         val numPages = mediaContent.getChildCount()
         pageIndicator.setNumPages(numPages)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 510d15b..b8da46e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -23,19 +23,22 @@
 import android.app.smartspace.SmartspaceAction;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.ColorStateList;
 import android.graphics.ColorMatrix;
 import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Rect;
+import android.graphics.drawable.Animatable;
+import android.graphics.drawable.Animatable2;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.media.session.MediaController;
 import android.media.session.MediaSession;
 import android.media.session.PlaybackState;
 import android.os.Process;
-import android.text.Layout;
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
@@ -89,6 +92,7 @@
     private static final int MEDIA_RECOMMENDATION_MAX_NUM = 6;
     private static final String KEY_SMARTSPACE_ARTIST_NAME = "artist_name";
     private static final String KEY_SMARTSPACE_OPEN_IN_FOREGROUND = "KEY_OPEN_IN_FOREGROUND";
+    private static final String KEY_SMARTSPACE_APP_NAME = "KEY_SMARTSPACE_APP_NAME";
 
     // Event types logged by smartspace
     private static final int SMARTSPACE_CARD_CLICK_EVENT = 760;
@@ -96,22 +100,22 @@
 
     private static final Intent SETTINGS_INTENT = new Intent(ACTION_MEDIA_CONTROLS_SETTINGS);
 
-    // Button IDs for QS controls
-    static final int[] ACTION_IDS = {
-            R.id.action0,
-            R.id.action1,
-            R.id.action2,
-            R.id.action3,
-            R.id.action4
-    };
-
     // Buttons to show in small player when using semantic actions
-    private static final List<Integer> SEMANTIC_ACTION_IDS = List.of(
+    private static final List<Integer> SEMANTIC_ACTIONS_COMPACT = List.of(
             R.id.actionPlayPause,
             R.id.actionPrev,
             R.id.actionNext
     );
 
+    // Buttons to show in small player when using semantic actions
+    private static final List<Integer> SEMANTIC_ACTIONS_ALL = List.of(
+            R.id.actionPlayPause,
+            R.id.actionPrev,
+            R.id.actionNext,
+            R.id.action0,
+            R.id.action1
+    );
+
     private final SeekBarViewModel mSeekBarViewModel;
     private SeekBarObserver mSeekBarObserver;
     protected final Executor mBackgroundExecutor;
@@ -127,8 +131,6 @@
     private MediaController mController;
     private Lazy<MediaDataManager> mMediaDataManagerLazy;
     private int mBackgroundColor;
-    private int mDevicePadding;
-    private int mAlbumArtSize;
     // Instance id for logging purpose.
     protected int mInstanceId = -1;
     // Uid for the media app.
@@ -137,7 +139,6 @@
     private MediaCarouselController mMediaCarouselController;
     private final MediaOutputDialogFactory mMediaOutputDialogFactory;
     private final FalsingManager mFalsingManager;
-    private final MediaFlags mMediaFlags;
 
     // Used for swipe-to-dismiss logging.
     protected boolean mIsImpressed = false;
@@ -156,7 +157,7 @@
             Lazy<MediaDataManager> lazyMediaDataManager,
             MediaOutputDialogFactory mediaOutputDialogFactory,
             MediaCarouselController mediaCarouselController,
-            FalsingManager falsingManager, MediaFlags mediaFlags, SystemClock systemClock) {
+            FalsingManager falsingManager, SystemClock systemClock) {
         mContext = context;
         mBackgroundExecutor = backgroundExecutor;
         mActivityStarter = activityStarter;
@@ -167,9 +168,7 @@
         mMediaOutputDialogFactory = mediaOutputDialogFactory;
         mMediaCarouselController = mediaCarouselController;
         mFalsingManager = falsingManager;
-        mMediaFlags = mediaFlags;
         mSystemClock = systemClock;
-        loadDimens();
 
         mSeekBarViewModel.setLogSmartspaceClick(() -> {
             logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT,
@@ -186,12 +185,6 @@
         mMediaViewController.onDestroy();
     }
 
-    private void loadDimens() {
-        mAlbumArtSize = mContext.getResources().getDimensionPixelSize(R.dimen.qs_media_album_size);
-        mDevicePadding = mContext.getResources()
-                .getDimensionPixelSize(R.dimen.qs_media_album_device_padding);
-    }
-
     /**
      * Get the view holder used to display media controls.
      *
@@ -243,15 +236,14 @@
     }
 
     /** Attaches the player to the player view holder. */
-    public void attachPlayer(MediaViewHolder vh, MediaViewController.TYPE playerType) {
+    public void attachPlayer(MediaViewHolder vh) {
         mMediaViewHolder = vh;
         TransitionLayout player = vh.getPlayer();
 
-        boolean useSessionLayout = playerType == MediaViewController.TYPE.PLAYER_SESSION;
-        mSeekBarObserver = new SeekBarObserver(vh, useSessionLayout);
+        mSeekBarObserver = new SeekBarObserver(vh);
         mSeekBarViewModel.getProgress().observeForever(mSeekBarObserver);
         mSeekBarViewModel.attachTouchHandlers(vh.getSeekBar());
-        mMediaViewController.attach(player, playerType);
+        mMediaViewController.attach(player, MediaViewController.TYPE.PLAYER);
 
         vh.getPlayer().setOnLongClickListener(v -> {
             if (!mMediaViewController.isGutsVisible()) {
@@ -307,16 +299,6 @@
         if (mMediaViewHolder == null) {
             return;
         }
-        bindPlayerCommon(data, key);
-        if (mMediaViewHolder instanceof PlayerViewHolder) {
-            bindNotificationPlayer(data, key);
-        } else if (mMediaViewHolder instanceof PlayerSessionViewHolder) {
-            bindSessionPlayer(data, key);
-        }
-    }
-
-    /** Bind elements common to both layouts */
-    private void bindPlayerCommon(@NonNull MediaData data, String key) {
         mKey = key;
         MediaSession.Token token = data.getToken();
         PackageManager packageManager = mContext.getPackageManager();
@@ -373,18 +355,24 @@
         final MediaController controller = getController();
         mBackgroundExecutor.execute(() -> mSeekBarViewModel.updateController(controller));
 
-        // Guts label
-        boolean isDismissible = data.isClearable();
-        mMediaViewHolder.getLongPressText().setText(isDismissible
-                ? R.string.controls_media_close_session
-                : R.string.controls_media_active_session);
+        bindOutputSwitcherChip(data);
+        bindLongPressMenu(data);
+        bindActionButtons(data);
+        bindArtworkAndColors(data);
 
+        // TODO: We don't need to refresh this state constantly, only if the state actually changed
+        // to something which might impact the measurement
+        mMediaViewController.refreshState();
+    }
+
+    private void bindOutputSwitcherChip(MediaData data) {
         // Output switcher chip
         ViewGroup seamlessView = mMediaViewHolder.getSeamless();
         seamlessView.setVisibility(View.VISIBLE);
         ImageView iconView = mMediaViewHolder.getSeamlessIcon();
         TextView deviceName = mMediaViewHolder.getSeamlessText();
         final MediaDeviceData device = data.getDevice();
+
         // Disable clicking on output switcher for invalid devices and resumption controls
         final boolean seamlessDisabled = (device != null && !device.getEnabled())
                 || data.getResumption();
@@ -428,9 +416,20 @@
                         mMediaOutputDialogFactory.create(data.getPackageName(), true,
                                 mMediaViewHolder.getSeamlessButton());
                     }
-            });
+                });
+    }
 
-        // Dismiss
+    private void bindLongPressMenu(MediaData data) {
+        boolean isDismissible = data.isClearable();
+        String dismissText;
+        if (isDismissible) {
+            dismissText = mContext.getString(R.string.controls_media_close_session, data.getApp());
+        } else {
+            dismissText = mContext.getString(R.string.controls_media_active_session);
+        }
+        mMediaViewHolder.getLongPressText().setText(dismissText);
+
+        // Dismiss button
         mMediaViewHolder.getDismissText().setAlpha(isDismissible ? 1 : DISABLED_ALPHA);
         mMediaViewHolder.getDismiss().setEnabled(isDismissible);
         mMediaViewHolder.getDismiss().setOnClickListener(v -> {
@@ -445,137 +444,16 @@
                         MediaViewController.GUTS_ANIMATION_DURATION + 100)) {
                     Log.w(TAG, "Manager failed to dismiss media " + mKey);
                     // Remove directly from carousel so user isn't stuck with defunct controls
-                    mMediaCarouselController.removePlayer(key, false, false);
+                    mMediaCarouselController.removePlayer(mKey, false, false);
                 }
             } else {
                 Log.w(TAG, "Dismiss media with null notification. Token uid="
                         + data.getToken().getUid());
             }
         });
-
-        // TODO: We don't need to refresh this state constantly, only if the state actually changed
-        // to something which might impact the measurement
-        mMediaViewController.refreshState();
     }
 
-    /** Bind elements specific to PlayerViewHolder */
-    private void bindNotificationPlayer(@NonNull MediaData data, String key) {
-        ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
-        ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();
-
-        // Album art
-        ImageView albumView = mMediaViewHolder.getAlbumView();
-        boolean hasArtwork = data.getArtwork() != null;
-        if (hasArtwork) {
-            Drawable artwork = getScaledThumbnail(data.getArtwork());
-            albumView.setPadding(0, 0, 0, 0);
-            albumView.setImageDrawable(artwork);
-        } else {
-            Drawable deviceIcon;
-            if (data.getDevice() != null && data.getDevice().getIcon() != null) {
-                deviceIcon = data.getDevice().getIcon().getConstantState().newDrawable().mutate();
-            } else {
-                deviceIcon = getContext().getDrawable(R.drawable.ic_headphone);
-            }
-            deviceIcon.setTintList(ColorStateList.valueOf(mBackgroundColor));
-            albumView.setPadding(mDevicePadding, mDevicePadding, mDevicePadding, mDevicePadding);
-            albumView.setImageDrawable(deviceIcon);
-        }
-
-        // App icon - use notification icon
-        ImageView appIconView = mMediaViewHolder.getAppIcon();
-        appIconView.clearColorFilter();
-        if (data.getAppIcon() != null && !data.getResumption()) {
-            appIconView.setImageIcon(data.getAppIcon());
-            int color = mContext.getColor(R.color.material_dynamic_secondary10);
-            appIconView.setColorFilter(color);
-        } else {
-            // Resume players use launcher icon
-            appIconView.setColorFilter(getGrayscaleFilter());
-            try {
-                Drawable icon = mContext.getPackageManager().getApplicationIcon(
-                        data.getPackageName());
-                appIconView.setImageDrawable(icon);
-            } catch (PackageManager.NameNotFoundException e) {
-                Log.w(TAG, "Cannot find icon for package " + data.getPackageName(), e);
-                appIconView.setImageResource(R.drawable.ic_music_note);
-            }
-        }
-
-        // Media action buttons
-        List<MediaAction> actionIcons = data.getActions();
-        List<Integer> actionsWhenCollapsed = data.getActionsToShowInCompact();
-
-        // If the session actions flag is enabled, but we're still using the regular layout, use
-        // the session actions anyways
-        if (mMediaFlags.areMediaSessionActionsEnabled() && data.getSemanticActions() != null) {
-            MediaButton semanticActions = data.getSemanticActions();
-
-            actionIcons = new ArrayList<MediaAction>();
-            actionIcons.add(semanticActions.getCustom0());
-            actionIcons.add(semanticActions.getPrevOrCustom());
-            actionIcons.add(semanticActions.getPlayOrPause());
-            actionIcons.add(semanticActions.getNextOrCustom());
-            actionIcons.add(semanticActions.getCustom1());
-
-            actionsWhenCollapsed = new ArrayList<Integer>();
-            actionsWhenCollapsed.add(1);
-            actionsWhenCollapsed.add(2);
-            actionsWhenCollapsed.add(3);
-        }
-
-        int i = 0;
-        for (; i < actionIcons.size() && i < ACTION_IDS.length; i++) {
-            int actionId = ACTION_IDS[i];
-            boolean visibleInCompat = actionsWhenCollapsed.contains(i);
-            final ImageButton button = mMediaViewHolder.getAction(actionId);
-            MediaAction mediaAction = actionIcons.get(i);
-            if (mediaAction != null) {
-                button.setImageIcon(mediaAction.getIcon());
-                button.setContentDescription(mediaAction.getContentDescription());
-                Runnable action = mediaAction.getAction();
-
-                if (action == null) {
-                    button.setEnabled(false);
-                } else {
-                    button.setEnabled(true);
-                    button.setOnClickListener(v -> {
-                        if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
-                            logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT,
-                                    /* isRecommendationCard */ false);
-                            action.run();
-                        }
-                    });
-                }
-                setVisibleAndAlpha(collapsedSet, actionId, visibleInCompat);
-                setVisibleAndAlpha(expandedSet, actionId, true /*visible */);
-            } else {
-                button.setImageIcon(null);
-                button.setContentDescription(null);
-                button.setEnabled(false);
-                setVisibleAndAlpha(collapsedSet, actionId, visibleInCompat);
-                // for expanded layout, set as INVISIBLE so that we still reserve space in the UI
-                expandedSet.setVisibility(actionId, ConstraintSet.INVISIBLE);
-                expandedSet.setAlpha(actionId, 0.0f);
-            }
-        }
-
-        // Hide any unused buttons
-        for (; i < ACTION_IDS.length; i++) {
-            setVisibleAndAlpha(collapsedSet, ACTION_IDS[i], false /*visible */);
-            setVisibleAndAlpha(expandedSet, ACTION_IDS[i], false /* visible */);
-        }
-        // If no actions, set the first view as INVISIBLE so expanded height remains constant
-        if (actionIcons.size() == 0) {
-            expandedSet.setVisibility(ACTION_IDS[0], ConstraintSet.INVISIBLE);
-        }
-    }
-
-    /** Bind elements specific to PlayerSessionViewHolder */
-    private void bindSessionPlayer(@NonNull MediaData data, String key) {
-        ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
-        ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();
-
+    private void bindArtworkAndColors(MediaData data) {
         // Default colors
         int surfaceColor = mBackgroundColor;
         int accentPrimary = com.android.settingslib.Utils.getColorAttr(mContext,
@@ -595,7 +473,7 @@
         boolean hasArtwork = data.getArtwork() != null;
         if (hasArtwork) {
             colorScheme = new ColorScheme(WallpaperColors.fromBitmap(data.getArtwork().getBitmap()),
-                        true);
+                    true);
 
             // Scale artwork to fit background
             int width = mMediaViewHolder.getPlayer().getWidth();
@@ -664,6 +542,14 @@
         seekbar.setProgressTintList(textColorList);
         seekbar.setProgressBackgroundTintList(ColorStateList.valueOf(textTertiary));
 
+        // Action buttons
+        mMediaViewHolder.getActionPlayPause().setBackgroundTintList(accentColorList);
+        mMediaViewHolder.getActionPlayPause().setImageTintList(
+                ColorStateList.valueOf(textPrimaryInverse));
+        for (ImageButton button : mMediaViewHolder.getTransparentActionButtons()) {
+            button.setImageTintList(textColorList);
+        }
+
         // Output switcher
         View seamlessView = mMediaViewHolder.getSeamlessButton();
         seamlessView.setBackgroundTintList(accentColorList);
@@ -672,21 +558,26 @@
         TextView seamlessText = mMediaViewHolder.getSeamlessText();
         seamlessText.setTextColor(surfaceColor);
 
-        // Media action buttons
+        // Long press buttons
+        mMediaViewHolder.getLongPressText().setTextColor(textColorList);
+        mMediaViewHolder.getSettings().setImageTintList(accentColorList);
+        mMediaViewHolder.getCancelText().setTextColor(textColorList);
+        mMediaViewHolder.getCancelText().setBackgroundTintList(accentColorList);
+        mMediaViewHolder.getDismissText().setTextColor(surfaceColor);
+        mMediaViewHolder.getDismissText().setBackgroundTintList(accentColorList);
+    }
+
+    private void bindActionButtons(MediaData data) {
         MediaButton semanticActions = data.getSemanticActions();
-        PlayerSessionViewHolder sessionHolder = (PlayerSessionViewHolder) mMediaViewHolder;
         ImageButton[] genericButtons = new ImageButton[]{
-                sessionHolder.getAction0(),
-                sessionHolder.getAction1(),
-                sessionHolder.getAction2(),
-                sessionHolder.getAction3(),
-                sessionHolder.getAction4()};
+                mMediaViewHolder.getAction0(),
+                mMediaViewHolder.getAction1(),
+                mMediaViewHolder.getAction2(),
+                mMediaViewHolder.getAction3(),
+                mMediaViewHolder.getAction4()};
 
-        ImageButton[] semanticButtons = new ImageButton[]{
-                sessionHolder.getActionPlayPause(),
-                sessionHolder.getActionNext(),
-                sessionHolder.getActionPrev()};
-
+        ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
+        ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();
         if (semanticActions != null) {
             // Hide all the generic buttons
             for (ImageButton b: genericButtons) {
@@ -694,22 +585,15 @@
                 setVisibleAndAlpha(expandedSet, b.getId(), false);
             }
 
-            // Play/pause button has a background
-            sessionHolder.getActionPlayPause().setBackgroundTintList(accentColorList);
-            setSemanticButton(sessionHolder.getActionPlayPause(), semanticActions.getPlayOrPause(),
-                    ColorStateList.valueOf(textPrimaryInverse), collapsedSet, expandedSet, true);
-
-            setSemanticButton(sessionHolder.getActionNext(), semanticActions.getNextOrCustom(),
-                    textColorList, collapsedSet, expandedSet, true);
-            setSemanticButton(sessionHolder.getActionPrev(), semanticActions.getPrevOrCustom(),
-                    textColorList, collapsedSet, expandedSet, true);
-            setSemanticButton(sessionHolder.getAction0(), semanticActions.getCustom0(),
-                    textColorList, collapsedSet, expandedSet, false);
-            setSemanticButton(sessionHolder.getAction1(), semanticActions.getCustom1(),
-                    textColorList, collapsedSet, expandedSet, false);
+            for (int id : SEMANTIC_ACTIONS_ALL) {
+                boolean showInCompact = SEMANTIC_ACTIONS_COMPACT.contains(id);
+                ImageButton button = mMediaViewHolder.getAction(id);
+                MediaAction action = semanticActions.getActionById(id);
+                setSemanticButton(button, action, collapsedSet, expandedSet, showInCompact);
+            }
         } else {
-            // Hide all the semantic buttons
-            for (int id : SEMANTIC_ACTION_IDS) {
+            // Hide buttons that only appear for semantic actions
+            for (int id : SEMANTIC_ACTIONS_COMPACT) {
                 setVisibleAndAlpha(collapsedSet, id, false);
                 setVisibleAndAlpha(expandedSet, id, false);
             }
@@ -720,39 +604,69 @@
             int i = 0;
             for (; i < actions.size(); i++) {
                 boolean showInCompact = actionsWhenCollapsed.contains(i);
-                setSemanticButton(genericButtons[i], actions.get(i), textColorList, collapsedSet,
+                setSemanticButton(genericButtons[i], actions.get(i),  collapsedSet,
                         expandedSet, showInCompact);
             }
             for (; i < 5; i++) {
                 // Hide any unused buttons
-                setSemanticButton(genericButtons[i], null, textColorList, collapsedSet,
-                        expandedSet, false);
+                setSemanticButton(genericButtons[i], null,  collapsedSet, expandedSet, false);
             }
         }
+        expandedSet.setVisibility(R.id.media_progress_bar, getSeekBarVisibility());
+        expandedSet.setAlpha(R.id.media_progress_bar, mSeekBarViewModel.getEnabled() ? 1.0f : 0.0f);
+    }
 
-        // If disabled, set progress bar to INVISIBLE instead of GONE so layout weights still work
+    private int getSeekBarVisibility() {
         boolean seekbarEnabled = mSeekBarViewModel.getEnabled();
-        expandedSet.setVisibility(R.id.media_progress_bar,
-                seekbarEnabled ? ConstraintSet.VISIBLE : ConstraintSet.INVISIBLE);
-        expandedSet.setAlpha(R.id.media_progress_bar, seekbarEnabled ? 1.0f : 0.0f);
+        if (seekbarEnabled) {
+            return ConstraintSet.VISIBLE;
+        }
+        // If disabled and "neighbours" are visible, set progress bar to INVISIBLE instead of GONE
+        // so layout weights still work.
+        return areAnyExpandedBottomActionsVisible() ? ConstraintSet.INVISIBLE : ConstraintSet.GONE;
+    }
 
-        // Long press buttons
-        mMediaViewHolder.getLongPressText().setTextColor(textColorList);
-        mMediaViewHolder.getSettingsText().setTextColor(textColorList);
-        mMediaViewHolder.getSettingsText().setBackgroundTintList(accentColorList);
-        mMediaViewHolder.getCancelText().setTextColor(textColorList);
-        mMediaViewHolder.getCancelText().setBackgroundTintList(accentColorList);
-        mMediaViewHolder.getDismissText().setTextColor(textColorList);
-        mMediaViewHolder.getDismissText().setBackgroundTintList(accentColorList);
+    private boolean areAnyExpandedBottomActionsVisible() {
+        ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
+        int[] referencedIds = mMediaViewHolder.getActionsTopBarrier().getReferencedIds();
+        for (int id : referencedIds) {
+            if (expandedSet.getVisibility(id) == ConstraintSet.VISIBLE) {
+                return true;
+            }
+        }
+        return false;
     }
 
     private void setSemanticButton(final ImageButton button, MediaAction mediaAction,
-            ColorStateList fgColor, ConstraintSet collapsedSet, ConstraintSet expandedSet,
-            boolean showInCompact) {
-        button.setImageTintList(fgColor);
+            ConstraintSet collapsedSet, ConstraintSet expandedSet, boolean showInCompact) {
+        AnimationBindHandler animHandler;
+        if (button.getTag() == null) {
+            animHandler = new AnimationBindHandler();
+            button.setTag(animHandler);
+        } else {
+            animHandler = (AnimationBindHandler) button.getTag();
+        }
+
+        animHandler.tryExecute(() -> {
+            bindSemanticButton(animHandler, button, mediaAction,
+                               collapsedSet, expandedSet, showInCompact);
+        });
+    }
+
+    private void bindSemanticButton(final AnimationBindHandler animHandler,
+            final ImageButton button, MediaAction mediaAction, ConstraintSet collapsedSet,
+            ConstraintSet expandedSet, boolean showInCompact) {
+
+        animHandler.unregisterAll();
         if (mediaAction != null) {
-            button.setImageIcon(mediaAction.getIcon());
+            final Drawable icon = mediaAction.getIcon();
+            button.setImageDrawable(icon);
             button.setContentDescription(mediaAction.getContentDescription());
+            final Drawable bgDrawable = mediaAction.getBackground();
+            button.setBackground(bgDrawable);
+
+            animHandler.tryRegister(icon);
+            animHandler.tryRegister(bgDrawable);
 
             Runnable action = mediaAction.getAction();
             if (action == null) {
@@ -764,19 +678,75 @@
                         logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT,
                                 /* isRecommendationCard */ false);
                         action.run();
+
+                        if (icon instanceof Animatable) {
+                            ((Animatable) icon).start();
+                        }
+                        if (bgDrawable instanceof Animatable) {
+                            ((Animatable) bgDrawable).start();
+                        }
                     }
                 });
             }
         } else {
-            button.setImageIcon(null);
+            button.setImageDrawable(null);
             button.setContentDescription(null);
             button.setEnabled(false);
+            button.setBackground(mContext.getDrawable(R.drawable.qs_media_round_button_background));
         }
 
         setVisibleAndAlpha(collapsedSet, button.getId(), mediaAction != null && showInCompact);
         setVisibleAndAlpha(expandedSet, button.getId(), mediaAction != null);
     }
 
+    private static class AnimationBindHandler extends Animatable2.AnimationCallback {
+        private ArrayList<Runnable> mOnAnimationsComplete = new ArrayList<>();
+        private ArrayList<Animatable2> mRegistrations = new ArrayList<>();
+
+        public void tryRegister(Drawable drawable) {
+            if (drawable instanceof Animatable2) {
+                Animatable2 anim = (Animatable2) drawable;
+                anim.registerAnimationCallback(this);
+                mRegistrations.add(anim);
+            }
+        }
+
+        public void unregisterAll() {
+            for (Animatable2 anim : mRegistrations) {
+                anim.unregisterAnimationCallback(this);
+            }
+            mRegistrations.clear();
+        }
+
+        public boolean isAnimationRunning() {
+            for (Animatable2 anim : mRegistrations) {
+                if (anim.isRunning()) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public void tryExecute(Runnable action) {
+            if (isAnimationRunning()) {
+                mOnAnimationsComplete.add(action);
+            } else {
+                action.run();
+            }
+        }
+
+        @Override
+        public void onAnimationEnd(Drawable drawable) {
+            super.onAnimationEnd(drawable);
+            if (!isAnimationRunning()) {
+                for (Runnable action : mOnAnimationsComplete) {
+                    action.run();
+                }
+                mOnAnimationsComplete.clear();
+            }
+        }
+    }
+
     @Nullable
     private ActivityLaunchAnimator.Controller buildLaunchAnimatorController(
             TransitionLayout player) {
@@ -852,18 +822,33 @@
         icon.setColorFilter(getGrayscaleFilter());
         ImageView headerLogoImageView = mRecommendationViewHolder.getCardIcon();
         headerLogoImageView.setImageDrawable(icon);
+
         // Set up media source app's label text.
-        CharSequence appLabel = packageManager.getApplicationLabel(applicationInfo);
-        if (appLabel.length() != 0) {
-            TextView headerTitleText = mRecommendationViewHolder.getCardText();
-            headerTitleText.setText(appLabel);
+        CharSequence appName = getAppName(data.getCardAction());
+        if (TextUtils.isEmpty(appName)) {
+            Intent launchIntent =
+                    packageManager.getLaunchIntentForPackage(data.getPackageName());
+            if (launchIntent != null) {
+                ActivityInfo launchActivity = launchIntent.resolveActivityInfo(packageManager, 0);
+                appName = launchActivity.loadLabel(packageManager);
+            } else {
+                Log.w(TAG, "Package " + data.getPackageName()
+                        +  " does not have a main launcher activity. Fallback to full app name");
+                appName = packageManager.getApplicationLabel(applicationInfo);
+            }
         }
+        // Set the app name as card's title.
+        if (!TextUtils.isEmpty(appName)) {
+            TextView headerTitleText = mRecommendationViewHolder.getCardText();
+            headerTitleText.setText(appName);
+        }
+
         // Set up media rec card's tap action if applicable.
         setSmartspaceRecItemOnClickListener(recommendationCard, data.getCardAction(),
                 /* interactedSubcardRank */ -1);
         // Set up media rec card's accessibility label.
         recommendationCard.setContentDescription(
-                mContext.getString(R.string.controls_media_smartspace_rec_description, appLabel));
+                mContext.getString(R.string.controls_media_smartspace_rec_description, appName));
 
         List<ImageView> mediaCoverItems = mRecommendationViewHolder.getMediaCoverItems();
         List<ViewGroup> mediaCoverContainers = mRecommendationViewHolder.getMediaCoverContainers();
@@ -908,12 +893,12 @@
                 mediaCoverImageView.setContentDescription(
                         mContext.getString(
                                 R.string.controls_media_smartspace_rec_item_no_artist_description,
-                                recommendation.getTitle(), appLabel));
+                                recommendation.getTitle(), appName));
             } else {
                 mediaCoverImageView.setContentDescription(
                         mContext.getString(
                                 R.string.controls_media_smartspace_rec_item_description,
-                                recommendation.getTitle(), artistName, appLabel));
+                                recommendation.getTitle(), artistName, appName));
             }
 
             if (uiComponentIndex < MEDIA_RECOMMENDATION_ITEMS_PER_ROW) {
@@ -985,60 +970,15 @@
     }
 
     private void openGuts() {
-        ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
-        ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();
-
-        boolean wasTruncated = false;
-        Layout l = null;
         if (mMediaViewHolder != null) {
             mMediaViewHolder.marquee(true, mMediaViewController.GUTS_ANIMATION_DURATION);
-            l = mMediaViewHolder.getSettingsText().getLayout();
         } else if (mRecommendationViewHolder != null) {
             mRecommendationViewHolder.marquee(true, mMediaViewController.GUTS_ANIMATION_DURATION);
-            l = mRecommendationViewHolder.getSettingsText().getLayout();
         }
-        if (l != null) {
-            wasTruncated = l.getEllipsisCount(0) > 0;
-        }
-        mMediaViewController.setShouldHideGutsSettings(wasTruncated);
-        if (wasTruncated) {
-            // not enough room for the settings button to show fully, let's hide it
-            expandedSet.constrainMaxWidth(R.id.settings, 0);
-            collapsedSet.constrainMaxWidth(R.id.settings, 0);
-        }
-
         mMediaViewController.openGuts();
     }
 
     /**
-     * Scale drawable to fit into the square album art thumbnail
-     */
-    @UiThread
-    private Drawable getScaledThumbnail(Icon icon) {
-        if (icon == null) {
-            return null;
-        }
-        // Let's scale down the View, such that the content always nicely fills the view.
-        // ThumbnailUtils actually scales it down such that it may not be filled for odd aspect
-        // ratios
-        Drawable drawable = icon.loadDrawable(mContext);
-        float aspectRatio = drawable.getIntrinsicHeight() / (float) drawable.getIntrinsicWidth();
-        Rect bounds;
-        if (aspectRatio > 1.0f) {
-            bounds = new Rect(0, 0, mAlbumArtSize, (int) (mAlbumArtSize * aspectRatio));
-        } else {
-            bounds = new Rect(0, 0, (int) (mAlbumArtSize / aspectRatio), mAlbumArtSize);
-        }
-        if (bounds.width() > mAlbumArtSize || bounds.height() > mAlbumArtSize) {
-            float offsetX = (bounds.width() - mAlbumArtSize) / 2.0f;
-            float offsetY = (bounds.height() - mAlbumArtSize) / 2.0f;
-            bounds.offset((int) -offsetX, (int) -offsetY);
-        }
-        drawable.setBounds(bounds);
-        return drawable;
-    }
-
-    /**
      * Scale artwork to fill the background of the panel
      */
     @UiThread
@@ -1140,6 +1080,17 @@
         });
     }
 
+    /** Returns the upstream app name if available. */
+    @Nullable
+    private String getAppName(SmartspaceAction action) {
+        if (action == null || action.getIntent() == null
+                || action.getIntent().getExtras() == null) {
+            return null;
+        }
+
+        return action.getIntent().getExtras().getString(KEY_SMARTSPACE_APP_NAME);
+    }
+
     /** Returns if the Smartspace action will open the activity in foreground. */
     private boolean shouldSmartspaceRecItemOpenInForeground(SmartspaceAction action) {
         if (action == null || action.getIntent() == null
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
index 4cf6291..47a0991 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
@@ -20,6 +20,7 @@
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.Icon
 import android.media.session.MediaSession
+import com.android.systemui.R
 
 /** State of a media view. */
 data class MediaData(
@@ -154,13 +155,25 @@
      * Second custom action space
      */
     var custom1: MediaAction? = null
-)
+) {
+    fun getActionById(id: Int): MediaAction? {
+        return when (id) {
+            R.id.actionPlayPause -> playOrPause
+            R.id.actionNext -> nextOrCustom
+            R.id.actionPrev -> prevOrCustom
+            R.id.action0 -> custom0
+            R.id.action1 -> custom1
+            else -> null
+        }
+    }
+}
 
 /** State of a media action. */
 data class MediaAction(
-    val icon: Icon?,
+    val icon: Drawable?,
     val action: Runnable?,
-    val contentDescription: CharSequence?
+    val contentDescription: CharSequence?,
+    val background: Drawable?
 )
 
 /** State of the media device. */
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 9e14fe9..5c36cab 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -105,6 +105,17 @@
 }
 
 /**
+ * Allow recommendations from smartspace to show in media controls.
+ * Requires [Utils.useQsMediaPlayer] to be enabled.
+ * On by default, but can be disabled by setting to 0
+ */
+private fun allowMediaRecommendations(context: Context): Boolean {
+    val flag = Settings.Secure.getInt(context.contentResolver,
+            Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION, 1)
+    return Utils.useQsMediaPlayer(context) && flag > 0
+}
+
+/**
  * A class that facilitates management and loading of Media Data, ready for binding.
  */
 @SysUISingleton
@@ -164,7 +175,7 @@
     // There should ONLY be at most one Smartspace media recommendation.
     var smartspaceMediaData: SmartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA
     private var smartspaceSession: SmartspaceSession? = null
-    private var allowMediaRecommendations = Utils.allowMediaRecommendations(context)
+    private var allowMediaRecommendations = allowMediaRecommendations(context)
 
     /**
      * Check whether this notification is an RCN
@@ -272,7 +283,7 @@
         smartspaceSession?.let { it.requestSmartspaceUpdate() }
         tunerService.addTunable(object : TunerService.Tunable {
             override fun onTuningChanged(key: String?, newValue: String?) {
-                allowMediaRecommendations = Utils.allowMediaRecommendations(context)
+                allowMediaRecommendations = allowMediaRecommendations(context)
                 if (!allowMediaRecommendations) {
                     dismissSmartspaceRecommendation(key = smartspaceMediaData.targetId, delay = 0L)
                 }
@@ -610,7 +621,8 @@
         var actionIcons: List<MediaAction> = emptyList()
         var actionsToShowCollapsed: List<Int> = emptyList()
         var semanticActions: MediaButton? = null
-        if (mediaFlags.areMediaSessionActionsEnabled() && mediaController.playbackState != null) {
+        if (mediaFlags.areMediaSessionActionsEnabled(sbn.packageName, sbn.user) &&
+                mediaController.playbackState != null) {
             semanticActions = createActionsFromState(sbn.packageName, mediaController)
         } else {
             val actions = createActionsFromNotification(sbn)
@@ -683,11 +695,12 @@
                     Icon.createWithResource(sbn.packageName, action.getIcon()!!.getResId())
                 } else {
                     action.getIcon()
-                }.setTint(themeText)
+                }.setTint(themeText).loadDrawable(context)
                 val mediaAction = MediaAction(
                     mediaActionIcon,
                     runnable,
-                    action.title)
+                    action.title,
+                    context.getDrawable(R.drawable.qs_media_round_button_background))
                 actionIcons.add(mediaAction)
             }
         }
@@ -726,7 +739,7 @@
                 }
             }
 
-            // Finally, assign the remaining button slots: C A play/pause B D
+            // Finally, assign the remaining button slots: play/pause A B C D
             // A = previous, else custom action (if not reserved)
             // B = next, else custom action (if not reserved)
             // C and D are always custom actions
@@ -777,30 +790,34 @@
         return when (action) {
             PlaybackState.ACTION_PLAY -> {
                 MediaAction(
-                    Icon.createWithResource(context, R.drawable.ic_media_play),
+                    context.getDrawable(R.drawable.ic_media_play),
                     { controller.transportControls.play() },
-                    context.getString(R.string.controls_media_button_play)
+                    context.getString(R.string.controls_media_button_play),
+                    context.getDrawable(R.drawable.ic_media_play_container)
                 )
             }
             PlaybackState.ACTION_PAUSE -> {
                 MediaAction(
-                    Icon.createWithResource(context, R.drawable.ic_media_pause),
+                    context.getDrawable(R.drawable.ic_media_pause),
                     { controller.transportControls.pause() },
-                    context.getString(R.string.controls_media_button_pause)
+                    context.getString(R.string.controls_media_button_pause),
+                    context.getDrawable(R.drawable.ic_media_pause_container)
                 )
             }
             PlaybackState.ACTION_SKIP_TO_PREVIOUS -> {
                 MediaAction(
-                    Icon.createWithResource(context, R.drawable.ic_media_prev),
+                    context.getDrawable(R.drawable.ic_media_prev),
                     { controller.transportControls.skipToPrevious() },
-                    context.getString(R.string.controls_media_button_prev)
+                    context.getString(R.string.controls_media_button_prev),
+                    context.getDrawable(R.drawable.qs_media_round_button_background)
                 )
             }
             PlaybackState.ACTION_SKIP_TO_NEXT -> {
                 MediaAction(
-                    Icon.createWithResource(context, R.drawable.ic_media_next),
+                    context.getDrawable(R.drawable.ic_media_next),
                     { controller.transportControls.skipToNext() },
-                    context.getString(R.string.controls_media_button_next)
+                    context.getString(R.string.controls_media_button_next),
+                    context.getDrawable(R.drawable.qs_media_round_button_background)
                 )
             }
             else -> null
@@ -823,9 +840,10 @@
 
         val it = state.customActions[index]
         return MediaAction(
-            Icon.createWithResource(packageName, it.icon),
+            Icon.createWithResource(packageName, it.icon).loadDrawable(context),
             { controller.transportControls.sendCustomAction(it, it.extras) },
-            it.name
+            it.name,
+            context.getDrawable(R.drawable.ic_media_pause_container)
         )
     }
 
@@ -888,9 +906,11 @@
 
     private fun getResumeMediaAction(action: Runnable): MediaAction {
         return MediaAction(
-            Icon.createWithResource(context, R.drawable.ic_media_play).setTint(themeText),
+            Icon.createWithResource(context, R.drawable.ic_media_play)
+                .setTint(themeText).loadDrawable(context),
             action,
-            context.getString(R.string.controls_media_resume)
+            context.getString(R.string.controls_media_resume),
+            context.getDrawable(R.drawable.ic_media_play_container)
         )
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt b/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt
index dd35a9a..b85ae48 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt
@@ -16,6 +16,8 @@
 
 package com.android.systemui.media
 
+import android.app.StatusBarManager
+import android.os.UserHandle
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
@@ -26,16 +28,10 @@
     /**
      * Check whether media control actions should be based on PlaybackState instead of notification
      */
-    fun areMediaSessionActionsEnabled(): Boolean {
-        return featureFlags.isEnabled(Flags.MEDIA_SESSION_ACTIONS)
-    }
-
-    /**
-     * Check whether media controls should use the new session-based layout
-     */
-    fun useMediaSessionLayout(): Boolean {
-        return featureFlags.isEnabled(Flags.MEDIA_SESSION_ACTIONS) &&
-            featureFlags.isEnabled(Flags.MEDIA_SESSION_LAYOUT)
+    fun areMediaSessionActionsEnabled(packageName: String, user: UserHandle): Boolean {
+        val enabled = StatusBarManager.useMediaSessionActionsForApp(packageName, user)
+        // Allow global override with flag
+        return enabled || featureFlags.isEnabled(Flags.MEDIA_SESSION_ACTIONS)
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index 18b6699..b0159ed 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -43,7 +43,7 @@
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.util.Utils
+import com.android.systemui.util.LargeScreenUtils
 import com.android.systemui.util.animation.UniqueObjectHostView
 import javax.inject.Inject
 
@@ -98,6 +98,10 @@
     private var currentBounds = Rect()
     private var animationStartBounds: Rect = Rect()
 
+    private var animationStartClipping = Rect()
+    private var currentClipping = Rect()
+    private var targetClipping = Rect()
+
     /**
      * The cross fade progress at the start of the animation. 0.5f means it's just switching between
      * the start and the end location and the content is fully faded, while 0.75f means that we're
@@ -144,7 +148,8 @@
             }
             interpolateBounds(animationStartBounds, targetBounds, boundsProgress,
                     result = currentBounds)
-            applyState(currentBounds, currentAlpha)
+            resolveClipping(currentClipping)
+            applyState(currentBounds, currentAlpha, clipBounds = currentClipping)
         }
         addListener(object : AnimatorListenerAdapter() {
             private var cancelled: Boolean = false
@@ -169,6 +174,12 @@
         })
     }
 
+    private fun resolveClipping(result: Rect) {
+        if (animationStartClipping.isEmpty) result.set(targetClipping)
+        else if (targetClipping.isEmpty) result.set(animationStartClipping)
+        else result.setIntersect(animationStartClipping, targetClipping)
+    }
+
     private val mediaHosts = arrayOfNulls<MediaHost>(LOCATION_DREAM_OVERLAY + 1)
     /**
      * The last location where this view was at before going to the desired location. This is
@@ -292,6 +303,18 @@
     }
 
     /**
+     * Returns the amount of translationY of the media container, during the current guided
+     * transformation, if running. If there is no guided transformation running, it will return 0.
+     */
+    fun getGuidedTransformationTranslationY(): Int {
+        if (!isCurrentlyInGuidedTransformation()) {
+            return -1
+        }
+        val startHost = getHost(previousLocation) ?: return 0
+        return targetBounds.top - startHost.currentBounds.top
+    }
+
+    /**
      * Is the shade currently collapsing from the expanded qs? If we're on the lockscreen and in qs,
      * we wouldn't want to transition in that case.
      */
@@ -491,7 +514,7 @@
     private fun updateConfiguration() {
         distanceForFullShadeTransition = context.resources.getDimensionPixelSize(
                 R.dimen.lockscreen_shade_media_transition_distance)
-        inSplitShade = Utils.shouldUseSplitNotificationShade(context.resources)
+        inSplitShade = LargeScreenUtils.shouldUseSplitNotificationShade(context.resources)
     }
 
     /**
@@ -617,10 +640,12 @@
                 // We also go in here in case the view was detached, since the bounds wouldn't
                 // be correct anymore
                 animationStartBounds.set(currentBounds)
+                animationStartClipping.set(currentClipping)
             } else {
                 // otherwise, let's take the freshest state, since the current one could
                 // be outdated
                 animationStartBounds.set(previousHost.currentBounds)
+                animationStartClipping.set(previousHost.currentClipping)
             }
             val transformationType = calculateTransformationType()
             var needsCrossFade = transformationType == TRANSFORMATION_TYPE_FADE
@@ -733,7 +758,7 @@
             // Let's immediately apply the target state (which is interpolated) if there is
             // no animation running. Otherwise the animation update will already update
             // the location
-            applyState(targetBounds, carouselAlpha)
+            applyState(targetBounds, carouselAlpha, clipBounds = targetClipping)
         }
     }
 
@@ -757,9 +782,11 @@
             val newBounds = endHost.currentBounds
             val previousBounds = starthost.currentBounds
             targetBounds = interpolateBounds(previousBounds, newBounds, progress)
+            targetClipping = endHost.currentClipping
         } else if (endHost != null) {
             val bounds = endHost.currentBounds
             targetBounds.set(bounds)
+            targetClipping = endHost.currentClipping
         }
     }
 
@@ -800,7 +827,7 @@
     @TransformationType
     fun calculateTransformationType(): Int {
         if (isTransitioningToFullShade) {
-            if (inSplitShade) {
+            if (inSplitShade && areGuidedTransitionHostsVisible()) {
                 return TRANSFORMATION_TYPE_TRANSITION
             }
             return TRANSFORMATION_TYPE_FADE
@@ -817,6 +844,11 @@
         return TRANSFORMATION_TYPE_TRANSITION
     }
 
+    private fun areGuidedTransitionHostsVisible(): Boolean {
+        return getHost(previousLocation)?.visible == true &&
+                getHost(desiredLocation)?.visible == true
+    }
+
     /**
      * @return the current transformation progress if we're in a guided transformation and -1
      * otherwise
@@ -862,8 +894,14 @@
     /**
      * Apply the current state to the view, updating it's bounds and desired state
      */
-    private fun applyState(bounds: Rect, alpha: Float, immediately: Boolean = false) {
+    private fun applyState(
+        bounds: Rect,
+        alpha: Float,
+        immediately: Boolean = false,
+        clipBounds: Rect = EMPTY_RECT
+    ) {
         currentBounds.set(bounds)
+        currentClipping = clipBounds
         carouselAlpha = if (isCurrentlyFading()) alpha else 1.0f
         val onlyUseEndState = !isCurrentlyInGuidedTransformation() || isCurrentlyFading()
         val startLocation = if (onlyUseEndState) -1 else previousLocation
@@ -872,6 +910,10 @@
         mediaCarouselController.setCurrentState(startLocation, endLocation, progress, immediately)
         updateHostAttachment()
         if (currentAttachmentLocation == IN_OVERLAY) {
+            // Setting the clipping on the hierarchy of `mediaFrame` does not work
+            if (!currentClipping.isEmpty) {
+                currentBounds.intersect(currentClipping)
+            }
             mediaFrame.setLeftTopRightBottom(
                     currentBounds.left,
                     currentBounds.top,
@@ -1096,6 +1138,7 @@
         const val TRANSFORMATION_TYPE_FADE = 1
     }
 }
+private val EMPTY_RECT = Rect()
 
 @IntDef(prefix = ["TRANSFORMATION_TYPE_"], value = [
     MediaHierarchyManager.TRANSFORMATION_TYPE_TRANSITION,
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
index 0a4b68b..d08b6f82 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
@@ -55,6 +55,13 @@
             return field
         }
 
+    /**
+     * Set the clipping that this host should use, based on its parent's bounds.
+     *
+     * Use [Rect.set].
+     */
+    val currentClipping = Rect()
+
     private val listener = object : MediaDataManager.Listener {
         override fun onMediaDataLoaded(
             key: String,
@@ -192,6 +199,14 @@
                 }
             }
 
+        override var squishFraction: Float = 1.0f
+            set(value) {
+                if (!value.equals(field)) {
+                    field = value
+                    changedListener?.invoke()
+                }
+            }
+
         override var showsOnlyActiveMedia: Boolean = false
             set(value) {
                 if (!value.equals(field)) {
@@ -242,6 +257,7 @@
         override fun copy(): MediaHostState {
             val mediaHostState = MediaHostStateHolder()
             mediaHostState.expansion = expansion
+            mediaHostState.squishFraction = squishFraction
             mediaHostState.showsOnlyActiveMedia = showsOnlyActiveMedia
             mediaHostState.measurementInput = measurementInput?.copy()
             mediaHostState.visible = visible
@@ -260,6 +276,9 @@
             if (expansion != other.expansion) {
                 return false
             }
+            if (squishFraction != other.squishFraction) {
+                return false
+            }
             if (showsOnlyActiveMedia != other.showsOnlyActiveMedia) {
                 return false
             }
@@ -278,6 +297,7 @@
         override fun hashCode(): Int {
             var result = measurementInput?.hashCode() ?: 0
             result = 31 * result + expansion.hashCode()
+            result = 31 * result + squishFraction.hashCode()
             result = 31 * result + falsingProtectionNeeded.hashCode()
             result = 31 * result + showsOnlyActiveMedia.hashCode()
             result = 31 * result + if (visible) 1 else 2
@@ -318,6 +338,11 @@
     var expansion: Float
 
     /**
+     * Fraction of the height animation.
+     */
+    var squishFraction: Float
+
+    /**
      * Is this host only showing active media or is it showing all of them including resumption?
      */
     var showsOnlyActiveMedia: Boolean
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
index 591aad1..5210499 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import android.content.res.Configuration
+import androidx.annotation.VisibleForTesting
 import androidx.constraintlayout.widget.ConstraintSet
 import com.android.systemui.R
 import com.android.systemui.statusbar.policy.ConfigurationController
@@ -42,7 +43,7 @@
      * session-based player, or recommendation
      */
     enum class TYPE {
-        PLAYER, PLAYER_SESSION, RECOMMENDATION
+        PLAYER, RECOMMENDATION
     }
 
     companion object {
@@ -188,11 +189,6 @@
     var isGutsVisible = false
         private set
 
-    /**
-     * Whether the settings button in the guts should be visible
-     */
-    var shouldHideGutsSettings = false
-
     init {
         mediaHostStatesManager.addController(this)
         layoutController.sizeChangedListener = { width: Int, height: Int ->
@@ -261,16 +257,13 @@
      */
     private fun setGutsViewState(viewState: TransitionViewState) {
         val controlsIds = when (type) {
-            TYPE.PLAYER -> PlayerViewHolder.controlsIds
-            TYPE.PLAYER_SESSION -> PlayerSessionViewHolder.controlsIds
+            TYPE.PLAYER -> MediaViewHolder.controlsIds
             TYPE.RECOMMENDATION -> RecommendationViewHolder.controlsIds
         }
         val gutsIds = when (type) {
-            TYPE.PLAYER -> PlayerViewHolder.gutsIds
-            TYPE.PLAYER_SESSION -> PlayerSessionViewHolder.gutsIds
+            TYPE.PLAYER -> MediaViewHolder.gutsIds
             TYPE.RECOMMENDATION -> RecommendationViewHolder.gutsIds
         }
-
         controlsIds.forEach { id ->
             viewState.widgetStates.get(id)?.let { state ->
                 // Make sure to use the unmodified state if guts are not visible.
@@ -282,59 +275,78 @@
             viewState.widgetStates.get(id)?.alpha = if (isGutsVisible) 1f else 0f
             viewState.widgetStates.get(id)?.gone = !isGutsVisible
         }
+    }
 
-        if (shouldHideGutsSettings) {
-            viewState.widgetStates.get(R.id.settings)?.gone = true
+    /**
+     * Apply squishFraction to a copy of viewState such that the cached version is untouched.
+     */
+    private fun squishViewState(
+        viewState: TransitionViewState,
+        squishFraction: Float
+    ): TransitionViewState {
+        val squishedViewState = viewState.copy()
+        squishedViewState.height = (squishedViewState.height * squishFraction).toInt()
+        val albumArtViewState = viewState.widgetStates.get(R.id.album_art)
+        if (albumArtViewState != null) {
+            albumArtViewState.height = squishedViewState.height
         }
+        return squishedViewState
     }
 
     /**
      * Obtain a new viewState for a given media state. This usually returns a cached state, but if
      * it's not available, it will recreate one by measuring, which may be expensive.
      */
-    private fun obtainViewState(state: MediaHostState?): TransitionViewState? {
+    @VisibleForTesting
+    public fun obtainViewState(state: MediaHostState?): TransitionViewState? {
         if (state == null || state.measurementInput == null) {
             return null
         }
         // Only a subset of the state is relevant to get a valid viewState. Let's get the cachekey
         var cacheKey = getKey(state, isGutsVisible, tmpKey)
         val viewState = viewStates[cacheKey]
+
         if (viewState != null) {
             // we already have cached this measurement, let's continue
+            if (state.squishFraction < 1f) {
+                return squishViewState(viewState, state.squishFraction)
+            }
             return viewState
         }
         // Copy the key since this might call recursively into it and we're using tmpKey
         cacheKey = cacheKey.copy()
         val result: TransitionViewState?
-        if (transitionLayout != null) {
-            // Let's create a new measurement
-            if (state.expansion == 0.0f || state.expansion == 1.0f) {
-                result = transitionLayout!!.calculateViewState(
-                        state.measurementInput!!,
-                        constraintSetForExpansion(state.expansion),
-                        TransitionViewState())
-
-                setGutsViewState(result)
-                // We don't want to cache interpolated or null states as this could quickly fill up
-                // our cache. We only cache the start and the end states since the interpolation
-                // is cheap
-                viewStates[cacheKey] = result
-            } else {
-                // This is an interpolated state
-                val startState = state.copy().also { it.expansion = 0.0f }
-
-                // Given that we have a measurement and a view, let's get (guaranteed) viewstates
-                // from the start and end state and interpolate them
-                val startViewState = obtainViewState(startState) as TransitionViewState
-                val endState = state.copy().also { it.expansion = 1.0f }
-                val endViewState = obtainViewState(endState) as TransitionViewState
-                result = layoutController.getInterpolatedState(
-                        startViewState,
-                        endViewState,
-                        state.expansion)
-            }
+        if (transitionLayout == null) {
+            return null
+        }
+        // Not cached. Let's create a new measurement
+        if (state.expansion == 0.0f || state.expansion == 1.0f) {
+            result = transitionLayout!!.calculateViewState(
+                    state.measurementInput!!,
+                    constraintSetForExpansion(state.expansion),
+                    TransitionViewState())
+            // We don't want to cache interpolated or null states as this could quickly fill up
+            // our cache. We only cache the start and the end states since the interpolation
+            // is cheap
+            setGutsViewState(result)
+            viewStates[cacheKey] = result
         } else {
-            result = null
+            // This is an interpolated state
+            val startState = state.copy().also { it.expansion = 0.0f }
+
+            // Given that we have a measurement and a view, let's get (guaranteed) viewstates
+            // from the start and end state and interpolate them
+            val startViewState = obtainViewState(startState) as TransitionViewState
+            val endState = state.copy().also { it.expansion = 1.0f }
+
+            val endViewState = obtainViewState(endState) as TransitionViewState
+            result = layoutController.getInterpolatedState(
+                    startViewState,
+                    endViewState,
+                    state.expansion)
+        }
+        if (state.squishFraction < 1f) {
+            return squishViewState(result, state.squishFraction)
         }
         return result
     }
@@ -475,10 +487,6 @@
         // These XML resources contain ConstraintSets that will apply to this player type's layout
         when (type) {
             TYPE.PLAYER -> {
-                collapsedLayout.load(context, R.xml.media_collapsed)
-                expandedLayout.load(context, R.xml.media_expanded)
-            }
-            TYPE.PLAYER_SESSION -> {
                 collapsedLayout.load(context, R.xml.media_session_collapsed)
                 expandedLayout.load(context, R.xml.media_session_expanded)
             }
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt
index 5f60696..e9c8886 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt
@@ -17,21 +17,23 @@
 package com.android.systemui.media
 
 import android.util.Log
+import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import android.widget.ImageButton
 import android.widget.ImageView
 import android.widget.SeekBar
 import android.widget.TextView
+import androidx.constraintlayout.widget.Barrier
 import com.android.systemui.R
 import com.android.systemui.util.animation.TransitionLayout
 
 private const val TAG = "MediaViewHolder"
 
 /**
- * Parent class for different media player views
+ * Holder class for media player view
  */
-abstract class MediaViewHolder constructor(itemView: View) {
+class MediaViewHolder constructor(itemView: View) {
     val player = itemView as TransitionLayout
 
     // Player information
@@ -57,22 +59,29 @@
     val cancelText = itemView.requireViewById<TextView>(R.id.cancel_text)
     val dismiss = itemView.requireViewById<ViewGroup>(R.id.dismiss)
     val dismissText = itemView.requireViewById<TextView>(R.id.dismiss_text)
-    val settings = itemView.requireViewById<View>(R.id.settings)
-    val settingsText = itemView.requireViewById<TextView>(R.id.settings_text)
+    val settings = itemView.requireViewById<ImageButton>(R.id.settings)
 
     // Action Buttons
+    val actionPlayPause = itemView.requireViewById<ImageButton>(R.id.actionPlayPause)
+    val actionNext = itemView.requireViewById<ImageButton>(R.id.actionNext)
+    val actionPrev = itemView.requireViewById<ImageButton>(R.id.actionPrev)
     val action0 = itemView.requireViewById<ImageButton>(R.id.action0)
     val action1 = itemView.requireViewById<ImageButton>(R.id.action1)
     val action2 = itemView.requireViewById<ImageButton>(R.id.action2)
     val action3 = itemView.requireViewById<ImageButton>(R.id.action3)
     val action4 = itemView.requireViewById<ImageButton>(R.id.action4)
 
+    val actionsTopBarrier = itemView.requireViewById<Barrier>(R.id.media_action_barrier_top)
+
     init {
         (player.background as IlluminationDrawable).let {
             it.registerLightSource(seamless)
             it.registerLightSource(cancel)
             it.registerLightSource(dismiss)
             it.registerLightSource(settings)
+            it.registerLightSource(actionPlayPause)
+            it.registerLightSource(actionNext)
+            it.registerLightSource(actionPrev)
             it.registerLightSource(action0)
             it.registerLightSource(action1)
             it.registerLightSource(action2)
@@ -81,7 +90,33 @@
         }
     }
 
-    abstract fun getAction(id: Int): ImageButton
+    fun getAction(id: Int): ImageButton {
+        return when (id) {
+            R.id.actionPlayPause -> actionPlayPause
+            R.id.actionNext -> actionNext
+            R.id.actionPrev -> actionPrev
+            R.id.action0 -> action0
+            R.id.action1 -> action1
+            R.id.action2 -> action2
+            R.id.action3 -> action3
+            R.id.action4 -> action4
+            else -> {
+                throw IllegalArgumentException()
+            }
+        }
+    }
+
+    fun getTransparentActionButtons(): List<ImageButton> {
+        return listOf(
+                actionNext,
+                actionPrev,
+                action0,
+                action1,
+                action2,
+                action3,
+                action4
+        )
+    }
 
     fun marquee(start: Boolean, delay: Long) {
         val longPressTextHandler = longPressText.getHandler()
@@ -91,4 +126,52 @@
         }
         longPressTextHandler.postDelayed({ longPressText.setSelected(start) }, delay)
     }
+
+    companion object {
+        /**
+         * Creates a MediaViewHolder.
+         *
+         * @param inflater LayoutInflater to use to inflate the layout.
+         * @param parent Parent of inflated view.
+         */
+        @JvmStatic fun create(
+            inflater: LayoutInflater,
+            parent: ViewGroup
+        ): MediaViewHolder {
+            val mediaView = inflater.inflate(R.layout.media_session_view, parent, false)
+            mediaView.setLayerType(View.LAYER_TYPE_HARDWARE, null)
+            // Because this media view (a TransitionLayout) is used to measure and layout the views
+            // in various states before being attached to its parent, we can't depend on the default
+            // LAYOUT_DIRECTION_INHERIT to correctly resolve the ltr direction.
+            mediaView.layoutDirection = View.LAYOUT_DIRECTION_LOCALE
+            return MediaViewHolder(mediaView).apply {
+                // Media playback is in the direction of tape, not time, so it stays LTR
+                seekBar.layoutDirection = View.LAYOUT_DIRECTION_LTR
+            }
+        }
+
+        val controlsIds = setOf(
+                R.id.icon,
+                R.id.app_name,
+                R.id.header_title,
+                R.id.header_artist,
+                R.id.media_seamless,
+                R.id.media_progress_bar,
+                R.id.actionPlayPause,
+                R.id.actionNext,
+                R.id.actionPrev,
+                R.id.action0,
+                R.id.action1,
+                R.id.action2,
+                R.id.action3,
+                R.id.action4,
+                R.id.icon
+        )
+        val gutsIds = setOf(
+                R.id.remove_text,
+                R.id.cancel,
+                R.id.dismiss,
+                R.id.settings
+        )
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerSessionViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerSessionViewHolder.kt
deleted file mode 100644
index 6928ebb..0000000
--- a/packages/SystemUI/src/com/android/systemui/media/PlayerSessionViewHolder.kt
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.media
-
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.ImageButton
-import com.android.systemui.R
-
-/**
- * ViewHolder for a media player with MediaSession-based controls
- */
-class PlayerSessionViewHolder private constructor(itemView: View) : MediaViewHolder(itemView) {
-
-    // Action Buttons
-    val actionPlayPause = itemView.requireViewById<ImageButton>(R.id.actionPlayPause)
-    val actionNext = itemView.requireViewById<ImageButton>(R.id.actionNext)
-    val actionPrev = itemView.requireViewById<ImageButton>(R.id.actionPrev)
-
-    init {
-        (player.background as IlluminationDrawable).let {
-            it.registerLightSource(actionPlayPause)
-            it.registerLightSource(actionNext)
-            it.registerLightSource(actionPrev)
-        }
-    }
-
-    override fun getAction(id: Int): ImageButton {
-        return when (id) {
-            R.id.actionPlayPause -> actionPlayPause
-            R.id.actionNext -> actionNext
-            R.id.actionPrev -> actionPrev
-            R.id.action0 -> action0
-            R.id.action1 -> action1
-            R.id.action2 -> action2
-            R.id.action3 -> action3
-            R.id.action4 -> action4
-            else -> {
-                throw IllegalArgumentException()
-            }
-        }
-    }
-
-    companion object {
-        /**
-         * Creates a PlayerSessionViewHolder.
-         *
-         * @param inflater LayoutInflater to use to inflate the layout.
-         * @param parent Parent of inflated view.
-         */
-        @JvmStatic fun create(
-            inflater: LayoutInflater,
-            parent: ViewGroup
-        ): PlayerSessionViewHolder {
-            val mediaView = inflater.inflate(R.layout.media_session_view, parent, false)
-            mediaView.setLayerType(View.LAYER_TYPE_HARDWARE, null)
-            // Because this media view (a TransitionLayout) is used to measure and layout the views
-            // in various states before being attached to its parent, we can't depend on the default
-            // LAYOUT_DIRECTION_INHERIT to correctly resolve the ltr direction.
-            mediaView.layoutDirection = View.LAYOUT_DIRECTION_LOCALE
-            return PlayerSessionViewHolder(mediaView).apply {
-                // Media playback is in the direction of tape, not time, so it stays LTR
-                seekBar.layoutDirection = View.LAYOUT_DIRECTION_LTR
-            }
-        }
-
-        val controlsIds = setOf(
-                R.id.icon,
-                R.id.app_name,
-                R.id.header_title,
-                R.id.header_artist,
-                R.id.media_seamless,
-                R.id.media_progress_bar,
-                R.id.actionPlayPause,
-                R.id.actionNext,
-                R.id.actionPrev,
-                R.id.action0,
-                R.id.action1,
-                R.id.action2,
-                R.id.action3,
-                R.id.action4,
-                R.id.icon
-        )
-        val gutsIds = setOf(
-                R.id.remove_text,
-                R.id.cancel,
-                R.id.dismiss,
-                R.id.settings
-        )
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
deleted file mode 100644
index dd3fa89..0000000
--- a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.media
-
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.ImageButton
-import android.widget.TextView
-import com.android.systemui.R
-
-/**
- * ViewHolder for a media player.
- */
-class PlayerViewHolder private constructor(itemView: View) : MediaViewHolder(itemView) {
-
-    // Seek bar
-    val progressTimes = itemView.requireViewById<ViewGroup>(R.id.notification_media_progress_time)
-    override val elapsedTimeView = itemView.requireViewById<TextView>(R.id.media_elapsed_time)
-    override val totalTimeView = itemView.requireViewById<TextView>(R.id.media_total_time)
-
-    override fun getAction(id: Int): ImageButton {
-        return when (id) {
-            R.id.action0 -> action0
-            R.id.action1 -> action1
-            R.id.action2 -> action2
-            R.id.action3 -> action3
-            R.id.action4 -> action4
-            else -> {
-                throw IllegalArgumentException()
-            }
-        }
-    }
-
-    companion object {
-        /**
-         * Creates a PlayerViewHolder.
-         *
-         * @param inflater LayoutInflater to use to inflate the layout.
-         * @param parent Parent of inflated view.
-         */
-        @JvmStatic fun create(inflater: LayoutInflater, parent: ViewGroup): PlayerViewHolder {
-            val mediaView = inflater.inflate(R.layout.media_view, parent, false)
-            mediaView.setLayerType(View.LAYER_TYPE_HARDWARE, null)
-            // Because this media view (a TransitionLayout) is used to measure and layout the views
-            // in various states before being attached to its parent, we can't depend on the default
-            // LAYOUT_DIRECTION_INHERIT to correctly resolve the ltr direction.
-            mediaView.layoutDirection = View.LAYOUT_DIRECTION_LOCALE
-            return PlayerViewHolder(mediaView).apply {
-                // Media playback is in the direction of tape, not time, so it stays LTR
-                seekBar.layoutDirection = View.LAYOUT_DIRECTION_LTR
-                progressTimes.layoutDirection = View.LAYOUT_DIRECTION_LTR
-            }
-        }
-
-        val controlsIds = setOf(
-                R.id.icon,
-                R.id.app_name,
-                R.id.album_art,
-                R.id.header_title,
-                R.id.header_artist,
-                R.id.media_seamless,
-                R.id.notification_media_progress_time,
-                R.id.media_progress_bar,
-                R.id.action0,
-                R.id.action1,
-                R.id.action2,
-                R.id.action3,
-                R.id.action4,
-                R.id.icon
-        )
-        val gutsIds = setOf(
-                R.id.remove_text,
-                R.id.cancel,
-                R.id.dismiss,
-                R.id.settings
-        )
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
index 57701ab..b76f6bb 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
@@ -27,28 +27,17 @@
  * <p>Updates the seek bar views in response to changes to the model.
  */
 class SeekBarObserver(
-    private val holder: MediaViewHolder,
-    private val useSessionLayout: Boolean
+    private val holder: MediaViewHolder
 ) : Observer<SeekBarViewModel.Progress> {
 
     val seekBarEnabledMaxHeight = holder.seekBar.context.resources
         .getDimensionPixelSize(R.dimen.qs_media_enabled_seekbar_height)
     val seekBarDisabledHeight = holder.seekBar.context.resources
         .getDimensionPixelSize(R.dimen.qs_media_disabled_seekbar_height)
-    val seekBarEnabledVerticalPadding = if (useSessionLayout) {
-        holder.seekBar.context.resources
+    val seekBarEnabledVerticalPadding = holder.seekBar.context.resources
                 .getDimensionPixelSize(R.dimen.qs_media_session_enabled_seekbar_vertical_padding)
-    } else {
-        holder.seekBar.context.resources
-                .getDimensionPixelSize(R.dimen.qs_media_enabled_seekbar_vertical_padding)
-    }
-    val seekBarDisabledVerticalPadding = if (useSessionLayout) {
-        holder.seekBar.context.resources
+    val seekBarDisabledVerticalPadding = holder.seekBar.context.resources
                 .getDimensionPixelSize(R.dimen.qs_media_session_disabled_seekbar_vertical_padding)
-    } else {
-        holder.seekBar.context.resources
-                .getDimensionPixelSize(R.dimen.qs_media_disabled_seekbar_vertical_padding)
-    }
 
     init {
         val seekBarProgressWavelength = holder.seekBar.context.resources
@@ -89,7 +78,7 @@
 
         holder.seekBar.thumb.alpha = if (data.seekAvailable) 255 else 0
         holder.seekBar.isEnabled = data.seekAvailable
-        progressDrawable?.animate = data.playing
+        progressDrawable?.animate = data.playing && !data.scrubbing
 
         if (holder.seekBar.maxHeight != seekBarEnabledMaxHeight) {
             holder.seekBar.maxHeight = seekBarEnabledMaxHeight
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
index 49cd161..a9a8fd1c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
@@ -74,7 +74,7 @@
 class SeekBarViewModel @Inject constructor(
     @Background private val bgExecutor: RepeatableExecutor
 ) {
-    private var _data = Progress(false, false, false, null, 0)
+    private var _data = Progress(false, false, false, false, null, 0)
         set(value) {
             field = value
             _progress.postValue(value)
@@ -127,6 +127,7 @@
             if (field != value) {
                 field = value
                 checkIfPollingNeeded()
+                _data = _data.copy(scrubbing = value)
             }
         }
 
@@ -200,7 +201,7 @@
         val enabled = if (playbackState == null ||
                 playbackState?.getState() == PlaybackState.STATE_NONE ||
                 (duration <= 0)) false else true
-        _data = Progress(enabled, seekAvailable, playing, position, duration)
+        _data = Progress(enabled, seekAvailable, playing, scrubbing, position, duration)
         checkIfPollingNeeded()
     }
 
@@ -418,6 +419,7 @@
         val enabled: Boolean,
         val seekAvailable: Boolean,
         val playing: Boolean,
+        val scrubbing: Boolean,
         val elapsedTime: Int?,
         val duration: Int
     )
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index 0b23ad5..f4fcf10 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -119,7 +119,9 @@
             mCheckBox.setVisibility(View.GONE);
             mStatusIcon.setVisibility(View.GONE);
             mContainerLayout.setOnClickListener(null);
-            mTitleText.setTextColor(mController.getColorInactiveItem());
+            mTitleText.setTextColor(mController.getColorItemContent());
+            mSubTitleText.setTextColor(mController.getColorItemContent());
+            mTwoLineTitleText.setTextColor(mController.getColorItemContent());
             mSeekBar.getProgressDrawable().setColorFilter(
                     new PorterDuffColorFilter(mController.getColorSeekbarProgress(),
                             PorterDuff.Mode.SRC_IN));
@@ -140,7 +142,7 @@
                         && !mController.hasAdjustVolumeUserRestriction()) {
                     mProgressBar.getIndeterminateDrawable().setColorFilter(
                             new PorterDuffColorFilter(
-                                    mController.getColorInactiveItem(),
+                                    mController.getColorItemContent(),
                                     PorterDuff.Mode.SRC_IN));
                     setSingleLineLayout(getItemTitle(device), true /* bFocused */,
                             false /* showSeekBar*/,
@@ -155,7 +157,7 @@
                     mTitleIcon.setAlpha(DEVICE_CONNECTED_ALPHA);
                     mStatusIcon.setImageDrawable(
                             mContext.getDrawable(R.drawable.media_output_status_failed));
-                    mStatusIcon.setColorFilter(mController.getColorInactiveItem());
+                    mStatusIcon.setColorFilter(mController.getColorItemContent());
                     setTwoLineLayout(device, false /* bFocused */,
                             false /* showSeekBar */, false /* showProgressBar */,
                             true /* showSubtitle */, true /* showStatus */);
@@ -163,40 +165,34 @@
                     mContainerLayout.setOnClickListener(v -> onItemClick(v, device));
                 } else if (mController.getSelectedMediaDevice().size() > 1
                         && isDeviceIncluded(mController.getSelectedMediaDevice(), device)) {
-                    mTitleText.setTextColor(mController.getColorActiveItem());
+                    mTitleText.setTextColor(mController.getColorItemContent());
                     setSingleLineLayout(getItemTitle(device), true /* bFocused */,
                             true /* showSeekBar */,
                             false /* showProgressBar */, false /* showStatus */);
-                    mCheckBox.setOnCheckedChangeListener(null);
                     mCheckBox.setVisibility(View.VISIBLE);
                     mCheckBox.setChecked(true);
-                    mCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
-                        onCheckBoxClicked(false, device);
-                    });
-                    setCheckBoxColor(mCheckBox, mController.getColorActiveItem());
+                    mSeekBar.setOnClickListener(null);
+                    mSeekBar.setOnClickListener(v -> onGroupActionTriggered(false, device));
+                    setCheckBoxColor(mCheckBox, mController.getColorItemContent());
                     initSeekbar(device);
                 } else if (!mController.hasAdjustVolumeUserRestriction() && currentlyConnected) {
                     mStatusIcon.setImageDrawable(
                             mContext.getDrawable(R.drawable.media_output_status_check));
-                    mStatusIcon.setColorFilter(mController.getColorActiveItem());
-                    mTitleText.setTextColor(mController.getColorActiveItem());
+                    mStatusIcon.setColorFilter(mController.getColorItemContent());
+                    mTitleText.setTextColor(mController.getColorItemContent());
                     setSingleLineLayout(getItemTitle(device), true /* bFocused */,
                             true /* showSeekBar */,
                             false /* showProgressBar */, true /* showStatus */);
                     initSeekbar(device);
                     mCurrentActivePosition = position;
                 } else if (isDeviceIncluded(mController.getSelectableMediaDevice(), device)) {
-                    mCheckBox.setOnCheckedChangeListener(null);
                     mCheckBox.setVisibility(View.VISIBLE);
                     mCheckBox.setChecked(false);
-                    mCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
-                        onCheckBoxClicked(true, device);
-                    });
-                    setCheckBoxColor(mCheckBox, mController.getColorInactiveItem());
+                    mContainerLayout.setOnClickListener(v -> onGroupActionTriggered(true, device));
+                    setCheckBoxColor(mCheckBox, mController.getColorItemContent());
                     setSingleLineLayout(getItemTitle(device), false /* bFocused */,
                             false /* showSeekBar */,
                             false /* showProgressBar */, false /* showStatus */);
-                    mContainerLayout.setOnClickListener(v -> onItemClick(v, device));
                 } else {
                     setSingleLineLayout(getItemTitle(device), false /* bFocused */);
                     mContainerLayout.setOnClickListener(v -> onItemClick(v, device));
@@ -214,7 +210,7 @@
         @Override
         void onBind(int customizedItem, boolean topMargin, boolean bottomMargin) {
             if (customizedItem == CUSTOMIZED_ITEM_PAIR_NEW) {
-                mTitleText.setTextColor(mController.getColorInactiveItem());
+                mTitleText.setTextColor(mController.getColorItemContent());
                 mCheckBox.setVisibility(View.GONE);
                 setSingleLineLayout(mContext.getText(R.string.media_output_dialog_pairing_new),
                         false /* bFocused */);
@@ -226,7 +222,7 @@
             }
         }
 
-        private void onCheckBoxClicked(boolean isChecked, MediaDevice device) {
+        private void onGroupActionTriggered(boolean isChecked, MediaDevice device) {
             if (isChecked && isDeviceIncluded(mController.getSelectableMediaDevice(), device)) {
                 mController.addDeviceToPlayMedia(device);
             } else if (!isChecked && isDeviceIncluded(mController.getDeselectableMediaDevice(),
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index c96aca3..df0c14b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -34,7 +34,6 @@
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.ProgressBar;
-import android.widget.RelativeLayout;
 import android.widget.SeekBar;
 import android.widget.TextView;
 
@@ -129,7 +128,7 @@
         final ImageView mTitleIcon;
         final ProgressBar mProgressBar;
         final SeekBar mSeekBar;
-        final RelativeLayout mTwoLineLayout;
+        final LinearLayout mTwoLineLayout;
         final ImageView mStatusIcon;
         final CheckBox mCheckBox;
         private String mDeviceId;
@@ -171,14 +170,16 @@
         void setSingleLineLayout(CharSequence title, boolean bFocused, boolean showSeekBar,
                 boolean showProgressBar, boolean showStatus) {
             mTwoLineLayout.setVisibility(View.GONE);
+            boolean isActive = showSeekBar || showProgressBar;
             final Drawable backgroundDrawable =
-                    showSeekBar || showProgressBar
+                    isActive
                             ? mContext.getDrawable(R.drawable.media_output_item_background_active)
                                     .mutate() : mContext.getDrawable(
                             R.drawable.media_output_item_background)
                             .mutate();
             backgroundDrawable.setColorFilter(new PorterDuffColorFilter(
-                    mController.getColorItemBackground(),
+                    isActive ? mController.getColorConnectedItemBackground()
+                            : mController.getColorItemBackground(),
                     PorterDuff.Mode.SRC_IN));
             mItemLayout.setBackground(backgroundDrawable);
             mProgressBar.setVisibility(showProgressBar ? View.VISIBLE : View.GONE);
@@ -367,7 +368,7 @@
                     .mutate();
             drawable.setColorFilter(
                     new PorterDuffColorFilter(Utils.getColorStateListDefaultColor(mContext,
-                            R.color.media_dialog_active_item_main_content),
+                            R.color.media_dialog_item_main_content),
                             PorterDuff.Mode.SRC_IN));
             return drawable;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index a8141c0..dcb1c7c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -216,6 +216,7 @@
                         PorterDuff.Mode.SRC_IN);
                 mDoneButton.getBackground().setColorFilter(buttonColorFilter);
                 mStopButton.getBackground().setColorFilter(buttonColorFilter);
+                mDoneButton.setTextColor(mAdapter.getController().getColorPositiveButtonText());
             }
             mHeaderIcon.setVisibility(View.VISIBLE);
             mHeaderIcon.setImageIcon(icon);
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 0b6c68d..1cc96c0f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -110,11 +110,12 @@
 
     private MediaOutputMetricLogger mMetricLogger;
 
-    private int mColorActiveItem;
-    private int mColorInactiveItem;
+    private int mColorItemContent;
     private int mColorSeekbarProgress;
     private int mColorButtonBackground;
     private int mColorItemBackground;
+    private int mColorConnectedItemBackground;
+    private int mColorPositiveButtonText;
 
     @Inject
     public MediaOutputController(@NonNull Context context, String packageName,
@@ -133,16 +134,18 @@
         mMetricLogger = new MediaOutputMetricLogger(mContext, mPackageName);
         mDialogLaunchAnimator = dialogLaunchAnimator;
         mNearbyMediaDevicesManager = nearbyMediaDevicesManagerOptional.orElse(null);
-        mColorActiveItem = Utils.getColorStateListDefaultColor(mContext,
-                R.color.media_dialog_active_item_main_content);
-        mColorInactiveItem = Utils.getColorStateListDefaultColor(mContext,
-                R.color.media_dialog_inactive_item_main_content);
+        mColorItemContent = Utils.getColorStateListDefaultColor(mContext,
+                R.color.media_dialog_item_main_content);
         mColorSeekbarProgress = Utils.getColorStateListDefaultColor(mContext,
-                android.R.color.system_accent1_200);
+                R.color.media_dialog_seekbar_progress);
         mColorButtonBackground = Utils.getColorStateListDefaultColor(mContext,
-                R.color.media_dialog_item_background);
+                R.color.media_dialog_button_background);
         mColorItemBackground = Utils.getColorStateListDefaultColor(mContext,
-                android.R.color.system_accent2_50);
+                R.color.media_dialog_item_background);
+        mColorConnectedItemBackground = Utils.getColorStateListDefaultColor(mContext,
+                R.color.media_dialog_connected_item_background);
+        mColorPositiveButtonText = Utils.getColorStateListDefaultColor(mContext,
+                R.color.media_dialog_solid_button_text);
     }
 
     void start(@NonNull Callback cb) {
@@ -322,8 +325,7 @@
     }
 
     void setColorFilter(Drawable drawable, boolean isActive) {
-        drawable.setColorFilter(new PorterDuffColorFilter(isActive
-                ? mColorActiveItem : mColorInactiveItem,
+        drawable.setColorFilter(new PorterDuffColorFilter(mColorItemContent,
                 PorterDuff.Mode.SRC_IN));
     }
 
@@ -358,26 +360,32 @@
         ColorScheme mCurrentColorScheme = new ColorScheme(wallpaperColors,
                 isDarkTheme);
         if (isDarkTheme) {
-            mColorActiveItem = mCurrentColorScheme.getNeutral1().get(10);
-            mColorInactiveItem = mCurrentColorScheme.getNeutral1().get(10);
-            mColorSeekbarProgress = mCurrentColorScheme.getAccent1().get(2);
-            mColorButtonBackground = mCurrentColorScheme.getAccent1().get(2);
-            mColorItemBackground = mCurrentColorScheme.getAccent2().get(0);
+            mColorItemContent = mCurrentColorScheme.getAccent1().get(2); // A1-100
+            mColorSeekbarProgress = mCurrentColorScheme.getAccent2().get(7); // A2-600
+            mColorButtonBackground = mCurrentColorScheme.getAccent1().get(4); // A1-300
+            mColorItemBackground = mCurrentColorScheme.getNeutral2().get(9); // N2-800
+            mColorConnectedItemBackground = mCurrentColorScheme.getAccent2().get(9); // A2-800
+            mColorPositiveButtonText = mCurrentColorScheme.getAccent2().get(9); // A2-800
         } else {
-            mColorActiveItem = mCurrentColorScheme.getNeutral1().get(10);
-            mColorInactiveItem = mCurrentColorScheme.getAccent1().get(7);
-            mColorSeekbarProgress = mCurrentColorScheme.getAccent1().get(3);
-            mColorButtonBackground = mCurrentColorScheme.getAccent1().get(3);
-            mColorItemBackground = mCurrentColorScheme.getAccent2().get(0);
+            mColorItemContent = mCurrentColorScheme.getAccent1().get(9); // A1-800
+            mColorSeekbarProgress = mCurrentColorScheme.getAccent1().get(4); // A1-300
+            mColorButtonBackground = mCurrentColorScheme.getAccent1().get(7); // A1-600
+            mColorItemBackground = mCurrentColorScheme.getAccent2().get(1); // A2-50
+            mColorConnectedItemBackground = mCurrentColorScheme.getAccent1().get(2); // A1-100
+            mColorPositiveButtonText = mCurrentColorScheme.getNeutral1().get(1); // N1-50
         }
     }
 
-    public int getColorActiveItem() {
-        return mColorActiveItem;
+    public int getColorConnectedItemBackground() {
+        return mColorConnectedItemBackground;
     }
 
-    public int getColorInactiveItem() {
-        return mColorInactiveItem;
+    public int getColorPositiveButtonText() {
+        return mColorPositiveButtonText;
+    }
+
+    public int getColorItemContent() {
+        return mColorItemContent;
     }
 
     public int getColorSeekbarProgress() {
@@ -629,7 +637,8 @@
     }
 
     private boolean isPlayBackInfoLocal() {
-        return mMediaController.getPlaybackInfo() != null
+        return mMediaController != null
+                && mMediaController.getPlaybackInfo() != null
                 && mMediaController.getPlaybackInfo().getPlaybackType()
                 == MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSeekbar.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSeekbar.java
new file mode 100644
index 0000000..0a3c5bf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSeekbar.java
@@ -0,0 +1,68 @@
+/*
+ * 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.systemui.media.dialog;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.SeekBar;
+
+/**
+ * Customized seekbar used by MediaOutputDialog, which only changes progress when dragging,
+ * otherwise performs click.
+ */
+public class MediaOutputSeekbar extends SeekBar {
+    private static final int DRAGGING_THRESHOLD = 20;
+    private boolean mIsDragging = false;
+
+    public MediaOutputSeekbar(Context context) {
+        super(context);
+    }
+
+    public MediaOutputSeekbar(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        int width = getWidth()
+                - getPaddingLeft()
+                - getPaddingRight();
+        int thumbPos = getPaddingLeft()
+                + width
+                * getProgress()
+                / getMax();
+        if (event.getAction() == MotionEvent.ACTION_DOWN
+                && Math.abs(event.getX() - thumbPos) < DRAGGING_THRESHOLD) {
+            mIsDragging = true;
+            super.onTouchEvent(event);
+        } else if (event.getAction() == MotionEvent.ACTION_MOVE && mIsDragging) {
+            super.onTouchEvent(event);
+        } else if (event.getAction() == MotionEvent.ACTION_UP && mIsDragging) {
+            mIsDragging = false;
+            super.onTouchEvent(event);
+        } else if (event.getAction() == MotionEvent.ACTION_UP && !mIsDragging) {
+            performClick();
+        }
+        return true;
+    }
+
+    @Override
+    public boolean performClick() {
+        return super.performClick();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
index 3961f07..8757904 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
@@ -66,11 +66,14 @@
                     as StatusBarManager
             val routeInfo = MediaRoute2Info.Builder("id", args[0])
                     .addFeature("feature")
-                    .setPackageName(TEST_PACKAGE_NAME)
-                    .build()
+            val useAppIcon = !(args.size >= 3 && args[2] == "useAppIcon=false")
+            if (useAppIcon) {
+                routeInfo.setPackageName(TEST_PACKAGE_NAME)
+            }
+
             statusBarManager.updateMediaTapToTransferSenderDisplay(
-                    displayState,
-                    routeInfo,
+                displayState,
+                routeInfo.build(),
                 getUndoExecutor(displayState),
                 getUndoCallback(displayState)
             )
@@ -106,7 +109,8 @@
         }
 
         override fun help(pw: PrintWriter) {
-            pw.println("Usage: adb shell cmd statusbar $SENDER_COMMAND <deviceName> <chipState>")
+            pw.println("Usage: adb shell cmd statusbar $SENDER_COMMAND " +
+                    "<deviceName> <chipState> useAppIcon=[true|false]")
         }
     }
 
@@ -128,19 +132,22 @@
                     as StatusBarManager
             val routeInfo = MediaRoute2Info.Builder("id", "Test Name")
                 .addFeature("feature")
-                .setPackageName(TEST_PACKAGE_NAME)
-                .build()
+            val useAppIcon = !(args.size >= 2 && args[1] == "useAppIcon=false")
+            if (useAppIcon) {
+                routeInfo.setPackageName(TEST_PACKAGE_NAME)
+            }
 
             statusBarManager.updateMediaTapToTransferReceiverDisplay(
                     displayState,
-                    routeInfo,
+                    routeInfo.build(),
                     null,
                     null
                 )
         }
 
         override fun help(pw: PrintWriter) {
-            pw.println("Usage: adb shell cmd statusbar $RECEIVER_COMMAND <chipState>")
+            pw.println("Usage: adb shell cmd statusbar $RECEIVER_COMMAND " +
+                    "<chipState> useAppIcon=[true|false]")
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
index 71cacac..54b0c13 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
@@ -31,7 +31,9 @@
 import android.view.View
 import android.view.ViewGroup
 import android.view.WindowManager
+import android.widget.LinearLayout
 import com.android.internal.widget.CachingIconView
+import com.android.settingslib.Utils
 import com.android.systemui.R
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.statusbar.gesture.TapGestureDetector
@@ -136,6 +138,11 @@
     abstract fun updateChipView(chipInfo: T, currentChipView: ViewGroup)
 
     /**
+     * Returns the size that the icon should be, or null if no size override is needed.
+     */
+    open fun getIconSize(isAppIcon: Boolean): Int? = null
+
+    /**
      * An internal method to set the icon on the view.
      *
      * This is in the common superclass since both the sender and the receiver show an icon.
@@ -150,40 +157,48 @@
         appNameOverride: CharSequence? = null,
     ) {
         val appIconView = currentChipView.requireViewById<CachingIconView>(R.id.app_icon)
-        appIconView.contentDescription = appNameOverride ?: getAppName(appPackageName)
+        val iconInfo = getIconInfo(appPackageName)
 
-        val appIcon = appIconDrawableOverride ?: getAppIcon(appPackageName)
-        val visibility = if (appIcon != null) {
-            View.VISIBLE
-        } else {
-            View.GONE
+        getIconSize(iconInfo.isAppIcon)?.let { size ->
+            val lp = appIconView.layoutParams
+            lp.width = size
+            lp.height = size
+            appIconView.layoutParams = lp
         }
-        appIconView.setImageDrawable(appIcon)
-        appIconView.visibility = visibility
+
+        appIconView.contentDescription = appNameOverride ?: iconInfo.iconName
+        appIconView.setImageDrawable(appIconDrawableOverride ?: iconInfo.icon)
     }
 
-    /** Returns the icon of the app playing the media or null if we can't find it. */
-    private fun getAppIcon(appPackageName: String?): Drawable? {
-        appPackageName ?: return null
-        return try {
-            context.packageManager.getApplicationIcon(appPackageName)
-        } catch (e: PackageManager.NameNotFoundException) {
-            Log.w(TAG, "Cannot find icon for package $appPackageName", e)
-            null
+    /**
+     * Returns the information needed to display the icon.
+     *
+     * The information will either contain app name and icon of the app playing media, or a default
+     * name and icon if we can't find the app name/icon.
+     */
+    private fun getIconInfo(appPackageName: String?): IconInfo {
+        if (appPackageName != null) {
+            try {
+                return IconInfo(
+                    iconName = context.packageManager.getApplicationInfo(
+                        appPackageName, PackageManager.ApplicationInfoFlags.of(0)
+                    ).loadLabel(context.packageManager).toString(),
+                    icon = context.packageManager.getApplicationIcon(appPackageName),
+                    isAppIcon = true
+                )
+            } catch (e: PackageManager.NameNotFoundException) {
+                Log.w(TAG, "Cannot find package $appPackageName", e)
+            }
         }
-    }
-
-    /** Returns the name of the app playing the media or null if we can't find it. */
-    private fun getAppName(appPackageName: String?): String? {
-        appPackageName ?: return null
-        return try {
-            context.packageManager.getApplicationInfo(
-                    appPackageName, PackageManager.ApplicationInfoFlags.of(0)
-            ).loadLabel(context.packageManager).toString()
-        } catch (e: PackageManager.NameNotFoundException) {
-            Log.w(TAG, "Cannot find name for package $appPackageName", e)
-            null
-        }
+        return IconInfo(
+            iconName = context.getString(R.string.media_output_dialog_unknown_launch_app_name),
+            icon = context.resources.getDrawable(R.drawable.ic_cast).apply {
+                this.setTint(
+                    Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary)
+                )
+            },
+            isAppIcon = false
+        )
     }
 
     private fun onScreenTapped(e: MotionEvent) {
@@ -205,3 +220,10 @@
     const val REASON_TIMEOUT = "TIMEOUT"
     const val REASON_SCREEN_TAP = "SCREEN_TAP"
 }
+
+private data class IconInfo(
+    val iconName: String,
+    val icon: Drawable,
+    /** True if [icon] is the app's icon, and false if [icon] is some generic default icon. */
+    val isAppIcon: Boolean
+)
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
index 44965d7..072263f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -127,6 +127,15 @@
                 chipInfo.appNameOverride
         )
     }
+
+    override fun getIconSize(isAppIcon: Boolean): Int? =
+        context.resources.getDimensionPixelSize(
+            if (isAppIcon) {
+                R.dimen.media_ttt_icon_size_receiver
+            } else {
+                R.dimen.media_ttt_generic_icon_size_receiver
+            }
+        )
 }
 
 data class ChipReceiverInfo(
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
index a1a3198..df820a7 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
@@ -33,6 +33,7 @@
 import android.os.Looper;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.provider.Settings.Secure;
 import android.view.View;
 import android.view.WindowInsets;
 import android.view.accessibility.AccessibilityManager;
@@ -72,6 +73,7 @@
  */
 @SysUISingleton
 public final class NavBarHelper implements
+        AccessibilityManager.AccessibilityServicesStateChangeListener,
         AccessibilityButtonModeObserver.ModeChangedListener,
         AccessibilityButtonTargetsObserver.TargetsChangedListener,
         OverviewProxyService.OverviewProxyListener, NavigationModeController.ModeChangedListener,
@@ -123,8 +125,7 @@
         mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
         mUserTracker = userTracker;
         mSystemActions = systemActions;
-        accessibilityManager.addAccessibilityServicesStateChangeListener(
-                accessibilityManager1 -> NavBarHelper.this.dispatchA11yEventUpdate());
+        accessibilityManager.addAccessibilityServicesStateChangeListener(this);
         mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
         mAccessibilityButtonTargetsObserver = accessibilityButtonTargetsObserver;
 
@@ -146,6 +147,7 @@
                 Settings.Secure.getUriFor(Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED),
                 false, mAssistContentObserver, UserHandle.USER_ALL);
         updateAssistantAvailability();
+        updateA11yState();
     }
 
     public void destroy() {
@@ -178,6 +180,12 @@
     }
 
     @Override
+    public void onAccessibilityServicesStateChanged(AccessibilityManager manager) {
+        dispatchA11yEventUpdate();
+        updateA11yState();
+    }
+
+    @Override
     public void onAccessibilityButtonModeChanged(int mode) {
         updateA11yState();
         dispatchA11yEventUpdate();
@@ -190,7 +198,9 @@
     }
 
     /**
-     * Updates the current accessibility button state.
+     * Updates the current accessibility button state. The accessibility button state is only
+     * used for {@link Secure#ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR} and
+     * {@link Secure#ACCESSIBILITY_BUTTON_MODE_GESTURE}, otherwise it is reset to 0.
      */
     private void updateA11yState() {
         final int prevState = mA11yButtonState;
@@ -213,6 +223,9 @@
             final int requestingServices = a11yButtonTargets.size();
 
             clickable = requestingServices >= 1;
+
+            // `longClickable` is used to determine whether to pop up the accessibility chooser
+            // dialog or not, and it’s also only for multiple services.
             longClickable = requestingServices >= 2;
             mA11yButtonState = (clickable ? SYSUI_STATE_A11Y_BUTTON_CLICKABLE : 0)
                     | (longClickable ? SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE : 0);
@@ -237,11 +250,13 @@
     }
 
     /**
-     * See {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_CLICKABLE} and
-     * {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE}
+     * Gets the accessibility button state based on the {@link Secure#ACCESSIBILITY_BUTTON_MODE}.
      *
-     * @return the a11y button clickable and long_clickable states, or 0 if there is no
-     *         a11y button in the navbar
+     * @return the accessibility button state:
+     * 0 = disable state
+     * 16 = {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_CLICKABLE}
+     * 48 = the combination of {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_CLICKABLE} and
+     * {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE}
      */
     public int getA11yButtonState() {
         return mA11yButtonState;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index ec6094d..fab19d6 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -47,6 +47,7 @@
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SWITCHER_SHOWING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
+import static com.android.systemui.shared.system.QuickStepContract.isGesturalMode;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
@@ -61,7 +62,6 @@
 import android.app.IActivityTaskManager;
 import android.app.StatusBarManager;
 import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -86,7 +86,6 @@
 import android.view.InsetsState.InternalInsetsType;
 import android.view.InsetsVisibilities;
 import android.view.KeyEvent;
-import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.View;
@@ -98,6 +97,7 @@
 import android.view.accessibility.AccessibilityManager;
 import android.view.inputmethod.InputMethodManager;
 
+import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity;
@@ -107,13 +107,17 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.LatencyTracker;
 import com.android.internal.view.AppearanceRegion;
+import com.android.systemui.Gefingerpoken;
 import com.android.systemui.R;
-import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.DisplayId;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.model.SysUiState;
+import com.android.systemui.navigationbar.NavigationBarComponent.NavigationBarScope;
+import com.android.systemui.navigationbar.NavigationModeController.ModeChangedListener;
 import com.android.systemui.navigationbar.buttons.ButtonDispatcher;
+import com.android.systemui.navigationbar.buttons.DeadZone;
 import com.android.systemui.navigationbar.buttons.KeyButtonView;
 import com.android.systemui.navigationbar.buttons.RotationContextButton;
 import com.android.systemui.navigationbar.gestural.QuickswitchOrientedNavHandle;
@@ -125,6 +129,7 @@
 import com.android.systemui.shared.rotation.RotationButtonController;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.QuickStepContract;
+import com.android.systemui.shared.system.SysUiStatsLog;
 import com.android.systemui.statusbar.AutoHideUiElement;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.CommandQueue.Callbacks;
@@ -137,7 +142,10 @@
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.LightBarController;
 import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.util.DeviceConfigProxy;
+import com.android.systemui.util.ViewController;
 import com.android.wm.shell.back.BackAnimation;
 import com.android.wm.shell.pip.Pip;
 
@@ -153,8 +161,8 @@
 /**
  * Contains logic for a navigation bar view.
  */
-public class NavigationBar implements View.OnAttachStateChangeListener,
-        Callbacks, NavigationModeController.ModeChangedListener {
+@NavigationBarScope
+public class NavigationBar extends ViewController<NavigationBarView> implements Callbacks {
 
     public static final String TAG = "NavigationBar";
     private static final boolean DEBUG = false;
@@ -169,39 +177,37 @@
     private static final long AUTODIM_TIMEOUT_MS = 2250;
 
     private final Context mContext;
+    private final Bundle mSavedState;
     private final WindowManager mWindowManager;
     private final AccessibilityManager mAccessibilityManager;
     private final DeviceProvisionedController mDeviceProvisionedController;
     private final StatusBarStateController mStatusBarStateController;
     private final MetricsLogger mMetricsLogger;
     private final Lazy<AssistManager> mAssistManagerLazy;
+    private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     private final SysUiState mSysUiFlagsContainer;
     private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
     private final ShadeController mShadeController;
     private final NotificationRemoteInputManager mNotificationRemoteInputManager;
     private final OverviewProxyService mOverviewProxyService;
     private final NavigationModeController mNavigationModeController;
-    private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
     private final BroadcastDispatcher mBroadcastDispatcher;
     private final CommandQueue mCommandQueue;
     private final Optional<Pip> mPipOptional;
     private final Optional<Recents> mRecentsOptional;
+    private final DeviceConfigProxy mDeviceConfigProxy;
     private final Optional<BackAnimation> mBackAnimation;
     private final Handler mHandler;
     private final NavigationBarOverlayController mNavbarOverlayController;
     private final UiEventLogger mUiEventLogger;
     private final NavBarHelper mNavBarHelper;
     private final NotificationShadeDepthController mNotificationShadeDepthController;
-
-    private Bundle mSavedState;
-    private NavigationBarView mNavigationBarView;
     private NavigationBarFrame mFrame;
 
     private @WindowVisibleState int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
 
     private int mNavigationIconHints = 0;
-    private @TransitionMode int mNavigationBarMode;
-    private ContentResolver mContentResolver;
+    private @TransitionMode int mTransitionMode;
     private boolean mLongPressHomeEnabled;
 
     private int mDisabledFlags1;
@@ -255,7 +261,8 @@
     private int mCurrentRotation;
     private ViewTreeObserver.OnGlobalLayoutListener mOrientationHandleGlobalLayoutListener;
     private boolean mShowOrientedHandleForImmersiveMode;
-
+    private final DeadZone mDeadZone;
+    private boolean mImeVisible;
 
     @com.android.internal.annotations.VisibleForTesting
     public enum NavBarActionEvent implements UiEventLogger.UiEventEnum {
@@ -309,7 +316,7 @@
                     // TODO(b/198002034): Content observers currently can still be called back after
                     //  being unregistered, and in this case we can ignore the change if the nav bar
                     //  has been destroyed already
-                    if (mNavigationBarView == null) {
+                    if (mView == null) {
                         return;
                     }
                     mLongPressHomeEnabled = mNavBarHelper.getLongPressHomeEnabled();
@@ -320,14 +327,14 @@
     private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
         @Override
         public void onConnectionChanged(boolean isConnected) {
-            mNavigationBarView.updateStates();
+            mView.updateStates();
             updateScreenPinningGestures();
         }
 
         @Override
         public void onQuickStepStarted() {
             // Use navbar dragging as a signal to hide the rotate button
-            mNavigationBarView.getRotationButtonController().setRotateSuggestionButtonState(false);
+            mView.getRotationButtonController().setRotateSuggestionButtonState(false);
 
             // Hide the notifications panel when quick step starts
             mShadeController.collapsePanel(true /* animate */);
@@ -364,12 +371,12 @@
                 // Disallow home handle animations when in gestural
                 animate = false;
                 forceVisible = mAllowForceNavBarHandleOpaque && mForceNavBarHandleOpaque;
-                buttonDispatcher = mNavigationBarView.getHomeHandle();
+                buttonDispatcher = mView.getHomeHandle();
                 if (getBarTransitions() != null) {
                     getBarTransitions().setBackgroundOverrideAlpha(alpha);
                 }
             } else if (QuickStepContract.isSwipeUpMode(mNavBarMode)) {
-                buttonDispatcher = mNavigationBarView.getBackButton();
+                buttonDispatcher = mView.getBackButton();
             }
             if (buttonDispatcher != null) {
                 buttonDispatcher.setVisibility(
@@ -380,7 +387,7 @@
 
         @Override
         public void onHomeRotationEnabled(boolean enabled) {
-            mNavigationBarView.getRotationButtonController().setHomeRotationEnabled(enabled);
+            mView.getRotationButtonController().setHomeRotationEnabled(enabled);
         }
 
         @Override
@@ -388,20 +395,18 @@
             // If the overview has fixed orientation that may change display to natural rotation,
             // we don't want the user rotation to be reset. So after user returns to application,
             // it can keep in the original rotation.
-            mNavigationBarView.getRotationButtonController().setSkipOverrideUserLockPrefsOnce();
+            mView.getRotationButtonController().setSkipOverrideUserLockPrefsOnce();
         }
 
         @Override
         public void onTaskbarStatusUpdated(boolean visible, boolean stashed) {
-            mNavigationBarView
-                    .getFloatingRotationButton()
-                    .onTaskbarStateChanged(visible, stashed);
+            mView.getFloatingRotationButton().onTaskbarStateChanged(visible, stashed);
         }
 
         @Override
         public void onToggleRecentApps() {
             // The same case as onOverviewShown but only for 3-button navigation.
-            mNavigationBarView.getRotationButtonController().setSkipOverrideUserLockPrefsOnce();
+            mView.getRotationButtonController().setSkipOverrideUserLockPrefsOnce();
         }
     };
 
@@ -414,11 +419,10 @@
             };
 
     private final Runnable mAutoDim = () -> getBarTransitions().setAutoDim(true);
-    private final Runnable mEnableLayoutTransitions = () ->
-            mNavigationBarView.setLayoutTransitionsEnabled(true);
+    private final Runnable mEnableLayoutTransitions = () -> mView.setLayoutTransitionsEnabled(true);
     private final Runnable mOnVariableDurationHomeLongClick = () -> {
-        if (onHomeLongClick(mNavigationBarView.getHomeButton().getCurrentView())) {
-            mNavigationBarView.getHomeButton().getCurrentView().performHapticFeedback(
+        if (onHomeLongClick(mView.getHomeButton().getCurrentView())) {
+            mView.getHomeButton().getCurrentView().performHapticFeedback(
                     HapticFeedbackConstants.LONG_PRESS,
                     HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
         }
@@ -437,7 +441,7 @@
                         mHomeButtonLongPressDurationMs = Optional.of(
                             properties.getLong(HOME_BUTTON_LONG_PRESS_DURATION_MS, 0)
                         ).filter(duration -> duration != 0);
-                        if (mNavigationBarView != null) {
+                        if (mView != null) {
                             reconfigureHomeLongClick();
                         }
                     }
@@ -467,20 +471,25 @@
                         return;
                     }
                     mHasBlurs = hasBlurs;
-                    mNavigationBarView.setWindowHasBlurs(hasBlurs);
+                    mView.setWindowHasBlurs(hasBlurs);
                 }
             };
 
-    private NavigationBar(Context context,
-            WindowManager windowManager,
+    @Inject
+    NavigationBar(
+            NavigationBarView navigationBarView,
+            NavigationBarFrame navigationBarFrame,
+            @Nullable Bundle savedState,
+            @DisplayId Context context,
+            @DisplayId WindowManager windowManager,
             Lazy<AssistManager> assistManagerLazy,
             AccessibilityManager accessibilityManager,
             DeviceProvisionedController deviceProvisionedController,
             MetricsLogger metricsLogger,
             OverviewProxyService overviewProxyService,
             NavigationModeController navigationModeController,
-            AccessibilityButtonModeObserver accessibilityButtonModeObserver,
             StatusBarStateController statusBarStateController,
+            StatusBarKeyguardViewManager statusBarKeyguardViewManager,
             SysUiState sysUiFlagsContainer,
             BroadcastDispatcher broadcastDispatcher,
             CommandQueue commandQueue,
@@ -500,25 +509,32 @@
             AutoHideController.Factory autoHideControllerFactory,
             Optional<TelecomManager> telecomManagerOptional,
             InputMethodManager inputMethodManager,
+            DeadZone deadZone,
+            DeviceConfigProxy deviceConfigProxy,
             Optional<BackAnimation> backAnimation) {
+        super(navigationBarView);
+        mFrame = navigationBarFrame;
         mContext = context;
+        mSavedState = savedState;
         mWindowManager = windowManager;
         mAccessibilityManager = accessibilityManager;
         mDeviceProvisionedController = deviceProvisionedController;
         mStatusBarStateController = statusBarStateController;
         mMetricsLogger = metricsLogger;
         mAssistManagerLazy = assistManagerLazy;
+        mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
         mSysUiFlagsContainer = sysUiFlagsContainer;
         mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
         mShadeController = shadeController;
         mNotificationRemoteInputManager = notificationRemoteInputManager;
         mOverviewProxyService = overviewProxyService;
         mNavigationModeController = navigationModeController;
-        mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
         mBroadcastDispatcher = broadcastDispatcher;
         mCommandQueue = commandQueue;
         mPipOptional = pipOptional;
         mRecentsOptional = recentsOptional;
+        mDeadZone = deadZone;
+        mDeviceConfigProxy = deviceConfigProxy;
         mBackAnimation = backAnimation;
         mHandler = mainHandler;
         mNavbarOverlayController = navbarOverlayController;
@@ -532,24 +548,27 @@
         mTelecomManagerOptional = telecomManagerOptional;
         mInputMethodManager = inputMethodManager;
 
-        mNavBarMode = mNavigationModeController.addListener(this);
+        mNavBarMode = mNavigationModeController.addListener(mModeChangedListener);
     }
 
     public NavigationBarView getView() {
-        return mNavigationBarView;
+        return mView;
     }
 
-    public View createView(Bundle savedState, boolean initialVisibility) {
-        mFrame = (NavigationBarFrame) LayoutInflater.from(mContext).inflate(
-                R.layout.navigation_bar_window, null);
-        View barView = LayoutInflater.from(mFrame.getContext()).inflate(
-                R.layout.navigation_bar, mFrame);
-        barView.addOnAttachStateChangeListener(this);
-        mNavigationBarView = barView.findViewById(R.id.navigation_bar_view);
+    @Override
+    public void onInit() {
+        // TODO: A great deal of this code should probalby live in onViewAttached.
+        // It should also has corresponding cleanup in onViewDetached.
+        mView.setTouchHandler(mTouchHandler);
+        mView.setNavBarMode(mNavBarMode);
 
-        mNavigationBarView.setVisibility(initialVisibility ? View.VISIBLE : View.INVISIBLE);
+        mView.updateRotationButton();
 
-        if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + barView);
+        mView.setVisibility(
+                mStatusBarKeyguardViewManager.isNavBarVisible() ? View.VISIBLE : View.INVISIBLE);
+
+        if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mView);
+
         mWindowManager.addView(mFrame,
                 getBarLayoutParams(mContext.getResources().getConfiguration().windowConfiguration
                         .getRotation()));
@@ -558,30 +577,28 @@
 
         mCommandQueue.addCallback(this);
         mLongPressHomeEnabled = mNavBarHelper.getLongPressHomeEnabled();
-        mContentResolver = mContext.getContentResolver();
         mNavBarHelper.init();
         mAllowForceNavBarHandleOpaque = mContext.getResources().getBoolean(
                 R.bool.allow_force_nav_bar_handle_opaque);
-        mForceNavBarHandleOpaque = DeviceConfig.getBoolean(
+        mForceNavBarHandleOpaque = mDeviceConfigProxy.getBoolean(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 NAV_BAR_HANDLE_FORCE_OPAQUE,
                 /* defaultValue = */ true);
-        mHomeButtonLongPressDurationMs = Optional.of(DeviceConfig.getLong(
+        mHomeButtonLongPressDurationMs = Optional.of(mDeviceConfigProxy.getLong(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 HOME_BUTTON_LONG_PRESS_DURATION_MS,
                 /* defaultValue = */ 0
         )).filter(duration -> duration != 0);
-        DeviceConfig.addOnPropertiesChangedListener(
+        mDeviceConfigProxy.addOnPropertiesChangedListener(
                 DeviceConfig.NAMESPACE_SYSTEMUI, mHandler::post, mOnPropertiesChangedListener);
 
-        if (savedState != null) {
-            mDisabledFlags1 = savedState.getInt(EXTRA_DISABLE_STATE, 0);
-            mDisabledFlags2 = savedState.getInt(EXTRA_DISABLE2_STATE, 0);
-            mAppearance = savedState.getInt(EXTRA_APPEARANCE, 0);
-            mBehavior = savedState.getInt(EXTRA_BEHAVIOR, 0);
-            mTransientShown = savedState.getBoolean(EXTRA_TRANSIENT_STATE, false);
+        if (mSavedState != null) {
+            mDisabledFlags1 = mSavedState.getInt(EXTRA_DISABLE_STATE, 0);
+            mDisabledFlags2 = mSavedState.getInt(EXTRA_DISABLE2_STATE, 0);
+            mAppearance = mSavedState.getInt(EXTRA_APPEARANCE, 0);
+            mBehavior = mSavedState.getInt(EXTRA_BEHAVIOR, 0);
+            mTransientShown = mSavedState.getBoolean(EXTRA_TRANSIENT_STATE, false);
         }
-        mSavedState = savedState;
 
         // Respect the latest disabled-flags.
         mCommandQueue.recomputeDisableFlags(mDisplayId, false);
@@ -589,43 +606,42 @@
         mIsCurrentUserSetup = mDeviceProvisionedController.isCurrentUserSetup();
         mDeviceProvisionedController.addCallback(mUserSetupListener);
         mNotificationShadeDepthController.addListener(mDepthListener);
-
-        return barView;
     }
 
     public void destroyView() {
         setAutoHideController(/* autoHideController */ null);
         mCommandQueue.removeCallback(this);
-        mWindowManager.removeViewImmediate(mNavigationBarView.getRootView());
-        mNavigationModeController.removeListener(this);
+        mWindowManager.removeViewImmediate(mView.getRootView());
+        mNavigationModeController.removeListener(mModeChangedListener);
 
         mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
         mNavBarHelper.destroy();
         mDeviceProvisionedController.removeCallback(mUserSetupListener);
         mNotificationShadeDepthController.removeListener(mDepthListener);
 
-        DeviceConfig.removeOnPropertiesChangedListener(mOnPropertiesChangedListener);
+        mDeviceConfigProxy.removeOnPropertiesChangedListener(mOnPropertiesChangedListener);
     }
 
     @Override
-    public void onViewAttachedToWindow(View v) {
-        final Display display = v.getDisplay();
-        mNavigationBarView.setComponents(mRecentsOptional);
-        mNavigationBarView.setComponents(mCentralSurfacesOptionalLazy.get().get().getPanelController());
-        mNavigationBarView.setDisabledFlags(mDisabledFlags1);
-        mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged);
-        mNavigationBarView.setOnTouchListener(this::onNavigationTouch);
+    public void onViewAttached() {
+        final Display display = mView.getDisplay();
+        mView.setComponents(mRecentsOptional);
+        mView.setComponents(mCentralSurfacesOptionalLazy.get().get().getPanelController());
+        mView.setDisabledFlags(mDisabledFlags1, mSysUiFlagsContainer);
+        mView.setOnVerticalChangedListener(this::onVerticalChanged);
+        mView.setOnTouchListener(this::onNavigationTouch);
         if (mSavedState != null) {
-            mNavigationBarView.getLightTransitionsController().restoreState(mSavedState);
+            mView.getLightTransitionsController().restoreState(mSavedState);
         }
-        mNavigationBarView.setNavigationIconHints(mNavigationIconHints);
-        mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
-        mNavigationBarView.setBehavior(mBehavior);
+        setNavigationIconHints(mNavigationIconHints);
+        mView.setWindowVisible(isNavBarWindowVisible());
+        mView.setBehavior(mBehavior);
+        mView.setNavBarMode(mNavBarMode);
 
         mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
 
-        mPipOptional.ifPresent(mNavigationBarView::addPipExclusionBoundsChangeListener);
-        mBackAnimation.ifPresent(mNavigationBarView::registerBackAnimation);
+        mPipOptional.ifPresent(mView::addPipExclusionBoundsChangeListener);
+        mBackAnimation.ifPresent(mView::registerBackAnimation);
 
         prepareNavigationBarView();
         checkNavBarModes();
@@ -643,7 +659,7 @@
         // Currently there is no accelerometer sensor on non-default display.
         if (mIsOnDefaultDisplay) {
             final RotationButtonController rotationButtonController =
-                    mNavigationBarView.getRotationButtonController();
+                    mView.getRotationButtonController();
             rotationButtonController.setRotationCallback(mRotationWatcher);
 
             // Reset user rotation pref to match that of the WindowManager if starting in locked
@@ -677,12 +693,12 @@
     }
 
     @Override
-    public void onViewDetachedFromWindow(View v) {
+    public void onViewDetached() {
         final RotationButtonController rotationButtonController =
-                mNavigationBarView.getRotationButtonController();
+                mView.getRotationButtonController();
         rotationButtonController.setRotationCallback(null);
-        mNavigationBarView.getBarTransitions().destroy();
-        mNavigationBarView.getLightTransitionsController().destroy(mContext);
+        mView.getBarTransitions().destroy();
+        mView.getLightTransitionsController().destroy(mContext);
         mOverviewProxyService.removeCallback(mOverviewProxyListener);
         mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver);
         if (mOrientationHandle != null) {
@@ -696,9 +712,8 @@
         mHandler.removeCallbacks(mOnVariableDurationHomeLongClick);
         mHandler.removeCallbacks(mEnableLayoutTransitions);
         mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
-        mPipOptional.ifPresent(mNavigationBarView::removePipExclusionBoundsChangeListener);
+        mPipOptional.ifPresent(mView::removePipExclusionBoundsChangeListener);
         mFrame = null;
-        mNavigationBarView = null;
         mOrientationHandle = null;
     }
 
@@ -709,7 +724,7 @@
         outState.putInt(EXTRA_APPEARANCE, mAppearance);
         outState.putInt(EXTRA_BEHAVIOR, mBehavior);
         outState.putBoolean(EXTRA_TRANSIENT_STATE, mTransientShown);
-        mNavigationBarView.getLightTransitionsController().saveState(outState);
+        mView.getLightTransitionsController().saveState(outState);
     }
 
     /**
@@ -772,7 +787,7 @@
                     mOrientationHandle.mapRectFromViewToScreenCoords(boundsOnScreen, true);
                     Rect boundsRounded = new Rect();
                     boundsOnScreen.roundOut(boundsRounded);
-                    mNavigationBarView.setOrientedHandleSamplingRegion(boundsRounded);
+                    mView.setOrientedHandleSamplingRegion(boundsRounded);
                 };
         mOrientationHandle.getViewTreeObserver().addOnGlobalLayoutListener(
                 mOrientationHandleGlobalLayoutListener);
@@ -801,7 +816,7 @@
                 case Surface.ROTATION_90:
                 case Surface.ROTATION_270:
                     height = dispSize.height();
-                    width = mNavigationBarView.getHeight();
+                    width = mView.getHeight();
                     break;
                 case Surface.ROTATION_180:
                 case Surface.ROTATION_0:
@@ -811,7 +826,7 @@
                         return;
                     }
                     width = dispSize.width();
-                    height = mNavigationBarView.getHeight();
+                    height = mView.getHeight();
                     break;
             }
 
@@ -821,7 +836,7 @@
             mOrientationParams.height = height;
             mOrientationParams.width = width;
             mWindowManager.updateViewLayout(mOrientationHandle, mOrientationParams);
-            mNavigationBarView.setVisibility(View.GONE);
+            mView.setVisibility(View.GONE);
             mOrientationHandle.setVisibility(View.VISIBLE);
         }
     }
@@ -832,22 +847,22 @@
             // mOrientedHandle is initialized lazily
             mOrientationHandle.setVisibility(View.GONE);
         }
-        mNavigationBarView.setVisibility(View.VISIBLE);
-        mNavigationBarView.setOrientedHandleSamplingRegion(null);
+        mView.setVisibility(View.VISIBLE);
+        mView.setOrientedHandleSamplingRegion(null);
     }
 
     private void reconfigureHomeLongClick() {
-        if (mNavigationBarView.getHomeButton().getCurrentView() == null) {
+        if (mView.getHomeButton().getCurrentView() == null) {
             return;
         }
         if (mHomeButtonLongPressDurationMs.isPresent() || !mLongPressHomeEnabled) {
-            mNavigationBarView.getHomeButton().getCurrentView().setLongClickable(false);
-            mNavigationBarView.getHomeButton().getCurrentView().setHapticFeedbackEnabled(false);
-            mNavigationBarView.getHomeButton().setOnLongClickListener(null);
+            mView.getHomeButton().getCurrentView().setLongClickable(false);
+            mView.getHomeButton().getCurrentView().setHapticFeedbackEnabled(false);
+            mView.getHomeButton().setOnLongClickListener(null);
         } else {
-            mNavigationBarView.getHomeButton().getCurrentView().setLongClickable(true);
-            mNavigationBarView.getHomeButton().getCurrentView().setHapticFeedbackEnabled(true);
-            mNavigationBarView.getHomeButton().setOnLongClickListener(this::onHomeLongClick);
+            mView.getHomeButton().getCurrentView().setLongClickable(true);
+            mView.getHomeButton().getCurrentView().setHapticFeedbackEnabled(true);
+            mView.getHomeButton().setOnLongClickListener(this::onHomeLongClick);
         }
     }
 
@@ -865,13 +880,13 @@
         pw.println("  mLongPressHomeEnabled=" + mLongPressHomeEnabled);
         pw.println("  mNavigationBarWindowState="
                 + windowStateToString(mNavigationBarWindowState));
-        pw.println("  mNavigationBarMode="
-                + BarTransitions.modeToString(mNavigationBarMode));
+        pw.println("  mTransitionMode="
+                + BarTransitions.modeToString(mTransitionMode));
         pw.println("  mTransientShown=" + mTransientShown);
         pw.println("  mTransientShownFromGestureOnSystemBar="
                 + mTransientShownFromGestureOnSystemBar);
-        dumpBarTransitions(pw, "mNavigationBarView", mNavigationBarView.getBarTransitions());
-        mNavigationBarView.dump(pw);
+        dumpBarTransitions(pw, "mNavigationBarView", mView.getBarTransitions());
+        mView.dump(pw);
     }
 
     // ----- CommandQueue Callbacks -----
@@ -888,11 +903,7 @@
                 imeShown, showImeSwitcher);
         if (hints == mNavigationIconHints) return;
 
-        mNavigationIconHints = hints;
-        if (!isTablet(mContext)) {
-            // All IME functions handled by launcher via Sysui flags for large screen
-            mNavigationBarView.setNavigationIconHints(hints);
-        }
+        setNavigationIconHints(hints);
         checkBarModes();
         updateSystemUiStateFlags();
     }
@@ -911,7 +922,7 @@
                 orientSecondaryHomeHandle();
             }
             if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state));
-            mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
+            mView.setWindowVisible(isNavBarWindowVisible());
         }
     }
 
@@ -920,12 +931,12 @@
         // The CommandQueue callbacks are added when the view is created to ensure we track other
         // states, but until the view is attached (at the next traversal), the view's display is
         // not valid.  Just ignore the rotation in this case.
-        if (!mNavigationBarView.isAttachedToWindow()) return;
+        if (!mView.isAttachedToWindow()) return;
 
         final boolean rotateSuggestionsDisabled = RotationButtonController
                 .hasDisable2RotateSuggestionFlag(mDisabledFlags2);
         final RotationButtonController rotationButtonController =
-                mNavigationBarView.getRotationButtonController();
+                mView.getRotationButtonController();
         final RotationButton rotationButton = rotationButtonController.getRotationButton();
 
         if (RotationContextButton.DEBUG_ROTATION) {
@@ -947,20 +958,20 @@
         if (running) {
             mNavbarOverlayController.setButtonState(/* visible */false, /* force */true);
         }
-        mNavigationBarView.getRotationButtonController().setRecentsAnimationRunning(running);
+        mView.getRotationButtonController().setRecentsAnimationRunning(running);
     }
 
     /** Restores the appearance and the transient saved state to {@link NavigationBar}. */
     public void restoreAppearanceAndTransientState() {
-        final int barMode = barMode(mTransientShown, mAppearance);
-        mNavigationBarMode = barMode;
+        final int transitionMode = transitionMode(mTransientShown, mAppearance);
+        mTransitionMode = transitionMode;
         checkNavBarModes();
         if (mAutoHideController != null) {
             mAutoHideController.touchAutoHide();
         }
         if (mLightBarController != null) {
             mLightBarController.onNavigationBarAppearanceChanged(mAppearance,
-                    true /* nbModeChanged */, barMode, false /* navbarColorManagedByIme */);
+                    true /* nbModeChanged */, transitionMode, false /* navbarColorManagedByIme */);
         }
     }
 
@@ -974,15 +985,15 @@
         boolean nbModeChanged = false;
         if (mAppearance != appearance) {
             mAppearance = appearance;
-            nbModeChanged = updateBarMode(barMode(mTransientShown, appearance));
+            nbModeChanged = updateTransitionMode(transitionMode(mTransientShown, appearance));
         }
         if (mLightBarController != null) {
             mLightBarController.onNavigationBarAppearanceChanged(appearance, nbModeChanged,
-                    mNavigationBarMode, navbarColorManagedByIme);
+                    mTransitionMode, navbarColorManagedByIme);
         }
         if (mBehavior != behavior) {
             mBehavior = behavior;
-            mNavigationBarView.setBehavior(behavior);
+            mView.setBehavior(behavior);
             updateSystemUiStateFlags();
         }
     }
@@ -1023,18 +1034,18 @@
     }
 
     private void handleTransientChanged() {
-        mNavigationBarView.onTransientStateChanged(mTransientShown,
+        mView.onTransientStateChanged(mTransientShown,
                 mTransientShownFromGestureOnSystemBar);
-        final int barMode = barMode(mTransientShown, mAppearance);
-        if (updateBarMode(barMode) && mLightBarController != null) {
-            mLightBarController.onNavigationBarModeChanged(barMode);
+        final int transitionMode = transitionMode(mTransientShown, mAppearance);
+        if (updateTransitionMode(transitionMode) && mLightBarController != null) {
+            mLightBarController.onNavigationBarModeChanged(transitionMode);
         }
     }
 
     // Returns true if the bar mode is changed.
-    private boolean updateBarMode(int barMode) {
-        if (mNavigationBarMode != barMode) {
-            mNavigationBarMode = barMode;
+    private boolean updateTransitionMode(int barMode) {
+        if (mTransitionMode != barMode) {
+            mTransitionMode = barMode;
             checkNavBarModes();
             if (mAutoHideController != null) {
                 mAutoHideController.touchAutoHide();
@@ -1044,7 +1055,7 @@
         return false;
     }
 
-    private static @TransitionMode int barMode(boolean isTransient, int appearance) {
+    private static @TransitionMode int transitionMode(boolean isTransient, int appearance) {
         final int lightsOutOpaque = APPEARANCE_LOW_PROFILE_BARS | APPEARANCE_OPAQUE_NAVIGATION_BARS;
         if (isTransient) {
             return MODE_SEMI_TRANSPARENT;
@@ -1073,7 +1084,7 @@
                 | StatusBarManager.DISABLE_SEARCH);
         if (masked != mDisabledFlags1) {
             mDisabledFlags1 = masked;
-            mNavigationBarView.setDisabledFlags(state1);
+            mView.setDisabledFlags(state1, mSysUiFlagsContainer);
             updateScreenPinningGestures();
         }
 
@@ -1089,13 +1100,13 @@
 
     private void setDisabled2Flags(int state2) {
         // Method only called on change of disable2 flags
-        mNavigationBarView.getRotationButtonController().onDisable2FlagChanged(state2);
+        mView.getRotationButtonController().onDisable2FlagChanged(state2);
     }
 
     // ----- Internal stuff -----
 
     private void refreshLayout(int layoutDirection) {
-        mNavigationBarView.setLayoutDirection(layoutDirection);
+        mView.setLayoutDirection(layoutDirection);
     }
 
     private boolean shouldDisableNavbarGestures() {
@@ -1104,7 +1115,7 @@
     }
 
     private void repositionNavigationBar(int rotation) {
-        if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return;
+        if (mView == null || !mView.isAttachedToWindow()) return;
 
         prepareNavigationBarView();
 
@@ -1114,10 +1125,10 @@
     private void updateScreenPinningGestures() {
         // Change the cancel pin gesture to home and back if recents button is invisible
         boolean pinningActive = ActivityManagerWrapper.getInstance().isScreenPinningActive();
-        ButtonDispatcher backButton = mNavigationBarView.getBackButton();
-        ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton();
+        ButtonDispatcher backButton = mView.getBackButton();
+        ButtonDispatcher recentsButton = mView.getRecentsButton();
         if (pinningActive) {
-            boolean recentsVisible = mNavigationBarView.isRecentsButtonVisible();
+            boolean recentsVisible = mView.isRecentsButtonVisible();
             backButton.setOnLongClickListener(recentsVisible
                     ? this::onLongPressBackRecents
                     : this::onLongPressBackHome);
@@ -1132,27 +1143,27 @@
     }
 
     private void notifyNavigationBarScreenOn() {
-        mNavigationBarView.updateNavButtonIcons();
+        mView.updateNavButtonIcons();
     }
 
     private void prepareNavigationBarView() {
-        mNavigationBarView.reorient();
+        mView.reorient();
 
-        ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton();
+        ButtonDispatcher recentsButton = mView.getRecentsButton();
         recentsButton.setOnClickListener(this::onRecentsClick);
         recentsButton.setOnTouchListener(this::onRecentsTouch);
 
-        ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
+        ButtonDispatcher homeButton = mView.getHomeButton();
         homeButton.setOnTouchListener(this::onHomeTouch);
 
         reconfigureHomeLongClick();
 
-        ButtonDispatcher accessibilityButton = mNavigationBarView.getAccessibilityButton();
+        ButtonDispatcher accessibilityButton = mView.getAccessibilityButton();
         accessibilityButton.setOnClickListener(this::onAccessibilityClick);
         accessibilityButton.setOnLongClickListener(this::onAccessibilityLongClick);
         updateAccessibilityStateFlags();
 
-        ButtonDispatcher imeSwitcherButton = mNavigationBarView.getImeSwitchButton();
+        ButtonDispatcher imeSwitcherButton = mView.getImeSwitchButton();
         imeSwitcherButton.setOnClickListener(this::onImeSwitcherClick);
 
         updateScreenPinningGestures();
@@ -1209,7 +1220,7 @@
 
     @VisibleForTesting
     boolean onHomeLongClick(View v) {
-        if (!mNavigationBarView.isRecentsButtonVisible()
+        if (!mView.isRecentsButtonVisible()
                 && ActivityManagerWrapper.getInstance().isScreenPinningActive()) {
             return onLongPressBackHome(v);
         }
@@ -1224,7 +1235,7 @@
                 AssistManager.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS);
         mAssistManagerLazy.get().startAssist(args);
         mCentralSurfacesOptionalLazy.get().ifPresent(CentralSurfaces::awakenDreams);
-        mNavigationBarView.abortCurrentGesture();
+        mView.abortCurrentGesture();
         return true;
     }
 
@@ -1299,8 +1310,7 @@
                         return true;
                     } else if (v.getId() == btnId1) {
                         ButtonDispatcher button = btnId2 == R.id.recent_apps
-                                ? mNavigationBarView.getRecentsButton()
-                                : mNavigationBarView.getHomeButton();
+                                ? mView.getRecentsButton() : mView.getHomeButton();
                         if (!button.getCurrentView().isPressed()) {
                             // If we aren't pressing recents/home right now then they presses
                             // won't be together, so send the standard long-press action.
@@ -1320,15 +1330,14 @@
                     } else if (v.getId() == btnId2) {
                         return btnId2 == R.id.recent_apps
                                 ? false
-                                : onHomeLongClick(
-                                        mNavigationBarView.getHomeButton().getCurrentView());
+                                : onHomeLongClick(mView.getHomeButton().getCurrentView());
                     }
                 }
             } finally {
                 if (stopLockTaskMode) {
                     activityManager.stopSystemLockTaskMode();
                     // When exiting refresh disabled flags.
-                    mNavigationBarView.updateNavButtonIcons();
+                    mView.updateNavButtonIcons();
                 }
             }
 
@@ -1360,11 +1369,11 @@
     }
 
     void updateAccessibilityStateFlags() {
-        if (mNavigationBarView != null) {
+        if (mView != null) {
             int a11yFlags = mNavBarHelper.getA11yButtonState();
             boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
             boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
-            mNavigationBarView.setAccessibilityButtonState(clickable, longClickable);
+            mView.setAccessibilityButtonState(clickable, longClickable);
         }
         updateSystemUiStateFlags();
     }
@@ -1413,7 +1422,7 @@
         mLightBarController = lightBarController;
         if (mLightBarController != null) {
             mLightBarController.setNavigationBar(
-                    mNavigationBarView.getLightTransitionsController());
+                    mView.getLightTransitionsController());
         }
     }
 
@@ -1423,7 +1432,7 @@
         if (mAutoHideController != null) {
             mAutoHideController.setNavigationBar(mAutoHideUiElement);
         }
-        mNavigationBarView.setAutoHideController(autoHideController);
+        mView.setAutoHideController(autoHideController);
     }
 
     private boolean isTransientShown() {
@@ -1455,28 +1464,11 @@
                 mCentralSurfacesOptionalLazy.get().map(CentralSurfaces::isDeviceInteractive)
                         .orElse(false)
                 && mNavigationBarWindowState != WINDOW_STATE_HIDDEN;
-        mNavigationBarView.getBarTransitions().transitionTo(mNavigationBarMode, anim);
-    }
-
-    @Override
-    public void onNavigationModeChanged(int mode) {
-        mNavBarMode = mode;
-
-        if (!QuickStepContract.isGesturalMode(mode)) {
-            // Reset the override alpha
-            if (getBarTransitions() != null) {
-                getBarTransitions().setBackgroundOverrideAlpha(1f);
-            }
-        }
-        updateScreenPinningGestures();
-
-        if (!canShowSecondaryHandle()) {
-            resetSecondaryHandle();
-        }
+        mView.getBarTransitions().transitionTo(mTransitionMode, anim);
     }
 
     public void disableAnimationsDuringHide(long delay) {
-        mNavigationBarView.setLayoutTransitionsEnabled(false);
+        mView.setLayoutTransitionsEnabled(false);
         mHandler.postDelayed(mEnableLayoutTransitions,
                 delay + StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
     }
@@ -1492,11 +1484,11 @@
     }
 
     public NavigationBarTransitions getBarTransitions() {
-        return mNavigationBarView.getBarTransitions();
+        return mView.getBarTransitions();
     }
 
     public void finishBarAnimations() {
-        mNavigationBarView.getBarTransitions().finishAnimations();
+        mView.getBarTransitions().finishAnimations();
     }
 
     private WindowManager.LayoutParams getBarLayoutParams(int rotation) {
@@ -1581,8 +1573,7 @@
     }
 
     private final Consumer<Integer> mRotationWatcher = rotation -> {
-        if (mNavigationBarView != null
-                && mNavigationBarView.needsReorient(rotation)) {
+        if (mView != null && mView.needsReorient(rotation)) {
             repositionNavigationBar(rotation);
         }
     };
@@ -1592,14 +1583,14 @@
         public void onReceive(Context context, Intent intent) {
             // TODO(193941146): Currently unregistering a receiver through BroadcastDispatcher is
             // async, but we've already cleared the fields. Just return early in this case.
-            if (mNavigationBarView == null) {
+            if (mView == null) {
                 return;
             }
             String action = intent.getAction();
             if (Intent.ACTION_SCREEN_OFF.equals(action)
                     || Intent.ACTION_SCREEN_ON.equals(action)) {
                 notifyNavigationBarScreenOn();
-                mNavigationBarView.onScreenStateChanged(Intent.ACTION_SCREEN_ON.equals(action));
+                mView.onScreenStateChanged(Intent.ACTION_SCREEN_ON.equals(action));
             }
             if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                 // The accessibility settings may be different for the new user
@@ -1613,114 +1604,92 @@
         return mNavigationIconHints;
     }
 
-    /**
-     * Injectable factory for construction a {@link NavigationBar}.
-     */
-    public static class Factory {
-        private final Lazy<AssistManager> mAssistManagerLazy;
-        private final AccessibilityManager mAccessibilityManager;
-        private final DeviceProvisionedController mDeviceProvisionedController;
-        private final MetricsLogger mMetricsLogger;
-        private final OverviewProxyService mOverviewProxyService;
-        private final NavigationModeController mNavigationModeController;
-        private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
-        private final StatusBarStateController mStatusBarStateController;
-        private final SysUiState mSysUiFlagsContainer;
-        private final BroadcastDispatcher mBroadcastDispatcher;
-        private final CommandQueue mCommandQueue;
-        private final Optional<Pip> mPipOptional;
-        private final Optional<Recents> mRecentsOptional;
-        private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
-        private final ShadeController mShadeController;
-        private final NotificationRemoteInputManager mNotificationRemoteInputManager;
-        private final NotificationShadeDepthController mNotificationShadeDepthController;
-        private final Handler mMainHandler;
-        private final NavigationBarOverlayController mNavbarOverlayController;
-        private final UiEventLogger mUiEventLogger;
-        private final NavBarHelper mNavBarHelper;
-        private final LightBarController mMainLightBarController;
-        private final LightBarController.Factory mLightBarControllerFactory;
-        private final AutoHideController mMainAutoHideController;
-        private final AutoHideController.Factory mAutoHideControllerFactory;
-        private final Optional<TelecomManager> mTelecomManagerOptional;
-        private final InputMethodManager mInputMethodManager;
-        private final Optional<BackAnimation> mBackAnimation;
+    private void setNavigationIconHints(int hints) {
+        if (hints == mNavigationIconHints) return;
+        if (!isTablet(mContext)) {
+            // All IME functions handled by launcher via Sysui flags for large screen
+            final boolean newBackAlt = (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
+            final boolean oldBackAlt =
+                    (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
+            if (newBackAlt != oldBackAlt) {
+                mView.onImeVisibilityChanged(newBackAlt);
+                mImeVisible = newBackAlt;
+            }
 
-        @Inject
-        public Factory(
-                Lazy<AssistManager> assistManagerLazy,
-                AccessibilityManager accessibilityManager,
-                DeviceProvisionedController deviceProvisionedController,
-                MetricsLogger metricsLogger,
-                OverviewProxyService overviewProxyService,
-                NavigationModeController navigationModeController,
-                AccessibilityButtonModeObserver accessibilityButtonModeObserver,
-                StatusBarStateController statusBarStateController,
-                SysUiState sysUiFlagsContainer,
-                BroadcastDispatcher broadcastDispatcher,
-                CommandQueue commandQueue,
-                Optional<Pip> pipOptional,
-                Optional<Recents> recentsOptional,
-                Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
-                ShadeController shadeController,
-                NotificationRemoteInputManager notificationRemoteInputManager,
-                NotificationShadeDepthController notificationShadeDepthController,
-                @Main Handler mainHandler,
-                NavigationBarOverlayController navbarOverlayController,
-                UiEventLogger uiEventLogger,
-                NavBarHelper navBarHelper,
-                LightBarController mainLightBarController,
-                LightBarController.Factory lightBarControllerFactory,
-                AutoHideController mainAutoHideController,
-                AutoHideController.Factory autoHideControllerFactory,
-                Optional<TelecomManager> telecomManagerOptional,
-                InputMethodManager inputMethodManager,
-                Optional<BackAnimation> backAnimation) {
-            mAssistManagerLazy = assistManagerLazy;
-            mAccessibilityManager = accessibilityManager;
-            mDeviceProvisionedController = deviceProvisionedController;
-            mMetricsLogger = metricsLogger;
-            mOverviewProxyService = overviewProxyService;
-            mNavigationModeController = navigationModeController;
-            mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
-            mStatusBarStateController = statusBarStateController;
-            mSysUiFlagsContainer = sysUiFlagsContainer;
-            mBroadcastDispatcher = broadcastDispatcher;
-            mCommandQueue = commandQueue;
-            mPipOptional = pipOptional;
-            mRecentsOptional = recentsOptional;
-            mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
-            mShadeController = shadeController;
-            mNotificationRemoteInputManager = notificationRemoteInputManager;
-            mNotificationShadeDepthController = notificationShadeDepthController;
-            mMainHandler = mainHandler;
-            mNavbarOverlayController = navbarOverlayController;
-            mUiEventLogger = uiEventLogger;
-            mNavBarHelper = navBarHelper;
-            mMainLightBarController = mainLightBarController;
-            mLightBarControllerFactory = lightBarControllerFactory;
-            mMainAutoHideController = mainAutoHideController;
-            mAutoHideControllerFactory = autoHideControllerFactory;
-            mTelecomManagerOptional = telecomManagerOptional;
-            mInputMethodManager = inputMethodManager;
-            mBackAnimation = backAnimation;
+            mView.setNavigationIconHints(hints);
         }
-
-        /** Construct a {@link NavigationBar} */
-        public NavigationBar create(Context context) {
-            final WindowManager wm = context.getSystemService(WindowManager.class);
-            return new NavigationBar(context, wm, mAssistManagerLazy,
-                    mAccessibilityManager, mDeviceProvisionedController, mMetricsLogger,
-                    mOverviewProxyService, mNavigationModeController,
-                    mAccessibilityButtonModeObserver, mStatusBarStateController,
-                    mSysUiFlagsContainer, mBroadcastDispatcher, mCommandQueue, mPipOptional,
-                    mRecentsOptional, mCentralSurfacesOptionalLazy,
-                    mShadeController, mNotificationRemoteInputManager,
-                    mNotificationShadeDepthController, mMainHandler,
-                    mNavbarOverlayController, mUiEventLogger, mNavBarHelper,
-                    mMainLightBarController, mLightBarControllerFactory,
-                    mMainAutoHideController, mAutoHideControllerFactory, mTelecomManagerOptional,
-                    mInputMethodManager, mBackAnimation);
+        if (DEBUG) {
+            android.widget.Toast.makeText(mContext,
+                    "Navigation icon hints = " + hints,
+                    500).show();
         }
+        mNavigationIconHints = hints;
     }
+
+    private final ModeChangedListener mModeChangedListener = new ModeChangedListener() {
+        @Override
+        public void onNavigationModeChanged(int mode) {
+            mNavBarMode = mode;
+
+            if (!QuickStepContract.isGesturalMode(mode)) {
+                // Reset the override alpha
+                if (getBarTransitions() != null) {
+                    getBarTransitions().setBackgroundOverrideAlpha(1f);
+                }
+            }
+            updateScreenPinningGestures();
+
+            if (!canShowSecondaryHandle()) {
+                resetSecondaryHandle();
+            }
+            if (mView != null) {
+                mView.setNavBarMode(mode);
+            }
+        }
+    };
+
+    private final Gefingerpoken mTouchHandler = new Gefingerpoken() {
+        private boolean mDeadZoneConsuming;
+
+        @Override
+        public boolean onInterceptTouchEvent(MotionEvent ev) {
+            if (isGesturalMode(mNavBarMode) && mImeVisible
+                    && ev.getAction() == MotionEvent.ACTION_DOWN) {
+                SysUiStatsLog.write(SysUiStatsLog.IME_TOUCH_REPORTED,
+                        (int) ev.getX(), (int) ev.getY());
+            }
+            return shouldDeadZoneConsumeTouchEvents(ev);
+        }
+
+        @Override
+        public boolean onTouchEvent(MotionEvent ev) {
+            shouldDeadZoneConsumeTouchEvents(ev);
+            return false;
+        }
+
+        private boolean shouldDeadZoneConsumeTouchEvents(MotionEvent event) {
+            int action = event.getActionMasked();
+            if (action == MotionEvent.ACTION_DOWN) {
+                mDeadZoneConsuming = false;
+            }
+            if (mDeadZone.onTouchEvent(event) || mDeadZoneConsuming) {
+                switch (action) {
+                    case MotionEvent.ACTION_DOWN:
+                        // Allow gestures starting in the deadzone to be slippery
+                        mView.setSlippery(true);
+                        mDeadZoneConsuming = true;
+                        break;
+                    case MotionEvent.ACTION_CANCEL:
+                    case MotionEvent.ACTION_UP:
+                        // When a gesture started in the deadzone is finished, restore
+                        // slippery state
+                        mView.updateSlippery();
+                        mDeadZoneConsuming = false;
+                        break;
+                }
+                return true;
+            }
+            return false;
+        }
+    };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarComponent.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarComponent.java
new file mode 100644
index 0000000..1d792af
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarComponent.java
@@ -0,0 +1,63 @@
+/*
+ * 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.systemui.navigationbar;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import androidx.annotation.Nullable;
+
+import com.android.systemui.dagger.qualifiers.DisplayId;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Scope;
+
+import dagger.BindsInstance;
+import dagger.Subcomponent;
+
+/**
+ * Subcomponent for a NavigationBar.
+ *
+ * Generally creatd on a per-display basis.
+ */
+@Subcomponent(modules = { NavigationBarModule.class })
+@NavigationBarComponent.NavigationBarScope
+public interface NavigationBarComponent {
+
+    /** Factory for {@link NavigationBarComponent}. */
+    @Subcomponent.Factory
+    interface Factory {
+        NavigationBarComponent create(
+                @BindsInstance @DisplayId Context context,
+                @BindsInstance @Nullable Bundle savedState);
+    }
+
+    /** */
+    NavigationBar getNavigationBar();
+
+    /**
+     * Scope annotation for singleton items within the NavigationBarComponent.
+     */
+    @Documented
+    @Retention(RUNTIME)
+    @Scope
+    @interface NavigationBarScope {}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index a049736..ade86ae 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -83,7 +83,7 @@
 
     private final Context mContext;
     private final Handler mHandler;
-    private final NavigationBar.Factory mNavigationBarFactory;
+    private final NavigationBarComponent.Factory mNavigationBarComponentFactory;
     private final DisplayManager mDisplayManager;
     private final TaskbarDelegate mTaskbarDelegate;
     private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@@ -109,7 +109,7 @@
             ConfigurationController configurationController,
             NavBarHelper navBarHelper,
             TaskbarDelegate taskbarDelegate,
-            NavigationBar.Factory navigationBarFactory,
+            NavigationBarComponent.Factory navigationBarComponentFactory,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
             DumpManager dumpManager,
             AutoHideController autoHideController,
@@ -118,7 +118,7 @@
             Optional<BackAnimation> backAnimation) {
         mContext = context;
         mHandler = mainHandler;
-        mNavigationBarFactory = navigationBarFactory;
+        mNavigationBarComponentFactory = navigationBarComponentFactory;
         mDisplayManager = mContext.getSystemService(DisplayManager.class);
         commandQueue.addCallback(this);
         configurationController.addCallback(this);
@@ -323,13 +323,13 @@
         final Context context = isOnDefaultDisplay
                 ? mContext
                 : mContext.createDisplayContext(display);
-        NavigationBar navBar = mNavigationBarFactory.create(context);
-
+        NavigationBarComponent component = mNavigationBarComponentFactory.create(
+                context, savedState);
+        NavigationBar navBar = component.getNavigationBar();
+        navBar.init();
         mNavigationBars.put(displayId, navBar);
 
-        boolean navBarVisible = mStatusBarKeyguardViewManager.isNavBarVisible();
-        View navigationBarView = navBar.createView(savedState, navBarVisible);
-        navigationBarView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+        navBar.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
             @Override
             public void onViewAttachedToWindow(View v) {
                 if (result != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarModule.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarModule.java
new file mode 100644
index 0000000..93bf136
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarModule.java
@@ -0,0 +1,65 @@
+/*
+ * 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.systemui.navigationbar;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+
+import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.DisplayId;
+import com.android.systemui.navigationbar.NavigationBarComponent.NavigationBarScope;
+
+import dagger.Module;
+import dagger.Provides;
+
+/** Module for {@link com.android.systemui.navigationbar.NavigationBarComponent}. */
+@Module
+public interface NavigationBarModule {
+    /** A Layout inflater specific to the display's context. */
+    @Provides
+    @NavigationBarScope
+    @DisplayId
+    static LayoutInflater provideLayoutInflater(@DisplayId Context context) {
+        return LayoutInflater.from(context);
+    }
+
+    /** */
+    @Provides
+    @NavigationBarScope
+    static NavigationBarFrame provideNavigationBarFrame(@DisplayId LayoutInflater layoutInflater) {
+        return (NavigationBarFrame) layoutInflater.inflate(R.layout.navigation_bar_window, null);
+    }
+
+    /** */
+    @Provides
+    @NavigationBarScope
+    static NavigationBarView provideNavigationBarview(
+            @DisplayId LayoutInflater layoutInflater, NavigationBarFrame frame) {
+        View barView = layoutInflater.inflate(R.layout.navigation_bar, frame);
+        return barView.findViewById(R.id.navigation_bar_view);
+    }
+
+    /** A WindowManager specific to the display's context. */
+    @Provides
+    @NavigationBarScope
+    @DisplayId
+    static WindowManager provideWindowManager(@DisplayId Context context) {
+        return context.getSystemService(WindowManager.class);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 017bbdf..f5abe28 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -65,6 +65,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settingslib.Utils;
 import com.android.systemui.Dependency;
+import com.android.systemui.Gefingerpoken;
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.model.SysUiState;
@@ -84,13 +85,12 @@
 import com.android.systemui.shared.rotation.RotationButtonController;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.shared.system.SysUiStatsLog;
 import com.android.systemui.shared.system.WindowManagerWrapper;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.AutoHideController;
+import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.LightBarTransitionsController;
 import com.android.systemui.statusbar.phone.NotificationPanelViewController;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.wm.shell.back.BackAnimation;
 import com.android.wm.shell.pip.Pip;
 
@@ -101,15 +101,14 @@
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 
-public class NavigationBarView extends FrameLayout implements
-        NavigationModeController.ModeChangedListener {
+/** */
+public class NavigationBarView extends FrameLayout {
     final static boolean DEBUG = false;
     final static String TAG = "NavBarView";
 
     final static boolean ALTERNATE_CAR_MODE_UI = false;
     private final RegionSamplingHelper mRegionSamplingHelper;
     private final int mNavColorSampleMargin;
-    private final SysUiState mSysUiFlagContainer;
 
     // The current view is one of mHorizontal or mVertical depending on the current configuration
     View mCurrentView = null;
@@ -197,6 +196,7 @@
      * <p>Cache the value here for better performance.</p>
      */
     private final boolean mImeCanRenderGesturalNavButtons = canImeRenderGesturalNavButtons();
+    private Gefingerpoken mTouchHandler;
 
     private class NavTransitionListener implements TransitionListener {
         private boolean mBackTransitioning;
@@ -333,10 +333,8 @@
         mDarkIconColor = Utils.getColorAttrDefaultColor(darkContext, R.attr.singleToneColor);
         mIsVertical = false;
         mLongClickableAccessibilityButton = false;
-        mNavBarMode = Dependency.get(NavigationModeController.class).addListener(this);
         mImeDrawsImeNavBar = Dependency.get(NavigationModeController.class).getImeDrawsImeNavBar();
 
-        mSysUiFlagContainer = Dependency.get(SysUiState.class);
         // Set up the context group of buttons
         mContextualButtonGroup = new ContextualButtonGroup(R.id.menu_container);
         final ContextualButton imeSwitcherButton = new ContextualButton(R.id.ime_switcher,
@@ -365,8 +363,6 @@
                 R.drawable.ic_sysbar_rotate_button_cw_start_90,
                 () -> getDisplay().getRotation());
 
-        updateRotationButton();
-
         mOverviewProxyService = Dependency.get(OverviewProxyService.class);
 
         mConfiguration = new Configuration();
@@ -448,19 +444,18 @@
         notifyVerticalChangedListener(mIsVertical);
     }
 
+    public void setTouchHandler(Gefingerpoken touchHandler) {
+        mTouchHandler = touchHandler;
+    }
+
     @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
-        if (isGesturalMode(mNavBarMode) && mImeVisible
-                && event.getAction() == MotionEvent.ACTION_DOWN) {
-            SysUiStatsLog.write(SysUiStatsLog.IME_TOUCH_REPORTED,
-                    (int) event.getX(), (int) event.getY());
-        }
-        return shouldDeadZoneConsumeTouchEvents(event) || super.onInterceptTouchEvent(event);
+        return mTouchHandler.onInterceptTouchEvent(event) || super.onInterceptTouchEvent(event);
     }
 
     @Override
     public boolean onTouchEvent(MotionEvent event) {
-        shouldDeadZoneConsumeTouchEvents(event);
+        mTouchHandler.onTouchEvent(event);
         return super.onTouchEvent(event);
     }
 
@@ -497,30 +492,6 @@
         }
     }
 
-    private boolean shouldDeadZoneConsumeTouchEvents(MotionEvent event) {
-        int action = event.getActionMasked();
-        if (action == MotionEvent.ACTION_DOWN) {
-            mDeadZoneConsuming = false;
-        }
-        if (mDeadZone.onTouchEvent(event) || mDeadZoneConsuming) {
-            switch (action) {
-                case MotionEvent.ACTION_DOWN:
-                    // Allow gestures starting in the deadzone to be slippery
-                    setSlippery(true);
-                    mDeadZoneConsuming = true;
-                    break;
-                case MotionEvent.ACTION_CANCEL:
-                case MotionEvent.ACTION_UP:
-                    // When a gesture started in the deadzone is finished, restore slippery state
-                    updateSlippery();
-                    mDeadZoneConsuming = false;
-                    break;
-            }
-            return true;
-        }
-        return false;
-    }
-
     public void abortCurrentGesture() {
         getHomeButton().abortCurrentGesture();
     }
@@ -589,7 +560,7 @@
         return (mDisabledFlags & View.STATUS_BAR_DISABLE_RECENT) == 0;
     }
 
-    public boolean isQuickStepSwipeUpEnabled() {
+    private boolean isQuickStepSwipeUpEnabled() {
         return mOverviewProxyService.shouldShowSwipeUpUI() && isOverviewEnabled();
     }
 
@@ -618,7 +589,7 @@
     /**
      * Updates the rotation button based on the current navigation mode.
      */
-    private void updateRotationButton() {
+    void updateRotationButton() {
         if (isGesturalMode(mNavBarMode)) {
             mContextualButtonGroup.removeButton(R.id.rotate_suggestion);
             mButtonDispatchers.remove(R.id.rotate_suggestion);
@@ -722,25 +693,13 @@
         super.setLayoutDirection(layoutDirection);
     }
 
-    public void setNavigationIconHints(int hints) {
+    void setNavigationIconHints(int hints) {
         if (hints == mNavigationIconHints) return;
-        final boolean newBackAlt = (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
-        final boolean oldBackAlt =
-                (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
-        if (newBackAlt != oldBackAlt) {
-            onImeVisibilityChanged(newBackAlt);
-        }
-
-        if (DEBUG) {
-            android.widget.Toast.makeText(getContext(),
-                "Navigation icon hints = " + hints,
-                500).show();
-        }
         mNavigationIconHints = hints;
         updateNavButtonIcons();
     }
 
-    private void onImeVisibilityChanged(boolean visible) {
+    void onImeVisibilityChanged(boolean visible) {
         if (!visible) {
             mTransitionListener.onBackAltCleared();
         }
@@ -751,7 +710,7 @@
         }
     }
 
-    public void setDisabledFlags(int disabledFlags) {
+    void setDisabledFlags(int disabledFlags, SysUiState sysUiState) {
         if (mDisabledFlags == disabledFlags) return;
 
         final boolean overviewEnabledBefore = isOverviewEnabled();
@@ -764,7 +723,7 @@
 
         updateNavButtonIcons();
         updateSlippery();
-        updateDisabledSystemUiStateFlags();
+        updateDisabledSystemUiStateFlags(sysUiState);
     }
 
     public void updateNavButtonIcons() {
@@ -907,10 +866,11 @@
         updateSlippery();
     }
 
-    public void updateDisabledSystemUiStateFlags() {
+    /** */
+    public void updateDisabledSystemUiStateFlags(SysUiState sysUiState) {
         int displayId = mContext.getDisplayId();
 
-        mSysUiFlagContainer.setFlag(SYSUI_STATE_SCREEN_PINNING,
+        sysUiState.setFlag(SYSUI_STATE_SCREEN_PINNING,
                         ActivityManagerWrapper.getInstance().isScreenPinningActive())
                 .setFlag(SYSUI_STATE_OVERVIEW_DISABLED,
                         (mDisabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0)
@@ -952,12 +912,12 @@
      * slippery is enabled, touch events will leave the nav bar window and enter into the fullscreen
      * app/home window, if not nav bar will receive a cancelled touch event once gesture leaves bar.
      */
-    public void updateSlippery() {
+    void updateSlippery() {
         setSlippery(!isQuickStepSwipeUpEnabled() ||
                 (mPanelView != null && mPanelView.isFullyExpanded() && !mPanelView.isCollapsing()));
     }
 
-    private void setSlippery(boolean slippery) {
+    void setSlippery(boolean slippery) {
         setWindowFlag(WindowManager.LayoutParams.FLAG_SLIPPERY, slippery);
     }
 
@@ -979,8 +939,7 @@
         wm.updateViewLayout(navbarView, lp);
     }
 
-    @Override
-    public void onNavigationModeChanged(int mode) {
+    void setNavBarMode(int mode) {
         mNavBarMode = mode;
         mImeDrawsImeNavBar = Dependency.get(NavigationModeController.class).getImeDrawsImeNavBar();
         mBarTransitions.onNavigationModeChanged(mNavBarMode);
@@ -1323,7 +1282,6 @@
         mEdgeBackGestureHandler.onNavBarAttached();
         requestApplyInsets();
         reorient();
-        onNavigationModeChanged(mNavBarMode);
         if (mRotationButtonController != null) {
             mRotationButtonController.registerListeners();
         }
@@ -1338,7 +1296,6 @@
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        Dependency.get(NavigationModeController.class).removeListener(this);
         for (int i = 0; i < mButtonDispatchers.size(); ++i) {
             mButtonDispatchers.valueAt(i).onDestroy();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/DeadZone.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/DeadZone.java
index 7fb58f0..9305d05 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/DeadZone.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/DeadZone.java
@@ -30,6 +30,8 @@
 import com.android.systemui.navigationbar.NavigationBarController;
 import com.android.systemui.navigationbar.NavigationBarView;
 
+import javax.inject.Inject;
+
 /**
  * The "dead zone" consumes unintentional taps along the top edge of the navigation bar.
  * When users are typing quickly on an IME they may attempt to hit the space bar, overshoot, and
@@ -82,6 +84,7 @@
         }
     };
 
+    @Inject
     public DeadZone(NavigationBarView view) {
         mNavigationBarView = view;
         mNavBarController = Dependency.get(NavigationBarController.class);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 4dacf5d..001a462 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -57,6 +57,7 @@
 
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.internal.policy.GestureNavigationSettingsObserver;
+import com.android.internal.util.LatencyTracker;
 import com.android.systemui.R;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -198,6 +199,7 @@
     private final Rect mNavBarOverlayExcludedBounds = new Rect();
     private final Region mExcludeRegion = new Region();
     private final Region mUnrestrictedExcludeRegion = new Region();
+    private final LatencyTracker mLatencyTracker;
 
     // The left side edge width where touch down is allowed
     private int mEdgeWidthLeft;
@@ -302,7 +304,7 @@
             BroadcastDispatcher broadcastDispatcher, ProtoTracer protoTracer,
             NavigationModeController navigationModeController, ViewConfiguration viewConfiguration,
             WindowManager windowManager, IWindowManager windowManagerService,
-            FalsingManager falsingManager) {
+            FalsingManager falsingManager, LatencyTracker latencyTracker) {
         super(broadcastDispatcher);
         mContext = context;
         mDisplayId = context.getDisplayId();
@@ -316,6 +318,7 @@
         mWindowManager = windowManager;
         mWindowManagerService = windowManagerService;
         mFalsingManager = falsingManager;
+        mLatencyTracker = latencyTracker;
         ComponentName recentsComponentName = ComponentName.unflattenFromString(
                 context.getString(com.android.internal.R.string.config_recentsComponentName));
         if (recentsComponentName != null) {
@@ -505,7 +508,8 @@
                     Choreographer.getInstance(), this::onInputEvent);
 
             // Add a nav bar panel window
-            setEdgeBackPlugin(new NavigationBarEdgePanel(mContext, mBackAnimation));
+            setEdgeBackPlugin(
+                    new NavigationBarEdgePanel(mContext, mBackAnimation, mLatencyTracker));
             mPluginManager.addPluginListener(
                     this, NavigationEdgeBackPlugin.class, /*allowMultiple=*/ false);
         }
@@ -520,7 +524,7 @@
 
     @Override
     public void onPluginDisconnected(NavigationEdgeBackPlugin plugin) {
-        setEdgeBackPlugin(new NavigationBarEdgePanel(mContext, mBackAnimation));
+        setEdgeBackPlugin(new NavigationBarEdgePanel(mContext, mBackAnimation, mLatencyTracker));
     }
 
     private void setEdgeBackPlugin(NavigationEdgeBackPlugin edgeBackPlugin) {
@@ -968,6 +972,7 @@
         private final WindowManager mWindowManager;
         private final IWindowManager mWindowManagerService;
         private final FalsingManager mFalsingManager;
+        private final LatencyTracker mLatencyTracker;
 
         @Inject
         public Factory(OverviewProxyService overviewProxyService,
@@ -975,7 +980,8 @@
                 BroadcastDispatcher broadcastDispatcher, ProtoTracer protoTracer,
                 NavigationModeController navigationModeController,
                 ViewConfiguration viewConfiguration, WindowManager windowManager,
-                IWindowManager windowManagerService, FalsingManager falsingManager) {
+                IWindowManager windowManagerService, FalsingManager falsingManager,
+                LatencyTracker latencyTracker) {
             mOverviewProxyService = overviewProxyService;
             mSysUiState = sysUiState;
             mPluginManager = pluginManager;
@@ -987,6 +993,7 @@
             mWindowManager = windowManager;
             mWindowManagerService = windowManagerService;
             mFalsingManager = falsingManager;
+            mLatencyTracker = latencyTracker;
         }
 
         /** Construct a {@link EdgeBackGestureHandler}. */
@@ -994,7 +1001,7 @@
             return new EdgeBackGestureHandler(context, mOverviewProxyService, mSysUiState,
                     mPluginManager, mExecutor, mBroadcastDispatcher, mProtoTracer,
                     mNavigationModeController, mViewConfiguration, mWindowManager,
-                    mWindowManagerService, mFalsingManager);
+                    mWindowManagerService, mFalsingManager, mLatencyTracker);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
index a6919e8..a1258df 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
@@ -51,6 +51,7 @@
 import androidx.dynamicanimation.animation.SpringAnimation;
 import androidx.dynamicanimation.animation.SpringForce;
 
+import com.android.internal.util.LatencyTracker;
 import com.android.settingslib.Utils;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
@@ -176,6 +177,7 @@
     private final ValueAnimator mArrowDisappearAnimation;
     private final SpringForce mRegularTranslationSpring;
     private final SpringForce mTriggerBackSpring;
+    private final LatencyTracker mLatencyTracker;
 
     private VelocityTracker mVelocityTracker;
     private boolean mIsDark = false;
@@ -225,6 +227,7 @@
     private float mDisappearAmount;
     private long mVibrationTime;
     private int mScreenSize;
+    private boolean mTrackingBackArrowLatency = false;
 
     private final Handler mHandler = new Handler();
     private final Runnable mFailsafeRunnable = this::onFailsafe;
@@ -283,7 +286,7 @@
     private BackAnimation mBackAnimation;
 
     public NavigationBarEdgePanel(Context context,
-            BackAnimation backAnimation) {
+            BackAnimation backAnimation, LatencyTracker latencyTracker) {
         super(context);
 
         mWindowManager = context.getSystemService(WindowManager.class);
@@ -383,6 +386,7 @@
                 }, backgroundExecutor);
         mRegionSamplingHelper.setWindowVisible(true);
         mShowProtection = !isPrimaryDisplay;
+        mLatencyTracker = latencyTracker;
     }
 
     public void setBackAnimation(BackAnimation backAnimation) {
@@ -492,6 +496,8 @@
                 updatePosition(event.getY());
                 mRegionSamplingHelper.start(mSamplingRect);
                 mWindowManager.updateViewLayout(this, mLayoutParams);
+                mLatencyTracker.onActionStart(LatencyTracker.ACTION_SHOW_BACK_ARROW);
+                mTrackingBackArrowLatency = true;
                 break;
             case MotionEvent.ACTION_MOVE:
                 handleMoveEvent(event);
@@ -547,6 +553,10 @@
 
         canvas.drawPath(arrowPath, mPaint);
         canvas.restore();
+        if (mTrackingBackArrowLatency) {
+            mLatencyTracker.onActionEnd(LatencyTracker.ACTION_SHOW_BACK_ARROW);
+            mTrackingBackArrowLatency = false;
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 2ac34b2..369a552 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -271,6 +271,9 @@
             mPlaySound = false;
             return;
         }
+        if (!showLowBatteryNotification()) {
+            return;
+        }
 
         final int warningLevel = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_lowBatteryWarningLevel);
@@ -323,6 +326,29 @@
         return isSevereState && mUseSevereDialog;
     }
 
+    /**
+     * Disable low battery warning notification if battery saver schedule mode set as
+     * "Based on percentage".
+     *
+     * return {@code false} if scheduled by percentage.
+     */
+    private boolean showLowBatteryNotification() {
+        final ContentResolver resolver = mContext.getContentResolver();
+        final int mode = Settings.Global.getInt(resolver, Global.AUTOMATIC_POWER_SAVE_MODE,
+                PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE);
+
+        // Return true if battery saver schedule mode will not trigger by percentage.
+        if (mode != PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE) {
+            return true;
+        }
+
+        // Return true if battery saver mode trigger percentage is less than 0, which means it is
+        // set as "Based on routine" mode, otherwise it will be "Based on percentage" mode.
+        final int threshold =
+                Settings.Global.getInt(resolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
+        return threshold <= 0;
+    }
+
     private void showAutoSaverSuggestionNotification() {
         final CharSequence message = mContext.getString(R.string.auto_saver_text);
         final Notification.Builder nb =
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
index 9cd97ff8..2a6ca1a 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
@@ -22,13 +22,14 @@
 import android.widget.LinearLayout
 import com.android.settingslib.Utils
 import com.android.systemui.R
+import com.android.systemui.statusbar.events.BackgroundAnimatableView
 
 class OngoingPrivacyChip @JvmOverloads constructor(
     context: Context,
     attrs: AttributeSet? = null,
     defStyleAttrs: Int = 0,
     defStyleRes: Int = 0
-) : FrameLayout(context, attrs, defStyleAttrs, defStyleRes) {
+) : FrameLayout(context, attrs, defStyleAttrs, defStyleRes), BackgroundAnimatableView {
 
     private var iconMargin = 0
     private var iconSize = 0
@@ -50,6 +51,16 @@
         updateResources()
     }
 
+    /**
+     * When animating as a chip in the status bar, we want to animate the width for the container
+     * of the privacy items. We have to subtract our own top and left offset because the bounds
+     * come to us as absolute on-screen bounds, and `iconsContainer` is laid out relative to the
+     * frame layout's bounds.
+     */
+    override fun setBoundsForAnimation(l: Int, t: Int, r: Int, b: Int) {
+        iconsContainer.setLeftTopRightBottom(l - left, t - top, r - left, b - top)
+    }
+
     // Should only be called if the builder icons or app changed
     private fun updateView(builder: PrivacyChipBuilder) {
         fun setIcons(chipBuilder: PrivacyChipBuilder, iconsContainer: ViewGroup) {
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt
index 6107123..8147877 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt
@@ -150,24 +150,27 @@
         packageName: String,
         userId: Int,
         permGroupName: CharSequence,
-        attributionTag: CharSequence?
+        attributionTag: CharSequence?,
+        isAttributionSupported: Boolean
     ): Intent
     {
         lateinit var intent: Intent
-        if (attributionTag != null) {
+        if (attributionTag != null && isAttributionSupported) {
             intent = Intent(Intent.ACTION_MANAGE_PERMISSION_USAGE)
             intent.setPackage(packageName)
             intent.putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, permGroupName.toString())
             intent.putExtra(Intent.EXTRA_ATTRIBUTION_TAGS, arrayOf(attributionTag.toString()))
             intent.putExtra(Intent.EXTRA_SHOWING_ATTRIBUTION, true)
             val resolveInfo = packageManager.resolveActivity(
-                intent, PackageManager.ResolveInfoFlags.of(0))
-                ?: return getDefaultManageAppPermissionsIntent(packageName, userId)
-            intent.component = ComponentName(packageName, resolveInfo.activityInfo.name)
-            return intent
-        } else {
-            return getDefaultManageAppPermissionsIntent(packageName, userId)
+                    intent, PackageManager.ResolveInfoFlags.of(0))
+            if (resolveInfo != null && resolveInfo.activityInfo != null &&
+                    resolveInfo.activityInfo.permission ==
+                    android.Manifest.permission.START_VIEW_PERMISSION_USAGE) {
+                intent.component = ComponentName(packageName, resolveInfo.activityInfo.name)
+                return intent
+            }
         }
+        return getDefaultManageAppPermissionsIntent(packageName, userId)
     }
 
     fun getDefaultManageAppPermissionsIntent(packageName: String, userId: Int): Intent {
@@ -226,9 +229,15 @@
                                 userInfo?.isManagedProfile ?: false,
                                 it.isPhoneCall,
                                 it.permissionGroupName,
-                                getManagePermissionIntent(it.packageName, userId,
-                                    it.permissionGroupName,
-                                it.attributionTag)
+                                getManagePermissionIntent(
+                                        it.packageName,
+                                        userId,
+                                        it.permissionGroupName,
+                                        it.attributionTag,
+                                        // attributionLabel is set only when subattribution policies
+                                        // are supported and satisfied
+                                        it.attributionLabel != null
+                                )
                         )
                     }
                 } else {
diff --git a/packages/SystemUI/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerController.java b/packages/SystemUI/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerController.java
index e26c768..8000bdc 100644
--- a/packages/SystemUI/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerController.java
+++ b/packages/SystemUI/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerController.java
@@ -160,14 +160,15 @@
      * Returns true if lock screen entry point for QR Code Scanner is to be enabled.
      */
     public boolean isEnabledForLockScreenButton() {
-        return mQRCodeScannerEnabled && mIntent != null && mConfigEnableLockScreenButton;
+        return mQRCodeScannerEnabled && mIntent != null && mConfigEnableLockScreenButton
+                && isActivityCallable(mIntent);
     }
 
     /**
      * Returns true if quick settings entry point for QR Code Scanner is to be enabled.
      */
     public boolean isEnabledForQuickSettings() {
-        return mIntent != null;
+        return mIntent != null && isActivityCallable(mIntent);
     }
 
     /**
@@ -278,7 +279,7 @@
             intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
         }
 
-        if (isActivityCallable(intent)) {
+        if (isActivityAvailable(intent)) {
             mQRCodeScannerActivity = qrCodeScannerActivity;
             mComponentName = componentName;
             mIntent = intent;
@@ -293,7 +294,7 @@
         }
     }
 
-    private boolean isActivityCallable(Intent intent) {
+    private boolean isActivityAvailable(Intent intent) {
         // Our intent should always be explicit and should have a component set
         if (intent.getComponent() == null) return false;
 
@@ -307,6 +308,17 @@
                 flags).isEmpty();
     }
 
+    private boolean isActivityCallable(Intent intent) {
+        // Our intent should always be explicit and should have a component set
+        if (intent.getComponent() == null) return false;
+
+        int flags = PackageManager.MATCH_DIRECT_BOOT_AWARE
+                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
+        return !mContext.getPackageManager().queryIntentActivities(intent,
+                flags).isEmpty();
+    }
+
     private void unregisterUserChangeObservers() {
         mUserTracker.removeCallback(mUserChangedListener);
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
index 27da6f3..842a1b9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
@@ -247,18 +247,7 @@
     }
 
     fun setExpansion(headerExpansionFraction: Float) {
-        if (featureFlags.isEnabled(Flags.NEW_FOOTER)) {
-            if (headerExpansionFraction != lastExpansion) {
-                if (headerExpansionFraction >= 1f) {
-                    mView.animate().alpha(1f).setDuration(500L).start()
-                } else if (lastExpansion >= 1f && headerExpansionFraction < 1f) {
-                    mView.animate().alpha(0f).setDuration(250L).start()
-                }
-                lastExpansion = headerExpansionFraction
-            }
-        } else {
-            alphaAnimator.setPosition(headerExpansionFraction)
-        }
+        alphaAnimator.setPosition(headerExpansionFraction)
     }
 
     fun setKeyguardShowing(showing: Boolean) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index d1b569f..4640205 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -241,7 +241,13 @@
 
     private void addNonFirstPageAnimators(int page) {
         Pair<HeightExpansionAnimator, TouchAnimator> pair = createSecondaryPageAnimators(page);
-        mNonFirstPageQSAnimators.put(page, pair);
+        if (pair != null) {
+            // pair is null in one of two cases:
+            // * mPagedTileLayout is null, meaning we are still setting up.
+            // * the page has no tiles
+            // In either case, don't add the animators to the map.
+            mNonFirstPageQSAnimators.put(page, pair);
+        }
     }
 
     @Override
@@ -518,6 +524,13 @@
         SideLabelTileLayout qqsLayout = (SideLabelTileLayout) mQuickQsPanel.getTileLayout();
         View view = mQs.getView();
         List<String> specs = mPagedLayout.getSpecsForPage(page);
+        if (specs.isEmpty()) {
+            // specs should not be empty in a valid secondary page, as we scrolled to it.
+            // We may crash later on because there's a null animator.
+            specs = mQsPanelController.getHost().mTileSpecs;
+            Log.e(TAG, "Trying to create animators for empty page " + page + ". Tiles: " + specs);
+            // return null;
+        }
 
         int row = -1;
         int lastTileTop = -1;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index f868055..519ed5c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -29,7 +29,6 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.qs.customize.QSCustomizer;
-import com.android.systemui.util.Utils;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -139,13 +138,17 @@
     }
 
     void updateResources(QSPanelController qsPanelController,
-            QuickStatusBarHeaderController quickStatusBarHeaderController) {
+            QuickStatusBarHeaderController quickStatusBarHeaderController,
+            boolean newFooter) {
+        int bottomPadding = 0;
+        if (newFooter) {
+            bottomPadding = getResources().getDimensionPixelSize(R.dimen.qs_panel_padding_bottom);
+        }
         mQSPanelContainer.setPaddingRelative(
                 mQSPanelContainer.getPaddingStart(),
-                Utils.getQsHeaderSystemIconsAreaHeight(mContext),
+                QSUtils.getQsHeaderSystemIconsAreaHeight(mContext),
                 mQSPanelContainer.getPaddingEnd(),
-                mQSPanelContainer.getPaddingBottom()
-        );
+                bottomPadding);
 
         int sideMargins = getResources().getDimensionPixelSize(R.dimen.notification_side_paddings);
         int padding = getResources().getDimensionPixelSize(
@@ -171,7 +174,6 @@
 
     public void updateExpansion() {
         int height = calculateContainerHeight();
-        int scrollBottom = calculateContainerBottom();
         setBottom(getTop() + height);
     }
 
@@ -183,15 +185,6 @@
                 + mHeader.getHeight();
     }
 
-    int calculateContainerBottom() {
-        int heightOverride = mHeightOverride != -1 ? mHeightOverride : getMeasuredHeight();
-        return mQSCustomizer.isCustomizing() ? mQSCustomizer.getHeight()
-                : Math.round(mQsExpansion
-                        * (heightOverride + mQSPanelContainer.getScrollRange()
-                                - mQSPanelContainer.getScrollY() - mHeader.getHeight()))
-                        + mHeader.getHeight();
-    }
-
     public void setExpansion(float expansion) {
         mQsExpansion = expansion;
         mQSPanelContainer.setScrollingEnabled(expansion > 0f);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java
index 7d61991..61da182 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java
@@ -18,6 +18,8 @@
 
 import android.content.res.Configuration;
 
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.qs.dagger.QSScope;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.util.ViewController;
@@ -30,23 +32,26 @@
     private final QSPanelController mQsPanelController;
     private final QuickStatusBarHeaderController mQuickStatusBarHeaderController;
     private final ConfigurationController mConfigurationController;
+    private final boolean mNewFooter;
 
     private final ConfigurationController.ConfigurationListener mConfigurationListener =
             new ConfigurationController.ConfigurationListener() {
         @Override
         public void onConfigChanged(Configuration newConfig) {
-            mView.updateResources(mQsPanelController, mQuickStatusBarHeaderController);
+            mView.updateResources(mQsPanelController, mQuickStatusBarHeaderController, mNewFooter);
         }
     };
 
     @Inject
     QSContainerImplController(QSContainerImpl view, QSPanelController qsPanelController,
             QuickStatusBarHeaderController quickStatusBarHeaderController,
-            ConfigurationController configurationController) {
+            ConfigurationController configurationController,
+            FeatureFlags featureFlags) {
         super(view);
         mQsPanelController = qsPanelController;
         mQuickStatusBarHeaderController = quickStatusBarHeaderController;
         mConfigurationController = configurationController;
+        mNewFooter = featureFlags.isEnabled(Flags.NEW_FOOTER);
     }
 
     @Override
@@ -60,7 +65,7 @@
 
     @Override
     protected void onViewAttached() {
-        mView.updateResources(mQsPanelController, mQuickStatusBarHeaderController);
+        mView.updateResources(mQsPanelController, mQuickStatusBarHeaderController, mNewFooter);
         mConfigurationController.addCallback(mConfigurationListener);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 3ef7220..e751d54 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -92,6 +92,7 @@
     private float mLastPanelFraction;
     private float mSquishinessFraction = 1;
     private boolean mQsDisabled;
+    private int[] mTemp = new int[2];
 
     private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
     private final MediaHost mQsMediaHost;
@@ -141,6 +142,8 @@
      */
     private float mFullShadeProgress;
 
+    private boolean mOverScrolling;
+
     @Inject
     public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
             QSTileHost qsTileHost,
@@ -498,6 +501,12 @@
     }
 
     @Override
+    public void setOverScrollAmount(int overScrollAmount) {
+        mOverScrolling = overScrollAmount != 0;
+        getView().setTranslationY(overScrollAmount);
+    }
+
+    @Override
     public int getHeightDiff() {
         return mQSPanelScrollView.getBottom() - mHeader.getBottom()
                 + mHeader.getPaddingBottom();
@@ -515,7 +524,7 @@
                 ? 1 : QSAnimator.SHORT_PARALLAX_AMOUNT) * (expansion - 1);
         boolean onKeyguard = isKeyguardState();
         boolean onKeyguardAndExpanded = onKeyguard && !mShowCollapsedOnKeyguard;
-        if (!mHeaderAnimating && !headerWillBeAnimating()) {
+        if (!mHeaderAnimating && !headerWillBeAnimating() && !mOverScrolling) {
             getView().setTranslationY(
                     onKeyguardAndExpanded
                             ? translationScaleY * mHeader.getHeight()
@@ -573,6 +582,7 @@
         if (mQSAnimator != null) {
             mQSAnimator.setPosition(expansion);
         }
+        mQqsMediaHost.setSquishFraction(mSquishinessFraction);
         updateMediaPositions();
     }
 
@@ -598,6 +608,12 @@
                     mQSPanelScrollView.getHeight());
         }
         mQSPanelScrollView.setClipBounds(mQsBounds);
+
+        mQSPanelScrollView.getLocationOnScreen(mTemp);
+        int top = mTemp[1];
+        mQsMediaHost.getCurrentClipping().set(0, top, getView().getMeasuredWidth(),
+                top + mQSPanelScrollView.getMeasuredHeight()
+                        - mQSPanelScrollView.getPaddingBottom());
     }
 
     private void updateMediaPositions() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index b04d752..11a36ad 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -374,7 +374,7 @@
         setPaddingRelative(getPaddingStart(),
                 paddingTop,
                 getPaddingEnd(),
-                mUseNewFooter ? res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom) : 0);
+                getPaddingEnd());
     }
 
     void addOnConfigurationChangedListener(OnConfigurationChangedListener listener) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index 865f093..dd2929c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -33,7 +33,6 @@
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
-import com.android.systemui.media.MediaFlags;
 import com.android.systemui.media.MediaHierarchyManager;
 import com.android.systemui.media.MediaHost;
 import com.android.systemui.media.MediaHostState;
@@ -46,7 +45,6 @@
 import com.android.systemui.settings.brightness.BrightnessSliderController;
 import com.android.systemui.statusbar.policy.BrightnessMirrorController;
 import com.android.systemui.tuner.TunerService;
-import com.android.systemui.util.Utils;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -65,7 +63,6 @@
     private final FalsingManager mFalsingManager;
     private final BrightnessController mBrightnessController;
     private final BrightnessSliderController mBrightnessSliderController;
-    private final MediaFlags mMediaFlags;
     private final BrightnessMirrorHandler mBrightnessMirrorHandler;
     private final FeatureFlags mFeatureFlags;
 
@@ -75,7 +72,6 @@
             new QSPanel.OnConfigurationChangedListener() {
         @Override
         public void onConfigurationChange(Configuration newConfig) {
-            updateMediaExpansion();
             mView.updateResources();
             mQsSecurityFooter.onConfigurationChanged();
             if (mView.isListening()) {
@@ -105,8 +101,7 @@
             DumpManager dumpManager, MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
             QSLogger qsLogger, BrightnessController.Factory brightnessControllerFactory,
             BrightnessSliderController.Factory brightnessSliderFactory,
-            FalsingManager falsingManager, FeatureFlags featureFlags,
-            MediaFlags mediaFlags) {
+            FalsingManager falsingManager, FeatureFlags featureFlags) {
         super(view, qstileHost, qsCustomizerController, usingMediaPlayer, mediaHost,
                 metricsLogger, uiEventLogger, qsLogger, dumpManager);
         mQSFgsManagerFooter = qsFgsManagerFooter;
@@ -117,7 +112,6 @@
         mFalsingManager = falsingManager;
 
         mBrightnessSliderController = brightnessSliderFactory.create(getContext(), mView);
-        mMediaFlags = mediaFlags;
         mView.setBrightnessView(mBrightnessSliderController.getRootView());
 
         mBrightnessController = brightnessControllerFactory.create(mBrightnessSliderController);
@@ -129,7 +123,7 @@
     @Override
     public void onInit() {
         super.onInit();
-        updateMediaExpansion();
+        mMediaHost.setExpansion(MediaHostState.EXPANDED);
         mMediaHost.setShowsOnlyActiveMedia(false);
         mMediaHost.init(MediaHierarchyManager.LOCATION_QS);
         mQsCustomizerController.init();
@@ -137,17 +131,6 @@
         mQSFgsManagerFooter.init();
     }
 
-    private void updateMediaExpansion() {
-        boolean inSplitShade = Utils.shouldUseSplitNotificationShade(getResources());
-        float expansion;
-        if (inSplitShade && !mMediaFlags.useMediaSessionLayout()) {
-            expansion = MediaHostState.COLLAPSED;
-        } else {
-            expansion = MediaHostState.EXPANDED;
-        }
-        mMediaHost.setExpansion(expansion);
-    }
-
     @Override
     protected void onViewAttached() {
         super.onViewAttached();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 6572daa..58007c0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -37,7 +37,7 @@
 import com.android.systemui.qs.customize.QSCustomizerController;
 import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.qs.logging.QSLogger;
-import com.android.systemui.util.Utils;
+import com.android.systemui.util.LargeScreenUtils;
 import com.android.systemui.util.ViewController;
 import com.android.systemui.util.animation.DisappearParameters;
 
@@ -88,7 +88,7 @@
                 @Override
                 public void onConfigurationChange(Configuration newConfig) {
                     mShouldUseSplitNotificationShade =
-                            Utils.shouldUseSplitNotificationShade(getResources());
+                            LargeScreenUtils.shouldUseSplitNotificationShade(getResources());
                     onConfigurationChanged();
                     if (newConfig.orientation != mLastOrientation) {
                         mLastOrientation = newConfig.orientation;
@@ -133,7 +133,7 @@
         mQSLogger = qsLogger;
         mDumpManager = dumpManager;
         mShouldUseSplitNotificationShade =
-                Utils.shouldUseSplitNotificationShade(getResources());
+                LargeScreenUtils.shouldUseSplitNotificationShade(getResources());
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index 3824e1b..ea9bc69 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -325,12 +325,12 @@
 
     private String getManagedDeviceMonitoringText(CharSequence organizationName) {
         if (organizationName == null) {
-            return mDpm.getString(
+            return mDpm.getResources().getString(
                     QS_MSG_MANAGEMENT_MONITORING,
                     () -> mContext.getString(
                             R.string.quick_settings_disclosure_management_monitoring));
         }
-        return mDpm.getString(
+        return mDpm.getResources().getString(
                 QS_MSG_NAMED_MANAGEMENT_MONITORING,
                 () -> mContext.getString(
                         R.string.quick_settings_disclosure_named_management_monitoring,
@@ -342,12 +342,12 @@
             String vpnName, String vpnNameWorkProfile, CharSequence organizationName) {
         if (vpnName != null && vpnNameWorkProfile != null) {
             if (organizationName == null) {
-                return mDpm.getString(
+                return mDpm.getResources().getString(
                         QS_MSG_MANAGEMENT_MULTIPLE_VPNS,
                         () -> mContext.getString(
                                 R.string.quick_settings_disclosure_management_vpns));
             }
-            return mDpm.getString(
+            return mDpm.getResources().getString(
                     QS_MSG_NAMED_MANAGEMENT_MULTIPLE_VPNS,
                     () -> mContext.getString(
                             R.string.quick_settings_disclosure_named_management_vpns,
@@ -356,14 +356,14 @@
         }
         String name = vpnName != null ? vpnName : vpnNameWorkProfile;
         if (organizationName == null) {
-            return mDpm.getString(
+            return mDpm.getResources().getString(
                     QS_MSG_MANAGEMENT_NAMED_VPN,
                     () -> mContext.getString(
                             R.string.quick_settings_disclosure_management_named_vpn,
                             name),
                     name);
         }
-        return mDpm.getString(
+        return mDpm.getResources().getString(
                 QS_MSG_NAMED_MANAGEMENT_NAMED_VPN,
                 () -> mContext.getString(
                         R.string.quick_settings_disclosure_named_management_named_vpn,
@@ -375,7 +375,7 @@
 
     private String getMangedDeviceGeneralText(CharSequence organizationName) {
         if (organizationName == null) {
-            return mDpm.getString(
+            return mDpm.getResources().getString(
                     QS_MSG_MANAGEMENT,
                     () -> mContext.getString(
                             R.string.quick_settings_disclosure_management));
@@ -385,7 +385,7 @@
                     R.string.quick_settings_financed_disclosure_named_management,
                     organizationName);
         } else {
-            return mDpm.getString(
+            return mDpm.getResources().getString(
                     QS_MSG_NAMED_MANAGEMENT,
                     () -> mContext.getString(
                             R.string.quick_settings_disclosure_named_management,
@@ -419,12 +419,12 @@
             CharSequence workProfileOrganizationName, boolean isWorkProfileOn) {
         if (hasCACertsInWorkProfile && isWorkProfileOn) {
             if (workProfileOrganizationName == null) {
-                return mDpm.getString(
+                return mDpm.getResources().getString(
                         QS_MSG_WORK_PROFILE_MONITORING,
                         () -> mContext.getString(
                                 R.string.quick_settings_disclosure_managed_profile_monitoring));
             }
-            return mDpm.getString(
+            return mDpm.getResources().getString(
                     QS_MSG_NAMED_WORK_PROFILE_MONITORING,
                     () -> mContext.getString(
                             R.string.quick_settings_disclosure_named_managed_profile_monitoring,
@@ -443,7 +443,7 @@
             return mContext.getString(R.string.quick_settings_disclosure_vpns);
         }
         if (vpnNameWorkProfile != null && isWorkProfileOn) {
-            return mDpm.getString(
+            return mDpm.getResources().getString(
                     QS_MSG_WORK_PROFILE_NAMED_VPN,
                     () -> mContext.getString(
                             R.string.quick_settings_disclosure_managed_profile_named_vpn,
@@ -452,7 +452,7 @@
         }
         if (vpnName != null) {
             if (hasWorkProfile) {
-                return mDpm.getString(
+                return mDpm.getResources().getString(
                         QS_MSG_PERSONAL_PROFILE_NAMED_VPN,
                         () -> mContext.getString(
                                 R.string.quick_settings_disclosure_personal_profile_named_vpn,
@@ -466,7 +466,7 @@
     }
 
     private String getManagedProfileNetworkActivityText() {
-        return mDpm.getString(
+        return mDpm.getResources().getString(
                 QS_MSG_WORK_PROFILE_NETWORK,
                 () -> mContext.getString(
                         R.string.quick_settings_disclosure_managed_profile_network_activity));
@@ -634,7 +634,7 @@
 
     @VisibleForTesting
     String getSettingsButton() {
-        return mDpm.getString(
+        return mDpm.getResources().getString(
                 QS_DIALOG_VIEW_POLICIES,
                 () -> mContext.getString(R.string.monitoring_button_view_policies));
     }
@@ -662,7 +662,7 @@
                 return mContext.getString(R.string.monitoring_financed_description_named_management,
                         organizationName, organizationName);
             } else {
-                return mDpm.getString(
+                return mDpm.getResources().getString(
                         QS_DIALOG_NAMED_MANAGEMENT,
                         () -> mContext.getString(
                                 R.string.monitoring_description_named_management,
@@ -670,7 +670,7 @@
                         organizationName);
             }
         }
-        return mDpm.getString(
+        return mDpm.getResources().getString(
                 QS_DIALOG_MANAGEMENT,
                 () -> mContext.getString(R.string.monitoring_description_management));
     }
@@ -680,13 +680,13 @@
             boolean hasCACertsInWorkProfile) {
         if (!(hasCACerts || hasCACertsInWorkProfile)) return null;
         if (isDeviceManaged) {
-            return mDpm.getString(
+            return mDpm.getResources().getString(
                     QS_DIALOG_MANAGEMENT_CA_CERT,
                     () -> mContext.getString(
                             R.string.monitoring_description_management_ca_certificate));
         }
         if (hasCACertsInWorkProfile) {
-            return mDpm.getString(
+            return mDpm.getResources().getString(
                     QS_DIALOG_WORK_PROFILE_CA_CERT,
                     () -> mContext.getString(
                             R.string.monitoring_description_managed_profile_ca_certificate));
@@ -699,12 +699,12 @@
             boolean isNetworkLoggingEnabled) {
         if (!isNetworkLoggingEnabled) return null;
         if (isDeviceManaged) {
-            return mDpm.getString(
+            return mDpm.getResources().getString(
                     QS_DIALOG_MANAGEMENT_NETWORK,
                     () -> mContext.getString(
                             R.string.monitoring_description_management_network_logging));
         } else {
-            return mDpm.getString(
+            return mDpm.getResources().getString(
                     QS_DIALOG_WORK_PROFILE_NETWORK,
                     () -> mContext.getString(
                             R.string.monitoring_description_managed_profile_network_logging));
@@ -718,7 +718,7 @@
         final SpannableStringBuilder message = new SpannableStringBuilder();
         if (isDeviceManaged) {
             if (vpnName != null && vpnNameWorkProfile != null) {
-                String namedVpns = mDpm.getString(
+                String namedVpns = mDpm.getResources().getString(
                         QS_DIALOG_MANAGEMENT_TWO_NAMED_VPN,
                         () -> mContext.getString(
                                 R.string.monitoring_description_two_named_vpns,
@@ -727,7 +727,7 @@
                 message.append(namedVpns);
             } else {
                 String name = vpnName != null ? vpnName : vpnNameWorkProfile;
-                String namedVp = mDpm.getString(
+                String namedVp = mDpm.getResources().getString(
                         QS_DIALOG_MANAGEMENT_NAMED_VPN,
                         () -> mContext.getString(R.string.monitoring_description_named_vpn, name),
                         name);
@@ -735,7 +735,7 @@
             }
         } else {
             if (vpnName != null && vpnNameWorkProfile != null) {
-                String namedVpns = mDpm.getString(
+                String namedVpns = mDpm.getResources().getString(
                         QS_DIALOG_MANAGEMENT_TWO_NAMED_VPN,
                         () -> mContext.getString(
                                 R.string.monitoring_description_two_named_vpns,
@@ -743,7 +743,7 @@
                         vpnName, vpnNameWorkProfile);
                 message.append(namedVpns);
             } else if (vpnNameWorkProfile != null) {
-                String namedVpn = mDpm.getString(
+                String namedVpn = mDpm.getResources().getString(
                         QS_DIALOG_WORK_PROFILE_NAMED_VPN,
                         () -> mContext.getString(
                                 R.string.monitoring_description_managed_profile_named_vpn,
@@ -751,7 +751,7 @@
                         vpnNameWorkProfile);
                 message.append(namedVpn);
             } else if (hasWorkProfile) {
-                String namedVpn = mDpm.getString(
+                String namedVpn = mDpm.getResources().getString(
                         QS_DIALOG_PERSONAL_PROFILE_NAMED_VPN,
                         () -> mContext.getString(
                                 R.string.monitoring_description_personal_profile_named_vpn,
@@ -775,7 +775,7 @@
             return mContext.getString(R.string.monitoring_title_financed_device,
                     deviceOwnerOrganization);
         } else {
-            return mDpm.getString(
+            return mDpm.getResources().getString(
                     QS_DIALOG_MANAGEMENT_TITLE,
                     () -> mContext.getString(R.string.monitoring_title_device_owned));
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSUtils.kt b/packages/SystemUI/src/com/android/systemui/qs/QSUtils.kt
new file mode 100644
index 0000000..e42264f24
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSUtils.kt
@@ -0,0 +1,24 @@
+package com.android.systemui.qs
+
+import android.content.Context
+import com.android.internal.policy.SystemBarUtils
+import com.android.systemui.util.LargeScreenUtils.shouldUseLargeScreenShadeHeader
+
+object QSUtils {
+
+    /**
+     * Gets the [R.dimen.qs_header_system_icons_area_height] unless we use large screen header.
+     *
+     * It's the same as [com.android.internal.R.dimen.quick_qs_offset_height] except for
+     * sw600dp-land.
+     */
+    @JvmStatic
+    fun getQsHeaderSystemIconsAreaHeight(context: Context): Int {
+        return if (shouldUseLargeScreenShadeHeader(context.resources)) {
+            // value should be 0 when using large screen shade header because it's not expandable
+            0
+        } else {
+            SystemBarUtils.getQuickQsOffsetHeight(context)
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
index b2e008b..c6ebd73 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -26,7 +26,6 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.R;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.media.MediaFlags;
 import com.android.systemui.media.MediaHierarchyManager;
 import com.android.systemui.media.MediaHost;
 import com.android.systemui.plugins.qs.QSTile;
@@ -53,7 +52,6 @@
                 }
             };
 
-    private final MediaFlags mMediaFlags;
     private final boolean mUsingCollapsedLandscapeMedia;
 
     @Inject
@@ -62,14 +60,12 @@
             @Named(QS_USING_MEDIA_PLAYER) boolean usingMediaPlayer,
             @Named(QUICK_QS_PANEL) MediaHost mediaHost,
             @Named(QS_USING_COLLAPSED_LANDSCAPE_MEDIA) boolean usingCollapsedLandscapeMedia,
-            MediaFlags mediaFlags,
             MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,
             DumpManager dumpManager
     ) {
         super(view, qsTileHost, qsCustomizerController, usingMediaPlayer, mediaHost, metricsLogger,
                 uiEventLogger, qsLogger, dumpManager);
         mUsingCollapsedLandscapeMedia = usingCollapsedLandscapeMedia;
-        mMediaFlags = mediaFlags;
     }
 
     @Override
@@ -84,8 +80,7 @@
         int rotation = getRotation();
         boolean isLandscape = rotation == RotationUtils.ROTATION_LANDSCAPE
                 || rotation == RotationUtils.ROTATION_SEASCAPE;
-        if (mMediaFlags.useMediaSessionLayout()
-                && (!mUsingCollapsedLandscapeMedia || !isLandscape)) {
+        if (!mUsingCollapsedLandscapeMedia || !isLandscape) {
             mMediaHost.setExpansion(MediaHost.EXPANDED);
         } else {
             mMediaHost.setExpansion(MediaHost.COLLAPSED);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 8c08873..c5ca285 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -44,6 +44,7 @@
 import com.android.systemui.statusbar.phone.StatusIconContainer;
 import com.android.systemui.statusbar.policy.Clock;
 import com.android.systemui.statusbar.policy.VariableDateView;
+import com.android.systemui.util.LargeScreenUtils;
 
 import java.util.List;
 
@@ -102,7 +103,7 @@
     private int mTopViewMeasureHeight;
 
     @NonNull
-    private List<String> mRssiIgnoredSlots;
+    private List<String> mRssiIgnoredSlots = List.of();
     private boolean mIsSingleCarrier;
 
     private boolean mHasCenterCutout;
@@ -242,11 +243,10 @@
 
     void updateResources() {
         Resources resources = mContext.getResources();
-        // status bar is already displayed out of QS in split shade
-        boolean shouldUseSplitShade =
-                resources.getBoolean(R.bool.config_use_split_notification_shade);
+        boolean largeScreenHeaderActive =
+                LargeScreenUtils.shouldUseLargeScreenShadeHeader(resources);
 
-        boolean gone = shouldUseSplitShade || mUseCombinedQSHeader || mQsDisabled;
+        boolean gone = largeScreenHeaderActive || mUseCombinedQSHeader || mQsDisabled;
         mStatusIconsView.setVisibility(gone ? View.GONE : View.VISIBLE);
         mDatePrivacyView.setVisibility(gone ? View.GONE : View.VISIBLE);
 
@@ -287,7 +287,7 @@
         }
 
         MarginLayoutParams qqsLP = (MarginLayoutParams) mHeaderQsPanel.getLayoutParams();
-        qqsLP.topMargin = shouldUseSplitShade || !mUseCombinedQSHeader ? mContext.getResources()
+        qqsLP.topMargin = largeScreenHeaderActive || !mUseCombinedQSHeader ? mContext.getResources()
                 .getDimensionPixelSize(R.dimen.qqs_layout_margin_top) : qsOffsetHeight;
         mHeaderQsPanel.setLayoutParams(qqsLP);
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index b59c0cc..71f0a33 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -36,8 +36,8 @@
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.plugins.qs.QSContainerController;
 import com.android.systemui.qs.QSDetailClipper;
+import com.android.systemui.qs.QSUtils;
 import com.android.systemui.statusbar.phone.LightBarController;
-import com.android.systemui.util.Utils;
 
 /**
  * Allows full-screen customization of QS, through show() and hide().
@@ -86,7 +86,7 @@
 
     void updateResources() {
         LayoutParams lp = (LayoutParams) mTransparentView.getLayoutParams();
-        lp.height = Utils.getQsHeaderSystemIconsAreaHeight(mContext);
+        lp.height = QSUtils.getQsHeaderSystemIconsAreaHeight(mContext);
         mTransparentView.setLayoutParams(lp);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index 32515a2..4cacbba 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -15,26 +15,22 @@
  */
 package com.android.systemui.qs.external;
 
-import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Icon;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.service.quicksettings.IQSService;
 import android.service.quicksettings.Tile;
-import android.service.quicksettings.TileService;
 import android.util.ArrayMap;
 import android.util.Log;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.android.internal.statusbar.StatusBarIcon;
@@ -42,6 +38,7 @@
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
@@ -51,6 +48,7 @@
 import java.util.Objects;
 
 import javax.inject.Inject;
+import javax.inject.Provider;
 
 /**
  * Runs the day-to-day operations of which tiles should be bound and when.
@@ -64,11 +62,12 @@
     private final ArrayMap<ComponentName, CustomTile> mTiles = new ArrayMap<>();
     private final ArrayMap<IBinder, CustomTile> mTokenMap = new ArrayMap<>();
     private final Context mContext;
-    private final Handler mHandler;
     private final Handler mMainHandler;
+    private final Provider<Handler> mHandlerProvider;
     private final QSTileHost mHost;
     private final KeyguardStateController mKeyguardStateController;
     private final BroadcastDispatcher mBroadcastDispatcher;
+    private final CommandQueue mCommandQueue;
     private final UserTracker mUserTracker;
 
     private int mMaxBound = DEFAULT_MAX_BOUND;
@@ -76,23 +75,20 @@
     @Inject
     public TileServices(
             QSTileHost host,
-            @Main Looper looper,
+            @Main Provider<Handler> handlerProvider,
             BroadcastDispatcher broadcastDispatcher,
             UserTracker userTracker,
-            KeyguardStateController keyguardStateController) {
+            KeyguardStateController keyguardStateController,
+            CommandQueue commandQueue) {
         mHost = host;
         mKeyguardStateController = keyguardStateController;
         mContext = mHost.getContext();
         mBroadcastDispatcher = broadcastDispatcher;
-        mHandler = new Handler(looper);
-        mMainHandler = new Handler(Looper.getMainLooper());
+        mHandlerProvider = handlerProvider;
+        mMainHandler = mHandlerProvider.get();
         mUserTracker = userTracker;
-        mBroadcastDispatcher.registerReceiver(
-                mRequestListeningReceiver,
-                new IntentFilter(TileService.ACTION_REQUEST_LISTENING),
-                null, // Use the default Executor
-                UserHandle.ALL
-        );
+        mCommandQueue = commandQueue;
+        mCommandQueue.addCallback(mRequestListeningCallback);
     }
 
     public Context getContext() {
@@ -118,7 +114,7 @@
 
     protected TileServiceManager onCreateTileService(ComponentName component,
             BroadcastDispatcher broadcastDispatcher) {
-        return new TileServiceManager(this, mHandler, component,
+        return new TileServiceManager(this, mHandlerProvider.get(), component,
                 broadcastDispatcher, mUserTracker);
     }
 
@@ -354,21 +350,14 @@
     public void destroy() {
         synchronized (mServices) {
             mServices.values().forEach(service -> service.handleDestroy());
-            mBroadcastDispatcher.unregisterReceiver(mRequestListeningReceiver);
         }
+        mCommandQueue.removeCallback(mRequestListeningCallback);
     }
 
-    private final BroadcastReceiver mRequestListeningReceiver = new BroadcastReceiver() {
+    private final CommandQueue.Callbacks mRequestListeningCallback = new CommandQueue.Callbacks() {
         @Override
-        public void onReceive(Context context, Intent intent) {
-            if (TileService.ACTION_REQUEST_LISTENING.equals(intent.getAction())) {
-                try {
-                    ComponentName c = intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME);
-                    requestListening(c);
-                } catch (ClassCastException ex) {
-                    Log.e(TAG, "Bad component name", ex);
-                }
-            }
+        public void requestTileServiceListeningState(@NonNull ComponentName componentName) {
+            mMainHandler.post(() -> requestListening(componentName));
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index 7fb9ef3..be6982a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -16,13 +16,14 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.ArgbEvaluator;
+import android.animation.PropertyValuesHolder;
 import android.animation.ValueAnimator;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.graphics.Color;
 import android.graphics.drawable.Animatable2;
 import android.graphics.drawable.Animatable2.AnimationCallback;
 import android.graphics.drawable.Drawable;
@@ -53,6 +54,8 @@
     @Nullable
     private QSTile.Icon mLastIcon;
 
+    private ValueAnimator mColorAnimator = new ValueAnimator();
+
     public QSIconViewImpl(Context context) {
         super(context);
 
@@ -61,6 +64,7 @@
 
         mIcon = createIcon();
         addView(mIcon);
+        mColorAnimator.setDuration(QS_ANIM_LENGTH);
     }
 
     @Override
@@ -165,7 +169,6 @@
             mState = state.state;
             if (mTint != 0 && allowAnimations && shouldAnimate(iv)) {
                 animateGrayScale(mTint, color, iv, () -> updateIcon(iv, state, allowAnimations));
-                mTint = color;
             } else {
                 if (iv instanceof AlphaControlledSlashImageView) {
                     ((AlphaControlledSlashImageView)iv)
@@ -173,7 +176,6 @@
                 } else {
                     setTint(iv, color);
                 }
-                mTint = color;
                 updateIcon(iv, state, allowAnimations);
             }
         } else {
@@ -191,39 +193,30 @@
             ((AlphaControlledSlashImageView)iv)
                     .setFinalImageTintList(ColorStateList.valueOf(toColor));
         }
+        mColorAnimator.cancel();
         if (mAnimationEnabled && ValueAnimator.areAnimatorsEnabled()) {
-            final float fromAlpha = Color.alpha(fromColor);
-            final float toAlpha = Color.alpha(toColor);
-            final float fromChannel = Color.red(fromColor);
-            final float toChannel = Color.red(toColor);
-
-            ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
-            anim.setDuration(QS_ANIM_LENGTH);
-            anim.addUpdateListener(animation -> {
-                float fraction = animation.getAnimatedFraction();
-                int alpha = (int) (fromAlpha + (toAlpha - fromAlpha) * fraction);
-                int channel = (int) (fromChannel + (toChannel - fromChannel) * fraction);
-
-                setTint(iv, Color.argb(alpha, channel, channel, channel));
+            PropertyValuesHolder values = PropertyValuesHolder.ofInt("color", fromColor, toColor);
+            values.setEvaluator(ArgbEvaluator.getInstance());
+            mColorAnimator.setValues(values);
+            mColorAnimator.removeAllListeners();
+            mColorAnimator.addUpdateListener(animation -> {
+                setTint(iv, (int) animation.getAnimatedValue());
             });
-            anim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    endRunnable.run();
-                }
-            });
-            anim.start();
+            mColorAnimator.addListener(new EndRunnableAnimatorListener(endRunnable));
+
+            mColorAnimator.start();
         } else {
+
             setTint(iv, toColor);
             endRunnable.run();
         }
     }
 
-    public static void setTint(ImageView iv, int color) {
+    public void setTint(ImageView iv, int color) {
         iv.setImageTintList(ColorStateList.valueOf(color));
+        mTint = color;
     }
 
-
     protected int getIconMeasureMode() {
         return MeasureSpec.EXACTLY;
     }
@@ -261,4 +254,25 @@
                 return 0;
         }
     }
+
+    private static class EndRunnableAnimatorListener extends AnimatorListenerAdapter {
+        private Runnable mRunnable;
+
+        EndRunnableAnimatorListener(Runnable endRunnable) {
+            super();
+            mRunnable = endRunnable;
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            super.onAnimationCancel(animation);
+            mRunnable.run();
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            super.onAnimationEnd(animation);
+            mRunnable.run();
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java
index b658025..b415022 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java
@@ -117,7 +117,6 @@
         state.icon = ResourceIcon.get(R.drawable.ic_qr_code_scanner);
         state.state = mQRCodeScannerController.isEnabledForQuickSettings() ? Tile.STATE_ACTIVE
                 : Tile.STATE_UNAVAILABLE;
-        state.secondaryLabel = mContext.getString(R.string.qr_code_scanner_description);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index 4279b62..7130294 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -104,7 +104,7 @@
     @Override
     public CharSequence getTileLabel() {
         DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
-        return dpm.getString(QS_WORK_PROFILE_LABEL,
+        return dpm.getResources().getString(QS_WORK_PROFILE_LABEL,
                 () -> mContext.getString(R.string.quick_settings_work_mode_label));
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
index 8bad2de..2cc3986 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
@@ -21,6 +21,7 @@
 import android.graphics.drawable.Drawable;
 import android.text.Html;
 import android.text.TextUtils;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -158,22 +159,47 @@
             final int security = wifiEntry.getSecurity();
             updateEndIcon(connectedState, security);
 
+            mWifiListLayout.setEnabled(shouldEnabled(wifiEntry));
             if (connectedState != WifiEntry.CONNECTED_STATE_DISCONNECTED) {
                 mWifiListLayout.setOnClickListener(
-                        v -> mInternetDialogController.launchWifiNetworkDetailsSetting(
+                        v -> mInternetDialogController.launchWifiDetailsSetting(
                                 wifiEntry.getKey(), v));
                 return;
             }
-            mWifiListLayout.setOnClickListener(v -> {
-                if (wifiEntry.shouldEditBeforeConnect()) {
-                    final Intent intent = WifiUtils.getWifiDialogIntent(wifiEntry.getKey(),
-                            true /* connectForCaller */);
-                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
-                    mContext.startActivity(intent);
-                }
+            mWifiListLayout.setOnClickListener(v -> onWifiClick(wifiEntry, v));
+        }
+
+        boolean shouldEnabled(@NonNull WifiEntry wifiEntry) {
+            if (wifiEntry.canConnect()) {
+                return true;
+            }
+            // If Wi-Fi is connected or saved network, leave it enabled to disconnect or configure.
+            if (wifiEntry.canDisconnect() || wifiEntry.isSaved()) {
+                return true;
+            }
+            return false;
+        }
+
+        void onWifiClick(@NonNull WifiEntry wifiEntry, @NonNull View view) {
+            if (wifiEntry.shouldEditBeforeConnect()) {
+                final Intent intent = WifiUtils.getWifiDialogIntent(wifiEntry.getKey(),
+                        true /* connectForCaller */);
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
+                mContext.startActivity(intent);
+                return;
+            }
+
+            if (wifiEntry.canConnect()) {
                 mInternetDialogController.connect(wifiEntry);
-            });
+                return;
+            }
+
+            if (wifiEntry.isSaved()) {
+                Log.w(TAG, "The saved Wi-Fi network does not allow to connect. SSID:"
+                        + wifiEntry.getSsid());
+                mInternetDialogController.launchWifiDetailsSetting(wifiEntry.getKey(), view);
+            }
         }
 
         void setWifiNetworkLayout(CharSequence title, CharSequence summary) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index d1c7844..8921e95 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -531,8 +531,7 @@
         if (mConnectedWifiEntry == null) {
             return;
         }
-        mInternetDialogController.launchWifiNetworkDetailsSetting(mConnectedWifiEntry.getKey(),
-                view);
+        mInternetDialogController.launchWifiDetailsSetting(mConnectedWifiEntry.getKey(), view);
     }
 
     void onClickSeeMoreButton(View view) {
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 b322cbf..d97ce77 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
@@ -635,7 +635,7 @@
         startActivity(getSettingsIntent(), view);
     }
 
-    void launchWifiNetworkDetailsSetting(String key, View view) {
+    void launchWifiDetailsSetting(String key, View view) {
         Intent intent = getWifiDetailsSettingsIntent(key);
         if (intent != null) {
             startActivity(intent, view);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index a3dea1c..53a27ff 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -101,8 +101,8 @@
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.phone.NotificationPanelViewController;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
+import com.android.systemui.statusbar.phone.NotificationPanelViewController;
 import com.android.systemui.statusbar.phone.StatusBarWindowCallback;
 import com.android.systemui.statusbar.policy.CallbackController;
 import com.android.wm.shell.back.BackAnimation;
@@ -675,7 +675,7 @@
             navBarFragment.updateSystemUiStateFlags();
         }
         if (navBarView != null) {
-            navBarView.updateDisabledSystemUiStateFlags();
+            navBarView.updateDisabledSystemUiStateFlags(mSysUiState);
         }
         if (panelController != null) {
             panelController.updateSystemUiStateFlags();
diff --git a/packages/SystemUI/src/com/android/systemui/scrim/ScrimDrawable.java b/packages/SystemUI/src/com/android/systemui/scrim/ScrimDrawable.java
index 3c6ab34..bbba007 100644
--- a/packages/SystemUI/src/com/android/systemui/scrim/ScrimDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/scrim/ScrimDrawable.java
@@ -199,7 +199,7 @@
             drawConcave(canvas);
         } else if (mCornerRadiusEnabled && mCornerRadius > 0) {
             canvas.drawRoundRect(getBounds().left, getBounds().top, getBounds().right,
-                    getBounds().bottom + mCornerRadius,
+                    getBounds().bottom,
                     /* x radius*/ mCornerRadius, /* y radius*/ mCornerRadius, mPaint);
         } else {
             canvas.drawRect(getBounds().left, getBounds().top, getBounds().right,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 5932a64..d9a98b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -163,6 +163,7 @@
     private static final int MSG_MEDIA_TRANSFER_RECEIVER_STATE = 65 << MSG_SHIFT;
     private static final int MSG_REGISTER_NEARBY_MEDIA_DEVICE_PROVIDER = 66 << MSG_SHIFT;
     private static final int MSG_UNREGISTER_NEARBY_MEDIA_DEVICE_PROVIDER = 67 << MSG_SHIFT;
+    private static final int MSG_TILE_SERVICE_REQUEST_LISTENING_STATE = 68 << MSG_SHIFT;
 
     public static final int FLAG_EXCLUDE_NONE = 0;
     public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -433,6 +434,11 @@
         default void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {}
 
         /**
+         * @see IStatusBar#requestTileServiceListeningState
+         */
+        default void requestTileServiceListeningState(@NonNull ComponentName componentName) {}
+
+        /**
          * @see IStatusBar#requestAddTile
          */
         default void requestAddTile(
@@ -1190,6 +1196,12 @@
     }
 
     @Override
+    public void requestTileServiceListeningState(@NonNull ComponentName componentName) {
+        mHandler.obtainMessage(MSG_TILE_SERVICE_REQUEST_LISTENING_STATE, componentName)
+                .sendToTarget();
+    }
+
+    @Override
     public void requestAddTile(
             @NonNull ComponentName componentName,
             @NonNull CharSequence appName,
@@ -1686,6 +1698,12 @@
                         mCallbacks.get(i).unregisterNearbyMediaDevicesProvider(provider);
                     }
                     break;
+                case MSG_TILE_SERVICE_REQUEST_LISTENING_STATE:
+                    ComponentName component = (ComponentName) msg.obj;
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).requestTileServiceListeningState(component);
+                    }
+                    break;
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index ccec0c2..55ca8f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -293,6 +293,14 @@
         }
     }
 
+    /**
+     * Cleanup
+     */
+    public void destroy() {
+        mHandler.removeCallbacksAndMessages(null);
+        mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver);
+    }
+
     private void handleAlignStateChanged(int alignState) {
         String alignmentIndication = "";
         if (alignState == DockManager.ALIGN_STATE_POOR) {
@@ -374,7 +382,7 @@
     private CharSequence getDisclosureText(@Nullable CharSequence organizationName) {
         final Resources packageResources = mContext.getResources();
         if (organizationName == null) {
-            return mDevicePolicyManager.getString(
+            return mDevicePolicyManager.getResources().getString(
                     KEYGUARD_MANAGEMENT_DISCLOSURE,
                     () -> packageResources.getString(R.string.do_disclosure_generic));
         } else if (mDevicePolicyManager.isDeviceManaged()
@@ -384,7 +392,7 @@
             return packageResources.getString(R.string.do_financed_disclosure_with_name,
                     organizationName);
         } else {
-            return mDevicePolicyManager.getString(
+            return mDevicePolicyManager.getResources().getString(
                     KEYGUARD_MANAGEMENT_DISCLOSURE,
                     () -> packageResources.getString(
                             R.string.do_disclosure_with_name, organizationName),
@@ -567,13 +575,7 @@
                                     return;
                                 }
                                 int currentUserId = KeyguardUpdateMonitor.getCurrentUser();
-                                try {
-                                    mIActivityManager.switchUser(UserHandle.USER_SYSTEM);
-                                    mIActivityManager.stopUser(currentUserId, true /* force */,
-                                            null);
-                                } catch (RemoteException re) {
-                                    Log.e(TAG, "Failed to logout user", re);
-                                }
+                                mDevicePolicyManager.logoutUser();
                             })
                             .build(),
                     false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockScreenShadeOverScroller.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockScreenShadeOverScroller.kt
new file mode 100644
index 0000000..de37a38
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockScreenShadeOverScroller.kt
@@ -0,0 +1,8 @@
+package com.android.systemui.statusbar
+
+/** Represents an over scroller for the transition to full shade on lock screen. */
+interface LockScreenShadeOverScroller {
+
+    /** The amount in pixels that the user has dragged to expand the shade. */
+    var expansionDragDownAmount: Float
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 1ab0345..3620e84 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -34,13 +34,13 @@
 import com.android.systemui.statusbar.notification.row.ExpandableView
 import com.android.systemui.statusbar.notification.stack.AmbientState
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.phone.CentralSurfaces
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.phone.LSShadeTransitionLogger
 import com.android.systemui.statusbar.phone.NotificationPanelViewController
 import com.android.systemui.statusbar.phone.ScrimController
-import com.android.systemui.statusbar.phone.CentralSurfaces
 import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.util.Utils
+import com.android.systemui.util.LargeScreenUtils
 import java.io.FileDescriptor
 import java.io.PrintWriter
 import javax.inject.Inject
@@ -64,6 +64,8 @@
     private val scrimController: ScrimController,
     private val depthController: NotificationShadeDepthController,
     private val context: Context,
+    private val splitShadeOverScrollerFactory: SplitShadeLockScreenOverScroller.Factory,
+    private val singleShadeOverScrollerFactory: SingleShadeLockScreenOverScroller.Factory,
     wakefulnessLifecycle: WakefulnessLifecycle,
     configurationController: ConfigurationController,
     falsingManager: FalsingManager,
@@ -116,6 +118,16 @@
     private var scrimTransitionDistance = 0
 
     /**
+     * Distance that it takes in order for the notifications scrim fade in to start.
+     */
+    private var notificationsScrimTransitionDelay = 0
+
+    /**
+     * Distance that it takes for the notifications scrim to fully fade if after it started.
+     */
+    private var notificationsScrimTransitionDistance = 0
+
+    /**
      * Distance that the full shade transition takes in order for the notification shelf to fully
      * expand.
      */
@@ -184,6 +196,27 @@
      */
     val touchHelper = DragDownHelper(falsingManager, falsingCollector, this, context)
 
+    private val splitShadeOverScroller: SplitShadeLockScreenOverScroller by lazy {
+        splitShadeOverScrollerFactory.create(qS, nsslController)
+    }
+
+    private val phoneShadeOverScroller: SingleShadeLockScreenOverScroller by lazy {
+        singleShadeOverScrollerFactory.create(nsslController)
+    }
+
+    /**
+     * [LockScreenShadeOverScroller] property that delegates to either
+     * [SingleShadeLockScreenOverScroller] or [SplitShadeLockScreenOverScroller].
+     *
+     * There are currently two different implementations, as the over scroll behavior is different
+     * on single shade and split shade.
+     *
+     * On single shade, only notifications are over scrolled, whereas on split shade, everything is
+     * over scrolled.
+     */
+    private val shadeOverScroller: LockScreenShadeOverScroller
+        get() = if (useSplitShade) splitShadeOverScroller else phoneShadeOverScroller
+
     init {
         updateResources()
         configurationController.addCallback(object : ConfigurationController.ConfigurationListener {
@@ -225,6 +258,10 @@
             R.dimen.lockscreen_shade_transition_by_tap_distance)
         scrimTransitionDistance = context.resources.getDimensionPixelSize(
                 R.dimen.lockscreen_shade_scrim_transition_distance)
+        notificationsScrimTransitionDelay = context.resources.getDimensionPixelSize(
+                R.dimen.lockscreen_shade_notifications_scrim_transition_delay)
+        notificationsScrimTransitionDistance = context.resources.getDimensionPixelSize(
+                R.dimen.lockscreen_shade_notifications_scrim_transition_distance)
         notificationShelfTransitionDistance = context.resources.getDimensionPixelSize(
                 R.dimen.lockscreen_shade_notif_shelf_transition_distance)
         qsTransitionDistance = context.resources.getDimensionPixelSize(
@@ -237,7 +274,7 @@
                 R.dimen.lockscreen_shade_udfps_keyguard_transition_distance)
         statusBarTransitionDistance = context.resources.getDimensionPixelSize(
                 R.dimen.lockscreen_shade_status_bar_transition_distance)
-        useSplitShade = Utils.shouldUseSplitNotificationShade(context.resources)
+        useSplitShade = LargeScreenUtils.shouldUseSplitNotificationShade(context.resources)
     }
 
     fun setStackScroller(nsslController: NotificationStackScrollLayoutController) {
@@ -396,7 +433,7 @@
                 if (!nsslController.isInLockedDownShade() || field == 0f || forceApplyAmount) {
                     val notificationShelfProgress =
                         MathUtils.saturate(dragDownAmount / notificationShelfTransitionDistance)
-                    nsslController.setTransitionToFullShadeAmount(field, notificationShelfProgress)
+                    nsslController.setTransitionToFullShadeAmount(notificationShelfProgress)
 
                     qSDragProgress = MathUtils.saturate(dragDownAmount / qsTransitionDistance)
                     qS.setTransitionToFullShadeAmount(field, qSDragProgress)
@@ -405,7 +442,10 @@
                             false /* animate */, 0 /* delay */)
 
                     mediaHierarchyManager.setTransitionToFullShadeAmount(field)
+                    transitionToShadeAmountScrim(field)
                     transitionToShadeAmountCommon(field)
+                    transitionToShadeAmountKeyguard(field)
+                    shadeOverScroller.expansionDragDownAmount = dragDownAmount
                 }
             }
         }
@@ -416,16 +456,18 @@
     var qSDragProgress = 0f
         private set
 
-    private fun transitionToShadeAmountCommon(dragDownAmount: Float) {
+    private fun transitionToShadeAmountScrim(dragDownAmount: Float) {
         val scrimProgress = MathUtils.saturate(dragDownAmount / scrimTransitionDistance)
-        scrimController.setTransitionToFullShadeProgress(scrimProgress)
+        val notificationsScrimDragAmount = dragDownAmount - notificationsScrimTransitionDelay
+        val notificationsScrimProgress = MathUtils.saturate(
+                notificationsScrimDragAmount / notificationsScrimTransitionDistance)
+        scrimController.setTransitionToFullShadeProgress(scrimProgress, notificationsScrimProgress)
+    }
 
-        // Fade out all content only visible on the lockscreen
-        val npvcProgress =
-            MathUtils.saturate(dragDownAmount / npvcKeyguardContentAlphaTransitionDistance)
-        notificationPanelController.setKeyguardOnlyContentAlpha(1.0f - npvcProgress)
-
-        if (depthControllerTransitionDistance > 0) {
+    private fun transitionToShadeAmountCommon(dragDownAmount: Float) {
+        if (depthControllerTransitionDistance == 0) { // split shade
+            depthController.transitionToFullShadeProgress = 0f
+        } else {
             val depthProgress =
                 MathUtils.saturate(dragDownAmount / depthControllerTransitionDistance)
             depthController.transitionToFullShadeProgress = depthProgress
@@ -438,6 +480,25 @@
         centralSurfaces.setTransitionToFullShadeProgress(statusBarProgress)
     }
 
+    private fun transitionToShadeAmountKeyguard(dragDownAmount: Float) {
+        // Fade out all content only visible on the lockscreen
+        val keyguardAlphaProgress =
+            MathUtils.saturate(dragDownAmount / npvcKeyguardContentAlphaTransitionDistance)
+        val keyguardAlpha = 1f - keyguardAlphaProgress
+        val keyguardTranslationY = if (useSplitShade) {
+            // On split-shade, the translationY of the keyguard should stay in sync with the
+            // translation of media.
+            mediaHierarchyManager.getGuidedTransformationTranslationY()
+        } else {
+            0
+        }
+        notificationPanelController
+            .setKeyguardTransitionProgress(keyguardAlpha, keyguardTranslationY)
+
+        val statusBarAlpha = if (useSplitShade) keyguardAlpha else -1f
+        notificationPanelController.setKeyguardStatusBarAlpha(statusBarAlpha)
+    }
+
     private fun setDragDownAmountAnimated(
         target: Float,
         delay: Long = 0,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 94a6d3e..66c1d87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -507,12 +507,11 @@
                 Math.max(cx + cy, cx + (h - cy)),
                 Math.max((w - cx) + cy, (w - cx) + (h - cy)));
 
-        riv.setRevealParameters(cx, cy, r);
-        riv.setPendingIntent(pendingIntent);
+        riv.getController().setRevealParams(new RemoteInputView.RevealParams(cx, cy, r));
         riv.getController().setPendingIntent(pendingIntent);
-        riv.setRemoteInput(inputs, input, editedSuggestionInfo);
         riv.getController().setRemoteInput(input);
         riv.getController().setRemoteInputs(inputs);
+        riv.getController().setEditedSuggestionInfo(editedSuggestionInfo);
         riv.focusAnimated();
         if (userMessageContent != null) {
             riv.setEditTextContent(userMessageContent);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 3dd717d..eaa66bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -226,10 +226,7 @@
                 ? MathUtils.lerp(shortestWidth, getWidth(), fractionToShade)
                 : getWidth();
         ActivatableNotificationView anv = (ActivatableNotificationView) this;
-        NotificationBackgroundView bg = anv.getBackgroundNormal();
-        if (bg != null) {
-            anv.getBackgroundNormal().setActualWidth((int) actualWidth);
-        }
+        anv.setBackgroundWidth((int) actualWidth);
         if (mShelfIcons != null) {
             mShelfIcons.setActualLayoutWidth((int) actualWidth);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index 3fe108f..f0e01a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -192,7 +192,10 @@
     override fun onTouchEvent(event: MotionEvent): Boolean {
         val finishExpanding = (event.action == MotionEvent.ACTION_CANCEL ||
             event.action == MotionEvent.ACTION_UP) && isExpanding
-        if (!canHandleMotionEvent() && !finishExpanding) {
+
+        val isDraggingNotificationOrCanBypass = mStartingChild?.showingPulsing() == true ||
+                bypassController.canBypass()
+        if ((!canHandleMotionEvent() || !isDraggingNotificationOrCanBypass) && !finishExpanding) {
             // We allow cancellations/finishing to still go through here to clean up the state
             return false
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt b/packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt
new file mode 100644
index 0000000..575f354
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt
@@ -0,0 +1,74 @@
+package com.android.systemui.statusbar
+
+import android.content.Context
+import android.content.res.Configuration
+import android.util.MathUtils
+import com.android.systemui.R
+import com.android.systemui.animation.Interpolators
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.policy.ConfigurationController
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+
+class SingleShadeLockScreenOverScroller
+@AssistedInject
+constructor(
+    configurationController: ConfigurationController,
+    private val context: Context,
+    private val statusBarStateController: SysuiStatusBarStateController,
+    @Assisted private val nsslController: NotificationStackScrollLayoutController
+) : LockScreenShadeOverScroller {
+
+    private var maxOverScrollAmount = 0
+    private var totalDistanceForFullShadeTransition = 0
+
+    init {
+        updateResources()
+        configurationController.addCallback(
+            object : ConfigurationController.ConfigurationListener {
+                override fun onConfigChanged(newConfig: Configuration?) {
+                    updateResources()
+                }
+            })
+    }
+
+    private fun updateResources() {
+        val resources = context.resources
+        totalDistanceForFullShadeTransition =
+            resources.getDimensionPixelSize(R.dimen.lockscreen_shade_qs_transition_distance)
+        maxOverScrollAmount =
+            resources.getDimensionPixelSize(R.dimen.lockscreen_shade_max_over_scroll_amount)
+    }
+
+    override var expansionDragDownAmount: Float = 0f
+        set(value) {
+            if (value == field) {
+                return
+            }
+            field = value
+            overScroll()
+        }
+
+    private fun overScroll() {
+        var extraTopInset = 0.0f
+        if (statusBarStateController.state == StatusBarState.KEYGUARD) {
+            val viewHeight = nsslController.height
+            val overallProgress = MathUtils.saturate(expansionDragDownAmount / viewHeight)
+            val transitionProgress =
+                Interpolators.getOvershootInterpolation(
+                    overallProgress,
+                    0.6f,
+                    totalDistanceForFullShadeTransition.toFloat() / viewHeight.toFloat())
+            extraTopInset = transitionProgress * maxOverScrollAmount
+        }
+        nsslController.setOverScrollAmount(extraTopInset.toInt())
+    }
+
+    @AssistedFactory
+    fun interface Factory {
+        fun create(
+            nsslController: NotificationStackScrollLayoutController
+        ): SingleShadeLockScreenOverScroller
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt b/packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt
new file mode 100644
index 0000000..96ce6b4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt
@@ -0,0 +1,129 @@
+package com.android.systemui.statusbar
+
+import android.animation.Animator
+import android.animation.ValueAnimator
+import android.content.Context
+import android.content.res.Configuration
+import android.util.MathUtils
+import android.view.animation.PathInterpolator
+import com.android.internal.annotations.VisibleForTesting
+import com.android.systemui.R
+import com.android.systemui.animation.Interpolators
+import com.android.systemui.plugins.qs.QS
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.phone.ScrimController
+import com.android.systemui.statusbar.policy.ConfigurationController
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+
+class SplitShadeLockScreenOverScroller
+@AssistedInject
+constructor(
+    configurationController: ConfigurationController,
+    private val context: Context,
+    private val scrimController: ScrimController,
+    private val statusBarStateController: SysuiStatusBarStateController,
+    @Assisted private val qS: QS,
+    @Assisted private val nsslController: NotificationStackScrollLayoutController
+) : LockScreenShadeOverScroller {
+
+    private var releaseOverScrollAnimator: Animator? = null
+    private var transitionToFullShadeDistance = 0
+    private var releaseOverScrollDuration = 0L
+    private var maxOverScrollAmount = 0
+    private var previousOverscrollAmount = 0
+
+    init {
+        updateResources()
+        configurationController.addCallback(
+            object : ConfigurationController.ConfigurationListener {
+                override fun onConfigChanged(newConfig: Configuration?) {
+                    updateResources()
+                }
+            })
+    }
+
+    private fun updateResources() {
+        val resources = context.resources
+        transitionToFullShadeDistance =
+            resources.getDimensionPixelSize(R.dimen.lockscreen_shade_full_transition_distance)
+        maxOverScrollAmount =
+            resources.getDimensionPixelSize(R.dimen.lockscreen_shade_max_over_scroll_amount)
+        releaseOverScrollDuration =
+            resources.getInteger(R.integer.lockscreen_shade_over_scroll_release_duration).toLong()
+    }
+
+    override var expansionDragDownAmount: Float = 0f
+        set(dragDownAmount) {
+            if (field == dragDownAmount) {
+                return
+            }
+            field = dragDownAmount
+            if (shouldOverscroll()) {
+                overScroll(dragDownAmount)
+            } else if (shouldReleaseOverscroll()) {
+                releaseOverScroll()
+            }
+        }
+
+    private fun shouldOverscroll() = statusBarStateController.state == StatusBarState.KEYGUARD
+
+    private fun shouldReleaseOverscroll() = !shouldOverscroll() && previousOverscrollAmount != 0
+
+    private fun overScroll(dragDownAmount: Float) {
+        val overscrollAmount: Int = calculateOverscrollAmount(dragDownAmount)
+        applyOverscroll(overscrollAmount)
+        previousOverscrollAmount = overscrollAmount
+    }
+
+    private fun applyOverscroll(overscrollAmount: Int) {
+        qS.setOverScrollAmount(overscrollAmount)
+        scrimController.setNotificationsOverScrollAmount(overscrollAmount)
+        nsslController.setOverScrollAmount(overscrollAmount)
+    }
+
+    private fun calculateOverscrollAmount(dragDownAmount: Float): Int {
+        val fullHeight: Int = nsslController.height
+        val fullHeightProgress: Float = MathUtils.saturate(dragDownAmount / fullHeight)
+        val overshootStart: Float = transitionToFullShadeDistance / fullHeight.toFloat()
+        val overShootTransitionProgress: Float =
+            Interpolators.getOvershootInterpolation(
+                fullHeightProgress, OVER_SHOOT_AMOUNT, overshootStart)
+        return (overShootTransitionProgress * maxOverScrollAmount).toInt()
+    }
+
+    private fun releaseOverScroll() {
+        val animator = ValueAnimator.ofInt(previousOverscrollAmount, 0)
+        animator.addUpdateListener {
+            val overScrollAmount = it.animatedValue as Int
+            qS.setOverScrollAmount(overScrollAmount)
+            scrimController.setNotificationsOverScrollAmount(overScrollAmount)
+            nsslController.setOverScrollAmount(overScrollAmount)
+        }
+        animator.interpolator = RELEASE_OVER_SCROLL_INTERPOLATOR
+        animator.duration = releaseOverScrollDuration
+        animator.start()
+        releaseOverScrollAnimator = animator
+        previousOverscrollAmount = 0
+    }
+
+    @VisibleForTesting
+    internal fun finishAnimations() {
+        releaseOverScrollAnimator?.end()
+        releaseOverScrollAnimator = null
+    }
+
+    @AssistedFactory
+    fun interface Factory {
+        fun create(
+            qS: QS,
+            nsslController: NotificationStackScrollLayoutController
+        ): SplitShadeLockScreenOverScroller
+    }
+
+    companion object {
+        private const val OVER_SHOOT_AMOUNT = 0.6f
+        private val RELEASE_OVER_SCROLL_INTERPOLATOR = PathInterpolator(0.17f, 0f, 0f, 1f)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
index 465ab93..3013ad0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -188,7 +188,7 @@
 
         setContentDescription(state.contentDescription);
         int newVisibility = state.visible && !mForceHidden ? View.VISIBLE : View.GONE;
-        if (newVisibility != mMobileGroup.getVisibility()) {
+        if (newVisibility != mMobileGroup.getVisibility() && STATE_ICON == mVisibleState) {
             mMobileGroup.setVisibility(newVisibility);
             needsLayout = true;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
index d4d84c1..4e1404d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.events
 
+import android.annotation.SuppressLint
 import android.content.Context
 import android.graphics.Color
 import android.graphics.drawable.ColorDrawable
@@ -27,13 +28,15 @@
 import com.android.systemui.privacy.OngoingPrivacyChip
 import com.android.systemui.privacy.PrivacyItem
 
+typealias ViewCreator = (context: Context) -> BackgroundAnimatableView
+
 interface StatusEvent {
     val priority: Int
     // Whether or not to force the status bar open and show a dot
     val forceVisible: Boolean
     // Whether or not to show an animation for this event
     val showAnimation: Boolean
-    val viewCreator: (context: Context) -> View
+    val viewCreator: ViewCreator
     var contentDescription: String?
 
     // Update this event with values from another event.
@@ -47,14 +50,37 @@
     }
 }
 
+class BGView(
+    context: Context
+) : View(context), BackgroundAnimatableView {
+    override val view: View
+        get() = this
+
+    override fun setBoundsForAnimation(l: Int, t: Int, r: Int, b: Int) {
+        setLeftTopRightBottom(l, t, r, b)
+    }
+}
+
+@SuppressLint("AppCompatCustomView")
+class BGImageView(
+    context: Context
+) : ImageView(context), BackgroundAnimatableView {
+    override val view: View
+        get() = this
+
+    override fun setBoundsForAnimation(l: Int, t: Int, r: Int, b: Int) {
+        setLeftTopRightBottom(l, t, r, b)
+    }
+}
+
 class BatteryEvent : StatusEvent {
     override val priority = 50
     override val forceVisible = false
     override val showAnimation = true
     override var contentDescription: String? = ""
 
-    override val viewCreator: (context: Context) -> View = { context ->
-        val iv = ImageView(context)
+    override val viewCreator: (context: Context) -> BGImageView = { context ->
+        val iv = BGImageView(context)
         iv.setImageDrawable(ThemedBatteryDrawable(context, Color.WHITE))
         iv.setBackgroundDrawable(ColorDrawable(Color.GREEN))
         iv
@@ -72,7 +98,7 @@
     var privacyItems: List<PrivacyItem> = listOf()
     private var privacyChip: OngoingPrivacyChip? = null
 
-    override val viewCreator: (context: Context) -> View = { context ->
+    override val viewCreator: ViewCreator = { context ->
         val v = LayoutInflater.from(context)
                 .inflate(R.layout.ongoing_privacy_chip, null) as OngoingPrivacyChip
         v.privacyList = privacyItems
@@ -82,7 +108,7 @@
     }
 
     override fun toString(): String {
-        return javaClass.simpleName
+        return "${javaClass.simpleName}(forceVisible=$forceVisible, privacyItems=$privacyItems)"
     }
 
     override fun shouldUpdateFromEvent(other: StatusEvent?): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
index d5a0467..b74140d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
@@ -16,18 +16,24 @@
 
 package com.android.systemui.statusbar.events
 
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.AnimatorSet
 import android.animation.ValueAnimator
 import android.content.Context
+import android.graphics.Rect
 import android.view.Gravity
 import android.view.LayoutInflater
 import android.view.View
+import android.view.View.MeasureSpec.AT_MOST
 import android.view.ViewGroup.LayoutParams.MATCH_PARENT
 import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
 import android.widget.FrameLayout
 import com.android.systemui.R
-import com.android.systemui.statusbar.phone.StatusBarLocationPublisher
+import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
 import com.android.systemui.statusbar.window.StatusBarWindowController
 import javax.inject.Inject
+import kotlin.math.roundToInt
 
 /**
  * Controls the view for system event animations.
@@ -35,105 +41,262 @@
 class SystemEventChipAnimationController @Inject constructor(
     private val context: Context,
     private val statusBarWindowController: StatusBarWindowController,
-    private val locationPublisher: StatusBarLocationPublisher
-) : SystemStatusChipAnimationCallback {
-    var showPersistentDot = false
-        set(value) {
-            field = value
-            statusBarWindowController.setForceStatusBarVisible(value)
-            maybeUpdateShowDot()
-        }
+    private val contentInsetsProvider: StatusBarContentInsetsProvider
+) : SystemStatusAnimationCallback {
 
     private lateinit var animationWindowView: FrameLayout
-    private lateinit var animationDotView: View
-    private var currentAnimatedView: View? = null
+
+    private var currentAnimatedView: BackgroundAnimatableView? = null
+
+    // Left for LTR, Right for RTL
+    private var animationDirection = LEFT
+    private var chipRight = 0
+    private var chipLeft = 0
+    private var chipWidth = 0
+    private var chipMinWidth = context.resources.getDimensionPixelSize(
+            R.dimen.ongoing_appops_chip_min_animation_width)
+    private var dotSize = context.resources.getDimensionPixelSize(
+            R.dimen.ongoing_appops_dot_diameter)
+    // Use during animation so that multiple animators can update the drawing rect
+    private var animRect = Rect()
 
     // TODO: move to dagger
     private var initialized = false
 
-    override fun onChipAnimationStart(
-        viewCreator: (context: Context) -> View,
-        @SystemAnimationState state: Int
-    ) {
-        if (!initialized) init()
+    /**
+     * Give the chip controller a chance to inflate and configure the chip view before we start
+     * animating
+     */
+    fun prepareChipAnimation(viewCreator: ViewCreator) {
+        if (!initialized) {
+            init()
+        }
+        animationDirection = if (animationWindowView.isLayoutRtl) RIGHT else LEFT
 
-        if (state == ANIMATING_IN) {
-            currentAnimatedView = viewCreator(context)
-            animationWindowView.addView(currentAnimatedView, layoutParamsDefault())
+        // Initialize the animated view
+        val insets = contentInsetsProvider.getStatusBarContentInsetsForCurrentRotation()
+        currentAnimatedView = viewCreator(context).also {
+            animationWindowView.addView(
+                    it.view,
+                    layoutParamsDefault(
+                            if (animationWindowView.isLayoutRtl) insets.first
+                            else insets.second))
+            it.view.alpha = 0f
+            // For some reason, the window view's measured width is always 0 here, so use the
+            // parent (status bar)
+            it.view.measure(
+                    View.MeasureSpec.makeMeasureSpec(
+                            (animationWindowView.parent as View).width, AT_MOST),
+                    View.MeasureSpec.makeMeasureSpec(animationWindowView.height, AT_MOST))
+            chipWidth = it.chipWidth
+        }
 
-            // We are animating IN; chip comes in from View.END
-            currentAnimatedView?.apply {
-                val translation = width.toFloat()
-                translationX = if (isLayoutRtl) -translation else translation
-                alpha = 0f
-                visibility = View.VISIBLE
-                setPadding(locationPublisher.marginLeft, 0, locationPublisher.marginRight, 0)
+        // decide which direction we're animating from, and then set some screen coordinates
+        val contentRect = contentInsetsProvider.getStatusBarContentAreaForCurrentRotation()
+        when (animationDirection) {
+            LEFT -> {
+                chipRight = contentRect.right
+                chipLeft = contentRect.right - chipWidth
             }
+            else /* RIGHT */ -> {
+                chipLeft = contentRect.left
+                chipRight = contentRect.left + chipWidth
+            }
+        }
+    }
+
+    override fun onSystemEventAnimationBegin(): Animator {
+        initializeAnimRect()
+
+        val alphaIn = ValueAnimator.ofFloat(0f, 1f).apply {
+            startDelay = 117
+            duration = 83
+            interpolator = null
+            addUpdateListener { currentAnimatedView?.view?.alpha = animatedValue as Float }
+        }
+        val moveIn = ValueAnimator.ofInt(chipMinWidth, chipWidth).apply {
+            startDelay = 117
+            duration = 383
+            interpolator = STATUS_BAR_X_MOVE_IN
+            addUpdateListener {
+                updateAnimatedViewBoundsWidth(animatedValue as Int)
+            }
+        }
+        val animSet = AnimatorSet()
+        animSet.playTogether(alphaIn, moveIn)
+        return animSet
+    }
+
+    override fun onSystemEventAnimationFinish(hasPersistentDot: Boolean): Animator {
+        initializeAnimRect()
+        val finish = if (hasPersistentDot) {
+            createMoveOutAnimationForDot()
         } else {
-            // We are animating away
-            currentAnimatedView?.apply {
-                translationX = 0f
-                alpha = 1f
-            }
+            createMoveOutAnimationDefault()
         }
+
+        finish.addListener(object : AnimatorListenerAdapter() {
+            override fun onAnimationEnd(animation: Animator?) {
+                animationWindowView.removeView(currentAnimatedView!!.view)
+            }
+        })
+
+        return finish
     }
 
-    override fun onChipAnimationEnd(@SystemAnimationState state: Int) {
-        if (state == ANIMATING_IN) {
-            // Finished animating in
-            currentAnimatedView?.apply {
-                translationX = 0f
-                alpha = 1f
+    private fun createMoveOutAnimationForDot(): Animator {
+        val width1 = ValueAnimator.ofInt(chipWidth, chipMinWidth).apply {
+            duration = 150
+            interpolator = STATUS_CHIP_WIDTH_TO_DOT_KEYFRAME_1
+            addUpdateListener {
+                updateAnimatedViewBoundsWidth(it.animatedValue as Int)
             }
-        } else {
-            // Finished animating away
-            currentAnimatedView?.apply {
-                visibility = View.INVISIBLE
-            }
-            animationWindowView.removeView(currentAnimatedView)
         }
+
+        val width2 = ValueAnimator.ofInt(chipMinWidth, dotSize).apply {
+            startDelay = 150
+            duration = 333
+            interpolator = STATUS_CHIP_WIDTH_TO_DOT_KEYFRAME_2
+            addUpdateListener {
+                updateAnimatedViewBoundsWidth(it.animatedValue as Int)
+            }
+        }
+
+        val keyFrame1Height = dotSize * 2
+        val v = currentAnimatedView!!.view
+        val chipVerticalCenter = v.top + v.measuredHeight / 2
+        val height1 = ValueAnimator.ofInt(
+                currentAnimatedView!!.view.measuredHeight, keyFrame1Height).apply {
+            startDelay = 133
+            duration = 100
+            interpolator = STATUS_CHIP_HEIGHT_TO_DOT_KEYFRAME_1
+            addUpdateListener {
+                updateAnimatedViewBoundsHeight(it.animatedValue as Int, chipVerticalCenter)
+            }
+        }
+
+        val height2 = ValueAnimator.ofInt(keyFrame1Height, dotSize).apply {
+            startDelay = 233
+            duration = 250
+            interpolator = STATUS_CHIP_HEIGHT_TO_DOT_KEYFRAME_2
+            addUpdateListener {
+                updateAnimatedViewBoundsHeight(it.animatedValue as Int, chipVerticalCenter)
+            }
+        }
+
+        // Move the chip view to overlap exactly with the privacy dot. The chip displays by default
+        // exactly adjacent to the dot, so we can just move over by the diameter of the dot itself
+        val moveOut = ValueAnimator.ofInt(0, dotSize).apply {
+            startDelay = 50
+            duration = 183
+            interpolator = STATUS_CHIP_MOVE_TO_DOT
+            addUpdateListener {
+                // If RTL, we can just invert the move
+                val amt = if (animationDirection == LEFT) {
+                        animatedValue as Int
+                } else {
+                    -(animatedValue as Int)
+                }
+                updateAnimatedBoundsX(amt)
+            }
+        }
+
+        val animSet = AnimatorSet()
+        animSet.playTogether(width1, width2, height1, height2, moveOut)
+        return animSet
     }
 
-    override fun onChipAnimationUpdate(
-        animator: ValueAnimator,
-        @SystemAnimationState state: Int
-    ) {
-        // Alpha is parameterized 0,1, and translation from (width, 0)
-        currentAnimatedView?.apply {
-            val amt = animator.animatedValue as Float
-
-            alpha = amt
-
-            val w = width
-            val translation = (1 - amt) * w
-            translationX = if (isLayoutRtl) -translation else translation
+    private fun createMoveOutAnimationDefault(): Animator {
+        val moveOut = ValueAnimator.ofInt(chipWidth, chipMinWidth).apply {
+            duration = 383
+            addUpdateListener {
+                currentAnimatedView?.apply {
+                    updateAnimatedViewBoundsWidth(it.animatedValue as Int)
+                }
+            }
         }
-    }
-
-    private fun maybeUpdateShowDot() {
-        if (!initialized) return
-        if (!showPersistentDot && currentAnimatedView == null) {
-            animationDotView.visibility = View.INVISIBLE
-        }
+        return moveOut
     }
 
     private fun init() {
         initialized = true
         animationWindowView = LayoutInflater.from(context)
                 .inflate(R.layout.system_event_animation_window, null) as FrameLayout
-        animationDotView = animationWindowView.findViewById(R.id.dot_view)
         val lp = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
         lp.gravity = Gravity.END or Gravity.CENTER_VERTICAL
         statusBarWindowController.addViewToWindow(animationWindowView, lp)
+        animationWindowView.clipToPadding = false
+        animationWindowView.clipChildren = false
     }
 
-    private fun start() = if (animationWindowView.isLayoutRtl) right() else left()
-    private fun right() = locationPublisher.marginRight
-    private fun left() = locationPublisher.marginLeft
+    private fun layoutParamsDefault(marginEnd: Int): FrameLayout.LayoutParams =
+            FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).also {
+                it.gravity = Gravity.END or Gravity.CENTER_VERTICAL
+                it.marginEnd = marginEnd
+            }
 
-    private fun layoutParamsDefault(): FrameLayout.LayoutParams =
-        FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).also {
-            it.gravity = Gravity.END or Gravity.CENTER_VERTICAL
-            it.marginStart = start()
+    private fun initializeAnimRect() = animRect.set(
+            chipLeft,
+            currentAnimatedView!!.view.top,
+            chipRight,
+            currentAnimatedView!!.view.bottom)
+
+    /**
+     * To be called during an animation, sets the width and updates the current animated chip view
+     */
+    private fun updateAnimatedViewBoundsWidth(width: Int) {
+        when (animationDirection) {
+            LEFT -> {
+                animRect.set((chipRight - width), animRect.top, chipRight, animRect.bottom)
+            } else /* RIGHT */ -> {
+                animRect.set(chipLeft, animRect.top, (chipLeft + width), animRect.bottom)
+            }
+        }
+
+        updateCurrentAnimatedView()
+    }
+
+    /**
+     * To be called during an animation, updates the animation rect and sends the update to the chip
+     */
+    private fun updateAnimatedViewBoundsHeight(height: Int, verticalCenter: Int) {
+        animRect.set(
+                animRect.left,
+                verticalCenter - (height.toFloat() / 2).roundToInt(),
+                animRect.right,
+                verticalCenter + (height.toFloat() / 2).roundToInt())
+
+        updateCurrentAnimatedView()
+    }
+
+    /**
+     * To be called during an animation, updates the animation rect offset and updates the chip
+     */
+    private fun updateAnimatedBoundsX(translation: Int) {
+        currentAnimatedView?.view?.translationX = translation.toFloat()
+    }
+
+    /**
+     * To be called during an animation. Sets the chip rect to animRect
+     */
+    private fun updateCurrentAnimatedView() {
+        currentAnimatedView?.setBoundsForAnimation(
+                animRect.left, animRect.top, animRect.right, animRect.bottom
+        )
     }
 }
+
+/**
+ * Chips should provide a view that can be animated with something better than a fade-in
+ */
+interface BackgroundAnimatableView {
+    val view: View // Since this can't extend View, add a view prop
+        get() = this as View
+    val chipWidth: Int
+        get() = view.measuredWidth
+    fun setBoundsForAnimation(l: Int, t: Int, r: Int, b: Int)
+}
+
+// Animation directions
+private const val LEFT = 1
+private const val RIGHT = 2
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt
index 04f7492..fde5d39 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt
@@ -70,11 +70,11 @@
     fun notifyPrivacyItemsChanged(showAnimation: Boolean = true) {
         val event = PrivacyEvent(showAnimation)
         event.privacyItems = privacyStateListener.currentPrivacyItems
-        event.contentDescription = {
+        event.contentDescription = run {
             val items = PrivacyChipBuilder(context, event.privacyItems).joinTypes()
             context.getString(
                     R.string.ongoing_privacy_chip_content_multiple_apps, items)
-        }()
+        }
         scheduler.onStatusEvent(event)
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
index 5a27329..36233e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
@@ -19,13 +19,11 @@
 import android.animation.Animator
 import android.animation.AnimatorListenerAdapter
 import android.animation.AnimatorSet
-import android.animation.ValueAnimator
 import android.annotation.IntDef
-import android.content.Context
 import android.os.Process
 import android.provider.DeviceConfig
 import android.util.Log
-import android.view.View
+import android.view.animation.PathInterpolator
 import com.android.systemui.Dumpable
 
 import com.android.systemui.dagger.SysUISingleton
@@ -38,6 +36,7 @@
 import com.android.systemui.util.time.SystemClock
 import java.io.FileDescriptor
 import java.io.PrintWriter
+import java.lang.IllegalStateException
 
 import javax.inject.Inject
 
@@ -45,7 +44,7 @@
  * Dead-simple scheduler for system status events. Obeys the following principles (all values TBD):
  *      - Avoiding log spam by only allowing 12 events per minute (1event/5s)
  *      - Waits 100ms to schedule any event for debouncing/prioritization
- *      - Simple prioritization: Privacy > Battery > connectivity (encoded in StatusEvent)
+ *      - Simple prioritization: Privacy > Battery > connectivity (encoded in [StatusEvent])
  *      - Only schedules a single event, and throws away lowest priority events
  *
  * There are 4 basic stages of animation at play here:
@@ -111,12 +110,15 @@
             scheduleEvent(event)
         } else if (scheduledEvent?.shouldUpdateFromEvent(event) == true) {
             if (DEBUG) {
-                Log.d(TAG, "updating current event from: $event")
+                Log.d(TAG, "updating current event from: $event. animationState=$animationState")
             }
             scheduledEvent?.updateFromEvent(event)
             if (event.forceVisible) {
                 hasPersistentDot = true
-                notifyTransitionToPersistentDot()
+                // If we missed the chance to show the persistent dot, do it now
+                if (animationState == IDLE) {
+                    notifyTransitionToPersistentDot()
+                }
             }
         } else {
             if (DEBUG) {
@@ -162,60 +164,90 @@
             return
         }
 
-        // Schedule the animation to start after a debounce period
-        cancelExecutionRunnable = executor.executeDelayed({
-            cancelExecutionRunnable = null
-            animationState = ANIMATING_IN
-            statusBarWindowController.setForceStatusBarVisible(true)
+        chipAnimationController.prepareChipAnimation(scheduledEvent!!.viewCreator)
+        animationState = ANIMATION_QUEUED
+        executor.executeDelayed({
+            runChipAnimation()
+        }, DEBOUNCE_DELAY)
+    }
 
-            val entranceAnimator = ValueAnimator.ofFloat(1f, 0f)
-            entranceAnimator.duration = ENTRANCE_ANIM_LENGTH
-            entranceAnimator.addListener(systemAnimatorAdapter)
-            entranceAnimator.addUpdateListener(systemUpdateListener)
+    /**
+     * 1. Define a total budget for the chip animation (1500ms)
+     * 2. Send out callbacks to listeners so that they can generate animations locally
+     * 3. Update the scheduler state so that clients know where we are
+     * 4. Maybe: provide scaffolding such as: dot location, margins, etc
+     * 5. Maybe: define a maximum animation length and enforce it. Probably only doable if we
+     * collect all of the animators and run them together.
+     */
+    private fun runChipAnimation() {
+        statusBarWindowController.setForceStatusBarVisible(true)
+        animationState = ANIMATING_IN
 
-            val chipAnimator = ValueAnimator.ofFloat(0f, 1f)
-            chipAnimator.duration = CHIP_ANIM_LENGTH
-            chipAnimator.addListener(
-                    ChipAnimatorAdapter(RUNNING_CHIP_ANIM, scheduledEvent!!.viewCreator))
-            chipAnimator.addUpdateListener(chipUpdateListener)
+        val animSet = collectStartAnimations()
+        if (animSet.totalDuration > 500) {
+            throw IllegalStateException("System animation total length exceeds budget. " +
+                    "Expected: 500, actual: ${animSet.totalDuration}")
+        }
+        animSet.addListener(object : AnimatorListenerAdapter() {
+            override fun onAnimationEnd(animation: Animator?) {
+                animationState = RUNNING_CHIP_ANIM
+            }
+        })
+        animSet.start()
 
-            val aSet2 = AnimatorSet()
-            aSet2.playSequentially(entranceAnimator, chipAnimator)
-            aSet2.start()
+        executor.executeDelayed({
+            val animSet2 = collectFinishAnimations()
+            animationState = ANIMATING_OUT
+            animSet2.addListener(object : AnimatorListenerAdapter() {
+                override fun onAnimationEnd(animation: Animator?) {
+                    animationState = if (hasPersistentDot) {
+                        SHOWING_PERSISTENT_DOT
+                    } else {
+                        IDLE
+                    }
 
-            executor.executeDelayed({
-                animationState = ANIMATING_OUT
-
-                val systemAnimator = ValueAnimator.ofFloat(0f, 1f)
-                systemAnimator.duration = ENTRANCE_ANIM_LENGTH
-                systemAnimator.addListener(systemAnimatorAdapter)
-                systemAnimator.addUpdateListener(systemUpdateListener)
-
-                val chipAnimator = ValueAnimator.ofFloat(1f, 0f)
-                chipAnimator.duration = CHIP_ANIM_LENGTH
-                val endState = if (hasPersistentDot) {
-                    SHOWING_PERSISTENT_DOT
-                } else {
-                    IDLE
+                    statusBarWindowController.setForceStatusBarVisible(false)
                 }
-                chipAnimator.addListener(
-                    ChipAnimatorAdapter(endState, scheduledEvent!!.viewCreator))
-                chipAnimator.addUpdateListener(chipUpdateListener)
+            })
+            animSet2.start()
+            scheduledEvent = null
+        }, DISPLAY_LENGTH)
+    }
 
-                val aSet2 = AnimatorSet()
+    private fun collectStartAnimations(): AnimatorSet {
+        val animators = mutableListOf<Animator>()
+        listeners.forEach { listener ->
+            listener.onSystemEventAnimationBegin()?.let { anim ->
+                animators.add(anim)
+            }
+        }
+        animators.add(chipAnimationController.onSystemEventAnimationBegin())
+        val animSet = AnimatorSet().also {
+            it.playTogether(animators)
+        }
 
-                aSet2.play(chipAnimator).before(systemAnimator)
-                if (hasPersistentDot) {
-                    val dotAnim = notifyTransitionToPersistentDot()
-                    if (dotAnim != null) aSet2.playTogether(systemAnimator, dotAnim)
-                }
+        return animSet
+    }
 
-                aSet2.start()
+    private fun collectFinishAnimations(): AnimatorSet {
+        val animators = mutableListOf<Animator>()
+        listeners.forEach { listener ->
+            listener.onSystemEventAnimationFinish(hasPersistentDot)?.let { anim ->
+                animators.add(anim)
+            }
+        }
+        animators.add(chipAnimationController.onSystemEventAnimationFinish(hasPersistentDot))
+        if (hasPersistentDot) {
+            val dotAnim = notifyTransitionToPersistentDot()
+            if (dotAnim != null) {
+                animators.add(dotAnim)
+            }
+        }
+        val animSet = AnimatorSet().also {
+            it.playTogether(animators)
+        }
 
-                statusBarWindowController.setForceStatusBarVisible(false)
-                scheduledEvent = null
-            }, DISPLAY_LENGTH)
-        }, DELAY)
+        return animSet
     }
 
     private fun notifyTransitionToPersistentDot(): Animator? {
@@ -249,18 +281,6 @@
         return null
     }
 
-    private fun notifySystemStart() {
-        listeners.forEach { it.onSystemChromeAnimationStart() }
-    }
-
-    private fun notifySystemFinish() {
-        listeners.forEach { it.onSystemChromeAnimationEnd() }
-    }
-
-    private fun notifySystemAnimationUpdate(anim: ValueAnimator) {
-        listeners.forEach { it.onSystemChromeAnimationUpdate(anim) }
-    }
-
     override fun addCallback(listener: SystemStatusAnimationCallback) {
         Assert.isMainThread()
 
@@ -279,24 +299,6 @@
         }
     }
 
-    private val systemUpdateListener = ValueAnimator.AnimatorUpdateListener {
-        anim -> notifySystemAnimationUpdate(anim)
-    }
-
-    private val systemAnimatorAdapter = object : AnimatorListenerAdapter() {
-        override fun onAnimationEnd(p0: Animator?) {
-            notifySystemFinish()
-        }
-
-        override fun onAnimationStart(p0: Animator?) {
-            notifySystemStart()
-        }
-    }
-
-    private val chipUpdateListener = ValueAnimator.AnimatorUpdateListener {
-        anim -> chipAnimationController.onChipAnimationUpdate(anim, animationState)
-    }
-
     override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
         pw.println("Scheduled event: $scheduledEvent")
         pw.println("Has persistent privacy dot: $hasPersistentDot")
@@ -310,24 +312,6 @@
             }
         }
     }
-
-    inner class ChipAnimatorAdapter(
-        @SystemAnimationState val endState: Int,
-        val viewCreator: (context: Context) -> View
-    ) : AnimatorListenerAdapter() {
-        override fun onAnimationEnd(p0: Animator?) {
-            chipAnimationController.onChipAnimationEnd(animationState)
-            animationState = if (endState == SHOWING_PERSISTENT_DOT && !hasPersistentDot) {
-                IDLE
-            } else {
-                endState
-            }
-        }
-
-        override fun onAnimationStart(p0: Animator?) {
-            chipAnimationController.onChipAnimationStart(viewCreator, animationState)
-        }
-    }
 }
 
 /**
@@ -336,16 +320,14 @@
  * create space for the chip animation to display. This means hiding the system elements in the
  * status bar and keyguard.
  *
- * TODO: the chip animation really only has one client, we can probably remove it from this
- * interface
- *
  * The value animators themselves are simple animators from 0.0 to 1.0. Listeners can apply any
  * interpolation they choose but realistically these are most likely to be simple alpha transitions
  */
 interface SystemStatusAnimationCallback {
-    @JvmDefault fun onSystemChromeAnimationUpdate(animator: ValueAnimator) {}
-    @JvmDefault fun onSystemChromeAnimationStart() {}
-    @JvmDefault fun onSystemChromeAnimationEnd() {}
+    /** Implement this method to return an [Animator] or [AnimatorSet] that presents the chip */
+    fun onSystemEventAnimationBegin(): Animator? { return null }
+    /** Implement this method to return an [Animator] or [AnimatorSet] that hides the chip */
+    fun onSystemEventAnimationFinish(hasPersistentDot: Boolean): Animator? { return null }
 
     // Best method name, change my mind
     @JvmDefault
@@ -355,50 +337,61 @@
     @JvmDefault fun onHidePersistentDot(): Animator? { return null }
 }
 
-interface SystemStatusChipAnimationCallback {
-    fun onChipAnimationUpdate(animator: ValueAnimator, @SystemAnimationState state: Int) {}
-
-    fun onChipAnimationStart(
-        viewCreator: (context: Context) -> View,
-        @SystemAnimationState state: Int
-    ) {}
-
-    fun onChipAnimationEnd(@SystemAnimationState state: Int) {}
-}
-
 /**
+ * Animation state IntDef
  */
 @Retention(AnnotationRetention.SOURCE)
 @IntDef(
         value = [
-            IDLE, ANIMATING_IN, RUNNING_CHIP_ANIM, ANIMATING_OUT
+            IDLE,
+            ANIMATION_QUEUED,
+            ANIMATING_IN,
+            RUNNING_CHIP_ANIM,
+            ANIMATING_OUT,
+            SHOWING_PERSISTENT_DOT
         ]
 )
 annotation class SystemAnimationState
 
 /** No animation is in progress */
 const val IDLE = 0
+/** An animation is queued, and awaiting the debounce period */
+const val ANIMATION_QUEUED = 1
 /** System is animating out, and chip is animating in */
-const val ANIMATING_IN = 1
+const val ANIMATING_IN = 2
 /** Chip has animated in and is awaiting exit animation, and optionally playing its own animation */
-const val RUNNING_CHIP_ANIM = 2
+const val RUNNING_CHIP_ANIM = 3
 /** Chip is animating away and system is animating back */
-const val ANIMATING_OUT = 3
+const val ANIMATING_OUT = 4
 /** Chip has animated away, and the persistent dot is showing */
-const val SHOWING_PERSISTENT_DOT = 4
+const val SHOWING_PERSISTENT_DOT = 5
+
+/** Commonly-needed interpolators can go here */
+@JvmField val STATUS_BAR_X_MOVE_OUT = PathInterpolator(0.33f, 0f, 0f, 1f)
+@JvmField val STATUS_BAR_X_MOVE_IN = PathInterpolator(0f, 0f, 0f, 1f)
+/**
+ * Status chip animation to dot have multiple stages of motion, the _1 and _2 interpolators should
+ * be used in succession
+ */
+val STATUS_CHIP_WIDTH_TO_DOT_KEYFRAME_1 = PathInterpolator(0.44f, 0f, 0.25f, 1f)
+val STATUS_CHIP_WIDTH_TO_DOT_KEYFRAME_2 = PathInterpolator(0.3f, 0f, 0.26f, 1f)
+val STATUS_CHIP_HEIGHT_TO_DOT_KEYFRAME_1 = PathInterpolator(0.4f, 0f, 0.17f, 1f)
+val STATUS_CHIP_HEIGHT_TO_DOT_KEYFRAME_2 = PathInterpolator(0.3f, 0f, 0f, 1f)
+val STATUS_CHIP_MOVE_TO_DOT = PathInterpolator(0f, 0f, 0.05f, 1f)
 
 private const val TAG = "SystemStatusAnimationScheduler"
-private const val DELAY = 0L
+private const val DEBOUNCE_DELAY = 100L
 
 /**
- * The total time spent animation should be 1500ms. The entrance animation is how much time
- * we give to the system to animate system elements out of the way. Total chip animation length
- * will be equivalent to 2*chip_anim_length + display_length
+ * The total time spent on the chip animation is 1500ms, broken up into 3 sections:
+ *   - 500ms to animate the chip in (including animating system icons away)
+ *   - 500ms holding the chip on screen
+ *   - 500ms to animate the chip away (and system icons back)
+ *
+ *   So DISPLAY_LENGTH should be the sum of the first 2 phases, while the final 500ms accounts for
+ *   the actual animation
  */
-private const val ENTRANCE_ANIM_LENGTH = 250L
-private const val CHIP_ANIM_LENGTH = 250L
-// 1s + entrance time + chip anim_length
-private const val DISPLAY_LENGTH = 1500L
+private const val DISPLAY_LENGTH = 1000L
 
 private const val MIN_UPTIME: Long = 5 * 1000
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
index 5b7d90b..df412ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
@@ -16,11 +16,9 @@
 
 package com.android.systemui.statusbar.notification;
 
-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_SPLIT_SCREEN_PRIMARY;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -182,25 +180,6 @@
     }
 
     /**
-     * Posts an instant app notification if the top activity of the primary container in the
-     * splitted screen is an instant app and the corresponding instant app notification is not
-     * posted yet. If the notification already exists, this method removes it from {@code
-     * notifs} in the arguments.
-     */
-    private void checkAndPostForPrimaryScreen(
-            @NonNull ArraySet<Pair<String, Integer>> notifs,
-            @NonNull NotificationManager noMan,
-            @NonNull IPackageManager pm) {
-        try {
-            final RootTaskInfo info = ActivityTaskManager.getService().getRootTaskInfo(
-                    WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED);
-            checkAndPostForStack(info, notifs, noMan, pm);
-        } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Posts an instant app notification if the top activity of the given stack is an instant app
      * and the corresponding instant app notification is not posted yet. If the notification already
      * exists, this method removes it from {@code notifs} in the arguments.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
index 2c1296f..02aa1f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
@@ -22,15 +22,18 @@
     private val headsUpManager: HeadsUpManagerPhone,
     private val jankMonitor: InteractionJankMonitor
 ) {
+    @JvmOverloads
     fun getAnimatorController(
-        notification: ExpandableNotificationRow
+        notification: ExpandableNotificationRow,
+        onFinishAnimationCallback: Runnable? = null
     ): NotificationLaunchAnimatorController {
         return NotificationLaunchAnimatorController(
             notificationShadeWindowViewController,
             notificationListContainer,
             headsUpManager,
             notification,
-            jankMonitor
+            jankMonitor,
+            onFinishAnimationCallback
         )
     }
 }
@@ -45,7 +48,8 @@
     private val notificationListContainer: NotificationListContainer,
     private val headsUpManager: HeadsUpManagerPhone,
     private val notification: ExpandableNotificationRow,
-    private val jankMonitor: InteractionJankMonitor
+    private val jankMonitor: InteractionJankMonitor,
+    private val onFinishAnimationCallback: Runnable?
 ) : ActivityLaunchAnimator.Controller {
 
     companion object {
@@ -119,6 +123,7 @@
 
         if (!willAnimate) {
             removeHun(animate = true)
+            onFinishAnimationCallback?.run()
         }
     }
 
@@ -137,6 +142,7 @@
         notificationShadeWindowViewController.setExpandAnimationRunning(false)
         notificationEntry.isExpandAnimationRunning = false
         removeHun(animate = true)
+        onFinishAnimationCallback?.run()
     }
 
     override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
@@ -156,6 +162,7 @@
         notificationListContainer.setExpandingNotification(null)
         applyParams(null)
         removeHun(animate = false)
+        onFinishAnimationCallback?.run()
     }
 
     private fun applyParams(params: ExpandAnimationParameters?) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index 369ef34..477db3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -230,7 +230,13 @@
         mPipelineState.requireState(STATE_IDLE);
 
         mNotifSections.clear();
+        NotifSectioner lastSection = null;
         for (NotifSectioner sectioner : sectioners) {
+            if (lastSection != null && lastSection.getBucket() > sectioner.getBucket()) {
+                throw new IllegalArgumentException("setSectioners with non contiguous sections "
+                        + lastSection.getName() + " - " + lastSection.getBucket() + " & "
+                        + sectioner.getName() + " - " + sectioner.getBucket());
+            }
             final NotifSection section = new NotifSection(sectioner, mNotifSections.size());
             final NotifComparator sectionComparator = section.getComparator();
             mNotifSections.add(section);
@@ -238,6 +244,7 @@
             if (sectionComparator != null) {
                 sectionComparator.setInvalidationListener(this::onNotifComparatorInvalidated);
             }
+            lastSection = sectioner;
         }
 
         mNotifSections.add(new NotifSection(DEFAULT_SECTIONER, mNotifSections.size()));
@@ -634,28 +641,37 @@
      * Returns true if the group change was suppressed, else false
      */
     private boolean maybeSuppressGroupChange(NotificationEntry entry, List<ListEntry> out) {
-        if (!entry.wasAttachedInPreviousPass()) {
-            return false; // new entries are allowed
-        }
-
         final GroupEntry prevParent = entry.getPreviousAttachState().getParent();
+        if (prevParent == null) {
+            // New entries are always allowed.
+            return false;
+        }
         final GroupEntry assignedParent = entry.getParent();
-        if (prevParent != assignedParent
-                && !getStabilityManager().isGroupChangeAllowed(entry.getRepresentativeEntry())) {
+        if (prevParent == assignedParent) {
+            // Nothing to change.
+            return false;
+        }
+        if (prevParent != ROOT_ENTRY && prevParent.getParent() == null) {
+            // Previous parent was a group, which has been removed (hence, its parent is null).
+            // Always allow this group change, otherwise the child will remain attached to the
+            // removed group and be removed from the shade until visual stability ends.
+            return false;
+        }
+        // TODO: Rather than perform "half" of the move here and require the caller remove the child
+        //  from the assignedParent, ideally we would have an atomic "move" operation.
+        if (!getStabilityManager().isGroupChangeAllowed(entry.getRepresentativeEntry())) {
             entry.getAttachState().getSuppressedChanges().setParent(assignedParent);
             entry.setParent(prevParent);
             if (prevParent == ROOT_ENTRY) {
                 out.add(entry);
-            } else if (prevParent != null) {
+            } else {
                 prevParent.addChild(entry);
                 if (!mGroups.containsKey(prevParent.getKey())) {
                     mGroups.put(prevParent.getKey(), prevParent);
                 }
             }
-
             return true;
         }
-
         return false;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
index 0df2162..da0169b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
@@ -72,10 +72,11 @@
     private var mEndLifetimeExtension: OnEndLifetimeExtensionCallback? = null
     private lateinit var mNotifPipeline: NotifPipeline
     private var mNow: Long = -1
-    // notifs we've extended the lifetime for
-    private val mNotifsExtendingLifetime = ArraySet<NotificationEntry>()
     private val mPostedEntries = LinkedHashMap<String, PostedEntry>()
 
+    // notifs we've extended the lifetime for with cancellation callbacks
+    private val mNotifsExtendingLifetime = ArrayMap<NotificationEntry, Runnable?>()
+
     override fun attach(pipeline: NotifPipeline) {
         mNotifPipeline = pipeline
         mHeadsUpManager.addListener(mOnHeadsUpChangedListener)
@@ -460,23 +461,20 @@
             }
             if (isSticky(entry)) {
                 val removeAfterMillis = mHeadsUpManager.getEarliestRemovalTime(entry.key)
-                mExecutor.executeDelayed({
-                    val canStillRemove = mHeadsUpManager.canRemoveImmediately(entry.key)
-                    if (mNotifsExtendingLifetime.contains(entry) && canStillRemove) {
-                        mHeadsUpManager.removeNotification(entry.key, /* releaseImmediately */ true)
-                    }
+                mNotifsExtendingLifetime[entry] = mExecutor.executeDelayed({
+                    mHeadsUpManager.removeNotification(entry.key, /* releaseImmediately */ true)
                 }, removeAfterMillis)
             } else {
                 mExecutor.execute {
                     mHeadsUpManager.removeNotification(entry.key, /* releaseImmediately */ false)
                 }
+                mNotifsExtendingLifetime[entry] = null
             }
-            mNotifsExtendingLifetime.add(entry)
             return true
         }
 
         override fun cancelLifetimeExtension(entry: NotificationEntry) {
-            mNotifsExtendingLifetime.remove(entry)
+            mNotifsExtendingLifetime.remove(entry)?.run()
         }
     }
 
@@ -543,7 +541,8 @@
         mPostedEntries[entry.key]?.calculateShouldBeHeadsUpStrict ?: isAttemptingToShowHun(entry)
 
     private fun endNotifLifetimeExtensionIfExtended(entry: NotificationEntry) {
-        if (mNotifsExtendingLifetime.remove(entry)) {
+        if (mNotifsExtendingLifetime.contains(entry)) {
+            mNotifsExtendingLifetime.remove(entry)?.run()
             mEndLifetimeExtension?.onEndLifetimeExtension(mLifetimeExtender, entry)
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
index 22300d8..aac5b8d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -16,36 +16,16 @@
 
 package com.android.systemui.statusbar.notification.collection.coordinator;
 
-import static android.app.Notification.VISIBILITY_SECRET;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.service.notification.StatusBarNotification;
-
-import androidx.annotation.MainThread;
-
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.SectionHeaderVisibilityProvider;
-import com.android.systemui.statusbar.notification.collection.GroupEntry;
-import com.android.systemui.statusbar.notification.collection.ListEntry;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
 
 import javax.inject.Inject;
 
@@ -56,171 +36,48 @@
 @CoordinatorScope
 public class KeyguardCoordinator implements Coordinator {
     private static final String TAG = "KeyguardCoordinator";
-
-    private final Context mContext;
-    private final Handler mMainHandler;
-    private final KeyguardStateController mKeyguardStateController;
-    private final NotificationLockscreenUserManager mLockscreenUserManager;
-    private final BroadcastDispatcher mBroadcastDispatcher;
     private final StatusBarStateController mStatusBarStateController;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final HighPriorityProvider mHighPriorityProvider;
     private final SectionHeaderVisibilityProvider mSectionHeaderVisibilityProvider;
-
-    private boolean mHideSilentNotificationsOnLockscreen;
+    private final KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
 
     @Inject
     public KeyguardCoordinator(
-            Context context,
-            @MainThread Handler mainThreadHandler,
-            KeyguardStateController keyguardStateController,
-            NotificationLockscreenUserManager lockscreenUserManager,
-            BroadcastDispatcher broadcastDispatcher,
             StatusBarStateController statusBarStateController,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             HighPriorityProvider highPriorityProvider,
-            SectionHeaderVisibilityProvider sectionHeaderVisibilityProvider) {
-        mContext = context;
-        mMainHandler = mainThreadHandler;
-        mKeyguardStateController = keyguardStateController;
-        mLockscreenUserManager = lockscreenUserManager;
-        mBroadcastDispatcher = broadcastDispatcher;
+            SectionHeaderVisibilityProvider sectionHeaderVisibilityProvider,
+            KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider) {
         mStatusBarStateController = statusBarStateController;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mHighPriorityProvider = highPriorityProvider;
         mSectionHeaderVisibilityProvider = sectionHeaderVisibilityProvider;
+        mKeyguardNotificationVisibilityProvider = keyguardNotificationVisibilityProvider;
     }
 
     @Override
     public void attach(NotifPipeline pipeline) {
-        readShowSilentNotificationSetting();
 
         setupInvalidateNotifListCallbacks();
         // Filter at the "finalize" stage so that views remain bound by PreparationCoordinator
         pipeline.addFinalizeFilter(mNotifFilter);
-
+        mKeyguardNotificationVisibilityProvider
+                .addOnStateChangedListener(this::invalidateListFromFilter);
         updateSectionHeadersVisibility();
     }
 
     private final NotifFilter mNotifFilter = new NotifFilter(TAG) {
         @Override
         public boolean shouldFilterOut(NotificationEntry entry, long now) {
-            final StatusBarNotification sbn = entry.getSbn();
-
-            // FILTER OUT the notification when the keyguard is showing and...
-            if (mKeyguardStateController.isShowing()) {
-                // ... user settings or the device policy manager doesn't allow lockscreen
-                // notifications;
-                if (!mLockscreenUserManager.shouldShowLockscreenNotifications()) {
-                    return true;
-                }
-
-                final int currUserId = mLockscreenUserManager.getCurrentUserId();
-                final int notifUserId = (sbn.getUser().getIdentifier() == UserHandle.USER_ALL)
-                        ? currUserId : sbn.getUser().getIdentifier();
-
-                // ... user is in lockdown
-                if (mKeyguardUpdateMonitor.isUserInLockdown(currUserId)
-                        || mKeyguardUpdateMonitor.isUserInLockdown(notifUserId)) {
-                    return true;
-                }
-
-                // ... device is in public mode and the user's settings doesn't allow
-                // notifications to show in public mode
-                if (mLockscreenUserManager.isLockscreenPublicMode(currUserId)
-                        || mLockscreenUserManager.isLockscreenPublicMode(notifUserId)) {
-                    if (entry.getRanking().getLockscreenVisibilityOverride() == VISIBILITY_SECRET) {
-                        return true;
-                    }
-
-                    if (!mLockscreenUserManager.userAllowsNotificationsInPublic(currUserId)
-                            || !mLockscreenUserManager.userAllowsNotificationsInPublic(
-                            notifUserId)) {
-                        return true;
-                    }
-                }
-
-                // ... neither this notification nor its group have high enough priority
-                // to be shown on the lockscreen
-                if (entry.getParent() != null) {
-                    final GroupEntry parent = entry.getParent();
-                    if (priorityExceedsLockscreenShowingThreshold(parent)) {
-                        return false;
-                    }
-                }
-                return !priorityExceedsLockscreenShowingThreshold(entry);
-            }
-            return false;
+            return mKeyguardNotificationVisibilityProvider.shouldHideNotification(entry);
         }
     };
 
-    private boolean priorityExceedsLockscreenShowingThreshold(ListEntry entry) {
-        if (entry == null) {
-            return false;
-        }
-        if (mHideSilentNotificationsOnLockscreen) {
-            return mHighPriorityProvider.isHighPriority(entry);
-        } else {
-            return entry.getRepresentativeEntry() != null
-                    && !entry.getRepresentativeEntry().getRanking().isAmbient();
-        }
-    }
-
     // TODO(b/206118999): merge this class with SensitiveContentCoordinator which also depends on
     // these same updates
     private void setupInvalidateNotifListCallbacks() {
-        // register onKeyguardShowing callback
-        mKeyguardStateController.addCallback(mKeyguardCallback);
-        mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
 
-        // register lockscreen settings changed callbacks:
-        final ContentObserver settingsObserver = new ContentObserver(mMainHandler) {
-            @Override
-            public void onChange(boolean selfChange, Uri uri) {
-                if (uri.equals(Settings.Secure.getUriFor(
-                        Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS))) {
-                    readShowSilentNotificationSetting();
-                }
-
-                if (mKeyguardStateController.isShowing()) {
-                    invalidateListFromFilter("Settings " + uri + " changed");
-                }
-            }
-        };
-
-        mContext.getContentResolver().registerContentObserver(
-                Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS),
-                false,
-                settingsObserver,
-                UserHandle.USER_ALL);
-
-        mContext.getContentResolver().registerContentObserver(
-                Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
-                true,
-                settingsObserver,
-                UserHandle.USER_ALL);
-
-        mContext.getContentResolver().registerContentObserver(
-                Settings.Global.getUriFor(Settings.Global.ZEN_MODE),
-                false,
-                settingsObserver);
-
-        mContext.getContentResolver().registerContentObserver(
-                Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS),
-                false,
-                settingsObserver,
-                UserHandle.USER_ALL);
-
-        // register (maybe) public mode changed callbacks:
-        mStatusBarStateController.addCallback(mStatusBarStateListener);
-        mBroadcastDispatcher.registerReceiver(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                if (mKeyguardStateController.isShowing()) {
-                    // maybe public mode changed
-                    invalidateListFromFilter(intent.getAction());
-                }
-            }}, new IntentFilter(Intent.ACTION_USER_SWITCHED));
     }
 
     private void invalidateListFromFilter(String reason) {
@@ -228,49 +85,10 @@
         mNotifFilter.invalidateList();
     }
 
-    private void readShowSilentNotificationSetting() {
-        mHideSilentNotificationsOnLockscreen =
-                Settings.Secure.getInt(
-                        mContext.getContentResolver(),
-                        Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS,
-                        1) == 0;
-    }
-
     private void updateSectionHeadersVisibility() {
         boolean onKeyguard = mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
         boolean neverShowSections = mSectionHeaderVisibilityProvider.getNeverShowSectionHeaders();
         boolean showSections = !onKeyguard && !neverShowSections;
         mSectionHeaderVisibilityProvider.setSectionHeadersVisible(showSections);
     }
-
-    private final KeyguardStateController.Callback mKeyguardCallback =
-            new KeyguardStateController.Callback() {
-        @Override
-        public void onUnlockedChanged() {
-            invalidateListFromFilter("onUnlockedChanged");
-        }
-
-        @Override
-        public void onKeyguardShowingChanged() {
-            invalidateListFromFilter("onKeyguardShowingChanged");
-        }
-    };
-
-    private final StatusBarStateController.StateListener mStatusBarStateListener =
-            new StatusBarStateController.StateListener() {
-                @Override
-                public void onStateChanged(int newState) {
-                    // maybe public mode changed
-                    invalidateListFromFilter("onStatusBarStateChanged");
-                }
-    };
-
-    private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
-            new KeyguardUpdateMonitorCallback() {
-        @Override
-        public void onStrongAuthStateChanged(int userId) {
-            // maybe lockdown mode changed
-            invalidateListFromFilter("onStrongAuthStateChanged");
-        }
-    };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
index 08b2483..31a13e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
@@ -19,8 +19,8 @@
 import com.android.internal.widget.MessagingGroup
 import com.android.internal.widget.MessagingMessage
 import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
 import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener
-import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl
 import com.android.systemui.statusbar.notification.collection.NotifPipeline
 import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager
@@ -35,7 +35,7 @@
 @CoordinatorScope
 class ViewConfigCoordinator @Inject internal constructor(
     private val mConfigurationController: ConfigurationController,
-    private val mLockscreenUserManager: NotificationLockscreenUserManagerImpl,
+    private val mLockscreenUserManager: NotificationLockscreenUserManager,
     private val mGutsManager: NotificationGutsManager,
     private val mKeyguardUpdateMonitor: KeyguardUpdateMonitor
 ) : Coordinator, UserChangedListener, ConfigurationController.ConfigurationListener {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
index 699c4e7..acc493d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
@@ -254,10 +254,14 @@
 
     @Override
     public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+        pw.println("pipelineRunAllowed: " + mPipelineRunAllowed);
+        pw.println("  notifPanelCollapsing: " + mNotifPanelCollapsing);
+        pw.println("  launchingNotifActivity: " + mNotifPanelLaunchingActivity);
         pw.println("reorderingAllowed: " + mReorderingAllowed);
         pw.println("  screenOn: " + mScreenOn);
         pw.println("  panelExpanded: " + mPanelExpanded);
         pw.println("  pulsing: " + mPulsing);
+        pw.println("isSuppressingPipelineRun: " + mIsSuppressingPipelineRun);
         pw.println("isSuppressingGroupChange: " + mIsSuppressingGroupChange);
         pw.println("isSuppressingEntryReorder: " + mIsSuppressingEntryReorder);
         pw.println("entriesWithSuppressedSectionChange: "
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
index cd2affe..7c4e449 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
@@ -73,7 +73,7 @@
         GroupExpansionManager,
         Dumpable {
 
-    private static final String TAG = "NotifGroupManager";
+    private static final String TAG = "LegacyNotifGroupManager";
     private static final boolean DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG);
     private static final boolean SPEW = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE);
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
index c35b77c..6db544c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
@@ -57,6 +57,7 @@
 
         var currentSection: NotifSection? = null
         val prevSections = mutableSetOf<NotifSection?>()
+        var lastSection: NotifSection? = null
         val showHeaders = sectionHeaderVisibilityProvider.sectionHeadersVisible
         val sectionOrder = mutableListOf<NotifSection?>()
         val sectionHeaders = mutableMapOf<NotifSection?, NodeController?>()
@@ -65,6 +66,14 @@
         for (entry in notifList) {
             val section = entry.section!!
 
+            lastSection?.let {
+                if (it.bucket > section.bucket) {
+                    throw IllegalStateException("buildNodeSpec with non contiguous section " +
+                            "buckets ${it.sectioner.name} - ${it.bucket} & " +
+                            "${it.sectioner.name} - ${it.bucket}")
+                }
+            }
+            lastSection = section
             if (prevSections.contains(section)) {
                 throw java.lang.RuntimeException("Section ${section.label} has been duplicated")
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
index 386e2d3..032e678 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
@@ -18,7 +18,6 @@
 
 import android.annotation.MainThread
 import android.view.View
-import com.android.systemui.util.kotlin.transform
 import com.android.systemui.util.traceSection
 
 /**
@@ -41,7 +40,6 @@
 ) {
     private val rootNode = ShadeNode(rootController)
     private val nodes = mutableMapOf(rootController to rootNode)
-    private val views = mutableMapOf<View, ShadeNode>()
 
     /**
      * Adds and removes views from the root (and its children) until their structure matches the
@@ -66,26 +64,25 @@
      *
      * For debugging purposes.
      */
-    fun getViewLabel(view: View): String = views[view]?.label ?: view.toString()
+    fun getViewLabel(view: View): String =
+            nodes.values.firstOrNull { node -> node.view === view }?.label ?: view.toString()
 
-    private fun detachChildren(
-        parentNode: ShadeNode,
-        specMap: Map<NodeController, NodeSpec>
-    ) {
-        val parentSpec = specMap[parentNode.controller]
-
-        for (i in parentNode.getChildCount() - 1 downTo 0) {
-            val childView = parentNode.getChildAt(i)
-            views[childView]?.let { childNode ->
-                val childSpec = specMap[childNode.controller]
-
-                maybeDetachChild(parentNode, parentSpec, childNode, childSpec)
-
-                if (childNode.controller.getChildCount() > 0) {
-                    detachChildren(childNode, specMap)
+    private fun detachChildren(parentNode: ShadeNode, specMap: Map<NodeController, NodeSpec>) {
+        val views = nodes.values.asSequence().map { node -> node.view to node }.toMap()
+        fun detachRecursively(parentNode: ShadeNode, specMap: Map<NodeController, NodeSpec>) {
+            val parentSpec = specMap[parentNode.controller]
+            for (i in parentNode.getChildCount() - 1 downTo 0) {
+                val childView = parentNode.getChildAt(i)
+                views[childView]?.let { childNode ->
+                    val childSpec = specMap[childNode.controller]
+                    maybeDetachChild(parentNode, parentSpec, childNode, childSpec)
+                    if (childNode.controller.getChildCount() > 0) {
+                        detachRecursively(childNode, specMap)
+                    }
                 }
             }
         }
+        detachRecursively(parentNode, specMap)
     }
 
     private fun maybeDetachChild(
@@ -94,14 +91,13 @@
         childNode: ShadeNode,
         childSpec: NodeSpec?
     ) {
-        val newParentNode = transform(childSpec?.parent) { getNode(it) }
+        val newParentNode = childSpec?.parent?.let { getNode(it) }
 
         if (newParentNode != parentNode) {
             val childCompletelyRemoved = newParentNode == null
 
             if (childCompletelyRemoved) {
                 nodes.remove(childNode.controller)
-                views.remove(childNode.controller.view)
             }
 
             logger.logDetachingChild(
@@ -115,10 +111,7 @@
         }
     }
 
-    private fun attachChildren(
-        parentNode: ShadeNode,
-        specMap: Map<NodeController, NodeSpec>
-    ) {
+    private fun attachChildren(parentNode: ShadeNode, specMap: Map<NodeController, NodeSpec>) {
         val parentSpec = checkNotNull(specMap[parentNode.controller])
 
         for ((index, childSpec) in parentSpec.children.withIndex()) {
@@ -160,7 +153,6 @@
         if (node == null) {
             node = ShadeNode(spec.controller)
             nodes[node.controller] = node
-            views[node.view] = node
         }
         return node
     }
@@ -194,10 +186,9 @@
 
 private class DuplicateNodeException(message: String) : RuntimeException(message)
 
-private class ShadeNode(
-    val controller: NodeController
-) {
-    val view = controller.view
+private class ShadeNode(val controller: NodeController) {
+    val view: View
+        get() = controller.view
 
     var parent: ShadeNode? = null
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index efe88e6..34c8044 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -73,6 +73,7 @@
 import com.android.systemui.statusbar.notification.init.NotificationsController;
 import com.android.systemui.statusbar.notification.init.NotificationsControllerImpl;
 import com.android.systemui.statusbar.notification.init.NotificationsControllerStub;
+import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProviderModule;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
@@ -107,9 +108,10 @@
  */
 @Module(includes = {
         CoordinatorsModule.class,
+        KeyguardNotificationVisibilityProviderModule.class,
         NotifActivityLaunchEventsModule.class,
-        NotifPipelineChoreographerModule.class,
         NotifPanelEventsModule.class,
+        NotifPipelineChoreographerModule.class,
         NotificationSectionHeadersModule.class,
 })
 public interface NotificationsModule {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt
new file mode 100644
index 0000000..e436ccf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt
@@ -0,0 +1,206 @@
+package com.android.systemui.statusbar.notification.interruption
+
+import android.app.Notification
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.database.ContentObserver
+import android.net.Uri
+import android.os.Handler
+import android.os.UserHandle
+import android.provider.Settings
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.systemui.CoreStartable
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.ListenerSet
+import com.android.systemui.util.settings.GlobalSettings
+import com.android.systemui.util.settings.SecureSettings
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+import java.util.function.Consumer
+import javax.inject.Inject
+
+/** Determines if notifications should be visible based on the state of the keyguard. */
+interface KeyguardNotificationVisibilityProvider {
+    /**
+     * Determines if the given notification should be hidden based on the current keyguard state.
+     * If a [Consumer] registered via [addOnStateChangedListener] is invoked, the results of this
+     * method may no longer be valid and should be re-queried.
+     */
+    fun shouldHideNotification(entry: NotificationEntry): Boolean
+
+    /** Registers a listener to be notified when the internal keyguard state has been updated. */
+    fun addOnStateChangedListener(listener: Consumer<String>)
+
+    /** Unregisters a listener previously registered with [addOnStateChangedListener]. */
+    fun removeOnStateChangedListener(listener: Consumer<String>)
+}
+
+/** Provides a [KeyguardNotificationVisibilityProvider] in [SysUISingleton] scope. */
+@Module(includes = [KeyguardNotificationVisibilityProviderImplModule::class])
+object KeyguardNotificationVisibilityProviderModule
+
+@Module
+private interface KeyguardNotificationVisibilityProviderImplModule {
+    @Binds
+    fun bindImpl(impl: KeyguardNotificationVisibilityProviderImpl):
+            KeyguardNotificationVisibilityProvider
+
+    @Binds
+    @IntoMap
+    @ClassKey(KeyguardNotificationVisibilityProvider::class)
+    fun bindStartable(impl: KeyguardNotificationVisibilityProviderImpl): CoreStartable
+}
+
+@SysUISingleton
+private class KeyguardNotificationVisibilityProviderImpl @Inject constructor(
+    context: Context,
+    @Main private val handler: Handler,
+    private val keyguardStateController: KeyguardStateController,
+    private val lockscreenUserManager: NotificationLockscreenUserManager,
+    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+    private val highPriorityProvider: HighPriorityProvider,
+    private val statusBarStateController: StatusBarStateController,
+    private val broadcastDispatcher: BroadcastDispatcher,
+    private val secureSettings: SecureSettings,
+    private val globalSettings: GlobalSettings
+) : CoreStartable(context), KeyguardNotificationVisibilityProvider {
+    private val showSilentNotifsUri =
+            secureSettings.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS)
+    private val onStateChangedListeners = ListenerSet<Consumer<String>>()
+    private var hideSilentNotificationsOnLockscreen: Boolean = false
+
+    override fun start() {
+        readShowSilentNotificationSetting()
+        keyguardStateController.addCallback(object : KeyguardStateController.Callback {
+            override fun onUnlockedChanged() {
+                notifyStateChanged("onUnlockedChanged")
+            }
+
+            override fun onKeyguardShowingChanged() {
+                notifyStateChanged("onKeyguardShowingChanged")
+            }
+        })
+        keyguardUpdateMonitor.registerCallback(object : KeyguardUpdateMonitorCallback() {
+            override fun onStrongAuthStateChanged(userId: Int) {
+                notifyStateChanged("onStrongAuthStateChanged")
+            }
+        })
+
+        // register lockscreen settings changed callbacks:
+        val settingsObserver: ContentObserver = object : ContentObserver(handler) {
+            override fun onChange(selfChange: Boolean, uri: Uri?) {
+                if (uri == showSilentNotifsUri) {
+                    readShowSilentNotificationSetting()
+                }
+                if (keyguardStateController.isShowing) {
+                    notifyStateChanged("Settings $uri changed")
+                }
+            }
+        }
+
+        secureSettings.registerContentObserverForUser(
+                Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
+                settingsObserver,
+                UserHandle.USER_ALL)
+
+        secureSettings.registerContentObserverForUser(
+                Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+                true,
+                settingsObserver,
+                UserHandle.USER_ALL)
+
+        globalSettings.registerContentObserver(Settings.Global.ZEN_MODE, settingsObserver)
+
+        secureSettings.registerContentObserverForUser(
+                Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS,
+                settingsObserver,
+                UserHandle.USER_ALL)
+
+        // register (maybe) public mode changed callbacks:
+        statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
+            override fun onStateChanged(state: Int) {
+                notifyStateChanged("onStatusBarStateChanged")
+            }
+        })
+        broadcastDispatcher.registerReceiver(object : BroadcastReceiver() {
+            override fun onReceive(context: Context, intent: Intent) {
+                if (keyguardStateController.isShowing) {
+                    // maybe public mode changed
+                    notifyStateChanged(intent.action!!)
+                }
+            }
+        }, IntentFilter(Intent.ACTION_USER_SWITCHED))
+    }
+
+    override fun addOnStateChangedListener(listener: Consumer<String>) {
+        onStateChangedListeners.addIfAbsent(listener)
+    }
+
+    override fun removeOnStateChangedListener(listener: Consumer<String>) {
+        onStateChangedListeners.remove(listener)
+    }
+
+    private fun notifyStateChanged(reason: String) {
+        onStateChangedListeners.forEach { it.accept(reason) }
+    }
+
+    override fun shouldHideNotification(entry: NotificationEntry): Boolean = when {
+        // Keyguard state doesn't matter if the keyguard is not showing.
+        !keyguardStateController.isShowing -> false
+        // Notifications not allowed on the lockscreen, always hide.
+        !lockscreenUserManager.shouldShowLockscreenNotifications() -> true
+        // User settings do not allow this notification on the lockscreen, so hide it.
+        userSettingsDisallowNotification(entry) -> true
+        // Parent priority is high enough to be shown on the lockscreen, do not hide.
+        entry.parent?.let(::priorityExceedsLockscreenShowingThreshold) == true -> false
+        // Entry priority is high enough to be shown on the lockscreen, do not hide.
+        priorityExceedsLockscreenShowingThreshold(entry) -> false
+        // Priority is too low, hide.
+        else -> true
+    }
+
+    private fun userSettingsDisallowNotification(entry: NotificationEntry): Boolean {
+        fun disallowForUser(user: Int) = when {
+            // user is in lockdown, always disallow
+            keyguardUpdateMonitor.isUserInLockdown(user) -> true
+            // device isn't public, no need to check public-related settings, so allow
+            !lockscreenUserManager.isLockscreenPublicMode(user) -> false
+            // entry is meant to be secret on the lockscreen, disallow
+            entry.ranking.lockscreenVisibilityOverride == Notification.VISIBILITY_SECRET -> true
+            // disallow if user disallows notifications in public
+            else -> !lockscreenUserManager.userAllowsNotificationsInPublic(user)
+        }
+        val currentUser = lockscreenUserManager.currentUserId
+        val notifUser = entry.sbn.user.identifier
+        return when {
+            disallowForUser(currentUser) -> true
+            notifUser == UserHandle.USER_ALL -> false
+            notifUser == currentUser -> false
+            else -> disallowForUser(notifUser)
+        }
+    }
+
+    private fun priorityExceedsLockscreenShowingThreshold(entry: ListEntry): Boolean = when {
+        hideSilentNotificationsOnLockscreen -> highPriorityProvider.isHighPriority(entry)
+        else -> entry.representativeEntry?.ranking?.isAmbient == false
+    }
+
+    private fun readShowSilentNotificationSetting() {
+        val showSilentNotifs =
+                secureSettings.getBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, true)
+        hideSilentNotificationsOnLockscreen = !showSilentNotifs
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
index c991376..6c99e3a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
@@ -211,6 +211,14 @@
             "Pulsing: $str1"
         })
     }
+
+    fun keyguardHideNotification(key: String) {
+        hunBuffer.log(TAG, DEBUG, {
+            str1 = key
+        }, {
+            "Keyguard Hide Notification: $str1"
+        })
+    }
 }
 
 private const val TAG = "InterruptionStateProvider"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index 7ed2699..e210f19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
@@ -36,6 +36,7 @@
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationFilter;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.policy.BatteryController;
@@ -66,6 +67,8 @@
     private final ContentObserver mHeadsUpObserver;
     private final HeadsUpManager mHeadsUpManager;
     private final NotificationInterruptLogger mLogger;
+    private final NotifPipelineFlags mFlags;
+    private final KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
 
     @VisibleForTesting
     protected boolean mUseHeadsUp = false;
@@ -81,7 +84,9 @@
             StatusBarStateController statusBarStateController,
             HeadsUpManager headsUpManager,
             NotificationInterruptLogger logger,
-            @Main Handler mainHandler) {
+            @Main Handler mainHandler,
+            NotifPipelineFlags flags,
+            KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider) {
         mContentResolver = contentResolver;
         mPowerManager = powerManager;
         mDreamManager = dreamManager;
@@ -91,6 +96,8 @@
         mStatusBarStateController = statusBarStateController;
         mHeadsUpManager = headsUpManager;
         mLogger = logger;
+        mFlags = flags;
+        mKeyguardNotificationVisibilityProvider = keyguardNotificationVisibilityProvider;
         mHeadsUpObserver = new ContentObserver(mainHandler) {
             @Override
             public void onChange(boolean selfChange) {
@@ -282,7 +289,7 @@
     private boolean canAlertCommon(NotificationEntry entry) {
         StatusBarNotification sbn = entry.getSbn();
 
-        if (mNotificationFilter.shouldFilterOut(entry)) {
+        if (!mFlags.isNewPipelineEnabled() && mNotificationFilter.shouldFilterOut(entry)) {
             mLogger.logNoAlertingFilteredOut(sbn);
             return false;
         }
@@ -305,6 +312,11 @@
             return false;
         }
 
+        if (mKeyguardNotificationVisibilityProvider.shouldHideNotification(entry)) {
+            mLogger.keyguardHideNotification(entry.getKey());
+            return false;
+        }
+
         return true;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index fca2aa1..577d536 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -163,10 +163,13 @@
     }
 
     /**
-     * @return The background of this view.
+     * @param width The actual width to apply to the background view.
      */
-    public NotificationBackgroundView getBackgroundNormal() {
-        return mBackgroundNormal;
+    public void setBackgroundWidth(int width) {
+        if (mBackgroundNormal == null) {
+            return;
+        }
+        mBackgroundNormal.setActualWidth(width);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index c237e1d..e479509 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -79,7 +79,6 @@
 import com.android.internal.util.ContrastColorUtil;
 import com.android.internal.widget.CachingIconView;
 import com.android.internal.widget.CallLayout;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.classifier.FalsingCollector;
@@ -90,6 +89,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.RemoteInputController;
+import com.android.systemui.statusbar.SmartReplyController;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
 import com.android.systemui.statusbar.notification.ExpandAnimationParameters;
@@ -111,10 +111,11 @@
 import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.SwipeableView;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
+import com.android.systemui.statusbar.policy.SmartReplyConstants;
 import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
 import com.android.systemui.util.Compile;
 import com.android.systemui.util.DumpUtilsKt;
@@ -169,6 +170,7 @@
     private RowContentBindStage mRowContentBindStage;
     private PeopleNotificationIdentifier mPeopleNotificationIdentifier;
     private Optional<BubblesManager> mBubblesManagerOptional;
+    private MetricsLogger mMetricsLogger;
     private int mIconTransformContentShift;
     private int mMaxHeadsUpHeightBeforeN;
     private int mMaxHeadsUpHeightBeforeP;
@@ -304,8 +306,7 @@
                 final boolean wasExpanded = mGroupExpansionManager.isGroupExpanded(mEntry);
                 boolean nowExpanded = mGroupExpansionManager.toggleGroupExpansion(mEntry);
                 mOnExpandClickListener.onExpandClicked(mEntry, v, nowExpanded);
-                MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
-                        nowExpanded);
+                mMetricsLogger.action(MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER, nowExpanded);
                 onExpansionChanged(true /* userAction */, wasExpanded);
             } else if (mEnableNonGroupedNotificationExpand) {
                 if (v.isAccessibilityFocused()) {
@@ -327,8 +328,7 @@
                 }
                 notifyHeightChanged(true);
                 mOnExpandClickListener.onExpandClicked(mEntry, v, nowExpanded);
-                MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
-                        nowExpanded);
+                mMetricsLogger.action(MetricsEvent.ACTION_NOTIFICATION_EXPANDER, nowExpanded);
             }
         }
     };
@@ -1271,7 +1271,7 @@
             addView(mMenuRow.getMenuView(), menuIndex);
         }
         for (NotificationContentView l : mLayouts) {
-            l.initView();
+            l.reinflate();
             l.reInflateViews();
         }
         mEntry.getSbn().clearPackageContext();
@@ -1464,7 +1464,7 @@
      * @param fromAccessibility whether this dismiss is coming from an accessibility action
      */
     public void performDismiss(boolean fromAccessibility) {
-        Dependency.get(MetricsLogger.class).count(NotificationCounters.NOTIFICATION_DISMISSED, 1);
+        mMetricsLogger.count(NotificationCounters.NOTIFICATION_DISMISSED, 1);
         dismiss(fromAccessibility);
         if (mEntry.isDismissable()) {
             if (mOnUserInteractionCallback != null) {
@@ -1600,7 +1600,10 @@
             PeopleNotificationIdentifier peopleNotificationIdentifier,
             OnUserInteractionCallback onUserInteractionCallback,
             Optional<BubblesManager> bubblesManagerOptional,
-            NotificationGutsManager gutsManager) {
+            NotificationGutsManager gutsManager,
+            MetricsLogger metricsLogger,
+            SmartReplyConstants smartReplyConstants,
+            SmartReplyController smartReplyController) {
         mEntry = entry;
         mAppName = appName;
         if (mMenuRow == null) {
@@ -1623,15 +1626,18 @@
         mFalsingManager = falsingManager;
         mFalsingCollector = falsingCollector;
         mStatusBarStateController = statusBarStateController;
-
         mPeopleNotificationIdentifier = peopleNotificationIdentifier;
         for (NotificationContentView l : mLayouts) {
-            l.setPeopleNotificationIdentifier(mPeopleNotificationIdentifier);
-            l.setRemoteInputViewSubcomponentFactory(rivSubcomponentFactory);
+            l.initialize(
+                    mPeopleNotificationIdentifier,
+                    rivSubcomponentFactory,
+                    smartReplyConstants,
+                    smartReplyController);
         }
         mOnUserInteractionCallback = onUserInteractionCallback;
         mBubblesManagerOptional = bubblesManagerOptional;
         mNotificationGutsManager = gutsManager;
+        mMetricsLogger = metricsLogger;
 
         cacheIsSystemNotification();
     }
@@ -3127,7 +3133,7 @@
         if (mGroupMembershipManager.isGroupSummary(mEntry)) {
             event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
         }
-        MetricsLogger.action(mContext, event, userExpanded);
+        mMetricsLogger.action(event, userExpanded);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index c4beb5b..599039d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -27,6 +27,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
@@ -35,6 +36,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.SmartReplyController;
 import com.android.systemui.statusbar.notification.FeedbackIcon;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
@@ -49,6 +51,7 @@
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.policy.SmartReplyConstants;
 import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
 import com.android.systemui.util.time.SystemClock;
 import com.android.systemui.wmshell.BubblesManager;
@@ -82,6 +85,7 @@
     private final HeadsUpManager mHeadsUpManager;
     private final ExpandableNotificationRow.OnExpandClickListener mOnExpandClickListener;
     private final StatusBarStateController mStatusBarStateController;
+    private final MetricsLogger mMetricsLogger;
 
     private final ExpandableNotificationRow.ExpansionLogger mExpansionLogger =
             this::logNotificationExpansion;
@@ -94,16 +98,21 @@
     private final boolean mAllowLongPress;
     private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
     private final Optional<BubblesManager> mBubblesManagerOptional;
+    private final SmartReplyConstants mSmartReplyConstants;
+    private final SmartReplyController mSmartReplyController;
 
     private final ExpandableNotificationRowDragController mDragController;
 
     @Inject
     public ExpandableNotificationRowController(
             ExpandableNotificationRow view,
-            NotificationListContainer listContainer,
-            RemoteInputViewSubcomponent.Factory rivSubcomponentFactory,
             ActivatableNotificationViewController activatableNotificationViewController,
+            RemoteInputViewSubcomponent.Factory rivSubcomponentFactory,
+            MetricsLogger metricsLogger,
+            NotificationListContainer listContainer,
             NotificationMediaManager mediaManager,
+            SmartReplyConstants smartReplyConstants,
+            SmartReplyController smartReplyController,
             PluginManager pluginManager,
             SystemClock clock,
             @AppName String appName,
@@ -152,6 +161,9 @@
         mPeopleNotificationIdentifier = peopleNotificationIdentifier;
         mBubblesManagerOptional = bubblesManagerOptional;
         mDragController = dragController;
+        mMetricsLogger = metricsLogger;
+        mSmartReplyConstants = smartReplyConstants;
+        mSmartReplyController = smartReplyController;
     }
 
     /**
@@ -179,7 +191,10 @@
                 mPeopleNotificationIdentifier,
                 mOnUserInteractionCallback,
                 mBubblesManagerOptional,
-                mNotificationGutsManager
+                mNotificationGutsManager,
+                mMetricsLogger,
+                mSmartReplyConstants,
+                mSmartReplyController
         );
         mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
         if (mAllowLongPress) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 9cb5dc5..b9c71132 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -39,7 +39,6 @@
 import android.widget.LinearLayout;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.statusbar.RemoteInputController;
@@ -94,7 +93,6 @@
     private final Rect mClipBounds = new Rect();
 
     private int mMinContractedHeight;
-    private int mNotificationContentMarginEnd;
     private View mContractedChild;
     private View mExpandedChild;
     private View mHeadsUpChild;
@@ -116,7 +114,7 @@
     private NotificationViewWrapper mContractedWrapper;
     private NotificationViewWrapper mExpandedWrapper;
     private NotificationViewWrapper mHeadsUpWrapper;
-    private HybridGroupManager mHybridGroupManager;
+    private final HybridGroupManager mHybridGroupManager;
     private int mClipTopAmount;
     private int mContentHeight;
     private int mVisibleType = VISIBLE_TYPE_NONE;
@@ -128,7 +126,6 @@
     private int mHeadsUpHeight;
     private int mNotificationMaxHeight;
     private NotificationEntry mNotificationEntry;
-    private GroupMembershipManager mGroupMembershipManager;
     private RemoteInputController mRemoteInputController;
     private Runnable mExpandedVisibleListener;
     private PeopleNotificationIdentifier mPeopleIdentifier;
@@ -184,7 +181,6 @@
     private boolean mFocusOnVisibilityChange;
     private boolean mHeadsUpAnimatingAway;
     private int mClipBottomAmount;
-    private boolean mIsLowPriority;
     private boolean mIsContentExpandable;
     private boolean mRemoteInputVisible;
     private int mUnrestrictedContentHeight;
@@ -192,16 +188,23 @@
     public NotificationContentView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mHybridGroupManager = new HybridGroupManager(getContext());
-        mSmartReplyConstants = Dependency.get(SmartReplyConstants.class);
-        mSmartReplyController = Dependency.get(SmartReplyController.class);
-        initView();
+        reinflate();
     }
 
-    public void initView() {
+    public void initialize(
+            PeopleNotificationIdentifier peopleNotificationIdentifier,
+            RemoteInputViewSubcomponent.Factory rivSubcomponentFactory,
+            SmartReplyConstants smartReplyConstants,
+            SmartReplyController smartReplyController) {
+        mPeopleIdentifier = peopleNotificationIdentifier;
+        mRemoteInputSubcomponentFactory = rivSubcomponentFactory;
+        mSmartReplyConstants = smartReplyConstants;
+        mSmartReplyController = smartReplyController;
+    }
+
+    public void reinflate() {
         mMinContractedHeight = getResources().getDimensionPixelSize(
                 R.dimen.min_notification_layout_height);
-        mNotificationContentMarginEnd = getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.notification_content_margin_end);
     }
 
     public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight) {
@@ -413,7 +416,10 @@
             if (mExpandedRemoteInput != null) {
                 mExpandedRemoteInput.onNotificationUpdateOrReset();
                 if (mExpandedRemoteInput.isActive()) {
-                    mPreviousExpandedRemoteInputIntent = mExpandedRemoteInput.getPendingIntent();
+                    if (mExpandedRemoteInputController != null) {
+                        mPreviousExpandedRemoteInputIntent =
+                                mExpandedRemoteInputController.getPendingIntent();
+                    }
                     mCachedExpandedRemoteInput = mExpandedRemoteInput;
                     mCachedExpandedRemoteInputViewController = mExpandedRemoteInputController;
                     mExpandedRemoteInput.dispatchStartTemporaryDetach();
@@ -460,7 +466,10 @@
             if (mHeadsUpRemoteInput != null) {
                 mHeadsUpRemoteInput.onNotificationUpdateOrReset();
                 if (mHeadsUpRemoteInput.isActive()) {
-                    mPreviousHeadsUpRemoteInputIntent = mHeadsUpRemoteInput.getPendingIntent();
+                    if (mHeadsUpRemoteInputController != null) {
+                        mPreviousHeadsUpRemoteInputIntent =
+                                mHeadsUpRemoteInputController.getPendingIntent();
+                    }
                     mCachedHeadsUpRemoteInput = mHeadsUpRemoteInput;
                     mCachedHeadsUpRemoteInputViewController = mHeadsUpRemoteInputController;
                     mHeadsUpRemoteInput.dispatchStartTemporaryDetach();
@@ -961,14 +970,16 @@
 
     private void transferRemoteInputFocus(int visibleType) {
         if (visibleType == VISIBLE_TYPE_HEADSUP
-                && mHeadsUpRemoteInput != null
-                && (mExpandedRemoteInput != null && mExpandedRemoteInput.isActive())) {
-            mHeadsUpRemoteInput.stealFocusFrom(mExpandedRemoteInput);
+                && mHeadsUpRemoteInputController != null
+                && mExpandedRemoteInputController != null
+                && mExpandedRemoteInputController.isActive()) {
+            mHeadsUpRemoteInputController.stealFocusFrom(mExpandedRemoteInputController);
         }
         if (visibleType == VISIBLE_TYPE_EXPANDED
-                && mExpandedRemoteInput != null
-                && (mHeadsUpRemoteInput != null && mHeadsUpRemoteInput.isActive())) {
-            mExpandedRemoteInput.stealFocusFrom(mHeadsUpRemoteInput);
+                && mExpandedRemoteInputController != null
+                && mHeadsUpRemoteInputController != null
+                && mHeadsUpRemoteInputController.isActive()) {
+            mExpandedRemoteInputController.stealFocusFrom(mHeadsUpRemoteInputController);
         }
     }
 
@@ -1313,7 +1324,6 @@
                     // If we find a matching action in the new notification, focus, otherwise close.
                     Notification.Action[] actions = entry.getSbn().getNotification().actions;
                     if (existingPendingIntent != null) {
-                        result.mView.setPendingIntent(existingPendingIntent);
                         result.mController.setPendingIntent(existingPendingIntent);
                     }
                     if (result.mController.updatePendingIntentFromActions(actions)) {
@@ -1599,7 +1609,6 @@
     }
 
     public void setGroupMembershipManager(GroupMembershipManager groupMembershipManager) {
-        mGroupMembershipManager = groupMembershipManager;
     }
 
     public void setRemoteInputController(RemoteInputController r) {
@@ -1687,10 +1696,6 @@
         mContainingNotification = containingNotification;
     }
 
-    public void setPeopleNotificationIdentifier(PeopleNotificationIdentifier peopleIdentifier) {
-        mPeopleIdentifier = peopleIdentifier;
-    }
-
     public void requestSelectLayout(boolean needsAnimation) {
         selectLayout(needsAnimation, false);
     }
@@ -1858,7 +1863,6 @@
     }
 
     public void setIsLowPriority(boolean isLowPriority) {
-        mIsLowPriority = isLowPriority;
     }
 
     public boolean isDimmable() {
@@ -2083,10 +2087,6 @@
         return false;
     }
 
-    public void setRemoteInputViewSubcomponentFactory(RemoteInputViewSubcomponent.Factory factory) {
-        mRemoteInputSubcomponentFactory = factory;
-    }
-
     private static class RemoteInputViewData {
         @Nullable RemoteInputView mView;
         @Nullable RemoteInputViewController mController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
index 4b0e2ff..41eeada0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
@@ -21,7 +21,6 @@
 import android.os.AsyncTask;
 import android.util.Log;
 
-import java.io.IOException;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutionException;
@@ -82,16 +81,8 @@
 
         @Override
         protected Drawable doInBackground(Uri... uris) {
-            Drawable drawable = null;
             Uri target = uris[0];
-
-            try {
-                drawable = mResolver.resolveImage(target);
-            } catch (IOException | SecurityException ex) {
-                Log.d(TAG, "PreloadImageTask: Resolve failed from " + target, ex);
-            }
-
-            return drawable;
+            return mResolver.resolveImage(target);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
index 44ccb68..b05e64ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
@@ -31,7 +31,6 @@
 import com.android.internal.widget.LocalImageResolver;
 import com.android.internal.widget.MessagingMessage;
 
-import java.io.IOException;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -111,30 +110,30 @@
      * To resolve image from specified uri directly. If the resulting image is larger than the
      * maximum allowed size, scale it down.
      * @param uri Uri of the image.
-     * @return Drawable of the image.
-     * @throws IOException Throws if failed at resolving the image.
+     * @return Drawable of the image, or null if unable to load.
      */
-    Drawable resolveImage(Uri uri) throws IOException {
-        return LocalImageResolver.resolveImage(uri, mContext, mMaxImageWidth, mMaxImageHeight);
+    Drawable resolveImage(Uri uri) {
+        try {
+            return LocalImageResolver.resolveImage(uri, mContext, mMaxImageWidth, mMaxImageHeight);
+        } catch (Exception ex) {
+            // Catch general Exception because ContentResolver can re-throw arbitrary Exception
+            // from remote process as a RuntimeException. See: Parcel#readException
+            Log.d(TAG, "resolveImage: Can't load image from " + uri, ex);
+        }
+        return null;
     }
 
     @Override
     public Drawable loadImage(Uri uri) {
-        Drawable result = null;
-        try {
-            if (hasCache()) {
-                // if the uri isn't currently cached, try caching it first
-                if (!mImageCache.hasEntry(uri)) {
-                    mImageCache.preload((uri));
-                }
-                result = mImageCache.get(uri);
-            } else {
-                result = resolveImage(uri);
-            }
-        } catch (IOException | SecurityException ex) {
-            Log.d(TAG, "loadImage: Can't load image from " + uri, ex);
+        return hasCache() ? loadImageFromCache(uri) : resolveImage(uri);
+    }
+
+    private Drawable loadImageFromCache(Uri uri) {
+        // if the uri isn't currently cached, try caching it first
+        if (!mImageCache.hasEntry(uri)) {
+            mImageCache.preload((uri));
         }
-        return result;
+        return mImageCache.get(uri);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 5b9dbd0..32d37d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -19,7 +19,6 @@
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_SCROLL_FLING;
 import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT;
 import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_SWIPE;
-import static com.android.systemui.util.Utils.shouldUseSplitNotificationShade;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
@@ -110,6 +109,7 @@
 import com.android.systemui.statusbar.policy.ScrollAdapter;
 import com.android.systemui.util.Assert;
 import com.android.systemui.util.DumpUtilsKt;
+import com.android.systemui.util.LargeScreenUtils;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -217,6 +217,7 @@
     private HashSet<View> mFromMoreCardAdditions = new HashSet<>();
     private ArrayList<AnimationEvent> mAnimationEvents = new ArrayList<>();
     private ArrayList<View> mSwipedOutViews = new ArrayList<>();
+    private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
     private final StackStateAnimator mStateAnimator = new StackStateAnimator(this);
     private boolean mAnimationsEnabled;
     private boolean mChangePositionInProgress;
@@ -415,6 +416,7 @@
     private NotificationShelf mShelf;
     private int mMaxDisplayedNotifications = -1;
     private float mKeyguardBottomPadding = -1;
+    private float mKeyguardNotificationAvailableSpace = -1;
     @VisibleForTesting int mStatusBarHeight;
     private int mMinInteractionHeight;
     private final Rect mClipRect = new Rect();
@@ -687,7 +689,8 @@
         boolean showFooterView = (showDismissView || mController.getVisibleNotificationCount() > 0)
                 && mIsCurrentUserSetup  // see: b/193149550
                 && mStatusBarState != StatusBarState.KEYGUARD
-                && mQsExpansionFraction != 1
+                // quick settings don't affect notifications when not in full screen
+                && (mQsExpansionFraction != 1 || !mQsFullScreen)
                 && !mScreenOffAnimationController.shouldHideNotificationsFooter()
                 && !mIsRemoteInputActive;
         boolean showHistory = mController.isHistoryEnabled();
@@ -757,30 +760,49 @@
         } else {
             mDebugTextUsedYPositions.clear();
         }
-        int y = mTopPadding;
-        drawDebugInfo(canvas, y, Color.RED, /* label= */ "mTopPadding");
+        int y = 0;
+        drawDebugInfo(canvas, y, Color.RED, /* label= */ "y = " + y);
+
+        y = mTopPadding;
+        drawDebugInfo(canvas, y, Color.RED, /* label= */ "mTopPadding = " + y);
 
         y = getLayoutHeight();
-        drawDebugInfo(canvas, y, Color.YELLOW, /* label= */ "getLayoutHeight()");
+        drawDebugInfo(canvas, y, Color.YELLOW, /* label= */ "getLayoutHeight() = " + y);
 
         y = (int) mMaxLayoutHeight;
-        drawDebugInfo(canvas, y, Color.MAGENTA, /* label= */ "mMaxLayoutHeight");
+        drawDebugInfo(canvas, y, Color.MAGENTA, /* label= */ "mMaxLayoutHeight = " + y);
 
         if (mKeyguardBottomPadding >= 0) {
             y = getHeight() - (int) mKeyguardBottomPadding;
             drawDebugInfo(canvas, y, Color.GRAY,
-                    /* label= */ "getHeight() - mKeyguardBottomPadding");
+                    /* label= */ "getHeight() - mKeyguardBottomPadding = " + y);
         }
 
         y = getHeight() - getEmptyBottomMargin();
-        drawDebugInfo(canvas, y, Color.GREEN, /* label= */ "getHeight() - getEmptyBottomMargin()");
+        drawDebugInfo(canvas, y, Color.GREEN,
+                /* label= */ "getHeight() - getEmptyBottomMargin() = " + y);
 
         y = (int) (mAmbientState.getStackY());
-        drawDebugInfo(canvas, y, Color.CYAN, /* label= */ "mAmbientState.getStackY()");
+        drawDebugInfo(canvas, y, Color.CYAN, /* label= */ "mAmbientState.getStackY() = " + y);
 
         y = (int) (mAmbientState.getStackY() + mAmbientState.getStackHeight());
         drawDebugInfo(canvas, y, Color.BLUE,
-                /* label= */ "mAmbientState.getStackY() + mAmbientState.getStackHeight()");
+                /* label= */ "mAmbientState.getStackY() + mAmbientState.getStackHeight() = " + y);
+
+        y = (int) mAmbientState.getStackY() + mContentHeight;
+        drawDebugInfo(canvas, y, Color.MAGENTA,
+                /* label= */ "mAmbientState.getStackY() + mContentHeight = " + y);
+
+        y = (int) mAmbientState.getStackY() + mIntrinsicContentHeight;
+        drawDebugInfo(canvas, y, Color.YELLOW,
+                /* label= */ "mAmbientState.getStackY() + mIntrinsicContentHeight = " + y);
+
+        y = (int) (mAmbientState.getStackY() + mKeyguardNotificationAvailableSpace);
+        drawDebugInfo(canvas, y, Color.RED, /* label= */
+                "mAmbientState.getStackY() + mKeyguardNotificationAvailableSpace = " + y);
+
+        drawDebugInfo(canvas, mRoundedRectClippingBottom, Color.DKGRAY,
+                /* label= */ "mRoundedRectClippingBottom) = " + y);
     }
 
     private void drawDebugInfo(Canvas canvas, int y, int color, String label) {
@@ -947,13 +969,15 @@
     }
 
     private void reinitView() {
-        initView(getContext(), mSwipeHelper);
+        initView(getContext(), mSwipeHelper, mNotificationStackSizeCalculator);
     }
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    void initView(Context context, NotificationSwipeHelper swipeHelper) {
+    void initView(Context context, NotificationSwipeHelper swipeHelper,
+            NotificationStackSizeCalculator notificationStackSizeCalculator) {
         mScroller = new OverScroller(getContext());
         mSwipeHelper = swipeHelper;
+        mNotificationStackSizeCalculator = notificationStackSizeCalculator;
 
         setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
         setClipChildren(false);
@@ -1291,15 +1315,14 @@
         if (mOnStackYChanged != null) {
             mOnStackYChanged.accept(listenerNeedsAnimation);
         }
-        if (mQsExpansionFraction <= 0 && !shouldSkipHeightUpdate()) {
-            final float endHeight = updateStackEndHeight(
-                    getHeight(), getEmptyBottomMargin(), mTopPadding);
+        if ((mQsExpansionFraction <= 0 || !mQsFullScreen) && !shouldSkipHeightUpdate()) {
+            final float endHeight = updateStackEndHeight();
             updateStackHeight(endHeight, fraction);
         }
     }
 
-    public float updateStackEndHeight(float height, float bottomMargin, float topPadding) {
-        final float stackEndHeight = Math.max(0f, height - bottomMargin - topPadding);
+    private float updateStackEndHeight() {
+        final float stackEndHeight = Math.max(0f, mIntrinsicContentHeight);
         mAmbientState.setStackEndHeight(stackEndHeight);
         return stackEndHeight;
     }
@@ -1332,12 +1355,7 @@
      */
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
     public void setExpandedHeight(float height) {
-        final float shadeBottom = getHeight() - getEmptyBottomMargin();
         final boolean skipHeightUpdate = shouldSkipHeightUpdate();
-        if (!skipHeightUpdate) {
-            final float expansionFraction = MathUtils.saturate(height / shadeBottom);
-            mAmbientState.setExpansionFraction(expansionFraction);
-        }
         updateStackPosition();
 
         if (!skipHeightUpdate) {
@@ -2245,48 +2263,10 @@
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
     private void updateContentHeight() {
         final float scrimTopPadding = mAmbientState.isOnKeyguard() ? 0 : mMinimumPaddings;
-        int height = (int) scrimTopPadding;
-        float previousPaddingRequest = mPaddingBetweenElements;
-        int numShownItems = 0;
-        int numShownNotifs = 0;
-        boolean finish = false;
-        int maxDisplayedNotifications = mMaxDisplayedNotifications;
-        ExpandableView previousView = null;
-
-        for (int i = 0; i < getChildCount(); i++) {
-            ExpandableView expandableView = (ExpandableView) getChildAt(i);
-            boolean footerViewOnLockScreen = expandableView == mFooterView && onKeyguard();
-
-            if (expandableView.getVisibility() != View.GONE
-                    && !expandableView.hasNoContentHeight() && !footerViewOnLockScreen) {
-
-                boolean limitReached = maxDisplayedNotifications != -1
-                        && numShownNotifs >= maxDisplayedNotifications;
-                final float viewHeight;
-                if (limitReached) {
-                    viewHeight = mShelf.getIntrinsicHeight();
-                    finish = true;
-                } else {
-                    viewHeight = expandableView.getIntrinsicHeight();
-                }
-                if (height != 0) {
-                    height += mPaddingBetweenElements;
-                }
-                float gapHeight = calculateGapHeight(previousView, expandableView, numShownNotifs);
-                height += gapHeight;
-                height += viewHeight;
-
-                numShownItems++;
-                if (viewHeight > 0 || !(expandableView instanceof MediaContainerView)) {
-                    // Only count the media as a notification if it has a positive height.
-                    numShownNotifs++;
-                }
-                previousView = expandableView;
-                if (finish) {
-                    break;
-                }
-            }
-        }
+        final int height =
+                (int) scrimTopPadding + (int) mNotificationStackSizeCalculator.computeHeight(
+                        /* notificationStackScrollLayout= */ this, mMaxDisplayedNotifications,
+                        mShelf != null ? mShelf.getIntrinsicHeight() : 0);
         mIntrinsicContentHeight = height;
 
         // The topPadding can be bigger than the regular padding when qs is expanded, in that
@@ -4929,6 +4909,15 @@
         mKeyguardBottomPadding = keyguardBottomPadding;
     }
 
+    /**
+     * For debugging only. Enables to draw a line related to the available size for notifications in
+     * keyguard.
+     */
+    public void setKeyguardAvailableSpaceForDebug(float keyguardNotificationAvailableSpace) {
+        mKeyguardNotificationAvailableSpace = keyguardNotificationAvailableSpace;
+    }
+
+
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public void setShouldShowShelfOnly(boolean shouldShowShelfOnly) {
         mShouldShowShelfOnly = shouldShowShelfOnly;
@@ -5037,6 +5026,7 @@
                 .append(" qsExpandFraction=").append(mQsExpansionFraction)
                 .append(" isCurrentUserSetup=").append(mIsCurrentUserSetup)
                 .append(" hideAmount=").append(mAmbientState.getHideAmount())
+                .append(" ambientStateSwipingUp=").append(mAmbientState.isSwipingUp())
                 .append("]");
         pw.println(sb.toString());
         DumpUtilsKt.withIncreasedIndent(pw, () -> {
@@ -5551,7 +5541,7 @@
     }
 
     private void updateSplitNotificationShade() {
-        boolean split = shouldUseSplitNotificationShade(getResources());
+        boolean split = LargeScreenUtils.shouldUseSplitNotificationShade(getResources());
         if (split != mShouldUseSplitNotificationShade) {
             mShouldUseSplitNotificationShade = split;
             updateDismissBehavior();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 6bbecc8..5bc50ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -41,7 +41,6 @@
 import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
 import android.util.Log;
-import android.util.MathUtils;
 import android.util.Pair;
 import android.view.Display;
 import android.view.LayoutInflater;
@@ -65,7 +64,6 @@
 import com.android.systemui.Gefingerpoken;
 import com.android.systemui.R;
 import com.android.systemui.SwipeHelper;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.classifier.Classifier;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -181,6 +179,7 @@
     private final SectionHeaderController mSilentHeaderController;
     private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
     private final InteractionJankMonitor mJankMonitor;
+    private final NotificationStackSizeCalculator mNotificationStackSizeCalculator;
     private final StackStateLogger mStackStateLogger;
     private final NotificationStackScrollLogger mLogger;
 
@@ -204,18 +203,6 @@
 
     private ColorExtractor.OnColorsChangedListener mOnColorsChangedListener;
 
-    /**
-     * The total distance in pixels that the full shade transition takes to transition entirely to
-     * the full shade.
-     */
-    private int mTotalDistanceForFullShadeTransition;
-
-    /**
-     * The amount of movement the notifications do when transitioning to the full shade before
-     * reaching the overstrech
-     */
-    private int mNotificationDragDownMovement;
-
     @VisibleForTesting
     final View.OnAttachStateChangeListener mOnAttachStateChangeListener =
             new View.OnAttachStateChangeListener() {
@@ -303,10 +290,7 @@
     private NotifStats mNotifStats = NotifStats.getEmpty();
 
     private void updateResources() {
-        mNotificationDragDownMovement = mResources.getDimensionPixelSize(
-                R.dimen.lockscreen_shade_notification_movement);
-        mTotalDistanceForFullShadeTransition = mResources.getDimensionPixelSize(
-                R.dimen.lockscreen_shade_qs_transition_distance);
+        mNotificationStackSizeCalculator.updateResources();
     }
 
     private final StatusBarStateController.StateListener mStateListener =
@@ -662,7 +646,8 @@
             ShadeController shadeController,
             InteractionJankMonitor jankMonitor,
             StackStateLogger stackLogger,
-            NotificationStackScrollLogger logger) {
+            NotificationStackScrollLogger logger,
+            NotificationStackSizeCalculator notificationStackSizeCalculator) {
         mStackStateLogger = stackLogger;
         mLogger = logger;
         mAllowLongPress = allowLongPress;
@@ -688,6 +673,7 @@
         mCentralSurfaces = centralSurfaces;
         mScrimController = scrimController;
         mJankMonitor = jankMonitor;
+        mNotificationStackSizeCalculator = notificationStackSizeCalculator;
         groupManager.registerGroupExpansionChangeListener(
                 (changedRow, expanded) -> mView.onGroupExpandChanged(changedRow, expanded));
         legacyGroupManager.registerGroupChangeListener(new OnGroupChangeListener() {
@@ -758,7 +744,7 @@
             });
         }
 
-        mView.initView(mView.getContext(), mSwipeHelper);
+        mView.initView(mView.getContext(), mSwipeHelper, mNotificationStackSizeCalculator);
         mView.setKeyguardBypassEnabled(mKeyguardBypassController.getBypassEnabled());
         mKeyguardBypassController
                 .registerOnBypassStateChangedListener(mView::setKeyguardBypassEnabled);
@@ -907,6 +893,13 @@
         return mView.getTop();
     }
 
+    /**
+     * @return the bottom of the view.
+     */
+    public int getBottom() {
+        return mView.getBottom();
+    }
+
     public float getTranslationX() {
         return mView.getTranslationX();
     }
@@ -1296,10 +1289,16 @@
      * appear on the keyguard.
      * Setting a negative number will disable rendering this line.
      */
-    public void setKeyguardBottomPadding(float keyguardBottomPadding) {
+    public void setKeyguardBottomPaddingForDebug(float keyguardBottomPadding) {
         mView.setKeyguardBottomPadding(keyguardBottomPadding);
     }
 
+    /** For debugging only. */
+    public void mKeyguardNotificationAvailableSpaceForDebug(
+            float keyguardNotificationAvailableSpace) {
+        mView.setKeyguardAvailableSpaceForDebug(keyguardNotificationAvailableSpace);
+    }
+
     public RemoteInputController.Delegate createDelegate() {
         return new RemoteInputController.Delegate() {
             public void setRemoteInputActive(NotificationEntry entry,
@@ -1520,8 +1519,6 @@
     }
 
     /**
-     * @param amount The amount of pixels we have currently dragged down
-     *               for the lockscreen to shade transition. 0f for all other states.
      * @param fraction The fraction of lockscreen to shade transition.
      *                 0f for all other states.
      *
@@ -1529,18 +1526,15 @@
      * LockscreenShadeTransitionController resets amount and fraction to 0, where they remain
      * until the next lockscreen-to-shade transition.
      */
-    public void setTransitionToFullShadeAmount(float amount, float fraction) {
+    public void setTransitionToFullShadeAmount(float fraction) {
         mView.setFractionToShade(fraction);
+    }
 
-        float extraTopInset = 0.0f;
-        if (mStatusBarStateController.getState() == KEYGUARD) {
-            float overallProgress = MathUtils.saturate(amount / mView.getHeight());
-            float transitionProgress = Interpolators.getOvershootInterpolation(overallProgress,
-                    0.6f,
-                    (float) mTotalDistanceForFullShadeTransition / (float) mView.getHeight());
-            extraTopInset = transitionProgress * mNotificationDragDownMovement;
-        }
-        mView.setExtraTopInsetForFullShadeTransition(extraTopInset);
+    /**
+     * Sets the amount of vertical over scroll that should be performed on NSSL.
+     */
+    public void setOverScrollAmount(int overScrollAmount) {
+        mView.setExtraTopInsetForFullShadeTransition(overScrollAmount);
     }
 
     /** */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
new file mode 100644
index 0000000..6c6ed85
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
@@ -0,0 +1,235 @@
+/*
+ * 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.systemui.statusbar.notification.stack
+
+import android.content.res.Resources
+import android.util.Log
+import android.view.View.GONE
+import com.android.systemui.R
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.statusbar.StatusBarState.KEYGUARD
+import com.android.systemui.statusbar.SysuiStatusBarStateController
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.ExpandableView
+import com.android.systemui.util.children
+import javax.inject.Inject
+import kotlin.math.max
+import kotlin.properties.Delegates.notNull
+
+private const val TAG = "NotificationStackSizeCalculator"
+private const val DEBUG = false
+
+/** Calculates number of notifications to display and the height of the notification stack. */
+@SysUISingleton
+class NotificationStackSizeCalculator
+@Inject
+constructor(
+    private val statusBarStateController: SysuiStatusBarStateController,
+    @Main private val resources: Resources
+) {
+
+    /**
+     * Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow shelf.
+     * If there are exactly 1 + mMaxKeyguardNotifications, and they fit in the available space
+     * (considering the overflow shelf is not displayed in this case), then all notifications are
+     * shown.
+     */
+    private var maxKeyguardNotifications by notNull<Int>()
+
+    /**
+     * Minimum space between two notifications. There might be more space, see [calculateGapHeight].
+     */
+    private var notificationPadding by notNull<Int>()
+
+    init {
+        updateResources()
+    }
+
+    /**
+     * Given the [availableSpace] constraint, calculates how many notification to show.
+     *
+     * This number is only valid in keyguard.
+     *
+     * @param availableSpace space for notifications. This doesn't include the space for the shelf.
+     */
+    fun computeMaxKeyguardNotifications(
+        stack: NotificationStackScrollLayout,
+        availableSpace: Float,
+        shelfHeight: Float
+    ): Int {
+        log {
+            "computeMaxKeyguardNotifications(" +
+                "availableSpace=$availableSpace shelfHeight=$shelfHeight)"
+        }
+
+        val children: Sequence<ExpandableView> = stack.childrenSequence
+        var remainingSpace: Float = availableSpace
+        var count = 0
+        var previous: ExpandableView? = null
+        val onLockscreen = true
+        val showableRows = children.filter { it.isShowable(onLockscreen) }
+        val showableRowsCount = showableRows.count()
+        showableRows.forEachIndexed { i, current ->
+            val spaceNeeded = current.spaceNeeded(count, previous, stack, onLockscreen)
+            previous = current
+            log { "\ti=$i spaceNeeded=$spaceNeeded remainingSpace=$remainingSpace" }
+
+            if (remainingSpace - spaceNeeded >= 0 && count < maxKeyguardNotifications) {
+                count += 1
+                remainingSpace -= spaceNeeded
+            } else if (remainingSpace - spaceNeeded > -shelfHeight && i == showableRowsCount - 1) {
+                log { "Showing all notifications. Shelf is not be needed." }
+                // If this is the last one, and it fits using the space shelf would use, then we can
+                // display it, as the shelf will not be needed (as all notifications are shown).
+                return count + 1
+            } else {
+                log {
+                    "No more fit. Returning $count. Space used: ${availableSpace - remainingSpace}"
+                }
+                return count
+            }
+        }
+        log { "All fit. Returning $count" }
+        return count
+    }
+
+    /**
+     * Given the [maxNotifications] constraint, calculates the height of the
+     * [NotificationStackScrollLayout]. This might or might not be in keyguard.
+     *
+     * @param stack stack containing notifications as children.
+     * @param maxNotifications Maximum number of notifications. When reached, the others will go
+     * into the shelf.
+     * @param shelfHeight height of the shelf. It might be zero.
+     *
+     * @return height of the stack, including shelf height, if needed.
+     */
+    fun computeHeight(
+        stack: NotificationStackScrollLayout,
+        maxNotifications: Int,
+        shelfHeight: Float
+    ): Float {
+        val children: Sequence<ExpandableView> = stack.childrenSequence
+        val maxNotificationsArg = infiniteIfNegative(maxNotifications)
+        var height = 0f
+        var previous: ExpandableView? = null
+        var count = 0
+        val onLockscreen = onLockscreen()
+
+        log { "computeHeight(maxNotification=$maxNotifications, shelf=$shelfHeight" }
+        children.filter { it.isShowable(onLockscreen) }.forEach { current ->
+            if (count < maxNotificationsArg) {
+                val spaceNeeded = current.spaceNeeded(count, previous, stack, onLockscreen)
+                log { "\ti=$count spaceNeeded=$spaceNeeded" }
+                height += spaceNeeded
+                count += 1
+            } else {
+                height += shelfHeight
+                log { "returning height with shelf -> $height" }
+                return height
+            }
+            previous = current
+        }
+        log { "Returning height without shelf -> $height" }
+        return height
+    }
+
+    fun updateResources() {
+        maxKeyguardNotifications =
+            infiniteIfNegative(resources.getInteger(R.integer.keyguard_max_notification_count))
+
+        notificationPadding =
+            max(1, resources.getDimensionPixelSize(R.dimen.notification_divider_height))
+    }
+
+    private val NotificationStackScrollLayout.childrenSequence: Sequence<ExpandableView>
+        get() = children.map { it as ExpandableView }
+
+    private fun onLockscreen() = statusBarStateController.state == KEYGUARD
+
+    private fun ExpandableView.spaceNeeded(
+        visibleIndex: Int,
+        previousView: ExpandableView?,
+        stack: NotificationStackScrollLayout,
+        onLockscreen: Boolean
+    ): Float {
+        assert(isShowable(onLockscreen))
+        var size =
+            if (onLockscreen) {
+                getMinHeight(/* ignoreTemporaryStates= */ true).toFloat()
+            } else {
+                intrinsicHeight.toFloat()
+            }
+        if (visibleIndex != 0) {
+            size += notificationPadding
+        }
+        size += calculateGapHeight(stack, previousView, visibleIndex)
+        return size
+    }
+
+    private fun ExpandableView.isShowable(onLockscreen: Boolean): Boolean {
+        if (visibility == GONE || hasNoContentHeight()) return false
+        if (onLockscreen) {
+            when (this) {
+                is ExpandableNotificationRow -> {
+                    if (!canShowViewOnLockscreen() || isRemoved) {
+                        return false
+                    }
+                }
+                is MediaContainerView -> if (intrinsicHeight == 0) return false
+                else -> return false
+            }
+        }
+        return true
+    }
+
+    private fun ExpandableView.calculateGapHeight(
+        stack: NotificationStackScrollLayout,
+        previous: ExpandableView?,
+        visibleIndex: Int
+    ) = stack.calculateGapHeight(previous, /* current= */ this, visibleIndex)
+
+    /**
+     * Can a view be shown on the lockscreen when calculating the number of allowed notifications to
+     * show?
+     *
+     * @return `true` if it can be shown.
+     */
+    private fun ExpandableView.canShowViewOnLockscreen(): Boolean {
+        if (hasNoContentHeight()) {
+            return false
+        } else if (visibility == GONE) {
+            return false
+        }
+        return true
+    }
+
+    private fun log(s: () -> String) {
+        if (DEBUG) {
+            Log.d(TAG, s())
+        }
+    }
+
+    /** Returns infinite when [v] is negative. Useful in case a resource doesn't limit when -1. */
+    private fun infiniteIfNegative(v: Int): Int =
+        if (v < 0) {
+            Int.MAX_VALUE
+        } else {
+            v
+        }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 952cd9a..e1f8c35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -202,12 +202,10 @@
             float newHeight = state.height;
             float newNotificationEnd = newYTranslation + newHeight;
             boolean isHeadsUp = (child instanceof ExpandableNotificationRow) && child.isPinned();
-            final boolean shadeClosedWithHUN =
-                    ambientState.isShadeOpening() && !ambientState.isShadeExpanded();
             if (mClipNotificationScrollToTop
                     && (!state.inShelf || (isHeadsUp && !firstHeadsUp))
                     && newYTranslation < clipStart
-                    && shadeClosedWithHUN) {
+                    && !ambientState.isShadeExpanded()) {
                 // The previous view is overlapping on top, clip!
                 float overlapAmount = clipStart - newYTranslation;
                 state.clipTopAmount = (int) overlapAmount;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 4bf944a..aab5ff8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -357,7 +357,7 @@
         }
         Trace.beginSection("BiometricUnlockController#onBiometricAcquired");
         releaseBiometricWakeLock();
-        if (isWakeAndUnlock()) {
+        if (mStatusBarStateController.isDozing()) {
             if (mLatencyTracker.isEnabled()) {
                 int action = LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK;
                 if (biometricSourceType == BiometricSourceType.FACE) {
@@ -537,27 +537,6 @@
         mPendingShowBouncer = false;
     }
 
-    @Override
-    public void onStartedGoingToSleep(int why) {
-        resetMode();
-        mFadedAwayAfterWakeAndUnlock = false;
-        mPendingAuthenticated = null;
-    }
-
-    @Override
-    public void onFinishedGoingToSleep(int why) {
-        Trace.beginSection("BiometricUnlockController#onFinishedGoingToSleep");
-        if (mPendingAuthenticated != null) {
-            PendingAuthenticated pendingAuthenticated = mPendingAuthenticated;
-            // Post this to make sure it's executed after the device is fully locked.
-            mHandler.post(() -> onBiometricAuthenticated(pendingAuthenticated.userId,
-                    pendingAuthenticated.biometricSourceType,
-                    pendingAuthenticated.isStrongBiometric));
-            mPendingAuthenticated = null;
-        }
-        Trace.endSection();
-    }
-
     public boolean hasPendingAuthentication() {
         return mPendingAuthenticated != null
                 && mUpdateMonitor
@@ -752,13 +731,34 @@
     @VisibleForTesting
     final WakefulnessLifecycle.Observer mWakefulnessObserver =
             new WakefulnessLifecycle.Observer() {
-        @Override
-        public void onFinishedWakingUp() {
-            if (mPendingShowBouncer) {
-                BiometricUnlockController.this.showBouncer();
-            }
-        }
-    };
+                @Override
+                public void onFinishedWakingUp() {
+                    if (mPendingShowBouncer) {
+                        BiometricUnlockController.this.showBouncer();
+                    }
+                }
+
+                @Override
+                public void onStartedGoingToSleep() {
+                    resetMode();
+                    mFadedAwayAfterWakeAndUnlock = false;
+                    mPendingAuthenticated = null;
+                }
+
+                @Override
+                public void onFinishedGoingToSleep() {
+                    Trace.beginSection("BiometricUnlockController#onFinishedGoingToSleep");
+                    if (mPendingAuthenticated != null) {
+                        PendingAuthenticated pendingAuthenticated = mPendingAuthenticated;
+                        // Post this to make sure it's executed after the device is fully locked.
+                        mHandler.post(() -> onBiometricAuthenticated(pendingAuthenticated.userId,
+                                pendingAuthenticated.biometricSourceType,
+                                pendingAuthenticated.isStrongBiometric));
+                        mPendingAuthenticated = null;
+                    }
+                    Trace.endSection();
+                }
+            };
 
     private final ScreenLifecycle.Observer mScreenObserver =
             new ScreenLifecycle.Observer() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index a7f950e..1932680 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -641,6 +641,7 @@
     private boolean mWallpaperSupported;
 
     private Runnable mLaunchTransitionEndRunnable;
+    private Runnable mLaunchTransitionCancelRunnable;
     private boolean mLaunchCameraWhenFinishedWaking;
     private boolean mLaunchCameraOnFinishedGoingToSleep;
     private boolean mLaunchEmergencyActionWhenFinishedWaking;
@@ -1695,12 +1696,20 @@
     public void startActivity(Intent intent, boolean dismissShade,
             @Nullable ActivityLaunchAnimator.Controller animationController,
             boolean showOverLockscreenWhenLocked) {
+        startActivity(intent, dismissShade, animationController, showOverLockscreenWhenLocked,
+                UserHandle.CURRENT);
+    }
+
+    @Override
+    public void startActivity(Intent intent, boolean dismissShade,
+            @Nullable ActivityLaunchAnimator.Controller animationController,
+            boolean showOverLockscreenWhenLocked, UserHandle userHandle) {
         // Make sure that we dismiss the keyguard if it is directly dismissable or when we don't
         // want to show the activity above it.
         if (mKeyguardStateController.isUnlocked() || !showOverLockscreenWhenLocked) {
             startActivityDismissingKeyguard(intent, false, dismissShade,
-                false /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */,
-                0 /* flags */, animationController);
+                    false /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */,
+                    0 /* flags */, animationController, userHandle);
             return;
         }
 
@@ -1755,7 +1764,7 @@
                         .create(mContext)
                         .addNextIntent(intent)
                         .startActivities(getActivityOptions(getDisplayId(), adapter),
-                                UserHandle.CURRENT));
+                                userHandle));
     }
 
     /**
@@ -1775,7 +1784,7 @@
     public void startActivity(Intent intent, boolean dismissShade, Callback callback) {
         startActivityDismissingKeyguard(intent, false, dismissShade,
                 false /* disallowEnterPictureInPictureWhileLaunching */, callback, 0,
-                null /* animationController */);
+                null /* animationController */, UserHandle.CURRENT);
     }
 
     public void setQsExpanded(boolean expanded) {
@@ -1869,13 +1878,7 @@
         if (!mPresenter.isCollapsing()) {
             onClosingFinished();
         }
-
-        // Collapse the panel if we're launching in fullscreen, over the lockscreen. Do not do this
-        // if the device has gone back to sleep - through a horrific chain of 15 or so function
-        // calls, instantCollapseNotificationPanel will eventually call through to
-        // StatusBar#wakeUpIfDozing, which will wake the device up even if it was put to sleep
-        // during the launch animation.
-        if (launchIsFullScreen && mPowerManager.isInteractive()) {
+        if (launchIsFullScreen) {
             instantCollapseNotificationPanel();
         }
     }
@@ -2417,7 +2420,7 @@
             boolean dismissShade, int flags) {
         startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade,
                 false /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */,
-                flags, null /* animationController */);
+                flags, null /* animationController */, UserHandle.CURRENT);
     }
 
     public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
@@ -2428,7 +2431,8 @@
     void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
             final boolean dismissShade, final boolean disallowEnterPictureInPictureWhileLaunching,
             final Callback callback, int flags,
-            @Nullable ActivityLaunchAnimator.Controller animationController) {
+            @Nullable ActivityLaunchAnimator.Controller animationController,
+            final UserHandle userHandle) {
         if (onlyProvisioned && !mDeviceProvisionedController.isDeviceProvisioned()) return;
 
         final boolean willLaunchResolverActivity =
@@ -2487,7 +2491,7 @@
                                     intent,
                                     intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                                     null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null,
-                                    options.toBundle(), UserHandle.CURRENT.getIdentifier());
+                                    options.toBundle(), userHandle.getIdentifier());
                         } catch (RemoteException e) {
                             Log.w(TAG, "Unable to start activity", e);
                         }
@@ -2860,7 +2864,8 @@
                                 false /* disallowEnterPictureInPictureWhileLaunching */,
                                 null /* callback */,
                                 0 /* flags */,
-                                animationController),
+                                animationController,
+                                UserHandle.CURRENT),
                 delay);
     }
 
@@ -2881,8 +2886,7 @@
     }
 
     boolean updateIsKeyguard(boolean forceStateChange) {
-        boolean wakeAndUnlocking = mBiometricUnlockController.getMode()
-                == BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
+        boolean wakeAndUnlocking = mBiometricUnlockController.isWakeAndUnlock();
 
         // For dozing, keyguard needs to be shown whenever the device is non-interactive. Otherwise
         // there's no surface we can show to the user. Note that the device goes fully interactive
@@ -2892,7 +2896,7 @@
                 && (!mDeviceInteractive || (isGoingToSleep()
                     && (isScreenFullyOff()
                         || (mKeyguardStateController.isShowing() && !isOccluded()))));
-        boolean isWakingAndOccluded = isOccluded() && isWaking();
+        boolean isWakingAndOccluded = isOccluded() && isWakingOrAwake();
         boolean shouldBeKeyguard = (mStatusBarStateController.isKeyguardRequested()
                 || keyguardForDozing) && !wakeAndUnlocking && !isWakingAndOccluded;
         if (keyguardForDozing) {
@@ -2964,12 +2968,15 @@
      *
      * @param beforeFading the runnable to be run when the circle is fully expanded and the fading
      *                     starts
-     * @param endRunnable the runnable to be run when the transition is done
+     * @param endRunnable the runnable to be run when the transition is done. Will not run
+     *                    if the transition is cancelled, instead cancelRunnable will run
+     * @param cancelRunnable the runnable to be run if the transition is cancelled
      */
     public void fadeKeyguardAfterLaunchTransition(final Runnable beforeFading,
-            Runnable endRunnable) {
+            Runnable endRunnable, Runnable cancelRunnable) {
         mMessageRouter.cancelMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
         mLaunchTransitionEndRunnable = endRunnable;
+        mLaunchTransitionCancelRunnable = cancelRunnable;
         Runnable hideRunnable = () -> {
             mKeyguardStateController.setLaunchTransitionFadingAway(true);
             if (beforeFading != null) {
@@ -2991,6 +2998,15 @@
         }
     }
 
+    private void cancelAfterLaunchTransitionRunnables() {
+        if (mLaunchTransitionCancelRunnable != null) {
+            mLaunchTransitionCancelRunnable.run();
+        }
+        mLaunchTransitionEndRunnable = null;
+        mLaunchTransitionCancelRunnable = null;
+        mNotificationPanelViewController.setLaunchTransitionEndRunnable(null);
+    }
+
     /**
      * Fades the content of the Keyguard while we are dozing and makes it invisible when finished
      * fading.
@@ -3030,6 +3046,7 @@
     }
 
     private void runLaunchTransitionEndRunnable() {
+        mLaunchTransitionCancelRunnable = null;
         if (mLaunchTransitionEndRunnable != null) {
             Runnable r = mLaunchTransitionEndRunnable;
 
@@ -3076,7 +3093,6 @@
         mMessageRouter.cancelMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
         releaseGestureWakeLock();
         mNotificationPanelViewController.onAffordanceLaunchEnded();
-        mNotificationPanelViewController.cancelAnimation();
         mNotificationPanelViewController.resetAlpha();
         mNotificationPanelViewController.resetTranslation();
         mNotificationPanelViewController.resetViewGroupFade();
@@ -3128,6 +3144,10 @@
     public void finishKeyguardFadingAway() {
         mKeyguardStateController.notifyKeyguardDoneFading();
         mScrimController.setExpansionAffectsAlpha(true);
+
+        // If the device was re-locked while unlocking, we might have a pending lock that was
+        // delayed because the keyguard was in the middle of going away.
+        mKeyguardViewMediator.maybeHandlePendingLock();
     }
 
     /**
@@ -3518,6 +3538,10 @@
         public void onStartedGoingToSleep() {
             String tag = "CentralSurfaces#onStartedGoingToSleep";
             DejankUtils.startDetectingBlockingIpcs(tag);
+
+            //  cancel stale runnables that could put the device in the wrong state
+            cancelAfterLaunchTransitionRunnables();
+
             updateRevealEffect(false /* wakingUp */);
             updateNotificationPanelTouchState();
             maybeEscalateHeadsUp();
@@ -3702,8 +3726,9 @@
                 == WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP;
     }
 
-    boolean isWaking() {
-        return mWakefulnessLifecycle.getWakefulness() == WakefulnessLifecycle.WAKEFULNESS_WAKING;
+    boolean isWakingOrAwake() {
+        return mWakefulnessLifecycle.getWakefulness() == WakefulnessLifecycle.WAKEFULNESS_WAKING
+                || mWakefulnessLifecycle.getWakefulness() == WakefulnessLifecycle.WAKEFULNESS_AWAKE;
     }
 
     public void notifyBiometricAuthModeChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
index 536be1c..c4e655a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
@@ -371,7 +371,7 @@
             mCentralSurfaces.startActivityDismissingKeyguard(cameraIntent,
                     false /* onlyProvisioned */, true /* dismissShade */,
                     true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
-                    null /* animationController */);
+                    null /* animationController */, UserHandle.CURRENT);
         } else {
             if (!mCentralSurfaces.isDeviceInteractive()) {
                 // Avoid flickering of the scrim when we instant launch the camera and the bouncer
@@ -428,7 +428,7 @@
             mCentralSurfaces.startActivityDismissingKeyguard(emergencyIntent,
                     false /* onlyProvisioned */, true /* dismissShade */,
                     true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
-                    null /* animationController */);
+                    null /* animationController */, UserHandle.CURRENT);
             return;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index dc1af36..347e05c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -555,6 +555,7 @@
         mControlsButton.setImageResource(mControlsComponent.getTileImageId());
         mControlsButton.setContentDescription(getContext()
                 .getString(mControlsComponent.getTileTitleId()));
+        updateAffordanceColors();
 
         boolean hasFavorites = mControlsComponent.getControlsController()
                 .map(c -> c.getFavorites().size() > 0)
@@ -1100,7 +1101,9 @@
             mIndicationArea.setPadding(mIndicationPadding, 0, mIndicationPadding, 0);
         } else {
             mQRCodeScannerButton.setVisibility(GONE);
-            mIndicationArea.setPadding(0, 0, 0, 0);
+            if (mControlsButton.getVisibility() == GONE) {
+                mIndicationArea.setPadding(0, 0, 0, 0);
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 95a2a6e..7d96240 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -606,11 +606,47 @@
         mResetCallbacks.remove(callback);
     }
 
+    /**
+     * Adds a callback to listen to bouncer expansion updates.
+     */
+    public void addBouncerExpansionCallback(BouncerExpansionCallback callback) {
+        if (!mExpansionCallbacks.contains(callback)) {
+            mExpansionCallbacks.add(callback);
+        }
+    }
+
+    /**
+     * Removes a previously added callback. If the callback was never added, this methood
+     * does nothing.
+     */
+    public void removeBouncerExpansionCallback(BouncerExpansionCallback callback) {
+        mExpansionCallbacks.remove(callback);
+    }
+
     public interface BouncerExpansionCallback {
-        void onFullyShown();
-        void onStartingToHide();
-        void onStartingToShow();
-        void onFullyHidden();
+        /**
+         * Invoked when the bouncer expansion reaches {@link KeyguardBouncer#EXPANSION_VISIBLE}.
+         */
+        default void onFullyShown() {
+        }
+
+        /**
+         * Invoked when the bouncer is starting to transition to a hidden state.
+         */
+        default void onStartingToHide() {
+        }
+
+        /**
+         * Invoked when the bouncer is starting to transition to a visible state.
+         */
+        default void onStartingToShow() {
+        }
+
+        /**
+         * Invoked when the bouncer expansion reaches {@link KeyguardBouncer#EXPANSION_HIDDEN}.
+         */
+        default void onFullyHidden() {
+        }
 
         /**
          * From 0f {@link KeyguardBouncer#EXPANSION_VISIBLE} when fully visible
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 732e5f0..83970dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -23,6 +23,7 @@
 import android.content.res.Resources;
 import android.util.MathUtils;
 
+import com.android.keyguard.BouncerPanelExpansionCalculator;
 import com.android.keyguard.KeyguardStatusView;
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
@@ -147,7 +148,7 @@
         mStatusViewBottomMargin = res.getDimensionPixelSize(
                 R.dimen.keyguard_status_view_bottom_margin);
         mSplitShadeTopNotificationsMargin =
-                res.getDimensionPixelSize(R.dimen.split_shade_header_height);
+                res.getDimensionPixelSize(R.dimen.large_screen_shade_header_height);
         mSplitShadeTargetTopMargin =
                 res.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin);
 
@@ -169,7 +170,8 @@
             boolean isSplitShade, float udfpsTop, float clockBottom, boolean isClockTopAligned) {
         mMinTopMargin = keyguardStatusBarHeaderHeight + Math.max(mContainerTopPadding,
                 userSwitchHeight);
-        mPanelExpansion = panelExpansion;
+        mPanelExpansion = BouncerPanelExpansionCalculator
+                .getKeyguardClockScaledExpansion(panelExpansion);
         mKeyguardStatusHeight = keyguardStatusHeight + mStatusViewBottomMargin;
         mUserSwitchHeight = userSwitchHeight;
         mUserSwitchPreferredY = userSwitchPreferredY;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
index 571c10b..64b0b4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
@@ -16,34 +16,52 @@
 
 package com.android.systemui.statusbar.phone
 
+import android.content.Context
+import android.content.pm.PackageManager
 import android.hardware.Sensor
 import android.hardware.TriggerEvent
 import android.hardware.TriggerEventListener
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.systemui.CoreStartable
 import com.android.systemui.Dumpable
+import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.util.Assert
 import com.android.systemui.util.sensors.AsyncSensorManager
 import java.io.FileDescriptor
 import java.io.PrintWriter
+import javax.inject.Inject
 
-class KeyguardLiftController constructor(
+/**
+ * Triggers face auth on lift when the device is showing the lock screen. Only initialized
+ * if face auth is supported on the device. Not to be confused with the lift to wake gesture
+ * which is handled by {@link com.android.server.policy.PhoneWindowManager}.
+ */
+@SysUISingleton
+class KeyguardLiftController @Inject constructor(
+    private val context: Context,
     private val statusBarStateController: StatusBarStateController,
     private val asyncSensorManager: AsyncSensorManager,
     private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
-    dumpManager: DumpManager
-) : StatusBarStateController.StateListener, Dumpable, KeyguardUpdateMonitorCallback() {
+    private val dumpManager: DumpManager
+) : Dumpable, CoreStartable(context) {
 
     private val pickupSensor = asyncSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE)
     private var isListening = false
     private var bouncerVisible = false
 
-    init {
+    override fun start() {
+        if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) {
+            init()
+        }
+    }
+
+    private fun init() {
         dumpManager.registerDumpable(javaClass.name, this)
-        statusBarStateController.addCallback(this)
-        keyguardUpdateMonitor.registerCallback(this)
+        statusBarStateController.addCallback(statusBarStateListener)
+        keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
         updateListeningState()
     }
 
@@ -58,17 +76,21 @@
         }
     }
 
-    override fun onDozingChanged(isDozing: Boolean) {
-        updateListeningState()
+    private val keyguardUpdateMonitorCallback = object : KeyguardUpdateMonitorCallback() {
+        override fun onKeyguardBouncerChanged(bouncer: Boolean) {
+            bouncerVisible = bouncer
+            updateListeningState()
+        }
+
+        override fun onKeyguardVisibilityChanged(showing: Boolean) {
+            updateListeningState()
+        }
     }
 
-    override fun onKeyguardBouncerChanged(bouncer: Boolean) {
-        bouncerVisible = bouncer
-        updateListeningState()
-    }
-
-    override fun onKeyguardVisibilityChanged(showing: Boolean) {
-        updateListeningState()
+    private val statusBarStateListener = object : StatusBarStateController.StateListener {
+        override fun onDozingChanged(isDozing: Boolean) {
+            updateListeningState()
+        }
     }
 
     override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 65173a2..cb332bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -174,7 +174,7 @@
     }
 
     private void updateKeyguardStatusBarHeight() {
-        MarginLayoutParams lp =  (MarginLayoutParams) getLayoutParams();
+        MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
         lp.height = getStatusBarHeaderHeightKeyguard(mContext);
         setLayoutParams(lp);
     }
@@ -510,28 +510,6 @@
         }
     }
 
-    void onSystemChromeAnimationStart(boolean isAnimatingOut) {
-        if (isAnimatingOut) {
-            mSystemIconsContainer.setVisibility(View.VISIBLE);
-            mSystemIconsContainer.setAlpha(0f);
-        }
-    }
-
-    void onSystemChromeAnimationEnd(boolean isAnimatingIn) {
-        // Make sure the system icons are out of the way
-        if (isAnimatingIn) {
-            mSystemIconsContainer.setVisibility(View.INVISIBLE);
-            mSystemIconsContainer.setAlpha(0f);
-        } else {
-            mSystemIconsContainer.setAlpha(1f);
-            mSystemIconsContainer.setVisibility(View.VISIBLE);
-        }
-    }
-
-    void onSystemChromeAnimationUpdate(float animatedValue) {
-        mSystemIconsContainer.setAlpha(animatedValue);
-    }
-
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         super.onLayout(changed, l, t, r, b);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 1df1aff..57d6348 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -17,8 +17,6 @@
 package com.android.systemui.statusbar.phone;
 
 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_IN;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_OUT;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -47,6 +45,7 @@
 import com.android.systemui.statusbar.notification.PropertyAnimator;
 import com.android.systemui.statusbar.notification.stack.AnimationProperties;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
+import com.android.systemui.statusbar.phone.fragment.StatusBarSystemEventAnimator;
 import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserInfoTracker;
 import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherController;
 import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherFeatureController;
@@ -59,7 +58,6 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
 
 import javax.inject.Inject;
@@ -107,6 +105,8 @@
                 @Override
                 public void onDensityOrFontScaleChanged() {
                     mView.loadDimens();
+                    // The animator is dependent on resources for offsets
+                    mSystemEventAnimator = new StatusBarSystemEventAnimator(mView, getResources());
                 }
 
                 @Override
@@ -123,21 +123,16 @@
 
     private final SystemStatusAnimationCallback mAnimationCallback =
             new SystemStatusAnimationCallback() {
+                @NonNull
                 @Override
-                public void onSystemChromeAnimationStart() {
-                    mView.onSystemChromeAnimationStart(
-                            mAnimationScheduler.getAnimationState() == ANIMATING_OUT);
+                public Animator onSystemEventAnimationFinish(boolean hasPersistentDot) {
+                    return mSystemEventAnimator.onSystemEventAnimationFinish(hasPersistentDot);
                 }
 
+                @NonNull
                 @Override
-                public void onSystemChromeAnimationEnd() {
-                    mView.onSystemChromeAnimationEnd(
-                            mAnimationScheduler.getAnimationState() == ANIMATING_IN);
-                }
-
-                @Override
-                public void onSystemChromeAnimationUpdate(@NonNull ValueAnimator anim) {
-                    mView.onSystemChromeAnimationUpdate((float) anim.getAnimatedValue());
+                public Animator onSystemEventAnimationBegin() {
+                    return mSystemEventAnimator.onSystemEventAnimationBegin();
                 }
             };
 
@@ -232,6 +227,12 @@
     private int mStatusBarState;
     private boolean mDozing;
     private boolean mShowingKeyguardHeadsUp;
+    private StatusBarSystemEventAnimator mSystemEventAnimator;
+
+    /**
+     * The alpha value to be set on the View. If -1, this value is to be ignored.
+     */
+    private float mExplicitAlpha = -1f;
 
     @Inject
     public KeyguardStatusBarViewController(
@@ -292,16 +293,15 @@
         );
 
         Resources r = getResources();
-        mBlockedIcons = Collections.unmodifiableList(Arrays.asList(
-                r.getString(com.android.internal.R.string.status_bar_volume),
-                r.getString(com.android.internal.R.string.status_bar_alarm_clock),
-                r.getString(com.android.internal.R.string.status_bar_call_strength)));
+        mBlockedIcons = Arrays.asList(r.getStringArray(
+                R.array.config_keyguard_statusbar_icon_blocklist));
         mNotificationsHeaderCollideDistance = r.getDimensionPixelSize(
                 R.dimen.header_notifications_collide_distance);
 
         mView.setKeyguardUserAvatarEnabled(
                 !mFeatureController.isStatusBarUserSwitcherFeatureEnabled());
         mFeatureController.addCallback(enabled -> mView.setKeyguardUserAvatarEnabled(!enabled));
+        mSystemEventAnimator = new StatusBarSystemEventAnimator(mView, r);
     }
 
     @Override
@@ -430,9 +430,15 @@
 
         float alphaQsExpansion = 1 - Math.min(
                 1, mNotificationPanelViewStateProvider.getLockscreenShadeDragProgress() * 2);
-        float newAlpha = Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
-                * mKeyguardStatusBarAnimateAlpha
-                * (1.0f - mKeyguardHeadsUpShowingAmount);
+
+        float newAlpha;
+        if (mExplicitAlpha != -1) {
+            newAlpha = mExplicitAlpha;
+        } else {
+            newAlpha = Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
+                    * mKeyguardStatusBarAnimateAlpha
+                    * (1.0f - mKeyguardHeadsUpShowingAmount);
+        }
 
         boolean hideForBypass =
                 mFirstBypassAttempt && mKeyguardUpdateMonitor.shouldListenForFace()
@@ -515,7 +521,17 @@
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("KeyguardStatusBarView:");
         pw.println("  mBatteryListening: " + mBatteryListening);
+        pw.println("  mExplicitAlpha: " + mExplicitAlpha);
         mView.dump(fd, pw, args);
     }
 
+    /**
+     * Sets the alpha to be set on the view.
+     *
+     * @param alpha a value between 0 and 1. -1 if the value is to be reset/ignored.
+     */
+    public void setAlpha(float alpha) {
+        mExplicitAlpha = alpha;
+        updateViewState();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LargeScreenShadeHeaderController.kt
similarity index 73%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/LargeScreenShadeHeaderController.kt
index 7555356..a5fcea7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LargeScreenShadeHeaderController.kt
@@ -31,35 +31,35 @@
 import com.android.systemui.qs.HeaderPrivacyIconsController
 import com.android.systemui.qs.carrier.QSCarrierGroupController
 import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope
-import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.SPLIT_SHADE_BATTERY_CONTROLLER
-import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.SPLIT_SHADE_HEADER
+import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.LARGE_SCREEN_BATTERY_CONTROLLER
+import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.LARGE_SCREEN_SHADE_HEADER
 import java.io.FileDescriptor
 import java.io.PrintWriter
 import javax.inject.Inject
 import javax.inject.Named
 
 @CentralSurfacesScope
-class SplitShadeHeaderController @Inject constructor(
-    @Named(SPLIT_SHADE_HEADER) private val statusBar: View,
+class LargeScreenShadeHeaderController @Inject constructor(
+    @Named(LARGE_SCREEN_SHADE_HEADER) private val header: View,
     private val statusBarIconController: StatusBarIconController,
     private val privacyIconsController: HeaderPrivacyIconsController,
     qsCarrierGroupControllerBuilder: QSCarrierGroupController.Builder,
     featureFlags: FeatureFlags,
-    @Named(SPLIT_SHADE_BATTERY_CONTROLLER) batteryMeterViewController: BatteryMeterViewController,
+    @Named(LARGE_SCREEN_BATTERY_CONTROLLER) batteryMeterViewController: BatteryMeterViewController,
     dumpManager: DumpManager
 ) : Dumpable {
 
     companion object {
         private val HEADER_TRANSITION_ID = R.id.header_transition
-        private val SPLIT_HEADER_TRANSITION_ID = R.id.split_header_transition
+        private val LARGE_SCREEN_HEADER_TRANSITION_ID = R.id.large_screen_header_transition
         private val QQS_HEADER_CONSTRAINT = R.id.qqs_header_constraint
         private val QS_HEADER_CONSTRAINT = R.id.qs_header_constraint
-        private val SPLIT_HEADER_CONSTRAINT = R.id.split_header_constraint
+        private val LARGE_SCREEN_HEADER_CONSTRAINT = R.id.large_screen_header_constraint
 
         private fun Int.stateToString() = when (this) {
             QQS_HEADER_CONSTRAINT -> "QQS Header"
             QS_HEADER_CONSTRAINT -> "QS Header"
-            SPLIT_HEADER_CONSTRAINT -> "Split Header"
+            LARGE_SCREEN_HEADER_CONSTRAINT -> "Large Screen Header"
             else -> "Unknown state"
         }
     }
@@ -87,19 +87,19 @@
             onShadeExpandedChanged()
         }
 
-    var splitShadeMode = false
+    var active = false
         set(value) {
             if (field == value) {
                 return
             }
             field = value
-            onSplitShadeModeChanged()
+            onHeaderStateChanged()
         }
 
     var shadeExpandedFraction = -1f
         set(value) {
             if (visible && field != value) {
-                statusBar.alpha = ShadeInterpolation.getContentAlpha(value)
+                header.alpha = ShadeInterpolation.getContentAlpha(value)
                 field = value
             }
         }
@@ -123,53 +123,53 @@
 
     private val chipVisibilityListener: ChipVisibilityListener = object : ChipVisibilityListener {
         override fun onChipVisibilityRefreshed(visible: Boolean) {
-            if (statusBar is MotionLayout) {
-                val state = statusBar.getConstraintSet(QQS_HEADER_CONSTRAINT).apply {
+            if (header is MotionLayout) {
+                val state = header.getConstraintSet(QQS_HEADER_CONSTRAINT).apply {
                     setAlpha(R.id.statusIcons, if (visible) 0f else 1f)
                     setAlpha(R.id.batteryRemainingIcon, if (visible) 0f else 1f)
                 }
-                statusBar.updateState(QQS_HEADER_CONSTRAINT, state)
+                header.updateState(QQS_HEADER_CONSTRAINT, state)
             }
         }
     }
 
     init {
-        if (statusBar is MotionLayout) {
-            val context = statusBar.context
-            val resources = statusBar.resources
-            statusBar.getConstraintSet(QQS_HEADER_CONSTRAINT)
+        if (header is MotionLayout) {
+            val context = header.context
+            val resources = header.resources
+            header.getConstraintSet(QQS_HEADER_CONSTRAINT)
                     .load(context, resources.getXml(R.xml.qqs_header))
-            statusBar.getConstraintSet(QS_HEADER_CONSTRAINT)
+            header.getConstraintSet(QS_HEADER_CONSTRAINT)
                     .load(context, resources.getXml(R.xml.qs_header))
-            statusBar.getConstraintSet(SPLIT_HEADER_CONSTRAINT)
-                    .load(context, resources.getXml(R.xml.split_header))
+            header.getConstraintSet(LARGE_SCREEN_HEADER_CONSTRAINT)
+                    .load(context, resources.getXml(R.xml.large_screen_shade_header))
             privacyIconsController.chipVisibilityListener = chipVisibilityListener
         }
     }
 
     init {
         batteryMeterViewController.init()
-        val batteryIcon: BatteryMeterView = statusBar.findViewById(R.id.batteryRemainingIcon)
+        val batteryIcon: BatteryMeterView = header.findViewById(R.id.batteryRemainingIcon)
 
         // battery settings same as in QS icons
         batteryMeterViewController.ignoreTunerUpdates()
         batteryIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE)
 
-        iconContainer = statusBar.findViewById(R.id.statusIcons)
+        iconContainer = header.findViewById(R.id.statusIcons)
         iconManager = StatusBarIconController.TintedIconManager(iconContainer, featureFlags)
-        iconManager.setTint(Utils.getColorAttrDefaultColor(statusBar.context,
+        iconManager.setTint(Utils.getColorAttrDefaultColor(header.context,
                 android.R.attr.textColorPrimary))
 
         carrierIconSlots = if (featureFlags.isEnabled(Flags.COMBINED_STATUS_BAR_SIGNAL_ICONS)) {
             listOf(
-                statusBar.context.getString(com.android.internal.R.string.status_bar_no_calling),
-                statusBar.context.getString(com.android.internal.R.string.status_bar_call_strength)
+                header.context.getString(com.android.internal.R.string.status_bar_no_calling),
+                header.context.getString(com.android.internal.R.string.status_bar_call_strength)
             )
         } else {
-            listOf(statusBar.context.getString(com.android.internal.R.string.status_bar_mobile))
+            listOf(header.context.getString(com.android.internal.R.string.status_bar_mobile))
         }
         qsCarrierGroupController = qsCarrierGroupControllerBuilder
-                .setQSCarrierGroup(statusBar.findViewById(R.id.carrier_group))
+                .setQSCarrierGroup(header.findViewById(R.id.carrier_group))
                 .build()
 
         dumpManager.registerDumpable(this)
@@ -179,8 +179,8 @@
     }
 
     private fun updateScrollY() {
-        if (!splitShadeMode && combinedHeaders) {
-            statusBar.scrollY = qsScrollY
+        if (!active && combinedHeaders) {
+            header.scrollY = qsScrollY
         }
     }
 
@@ -194,8 +194,8 @@
         updatePosition()
     }
 
-    private fun onSplitShadeModeChanged() {
-        if (splitShadeMode || combinedHeaders) {
+    private fun onHeaderStateChanged() {
+        if (active || combinedHeaders) {
             privacyIconsController.onParentVisible()
         } else {
             privacyIconsController.onParentInvisible()
@@ -205,15 +205,15 @@
     }
 
     private fun updateVisibility() {
-        val visibility = if (!splitShadeMode && !combinedHeaders) {
+        val visibility = if (!active && !combinedHeaders) {
             View.GONE
         } else if (shadeExpanded) {
             View.VISIBLE
         } else {
             View.INVISIBLE
         }
-        if (statusBar.visibility != visibility) {
-            statusBar.visibility = visibility
+        if (header.visibility != visibility) {
+            header.visibility = visibility
             visible = visibility == View.VISIBLE
         }
     }
@@ -222,20 +222,20 @@
         if (!combinedHeaders) {
             return
         }
-        statusBar as MotionLayout
-        if (splitShadeMode) {
-            statusBar.setTransition(SPLIT_HEADER_TRANSITION_ID)
+        header as MotionLayout
+        if (active) {
+            header.setTransition(LARGE_SCREEN_HEADER_TRANSITION_ID)
         } else {
-            statusBar.setTransition(HEADER_TRANSITION_ID)
-            statusBar.transitionToStart()
+            header.setTransition(HEADER_TRANSITION_ID)
+            header.transitionToStart()
             updatePosition()
             updateScrollY()
         }
     }
 
     private fun updatePosition() {
-        if (statusBar is MotionLayout && !splitShadeMode && visible) {
-            statusBar.setProgress(qsExpandedFraction)
+        if (header is MotionLayout && !active && visible) {
+            header.setProgress(qsExpandedFraction)
         }
     }
 
@@ -263,12 +263,12 @@
         pw.println("visible: $visible")
         pw.println("shadeExpanded: $shadeExpanded")
         pw.println("shadeExpandedFraction: $shadeExpandedFraction")
-        pw.println("splitShadeMode: $splitShadeMode")
+        pw.println("active: $active")
         pw.println("qsExpandedFraction: $qsExpandedFraction")
         pw.println("qsScrollY: $qsScrollY")
         if (combinedHeaders) {
-            statusBar as MotionLayout
-            pw.println("currentState: ${statusBar.currentState.stateToString()}")
+            header as MotionLayout
+            pw.println("currentState: ${header.currentState.stateToString()}")
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java
index 324d47e..799e5fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java
@@ -19,6 +19,7 @@
 import static com.android.systemui.DejankUtils.whitelistIpcs;
 
 import android.content.Intent;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.view.View;
 import android.view.ViewGroup;
@@ -62,7 +63,7 @@
 
                 mActivityStarter.startActivity(intent, true /* dismissShade */,
                         ActivityLaunchAnimator.Controller.fromView(v, null),
-                        true /* showOverlockscreenwhenlocked */);
+                        true /* showOverlockscreenwhenlocked */, UserHandle.SYSTEM);
             } else {
                 mUserSwitchDialogController.showDialog(v);
             }
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 0a2ea4c..2d16b52 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.phone;
 
 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
-import static android.view.View.GONE;
 
 import static androidx.constraintlayout.widget.ConstraintSet.END;
 import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID;
@@ -144,7 +143,6 @@
 import com.android.systemui.statusbar.KeyguardAffordanceView;
 import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -165,17 +163,16 @@
 import com.android.systemui.statusbar.notification.ViewGroupFadeHelper;
 import com.android.systemui.statusbar.notification.collection.ListEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
 import com.android.systemui.statusbar.notification.collection.render.ShadeViewManager;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
 import com.android.systemui.statusbar.notification.stack.AmbientState;
 import com.android.systemui.statusbar.notification.stack.AnimationProperties;
-import com.android.systemui.statusbar.notification.stack.MediaContainerView;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
 import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
@@ -190,6 +187,7 @@
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.statusbar.window.StatusBarWindowStateController;
 import com.android.systemui.unfold.SysUIUnfoldComponent;
+import com.android.systemui.util.LargeScreenUtils;
 import com.android.systemui.util.ListenerSet;
 import com.android.systemui.util.Utils;
 import com.android.systemui.util.settings.SecureSettings;
@@ -312,17 +310,16 @@
     private final ControlsComponent mControlsComponent;
     private final NotificationRemoteInputManager mRemoteInputManager;
 
-    // Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow card.
-    // If there are exactly 1 + mMaxKeyguardNotifications, then still shows all notifications
-    private final int mMaxKeyguardNotifications;
     private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
     private final TapAgainViewController mTapAgainViewController;
-    private final SplitShadeHeaderController mSplitShadeHeaderController;
+    private final LargeScreenShadeHeaderController mLargeScreenShadeHeaderController;
     private final RecordingController mRecordingController;
     private final PanelEventsEmitter mPanelEventsEmitter;
     private boolean mShouldUseSplitNotificationShade;
     // The bottom padding reserved for elements of the keyguard measuring notifications
     private float mKeyguardNotificationBottomPadding;
+    // Space available for notifications.
+    private float mKeyguardNotificationAvailableSpace;
     // Current max allowed keyguard notifications determined by measuring the panel
     private int mMaxAllowedKeyguardNotifications;
 
@@ -340,7 +337,7 @@
     private NotificationsQuickSettingsContainer mNotificationContainerParent;
     private NotificationsQSContainerController mNotificationsQSContainerController;
     private boolean mAnimateNextPositionUpdate;
-    private float mQuickQsOffsetHeight;
+    private float mQuickQsHeaderHeight;
     private ScreenOffAnimationController mScreenOffAnimationController;
 
     private int mTrackingPointer;
@@ -391,7 +388,7 @@
     private float mDownY;
     private int mDisplayTopInset = 0; // in pixels
     private int mDisplayRightInset = 0; // in pixels
-    private int mSplitShadeStatusBarHeight;
+    private int mLargeScreenShadeHeaderHeight;
     private int mSplitShadeNotificationsScrimMarginBottom;
 
     private final KeyguardClockPositionAlgorithm
@@ -446,8 +443,6 @@
         setHeadsUpAnimatingAway(false);
         updatePanelExpansionAndVisibility();
     };
-    // TODO (b/162832756): once migrated to the new pipeline, delete legacy group manager
-    private NotificationGroupManagerLegacy mGroupManager;
     private boolean mShowIconsWhenExpanded;
     private int mIndicationBottomPadding;
     private int mAmbientIndicationBottomPadding;
@@ -509,7 +504,6 @@
     private final NotificationEntryManager mEntryManager;
 
     private final CommandQueue mCommandQueue;
-    private final NotificationLockscreenUserManager mLockscreenUserManager;
     private final UserManager mUserManager;
     private final MediaDataManager mMediaDataManager;
     private final SysUiState mSysUiState;
@@ -616,6 +610,11 @@
      */
     private float mKeyguardOnlyContentAlpha = 1.0f;
 
+    /**
+     * The translationY of the views which only show on the keyguard but in shade / shade locked.
+     */
+    private int mKeyguardOnlyTransitionTranslationY = 0;
+
     private float mUdfpsMaxYBurnInOffset;
 
     /**
@@ -646,6 +645,7 @@
             mNotificationPanelUnfoldAnimationController;
 
     private final NotificationListContainer mNotificationListContainer;
+    private final NotificationStackSizeCalculator mNotificationStackSizeCalculator;
 
     private View.AccessibilityDelegate mAccessibilityDelegate = new View.AccessibilityDelegate() {
         @Override
@@ -690,7 +690,6 @@
             DynamicPrivacyController dynamicPrivacyController,
             KeyguardBypassController bypassController, FalsingManager falsingManager,
             FalsingCollector falsingCollector,
-            NotificationLockscreenUserManager notificationLockscreenUserManager,
             NotificationEntryManager notificationEntryManager,
             KeyguardStateController keyguardStateController,
             StatusBarStateController statusBarStateController,
@@ -716,7 +715,6 @@
             KeyguardUserSwitcherComponent.Factory keyguardUserSwitcherComponentFactory,
             KeyguardStatusBarViewComponent.Factory keyguardStatusBarViewComponentFactory,
             LockscreenShadeTransitionController lockscreenShadeTransitionController,
-            NotificationGroupManagerLegacy groupManager,
             NotificationIconAreaController notificationIconAreaController,
             AuthController authController,
             ScrimController scrimController,
@@ -736,7 +734,7 @@
             RecordingController recordingController,
             @Main Executor uiExecutor,
             SecureSettings secureSettings,
-            SplitShadeHeaderController splitShadeHeaderController,
+            LargeScreenShadeHeaderController largeScreenShadeHeaderController,
             ScreenOffAnimationController screenOffAnimationController,
             LockscreenGestureLogger lockscreenGestureLogger,
             PanelExpansionStateManager panelExpansionStateManager,
@@ -748,7 +746,8 @@
             SysUiState sysUiState,
             KeyguardUnlockAnimationController keyguardUnlockAnimationController,
             NotificationListContainer notificationListContainer,
-            PanelEventsEmitter panelEventsEmitter) {
+            PanelEventsEmitter panelEventsEmitter,
+            NotificationStackSizeCalculator notificationStackSizeCalculator) {
         super(view,
                 falsingManager,
                 dozeLog,
@@ -780,9 +779,9 @@
         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
         mNotificationsQSContainerController = notificationsQSContainerController;
         mNotificationListContainer = notificationListContainer;
+        mNotificationStackSizeCalculator = notificationStackSizeCalculator;
         mNotificationsQSContainerController.init();
         mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
-        mGroupManager = groupManager;
         mNotificationIconAreaController = notificationIconAreaController;
         mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
         mKeyguardStatusBarViewComponentFactory = keyguardStatusBarViewComponentFactory;
@@ -793,9 +792,9 @@
         mFragmentService = fragmentService;
         mSettingsChangeObserver = new SettingsChangeObserver(handler);
         mShouldUseSplitNotificationShade =
-                Utils.shouldUseSplitNotificationShade(mResources);
+                LargeScreenUtils.shouldUseSplitNotificationShade(mResources);
         mView.setWillNotDraw(!DEBUG);
-        mSplitShadeHeaderController = splitShadeHeaderController;
+        mLargeScreenShadeHeaderController = largeScreenShadeHeaderController;
         mLayoutInflater = layoutInflater;
         mFeatureFlags = featureFlags;
         mFalsingManager = falsingManager;
@@ -844,7 +843,6 @@
         });
         mBottomAreaShadeAlphaAnimator.setDuration(160);
         mBottomAreaShadeAlphaAnimator.setInterpolator(Interpolators.ALPHA_OUT);
-        mLockscreenUserManager = notificationLockscreenUserManager;
         mEntryManager = notificationEntryManager;
         mConversationNotificationManager = conversationNotificationManager;
         mAuthController = authController;
@@ -869,7 +867,6 @@
             mView.getOverlay().add(new DebugDrawable());
         }
 
-        mMaxKeyguardNotifications = resources.getInteger(R.integer.keyguard_max_notification_count);
         mKeyguardUnfoldTransition = unfoldComponent.map(c -> c.getKeyguardUnfoldTransition());
         mNotificationPanelUnfoldAnimationController = unfoldComponent.map(
                 SysUIUnfoldComponent::getNotificationPanelUnfoldAnimationController);
@@ -897,10 +894,17 @@
                         mDepthController.setBlursDisabledForUnlock(mTracking);
 
                         if (playingCannedAnimation && !isWakeAndUnlock) {
-                            // Fling the panel away so it's not in the way or the surface behind the
+                            // Hide the panel so it's not in the way or the surface behind the
                             // keyguard, which will be appearing. If we're wake and unlocking, the
                             // lock screen is hidden instantly so should not be flung away.
-                            fling(0f, false, 0.7f, false);
+                            if (isTracking() || isFlinging()) {
+                                // Instant collpase the notification panel since the notification
+                                // panel is already in the middle animating
+                                onTrackingStopped(false);
+                                instantCollapse();
+                            } else {
+                                fling(0f, false, 0.7f, false);
+                            }
                         }
                     }
                 });
@@ -1075,24 +1079,28 @@
     }
 
     public void updateResources() {
-        mQuickQsOffsetHeight = SystemBarUtils.getQuickQsOffsetHeight(mView.getContext());
         mSplitShadeNotificationsScrimMarginBottom =
                 mResources.getDimensionPixelSize(
                         R.dimen.split_shade_notifications_scrim_margin_bottom);
 
         final boolean newShouldUseSplitNotificationShade =
-                Utils.shouldUseSplitNotificationShade(mResources);
+                LargeScreenUtils.shouldUseSplitNotificationShade(mResources);
         final boolean splitNotificationShadeChanged =
                 mShouldUseSplitNotificationShade != newShouldUseSplitNotificationShade;
 
         mShouldUseSplitNotificationShade = newShouldUseSplitNotificationShade;
+        boolean useLargeScreenShadeHeader =
+                LargeScreenUtils.shouldUseLargeScreenShadeHeader(mView.getResources());
         if (mQs != null) {
             mQs.setInSplitShade(mShouldUseSplitNotificationShade);
         }
-        mSplitShadeStatusBarHeight = Utils.getSplitShadeStatusBarHeight(mView.getContext());
-        int topMargin = mShouldUseSplitNotificationShade ? mSplitShadeStatusBarHeight :
+        mLargeScreenShadeHeaderHeight =
+                mResources.getDimensionPixelSize(R.dimen.large_screen_shade_header_height);
+        mQuickQsHeaderHeight = useLargeScreenShadeHeader ? mLargeScreenShadeHeaderHeight :
+                SystemBarUtils.getQuickQsOffsetHeight(mView.getContext());
+        int topMargin = useLargeScreenShadeHeader ? mLargeScreenShadeHeaderHeight :
                 mResources.getDimensionPixelSize(R.dimen.notification_panel_margin_top);
-        mSplitShadeHeaderController.setSplitShadeMode(mShouldUseSplitNotificationShade);
+        mLargeScreenShadeHeaderController.setActive(useLargeScreenShadeHeader);
         mAmbientState.setStackTopMargin(topMargin);
         mNotificationsQSContainerController.updateResources();
 
@@ -1102,6 +1110,8 @@
 
         if (splitNotificationShadeChanged) {
             updateClockAppearance();
+            updateQsState();
+            mNotificationStackScrollLayoutController.updateFooter();
         }
     }
 
@@ -1233,12 +1243,14 @@
         if (mKeyguardShowing && !mKeyguardBypassController.getBypassEnabled()) {
             mNotificationStackScrollLayoutController.setMaxDisplayedNotifications(
                     mMaxAllowedKeyguardNotifications);
-            mNotificationStackScrollLayoutController.setKeyguardBottomPadding(
+            mNotificationStackScrollLayoutController.setKeyguardBottomPaddingForDebug(
                     mKeyguardNotificationBottomPadding);
+            mNotificationStackScrollLayoutController.mKeyguardNotificationAvailableSpaceForDebug(
+                    mKeyguardNotificationAvailableSpace);
         } else {
             // no max when not on the keyguard
             mNotificationStackScrollLayoutController.setMaxDisplayedNotifications(-1);
-            mNotificationStackScrollLayoutController.setKeyguardBottomPadding(-1f);
+            mNotificationStackScrollLayoutController.setKeyguardBottomPaddingForDebug(-1f);
         }
     }
 
@@ -1449,132 +1461,45 @@
      * @return the maximum keyguard notifications that can fit on the screen
      */
     private int computeMaxKeyguardNotifications() {
-        float minPadding = mClockPositionAlgorithm.getMinStackScrollerPadding();
         int notificationPadding = Math.max(
                 1, mResources.getDimensionPixelSize(R.dimen.notification_divider_height));
-        float shelfSize =
+        float topPadding = mNotificationStackScrollLayoutController.getTopPadding();
+        float shelfHeight =
                 mNotificationShelfController.getVisibility() == View.GONE
                         ? 0
                         : mNotificationShelfController.getIntrinsicHeight() + notificationPadding;
 
+        // Padding to add to the bottom of the stack to keep a minimum distance from the top of
+        // the lock icon.
         float lockIconPadding = 0;
         if (mLockIconViewController.getTop() != 0) {
-            lockIconPadding = mCentralSurfaces.getDisplayHeight() - mLockIconViewController.getTop()
-                + mResources.getDimensionPixelSize(R.dimen.min_lock_icon_padding);
+            final float lockIconTopWithPadding = mLockIconViewController.getTop()
+                    - mResources.getDimensionPixelSize(R.dimen.min_lock_icon_padding);
+            lockIconPadding = mNotificationStackScrollLayoutController.getBottom()
+                    - lockIconTopWithPadding;
         }
 
-        float bottomPadding = Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding);
-        bottomPadding = Math.max(lockIconPadding, bottomPadding);
+        float bottomPadding = Math.max(lockIconPadding,
+                Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding));
         mKeyguardNotificationBottomPadding = bottomPadding;
 
         float availableSpace =
                 mNotificationStackScrollLayoutController.getHeight()
-                        - minPadding
-                        - shelfSize
+                        - topPadding
+                        - shelfHeight
                         - bottomPadding;
+        mKeyguardNotificationAvailableSpace = availableSpace;
 
-        int count = 0;
-        ExpandableView previousView = null;
-        for (int i = 0; i < mNotificationStackScrollLayoutController.getChildCount(); i++) {
-            ExpandableView child = mNotificationStackScrollLayoutController.getChildAt(i);
-            if (child instanceof ExpandableNotificationRow) {
-                ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-                boolean suppressedSummary = mGroupManager != null
-                        && mGroupManager.isSummaryOfSuppressedGroup(row.getEntry().getSbn());
-                if (suppressedSummary) {
-                    continue;
-                }
-                if (!canShowViewOnLockscreen(child)) {
-                    continue;
-                }
-                if (row.isRemoved()) {
-                    continue;
-                }
-            } else if (child instanceof MediaContainerView) {
-                if (child.getVisibility() == GONE) {
-                    continue;
-                }
-                if (child.getIntrinsicHeight() == 0) {
-                    continue;
-                }
-            } else {
-                continue;
-            }
-            availableSpace -= child.getMinHeight(true /* ignoreTemporaryStates */);
-            availableSpace -= count == 0 ? 0 : notificationPadding;
-            availableSpace -= mNotificationStackScrollLayoutController
-                    .calculateGapHeight(previousView, child, count);
-            previousView = child;
-            if (availableSpace >= 0
-                    && (mMaxKeyguardNotifications == -1 || count < mMaxKeyguardNotifications)) {
-                count++;
-            } else if (availableSpace > -shelfSize) {
-                // if we are exactly the last view, then we can show us still!
-                int childCount = mNotificationStackScrollLayoutController.getChildCount();
-                for (int j = i + 1; j < childCount; j++) {
-                    ExpandableView view = mNotificationStackScrollLayoutController.getChildAt(j);
-                    if (view instanceof ExpandableNotificationRow
-                            && canShowViewOnLockscreen(view)) {
-                        return count;
-                    }
-                }
-                count++;
-                return count;
-            } else {
-                return count;
-            }
-        }
-        return count;
-    }
-
-    /**
-     * Can a view be shown on the lockscreen when calculating the number of allowed notifications
-     * to show?
-     *
-     * @param child the view in question
-     * @return true if it can be shown
-     */
-    private boolean canShowViewOnLockscreen(ExpandableView child) {
-        if (child.hasNoContentHeight()) {
-            return false;
-        }
-        if (child instanceof ExpandableNotificationRow &&
-                !canShowRowOnLockscreen((ExpandableNotificationRow) child)) {
-            return false;
-        } else if (child.getVisibility() == GONE) {
-            // ENRs can be gone and count because their visibility is only set after
-            // this calculation, but all other views should be up to date
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Can a row be shown on the lockscreen when calculating the number of allowed notifications
-     * to show?
-     *
-     * @param row the row in question
-     * @return true if it can be shown
-     */
-    private boolean canShowRowOnLockscreen(ExpandableNotificationRow row) {
-        boolean suppressedSummary =
-                mGroupManager != null && mGroupManager.isSummaryOfSuppressedGroup(
-                        row.getEntry().getSbn());
-        if (suppressedSummary) {
-            return false;
-        }
-        if (!mLockscreenUserManager.shouldShowOnKeyguard(row.getEntry())) {
-            return false;
-        }
-        if (row.isRemoved()) {
-            return false;
-        }
-        return true;
+        return mNotificationStackSizeCalculator.computeMaxKeyguardNotifications(
+                mNotificationStackScrollLayoutController.getView(), availableSpace,
+                shelfHeight);
     }
 
     private void updateClock() {
         float alpha = mClockPositionResult.clockAlpha * mKeyguardOnlyContentAlpha;
         mKeyguardStatusViewController.setAlpha(alpha);
+        mKeyguardStatusViewController
+                .setTranslationYExcludingMedia(mKeyguardOnlyTransitionTranslationY);
         if (mKeyguardQsUserSwitchController != null) {
             mKeyguardQsUserSwitchController.setAlpha(alpha);
         }
@@ -2355,9 +2280,9 @@
         float shadeExpandedFraction = mTransitioningToFullShadeProgress > 0
                 ? mLockscreenShadeTransitionController.getQSDragProgress()
                 : getExpandedFraction();
-        mSplitShadeHeaderController.setShadeExpandedFraction(shadeExpandedFraction);
-        mSplitShadeHeaderController.setQsExpandedFraction(qsExpansionFraction);
-        mSplitShadeHeaderController.setShadeExpanded(mQsVisible);
+        mLargeScreenShadeHeaderController.setShadeExpandedFraction(shadeExpandedFraction);
+        mLargeScreenShadeHeaderController.setQsExpandedFraction(qsExpansionFraction);
+        mLargeScreenShadeHeaderController.setShadeExpanded(mQsVisible);
     }
 
     private void onStackYChanged(boolean shouldAnimate) {
@@ -2376,7 +2301,7 @@
     }
 
     private void updateQSExpansionEnabledAmbient() {
-        final float scrollRangeToTop = mAmbientState.getTopPadding() - mQuickQsOffsetHeight;
+        final float scrollRangeToTop = mAmbientState.getTopPadding() - mQuickQsHeaderHeight;
         mQsExpansionEnabledAmbient = mShouldUseSplitNotificationShade
                 || (mAmbientState.getScrollY() <= scrollRangeToTop);
         setQsExpansionEnabled();
@@ -2402,7 +2327,7 @@
     private int calculateTopQsClippingBound(int qsPanelBottomY) {
         int top;
         if (mShouldUseSplitNotificationShade) {
-            top = Math.min(qsPanelBottomY, mSplitShadeStatusBarHeight);
+            top = Math.min(qsPanelBottomY, mLargeScreenShadeHeaderHeight);
         } else {
             if (mTransitioningToFullShadeProgress > 0.0f) {
                 // If we're transitioning, let's use the actual value. The else case
@@ -2437,7 +2362,7 @@
     private int calculateBottomQsClippingBound(int top) {
         if (mShouldUseSplitNotificationShade) {
             return top + mNotificationStackScrollLayoutController.getHeight()
-                    - mSplitShadeNotificationsScrimMarginBottom;
+                    + mSplitShadeNotificationsScrimMarginBottom;
         } else {
             return getView().getBottom();
         }
@@ -2539,8 +2464,8 @@
             mQsTranslationForFullShadeTransition = qsTranslation;
             updateQsFrameTranslation();
             float currentTranslation = mQsFrame.getTranslationY();
-            mQsClipTop = (int) (top - currentTranslation);
-            mQsClipBottom = (int) (bottom - currentTranslation);
+            mQsClipTop = (int) (top - currentTranslation - mQsFrame.getTop());
+            mQsClipBottom = (int) (bottom - currentTranslation - mQsFrame.getTop());
             mQsVisible = qsVisible;
             mQs.setFancyClipping(
                     mQsClipTop,
@@ -2555,7 +2480,12 @@
             // be visible, otherwise you can see the bounds once swiping up to see bouncer
             mScrimController.setNotificationsBounds(0, 0, 0, 0);
         } else {
-            mScrimController.setNotificationsBounds(left, top, right, bottom);
+            // Increase the height of the notifications scrim when not in split shade
+            // (e.g. portrait tablet) so the rounded corners are not visible at the bottom,
+            // in this case they are rendered off-screen
+            final int notificationsScrimBottom =
+                    mShouldUseSplitNotificationShade ? bottom : bottom + radius;
+            mScrimController.setNotificationsBounds(left, top, right, notificationsScrimBottom);
         }
 
         if (mShouldUseSplitNotificationShade) {
@@ -2565,10 +2495,13 @@
         }
 
         mScrimController.setScrimCornerRadius(radius);
+
+        // Convert global clipping coordinates to local ones,
+        // relative to NotificationStackScrollLayout
         int nsslLeft = left - mNotificationStackScrollLayoutController.getLeft();
         int nsslRight = right - mNotificationStackScrollLayoutController.getLeft();
         int nsslTop = top - mNotificationStackScrollLayoutController.getTop();
-        int nsslBottom = bottom;
+        int nsslBottom = bottom - mNotificationStackScrollLayoutController.getTop();
         int bottomRadius = mShouldUseSplitNotificationShade ? radius : 0;
         mNotificationStackScrollLayoutController.setRoundedClippingBounds(
                 nsslLeft, nsslTop, nsslRight, nsslBottom, radius, bottomRadius);
@@ -2576,8 +2509,11 @@
 
     private float getQSEdgePosition() {
         // TODO: replace StackY with unified calculation
-        return Math.max(mQuickQsOffsetHeight * mAmbientState.getExpansionFraction(),
-                mAmbientState.getStackY() - mAmbientState.getScrollY());
+        return Math.max(mQuickQsHeaderHeight * mAmbientState.getExpansionFraction(),
+                mAmbientState.getStackY()
+                        // need to adjust for extra margin introduced by large screen shade header
+                        + mAmbientState.getStackTopMargin() * mAmbientState.getExpansionFraction()
+                        - mAmbientState.getScrollY());
     }
 
     private int calculateQsBottomPosition(float qsExpansionFraction) {
@@ -2732,11 +2668,12 @@
     }
 
     /**
-     * Set the alpha of the keyguard elements which only show on the lockscreen, but not in
-     * shade locked / shade. This is used when dragging down to the full shade.
+     * Set the alpha and translationY of the keyguard elements which only show on the lockscreen,
+     * but not in shade locked / shade. This is used when dragging down to the full shade.
      */
-    public void setKeyguardOnlyContentAlpha(float keyguardAlpha) {
+    public void setKeyguardTransitionProgress(float keyguardAlpha, int keyguardTranslationY) {
         mKeyguardOnlyContentAlpha = Interpolators.ALPHA_IN.getInterpolation(keyguardAlpha);
+        mKeyguardOnlyTransitionTranslationY = keyguardTranslationY;
         if (mBarState == KEYGUARD) {
             // If the animator is running, it's already fading out the content and this is a reset
             mBottomAreaShadeAlpha = mKeyguardOnlyContentAlpha;
@@ -2745,6 +2682,15 @@
         updateClock();
     }
 
+    /**
+     * Sets the alpha value to be set on the keyguard status bar.
+     *
+     * @param alpha value between 0 and 1. -1 if the value is to be reset.
+     */
+    public void setKeyguardStatusBarAlpha(float alpha) {
+        mKeyguardStatusBarViewController.setAlpha(alpha);
+    }
+
     private void trackMovement(MotionEvent event) {
         if (mQsVelocityTracker != null) mQsVelocityTracker.addMovement(event);
     }
@@ -3001,9 +2947,7 @@
     }
 
     private int calculatePanelHeightShade() {
-        int emptyBottomMargin = mNotificationStackScrollLayoutController.getEmptyBottomMargin();
-        int maxHeight = mNotificationStackScrollLayoutController.getHeight() - emptyBottomMargin;
-
+        final int maxHeight = mNotificationStackScrollLayoutController.getHeight();
         if (mBarState == KEYGUARD) {
             int minKeyguardPanelBottom = mClockPositionAlgorithm.getLockscreenStatusViewHeight()
                     + mNotificationStackScrollLayoutController.getIntrinsicContentHeight();
@@ -3275,12 +3219,14 @@
     @Override
     protected void onUnlockHintFinished() {
         super.onUnlockHintFinished();
+        mScrimController.setExpansionAffectsAlpha(true);
         mNotificationStackScrollLayoutController.setUnlockHintRunning(false);
     }
 
     @Override
     protected void onUnlockHintStarted() {
         super.onUnlockHintStarted();
+        mScrimController.setExpansionAffectsAlpha(false);
         mNotificationStackScrollLayoutController.setUnlockHintRunning(true);
     }
 
@@ -3610,7 +3556,7 @@
     public final QS.ScrollListener mScrollListener = new QS.ScrollListener() {
         @Override
         public void onQsPanelScrollChanged(int scrollY) {
-            mSplitShadeHeaderController.setQsScrollY(scrollY);
+            mLargeScreenShadeHeaderController.setQsScrollY(scrollY);
             if (scrollY > 0 && !mQsFullyExpanded) {
                 if (DEBUG) Log.d(TAG, "Scrolling while not expanded. Forcing expand");
                 // If we are scrolling QS, we should be fully expanded.
@@ -4877,6 +4823,8 @@
                     "calculateNotificationsTopPadding()");
             drawDebugInfo(canvas, mClockPositionResult.clockY, Color.GRAY,
                     "mClockPositionResult.clockY");
+            drawDebugInfo(canvas, (int) mLockIconViewController.getTop(), Color.GRAY,
+                    "mLockIconViewController.getTop()");
 
             mDebugPaint.setColor(Color.CYAN);
             canvas.drawLine(0, mClockPositionResult.stackScrollerPadding, mView.getWidth(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
index 0ff010a..16e5732 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -386,10 +386,12 @@
             }
             visible = true;
         }
-        if (visible) {
-            mNotificationShadeView.setVisibility(View.VISIBLE);
-        } else {
-            mNotificationShadeView.setVisibility(View.INVISIBLE);
+        if (mNotificationShadeView != null) {
+            if (visible) {
+                mNotificationShadeView.setVisibility(View.VISIBLE);
+            } else {
+                mNotificationShadeView.setVisibility(View.INVISIBLE);
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
index 101c86f..787c4c03 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
@@ -36,12 +36,14 @@
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.dock.DockManager;
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.lowlightclock.LowLightClockController;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.notification.stack.AmbientState;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
@@ -71,6 +73,8 @@
     private final LockIconViewController mLockIconViewController;
     private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     private final StatusBarWindowStateController mStatusBarWindowStateController;
+    private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+    private final AmbientState mAmbientState;
 
     private GestureDetector mGestureDetector;
     private View mBrightnessMirror;
@@ -109,7 +113,9 @@
             LockIconViewController lockIconViewController,
             Optional<LowLightClockController> lowLightClockController,
             CentralSurfaces centralSurfaces,
-            NotificationShadeWindowController controller) {
+            NotificationShadeWindowController controller,
+            KeyguardUnlockAnimationController keyguardUnlockAnimationController,
+            AmbientState ambientState) {
         mLockscreenShadeTransitionController = transitionController;
         mFalsingCollector = falsingCollector;
         mTunerService = tunerService;
@@ -126,6 +132,8 @@
         mLowLightClockController = lowLightClockController;
         mService = centralSurfaces;
         mNotificationShadeWindowController = controller;
+        mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
+        mAmbientState = ambientState;
 
         // This view is not part of the newly inflated expanded status bar.
         mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container);
@@ -203,7 +211,6 @@
                 // Reset manual touch dispatch state here but make sure the UP/CANCEL event still
                 // gets
                 // delivered.
-
                 if (!isCancel && mService.shouldIgnoreTouch()) {
                     return false;
                 }
@@ -219,6 +226,16 @@
                     return false;
                 }
 
+                if (mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) {
+                    // If the user was sliding their finger across the lock screen,
+                    // we may have been intercepting the touch and forwarding it to the
+                    // UDFPS affordance via mStatusBarKeyguardViewManager.onTouch (see below).
+                    // If this touch ended up unlocking the device, we want to cancel the touch
+                    // immediately, so we don't cause swipe or expand animations afterwards.
+                    cancelCurrentTouch();
+                    return true;
+                }
+
                 mFalsingCollector.onTouchEvent(ev);
                 mGestureDetector.onTouchEvent(ev);
                 mStatusBarKeyguardViewManager.onTouch(ev);
@@ -430,6 +447,7 @@
             event.recycle();
             mTouchCancelled = true;
         }
+        mAmbientState.setSwipingUp(false);
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt
index e4161a3..745228e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt
@@ -4,6 +4,7 @@
 import android.view.ViewGroup
 import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
 import android.view.WindowInsets
+import androidx.annotation.VisibleForTesting
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
 import androidx.constraintlayout.widget.ConstraintSet.END
@@ -11,6 +12,7 @@
 import androidx.constraintlayout.widget.ConstraintSet.START
 import androidx.constraintlayout.widget.ConstraintSet.TOP
 import com.android.systemui.R
+import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
 import com.android.systemui.navigationbar.NavigationModeController
@@ -19,16 +21,21 @@
 import com.android.systemui.recents.OverviewProxyService
 import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener
 import com.android.systemui.shared.system.QuickStepContract
-import com.android.systemui.util.Utils
+import com.android.systemui.util.LargeScreenUtils
 import com.android.systemui.util.ViewController
+import com.android.systemui.util.concurrency.DelayableExecutor
 import java.util.function.Consumer
 import javax.inject.Inject
 
+@VisibleForTesting
+internal const val INSET_DEBOUNCE_MILLIS = 500L
+
 class NotificationsQSContainerController @Inject constructor(
     view: NotificationsQuickSettingsContainer,
     private val navigationModeController: NavigationModeController,
     private val overviewProxyService: OverviewProxyService,
-    private val featureFlags: FeatureFlags
+    private val featureFlags: FeatureFlags,
+    @Main private val delayableExecutor: DelayableExecutor
 ) : ViewController<NotificationsQuickSettingsContainer>(view), QSContainerController {
 
     var qsExpanded = false
@@ -43,7 +50,8 @@
     private var isQSCustomizing = false
     private var isQSCustomizerAnimating = false
 
-    private var splitShadeStatusBarHeight = 0
+    private var largeScreenShadeHeaderHeight = 0
+    private var largeScreenShadeHeaderActive = false
     private var notificationsBottomMargin = 0
     private var scrimShadeBottomMargin = 0
     private var bottomStableInsets = 0
@@ -60,11 +68,29 @@
             taskbarVisible = visible
         }
     }
-    private val windowInsetsListener: Consumer<WindowInsets> = Consumer { insets ->
-        // when taskbar is visible, stableInsetBottom will include its height
-        bottomStableInsets = insets.stableInsetBottom
-        bottomCutoutInsets = insets.displayCutout?.safeInsetBottom ?: 0
-        updateBottomSpacing()
+
+    // With certain configuration changes (like light/dark changes), the nav bar will disappear
+    // for a bit, causing `bottomStableInsets` to be unstable for some time. Debounce the value
+    // for 500ms.
+    // All interactions with this object happen in the main thread.
+    private val delayedInsetSetter = object : Runnable, Consumer<WindowInsets> {
+        private var canceller: Runnable? = null
+        private var stableInsets = 0
+        private var cutoutInsets = 0
+
+        override fun accept(insets: WindowInsets) {
+            // when taskbar is visible, stableInsetBottom will include its height
+            stableInsets = insets.stableInsetBottom
+            cutoutInsets = insets.displayCutout?.safeInsetBottom ?: 0
+            canceller?.run()
+            canceller = delayableExecutor.executeDelayed(this, INSET_DEBOUNCE_MILLIS)
+        }
+
+        override fun run() {
+            bottomStableInsets = stableInsets
+            bottomCutoutInsets = cutoutInsets
+            updateBottomSpacing()
+        }
     }
 
     override fun onInit() {
@@ -77,7 +103,7 @@
     public override fun onViewAttached() {
         updateResources()
         overviewProxyService.addCallback(taskbarVisibilityListener)
-        mView.setInsetsChangedListener(windowInsetsListener)
+        mView.setInsetsChangedListener(delayedInsetSetter)
         mView.setQSFragmentAttachedListener { qs: QS -> qs.setContainerController(this) }
         mView.setConfigurationChangedListener { updateResources() }
     }
@@ -90,16 +116,18 @@
     }
 
     fun updateResources() {
-        val newSplitShadeEnabled = Utils.shouldUseSplitNotificationShade(resources)
+        val newSplitShadeEnabled = LargeScreenUtils.shouldUseSplitNotificationShade(resources)
         val splitShadeEnabledChanged = newSplitShadeEnabled != splitShadeEnabled
         splitShadeEnabled = newSplitShadeEnabled
+        largeScreenShadeHeaderActive = LargeScreenUtils.shouldUseLargeScreenShadeHeader(resources)
         notificationsBottomMargin = resources.getDimensionPixelSize(
                 R.dimen.notification_panel_margin_bottom)
-        splitShadeStatusBarHeight = Utils.getSplitShadeStatusBarHeight(context)
+        largeScreenShadeHeaderHeight =
+                resources.getDimensionPixelSize(R.dimen.large_screen_shade_header_height)
         panelMarginHorizontal = resources.getDimensionPixelSize(
                 R.dimen.notification_panel_margin_horizontal)
-        topMargin = if (splitShadeEnabled) {
-            splitShadeStatusBarHeight
+        topMargin = if (largeScreenShadeHeaderActive) {
+            largeScreenShadeHeaderHeight
         } else {
             resources.getDimensionPixelSize(R.dimen.notification_panel_margin_top)
         }
@@ -204,13 +232,13 @@
         setKeyguardStatusViewConstraints(constraintSet)
         setQsConstraints(constraintSet)
         setNotificationsConstraints(constraintSet)
-        setSplitShadeStatusBarConstraints(constraintSet)
+        setLargeScreenShadeHeaderConstraints(constraintSet)
         mView.applyConstraints(constraintSet)
     }
 
-    private fun setSplitShadeStatusBarConstraints(constraintSet: ConstraintSet) {
-        if (splitShadeEnabled) {
-            constraintSet.constrainHeight(R.id.split_shade_status_bar, splitShadeStatusBarHeight)
+    private fun setLargeScreenShadeHeaderConstraints(constraintSet: ConstraintSet) {
+        if (largeScreenShadeHeaderActive) {
+            constraintSet.constrainHeight(R.id.split_shade_status_bar, largeScreenShadeHeaderHeight)
         } else {
             if (useCombinedQSHeaders) {
                 constraintSet.constrainHeight(R.id.split_shade_status_bar, WRAP_CONTENT)
@@ -234,7 +262,7 @@
         val endConstraintId = if (splitShadeEnabled) R.id.qs_edge_guideline else PARENT_ID
         constraintSet.apply {
             connect(R.id.qs_frame, END, endConstraintId, END)
-            setMargin(R.id.qs_frame, START, panelMarginHorizontal)
+            setMargin(R.id.qs_frame, START, if (splitShadeEnabled) 0 else panelMarginHorizontal)
             setMargin(R.id.qs_frame, END, if (splitShadeEnabled) 0 else panelMarginHorizontal)
             setMargin(R.id.qs_frame, TOP, topMargin)
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 1d560c4..9398fcd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -382,7 +382,7 @@
 
     protected void startExpandMotion(float newX, float newY, boolean startTracking,
             float expandedHeight) {
-        if (!mHandlingPointerUp) {
+        if (!mHandlingPointerUp && !mStatusBarStateController.isDozing()) {
             beginJankMonitoring(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
         }
         mInitialOffsetOnTouch = expandedHeight;
@@ -445,7 +445,7 @@
                 mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_UNLOCK);
             }
             @Classifier.InteractionType int interactionType = vel == 0 ? GENERIC
-                    : vel > 0 ? QUICK_SETTINGS
+                    : y - mInitialTouchY > 0 ? QUICK_SETTINGS
                             : (mKeyguardStateController.canDismissLockScreen()
                                     ? UNLOCK : BOUNCER_UNLOCK);
 
@@ -532,7 +532,7 @@
             return true;
         }
 
-        @Classifier.InteractionType int interactionType = vel > 0
+        @Classifier.InteractionType int interactionType = y - mInitialTouchY > 0
                 ? QUICK_SETTINGS : (
                         mKeyguardStateController.canDismissLockScreen() ? UNLOCK : BOUNCER_UNLOCK);
 
@@ -654,7 +654,9 @@
 
             @Override
             public void onAnimationStart(Animator animation) {
-                beginJankMonitoring(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
+                if (!mStatusBarStateController.isDozing()) {
+                    beginJankMonitoring(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
+                }
             }
 
             @Override
@@ -794,6 +796,7 @@
             }
             mExpandedFraction = Math.min(1f,
                     maxPanelHeight == 0 ? 0 : mExpandedHeight / maxPanelHeight);
+            mAmbientState.setExpansionFraction(mExpandedFraction);
             onHeightUpdated(mExpandedHeight);
             updatePanelExpansionAndVisibility();
         });
@@ -862,6 +865,10 @@
         return mClosing || mIsLaunchAnimationRunning;
     }
 
+    public boolean isFlinging() {
+        return mIsFlinging;
+    }
+
     public boolean isTracking() {
         return mTracking;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 0059c1b..d7abf74 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -349,7 +349,7 @@
     }
 
     private String getManagedProfileAccessibilityString() {
-        return mDevicePolicyManager.getString(
+        return mDevicePolicyManager.getResources().getString(
                 STATUS_BAR_WORK_ICON_ACCESSIBILITY,
                 () -> mResources.getString(R.string.accessibility_managed_profile));
     }
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 419661b7..7e22510 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -41,6 +41,7 @@
 import com.android.internal.colorextraction.ColorExtractor.GradientColors;
 import com.android.internal.graphics.ColorUtils;
 import com.android.internal.util.function.TriConsumer;
+import com.android.keyguard.BouncerPanelExpansionCalculator;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.settingslib.Utils;
@@ -51,6 +52,7 @@
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dock.DockManager;
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.scrim.ScrimView;
 import com.android.systemui.statusbar.notification.stack.ViewState;
 import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
@@ -116,6 +118,15 @@
     private float mTransitionToFullShadeProgress;
 
     /**
+     * Same as {@link #mTransitionToFullShadeProgress}, but specifically for the notifications scrim
+     * on the lock screen.
+     *
+     * On split shade lock screen we want the different scrims to fade in at different times and
+     * rates.
+     */
+    private float mTransitionToLockScreenFullShadeNotificationsProgress;
+
+    /**
      * If we're currently transitioning to the full shade.
      */
     private boolean mTransitioningToFullShade;
@@ -185,6 +196,7 @@
     private final Handler mHandler;
     private final Executor mMainExecutor;
     private final ScreenOffAnimationController mScreenOffAnimationController;
+    private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
 
     private GradientColors mColors;
     private boolean mNeedsDrawableColorUpdate;
@@ -201,6 +213,7 @@
     private float mPanelExpansionFraction = 1f; // Assume shade is expanded during initialization
     private float mQsExpansion;
     private boolean mQsBottomVisible;
+    private boolean mAnimatingPanelExpansionOnUnlock; // don't animate scrim
 
     private boolean mDarkenWhileDragging;
     private boolean mExpansionAffectsAlpha = true;
@@ -245,7 +258,8 @@
             KeyguardUpdateMonitor keyguardUpdateMonitor, DockManager dockManager,
             ConfigurationController configurationController, @Main Executor mainExecutor,
             ScreenOffAnimationController screenOffAnimationController,
-            PanelExpansionStateManager panelExpansionStateManager) {
+            PanelExpansionStateManager panelExpansionStateManager,
+            KeyguardUnlockAnimationController keyguardUnlockAnimationController) {
         mScrimStateListener = lightBarController::setScrimState;
         mDefaultScrimAlpha = BUSY_SCRIM_ALPHA;
 
@@ -263,6 +277,7 @@
         // to make sure that text on top of it is legible.
         mDozeParameters = dozeParameters;
         mDockManager = dockManager;
+        mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
         keyguardStateController.addCallback(new KeyguardStateController.Callback() {
             @Override
             public void onKeyguardFadingAwayChanged() {
@@ -487,6 +502,9 @@
     public void onTrackingStarted() {
         mTracking = true;
         mDarkenWhileDragging = !mKeyguardStateController.canDismissLockScreen();
+        if (!mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) {
+            mAnimatingPanelExpansionOnUnlock = false;
+        }
     }
 
     public void onExpandingFinished() {
@@ -557,13 +575,20 @@
         }
 
         if (mPanelExpansionFraction != panelExpansionFraction) {
+            if (panelExpansionFraction != 0f
+                    && mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) {
+                mAnimatingPanelExpansionOnUnlock = true;
+            } else if (panelExpansionFraction == 0f) {
+                mAnimatingPanelExpansionOnUnlock = false;
+            }
+
             mPanelExpansionFraction = panelExpansionFraction;
 
             boolean relevantState = (mState == ScrimState.UNLOCKED
                     || mState == ScrimState.KEYGUARD
                     || mState == ScrimState.SHADE_LOCKED
                     || mState == ScrimState.PULSING);
-            if (!(relevantState && mExpansionAffectsAlpha)) {
+            if (!(relevantState && mExpansionAffectsAlpha) || mAnimatingPanelExpansionOnUnlock) {
                 return;
             }
             applyAndDispatchState();
@@ -574,11 +599,17 @@
      * Set the amount of progress we are currently in if we're transitioning to the full shade.
      * 0.0f means we're not transitioning yet, while 1 means we're all the way in the full
      * shade.
+     *
+     * @param progress the progress for all scrims.
+     * @param lockScreenNotificationsProgress the progress specifically for the notifications scrim.
      */
-    public void setTransitionToFullShadeProgress(float progress) {
-        if (progress != mTransitionToFullShadeProgress) {
+    public void setTransitionToFullShadeProgress(float progress,
+            float lockScreenNotificationsProgress) {
+        if (progress != mTransitionToFullShadeProgress || lockScreenNotificationsProgress
+                != mTransitionToLockScreenFullShadeNotificationsProgress) {
             mTransitionToFullShadeProgress = progress;
-            setTransitionToFullShade(progress > 0.0f);
+            mTransitionToLockScreenFullShadeNotificationsProgress = lockScreenNotificationsProgress;
+            setTransitionToFullShade(progress > 0.0f || lockScreenNotificationsProgress > 0.0f);
             applyAndDispatchState();
         }
     }
@@ -614,6 +645,13 @@
     }
 
     /**
+     * Sets the amount of vertical over scroll that should be performed on the notifications scrim.
+     */
+    public void setNotificationsOverScrollAmount(int overScrollAmount) {
+        mNotificationsScrim.setTranslationY(overScrollAmount);
+    }
+
+    /**
      * Current state of the QuickSettings when pulling it from the top.
      *
      * @param expansionFraction From 0 to 1 where 0 means collapsed and 1 expanded.
@@ -705,8 +743,10 @@
 
         if (mState == ScrimState.UNLOCKED) {
             // Darken scrim as you pull down the shade when unlocked, unless the shade is expanding
-            // because we're doing the screen off animation.
-            if (!mScreenOffAnimationController.shouldExpandNotifications()) {
+            // because we're doing the screen off animation OR the shade is collapsing because
+            // we're playing the unlock animation
+            if (!mScreenOffAnimationController.shouldExpandNotifications()
+                    && !mAnimatingPanelExpansionOnUnlock) {
                 float behindFraction = getInterpolatedFraction();
                 behindFraction = (float) Math.pow(behindFraction, 0.8f);
                 if (mClipsQsScrim) {
@@ -754,12 +794,13 @@
                 } else {
                     mNotificationsAlpha = Math.max(1.0f - getInterpolatedFraction(), mQsExpansion);
                 }
-                if (mState == ScrimState.KEYGUARD && mTransitionToFullShadeProgress > 0.0f) {
+                if (mState == ScrimState.KEYGUARD
+                        && mTransitionToLockScreenFullShadeNotificationsProgress > 0.0f) {
                     // Interpolate the notification alpha when transitioning!
                     mNotificationsAlpha = MathUtils.lerp(
                             mNotificationsAlpha,
                             getInterpolatedFraction(),
-                            mTransitionToFullShadeProgress);
+                            mTransitionToLockScreenFullShadeNotificationsProgress);
                 }
                 mNotificationsTint = mState.getNotifTint();
                 mBehindTint = behindTint;
@@ -777,6 +818,9 @@
                 mNotificationsTint = ScrimState.KEYGUARD.getNotifTint();
             }
         }
+        if (mState != ScrimState.UNLOCKED) {
+            mAnimatingPanelExpansionOnUnlock = false;
+        }
 
         assertAlphasValid();
     }
@@ -792,7 +836,15 @@
     private Pair<Integer, Float> calculateBackStateForState(ScrimState state) {
         // Either darken of make the scrim transparent when you
         // pull down the shade
-        float interpolatedFract = getInterpolatedFraction();
+        float interpolatedFract;
+
+        if (state == ScrimState.KEYGUARD)  {
+            interpolatedFract = BouncerPanelExpansionCalculator
+                    .getBackScrimScaledExpansion(mPanelExpansionFraction);
+        } else {
+            interpolatedFract = getInterpolatedFraction();
+        }
+
         float stateBehind = mClipsQsScrim ? state.getNotifAlpha() : state.getBehindAlpha();
         float behindAlpha;
         int behindTint;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index c160c22..b847885 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -19,6 +19,7 @@
 import static android.view.WindowInsets.Type.navigationBars;
 
 import static com.android.systemui.plugins.ActivityStarter.OnDismissAction;
+import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_UNLOCK_COLLAPSING;
 import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_UNLOCK_FADING;
 import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
 import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
@@ -360,7 +361,9 @@
         } else if (bouncerNeedsScrimming()) {
             mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
         } else if (mShowing) {
-            if (!isWakeAndUnlocking() && !mCentralSurfaces.isInLaunchTransition()) {
+            if (!isWakeAndUnlocking()
+                    && !mCentralSurfaces.isInLaunchTransition()
+                    && !isUnlockCollapsing()) {
                 mBouncer.setExpansion(fraction);
             }
             if (fraction != KeyguardBouncer.EXPANSION_HIDDEN && tracking
@@ -528,6 +531,11 @@
         return mode == MODE_WAKE_AND_UNLOCK || mode == MODE_WAKE_AND_UNLOCK_PULSING;
     }
 
+    private boolean isUnlockCollapsing() {
+        int mode = mBiometricUnlockController.getMode();
+        return mode == MODE_UNLOCK_COLLAPSING;
+    }
+
     /**
      * Adds a {@param runnable} to be executed after Keyguard is gone.
      */
@@ -657,14 +665,17 @@
                     SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__OCCLUDED);
             if (mCentralSurfaces.isInLaunchTransition()) {
                 setOccludedAndUpdateStates(true);
-                mCentralSurfaces.fadeKeyguardAfterLaunchTransition(null /* beforeFading */,
-                        new Runnable() {
-                            @Override
-                            public void run() {
-                                mNotificationShadeWindowController.setKeyguardOccluded(mOccluded);
-                                reset(true /* hideBouncerWhenShowing */);
-                            }
-                        });
+                final Runnable endRunnable = new Runnable() {
+                    @Override
+                    public void run() {
+                        mNotificationShadeWindowController.setKeyguardOccluded(mOccluded);
+                        reset(true /* hideBouncerWhenShowing */);
+                    }
+                };
+                mCentralSurfaces.fadeKeyguardAfterLaunchTransition(
+                        null /* beforeFading */,
+                        endRunnable,
+                        endRunnable);
                 return;
             }
 
@@ -759,7 +770,7 @@
                     hideBouncer(true /* destroyView */);
                     updateStates();
                 }
-            }, new Runnable() {
+            }, /* endRunnable */ new Runnable() {
                 @Override
                 public void run() {
                     mCentralSurfaces.hideKeyguard();
@@ -772,6 +783,15 @@
                     mViewMediatorCallback.keyguardGone();
                     executeAfterKeyguardGoneAction();
                 }
+            }, /* cancelRunnable */ new Runnable() {
+                @Override
+                public void run() {
+                    mNotificationShadeWindowController.setKeyguardFadingAway(false);
+                    if (wasFlingingToDismissKeyguard) {
+                        mCentralSurfaces.finishKeyguardFadingAway();
+                    }
+                    cancelPostAuthActions();
+                }
             });
         } else {
             executeAfterKeyguardGoneAction();
@@ -1016,6 +1036,7 @@
         if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) {
             mNotificationShadeWindowController.setBouncerShowing(bouncerShowing);
             mCentralSurfaces.setBouncerShowing(bouncerShowing);
+            mKeyguardMessageAreaController.setBouncerShowing(bouncerShowing);
         }
 
         if (occluded != mLastOccluded || mFirstUpdate) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 108d98a..6fe92fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -370,6 +370,8 @@
             mLogger.logExpandingBubble(notificationKey);
             removeHunAfterClick(row);
             expandBubbleStackOnMainThread(entry);
+            mMainThreadHandler.post(
+                    () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry));
         } else {
             startNotificationIntent(intent, fillInIntent, entry, row, animate, isActivityIntent);
         }
@@ -395,17 +397,23 @@
             mMainThreadHandler.post(() -> {
                 final Runnable removeNotification = () -> {
                     mOnUserInteractionCallback.onDismiss(entry, REASON_CLICK, summaryToRemove);
-                    mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry);
+                    if (!animate) {
+                        // If we're animating, this would be invoked after the activity launch
+                        // animation completes. Since we're not animating, the launch already
+                        // happened synchronously, so we notify the launch is complete here after
+                        // onDismiss.
+                        mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry);
+                    }
                 };
                 if (mPresenter.isCollapsing()) {
-                    // To avoid lags we're only performing the remove
-                    // after the shade is collapsed
+                    // To avoid lags we're only performing the remove after the shade is collapsed
                     mShadeController.addPostCollapseAction(removeNotification);
                 } else {
                     removeNotification.run();
                 }
             });
-        } else {
+        } else if (!canBubble && !animate) {
+            // Not animating, this is the end of the launch flow (see above comment for more info).
             mMainThreadHandler.post(
                     () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry));
         }
@@ -483,14 +491,20 @@
             boolean isActivityIntent) {
         mLogger.logStartNotificationIntent(entry.getKey(), intent);
         try {
+            Runnable onFinishAnimationCallback = animate
+                    ? () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry)
+                    : null;
             ActivityLaunchAnimator.Controller animationController =
                     new StatusBarLaunchAnimatorController(
-                            mNotificationAnimationProvider.getAnimatorController(row),
+                            mNotificationAnimationProvider
+                                    .getAnimatorController(row, onFinishAnimationCallback),
                             mCentralSurfaces,
                             isActivityIntent);
-
-            mActivityLaunchAnimator.startPendingIntentWithAnimation(animationController,
-                    animate, intent.getCreatorPackage(), (adapter) -> {
+            mActivityLaunchAnimator.startPendingIntentWithAnimation(
+                    animationController,
+                    animate,
+                    intent.getCreatorPackage(),
+                    (adapter) -> {
                         long eventTime = row.getAndResetLastActionUpTime();
                         Bundle options = eventTime > 0
                                 ? getActivityOptions(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index 79d646c..d26b378 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -63,6 +63,8 @@
     // TODO(b/203389579): Remove this once the dialog width on large screens has been agreed on.
     private static final String FLAG_TABLET_DIALOG_WIDTH =
             "persist.systemui.flag_tablet_dialog_width";
+    private static final int DEFAULT_THEME = R.style.Theme_SystemUI_Dialog;
+    private static final boolean DEFAULT_DISMISS_ON_DEVICE_LOCK = true;
 
     private final Context mContext;
     @Nullable private final DismissReceiver mDismissReceiver;
@@ -78,11 +80,15 @@
     private List<Runnable> mOnCreateRunnables = new ArrayList<>();
 
     public SystemUIDialog(Context context) {
-        this(context, R.style.Theme_SystemUI_Dialog);
+        this(context, DEFAULT_THEME, DEFAULT_DISMISS_ON_DEVICE_LOCK);
     }
 
     public SystemUIDialog(Context context, int theme) {
-        this(context, theme, true /* dismissOnDeviceLock */);
+        this(context, theme, DEFAULT_DISMISS_ON_DEVICE_LOCK);
+    }
+
+    public SystemUIDialog(Context context, boolean dismissOnDeviceLock) {
+        this(context, DEFAULT_THEME, dismissOnDeviceLock);
     }
 
     public SystemUIDialog(Context context, int theme, boolean dismissOnDeviceLock) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
index a86ad6b..5d38eea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
@@ -31,10 +31,10 @@
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutListContainerModule;
 import com.android.systemui.statusbar.phone.CentralSurfacesCommandQueueCallbacks;
+import com.android.systemui.statusbar.phone.LargeScreenShadeHeaderController;
 import com.android.systemui.statusbar.phone.NotificationPanelViewController;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController;
-import com.android.systemui.statusbar.phone.SplitShadeHeaderController;
 import com.android.systemui.statusbar.phone.StatusBarHeadsUpChangeListener;
 import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarterModule;
 import com.android.systemui.statusbar.phone.StatusBarNotificationPresenterModule;
@@ -133,9 +133,9 @@
     CentralSurfacesCommandQueueCallbacks getCentralSurfacesCommandQueueCallbacks();
 
     /**
-     * Creates a SplitShadeHeaderController.
+     * Creates a {@link LargeScreenShadeHeaderController}.
      */
-    SplitShadeHeaderController getSplitShadeHeaderController();
+    LargeScreenShadeHeaderController getLargeScreenShadeHeaderController();
 
     /**
      * Creates a new {@link CollapsedStatusBarFragment} each time it's called. See
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
index 79fe700..6c6ec19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
@@ -73,9 +73,9 @@
 @Module(subcomponents = StatusBarFragmentComponent.class)
 public abstract class StatusBarViewModule {
 
-    public static final String SPLIT_SHADE_HEADER = "split_shade_header";
+    public static final String LARGE_SCREEN_SHADE_HEADER = "large_screen_shade_header";
     private static final String SPLIT_SHADE_BATTERY_VIEW = "split_shade_battery_view";
-    public static final String SPLIT_SHADE_BATTERY_CONTROLLER = "split_shade_battery_controller";
+    public static final String LARGE_SCREEN_BATTERY_CONTROLLER = "split_shade_battery_controller";
     public static final String STATUS_BAR_FRAGMENT = "status_bar_fragment";
 
     /** */
@@ -159,15 +159,15 @@
 
     /** */
     @Provides
-    @Named(SPLIT_SHADE_HEADER)
+    @Named(LARGE_SCREEN_SHADE_HEADER)
     @CentralSurfacesComponent.CentralSurfacesScope
-    public static View getSplitShadeStatusBarView(
+    public static View getLargeScreenShadeHeaderBarView(
             NotificationShadeWindowView notificationShadeWindowView,
             FeatureFlags featureFlags) {
         ViewStub stub = notificationShadeWindowView.findViewById(R.id.qs_header_stub);
         int layoutId = featureFlags.isEnabled(Flags.COMBINED_QS_HEADERS)
                 ? R.layout.combined_qs_header
-                : R.layout.split_shade_header;
+                : R.layout.large_screen_shade_header;
         stub.setLayoutResource(layoutId);
         View v = stub.inflate();
         return v;
@@ -177,14 +177,15 @@
     @Provides
     @CentralSurfacesComponent.CentralSurfacesScope
     public static OngoingPrivacyChip getSplitShadeOngoingPrivacyChip(
-            @Named(SPLIT_SHADE_HEADER) View header) {
+            @Named(LARGE_SCREEN_SHADE_HEADER) View header) {
         return header.findViewById(R.id.privacy_chip);
     }
 
     /** */
     @Provides
     @CentralSurfacesComponent.CentralSurfacesScope
-    static StatusIconContainer providesStatusIconContainer(@Named(SPLIT_SHADE_HEADER) View header) {
+    static StatusIconContainer providesStatusIconContainer(
+            @Named(LARGE_SCREEN_SHADE_HEADER) View header) {
         return header.findViewById(R.id.statusIcons);
     }
 
@@ -192,13 +193,13 @@
     @Provides
     @CentralSurfacesComponent.CentralSurfacesScope
     @Named(SPLIT_SHADE_BATTERY_VIEW)
-    static BatteryMeterView getBatteryMeterView(@Named(SPLIT_SHADE_HEADER) View view) {
+    static BatteryMeterView getBatteryMeterView(@Named(LARGE_SCREEN_SHADE_HEADER) View view) {
         return view.findViewById(R.id.batteryRemainingIcon);
     }
 
     @Provides
     @CentralSurfacesComponent.CentralSurfacesScope
-    @Named(SPLIT_SHADE_BATTERY_CONTROLLER)
+    @Named(LARGE_SCREEN_BATTERY_CONTROLLER)
     static BatteryMeterViewController getBatteryMeterViewController(
             @Named(SPLIT_SHADE_BATTERY_VIEW) BatteryMeterView batteryMeterView,
             ConfigurationController configurationController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 2c84219..8194957 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -20,12 +20,10 @@
 import static android.app.StatusBarManager.DISABLE_ONGOING_CALL_CHIP;
 import static android.app.StatusBarManager.DISABLE_SYSTEM_INFO;
 
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_IN;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_OUT;
 import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.IDLE;
 import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.SHOWING_PERSISTENT_DOT;
 
-import android.animation.ValueAnimator;
+import android.animation.Animator;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
@@ -74,6 +72,7 @@
 import com.android.systemui.util.settings.SecureSettings;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.Executor;
 
@@ -136,6 +135,7 @@
         }
     };
     private OperatorNameViewController mOperatorNameViewController;
+    private StatusBarSystemEventAnimator mSystemEventAnimator;
 
     @SuppressLint("ValidFragment")
     public CollapsedStatusBarFragment(
@@ -210,18 +210,31 @@
         initEmergencyCryptkeeperText();
         initOperatorName();
         initNotificationIconArea();
-        mAnimationScheduler.addCallback(this);
+        mSystemEventAnimator =
+                new StatusBarSystemEventAnimator(mSystemIconArea, getResources());
     }
 
     @VisibleForTesting
     void updateBlockedIcons() {
         mBlockedIcons.clear();
 
-        if (mSecureSettings.getInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0) == 0) {
-            mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_volume));
+        // Reload the blocklist from res
+        List<String> blockList = Arrays.asList(getResources().getStringArray(
+                R.array.config_collapsed_statusbar_icon_blocklist));
+        String vibrateIconSlot = getString(com.android.internal.R.string.status_bar_volume);
+        boolean showVibrateIcon =
+                mSecureSettings.getInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0) == 0;
+
+        // Filter out vibrate icon from the blocklist if the setting is on
+        for (int i = 0; i < blockList.size(); i++) {
+            if (blockList.get(i).equals(vibrateIconSlot)) {
+                if (showVibrateIcon) {
+                    mBlockedIcons.add(blockList.get(i));
+                }
+            } else {
+                mBlockedIcons.add(blockList.get(i));
+            }
         }
-        mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_alarm_clock));
-        mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_call_strength));
 
         mMainExecutor.execute(() -> mDarkIconManager.setBlockList(mBlockedIcons));
     }
@@ -245,6 +258,7 @@
         mCommandQueue.addCallback(this);
         mStatusBarStateController.addCallback(this);
         initOngoingCallChip();
+        mAnimationScheduler.addCallback(this);
 
         mSecureSettings.registerContentObserver(
                 Settings.Secure.getUriFor(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON),
@@ -258,6 +272,7 @@
         mCommandQueue.removeCallback(this);
         mStatusBarStateController.removeCallback(this);
         mOngoingCallController.removeCallback(mOngoingCallListener);
+        mAnimationScheduler.removeCallback(this);
         mSecureSettings.unregisterContentObserver(mVolumeSettingObserver);
     }
 
@@ -265,7 +280,6 @@
     public void onDestroyView() {
         super.onDestroyView();
         mStatusBarIconController.removeIconGroup(mDarkIconManager);
-        mAnimationScheduler.removeCallback(this);
         if (mNetworkController.hasEmergencyCryptKeeperText()) {
             mNetworkController.removeCallback(mSignalCallback);
         }
@@ -576,35 +590,16 @@
         disable(getContext().getDisplayId(), mDisabled1, mDisabled2, false /* animate */);
     }
 
+    @Nullable
     @Override
-    public void onSystemChromeAnimationStart() {
-        if (mAnimationScheduler.getAnimationState() == ANIMATING_OUT
-                && !isSystemIconAreaDisabled()) {
-            mSystemIconArea.setVisibility(View.VISIBLE);
-            mSystemIconArea.setAlpha(0f);
-        }
+    public Animator onSystemEventAnimationBegin() {
+        return mSystemEventAnimator.onSystemEventAnimationBegin();
     }
 
+    @Nullable
     @Override
-    public void onSystemChromeAnimationEnd() {
-        // Make sure the system icons are out of the way
-        if (mAnimationScheduler.getAnimationState() == ANIMATING_IN) {
-            mSystemIconArea.setVisibility(View.INVISIBLE);
-            mSystemIconArea.setAlpha(0f);
-        } else {
-            if (isSystemIconAreaDisabled()) {
-                // don't unhide
-                return;
-            }
-
-            mSystemIconArea.setAlpha(1f);
-            mSystemIconArea.setVisibility(View.VISIBLE);
-        }
-    }
-
-    @Override
-    public void onSystemChromeAnimationUpdate(@NonNull ValueAnimator animator) {
-        mSystemIconArea.setAlpha((float) animator.getAnimatedValue());
+    public Animator onSystemEventAnimationFinish(boolean hasPersistentDot) {
+        return mSystemEventAnimator.onSystemEventAnimationFinish(hasPersistentDot);
     }
 
     private boolean isSystemIconAreaDisabled() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt
new file mode 100644
index 0000000..f530ec8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt
@@ -0,0 +1,84 @@
+/*
+ * 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.systemui.statusbar.phone.fragment
+
+import android.animation.Animator
+import android.animation.AnimatorSet
+import android.animation.ValueAnimator
+import android.content.res.Resources
+import android.view.View
+import com.android.systemui.R
+import com.android.systemui.statusbar.events.STATUS_BAR_X_MOVE_IN
+import com.android.systemui.statusbar.events.STATUS_BAR_X_MOVE_OUT
+import com.android.systemui.statusbar.events.SystemStatusAnimationCallback
+
+/**
+ * Tied directly to [SystemStatusAnimationScheduler]. Any StatusBar-like thing (keyguard, collapsed
+ * status bar fragment), can just feed this an animatable view to get the default system status
+ * animation.
+ *
+ * This animator relies on resources, and should be recreated whenever resources are updated. While
+ * this class could be used directly as the animation callback, it's probably best to forward calls
+ * to it so that it can be recreated at any moment without needing to remove/add callback.
+ */
+class StatusBarSystemEventAnimator(
+    val animatedView: View,
+    resources: Resources
+) : SystemStatusAnimationCallback {
+    private val translationXIn: Int = resources.getDimensionPixelSize(
+            R.dimen.ongoing_appops_chip_animation_in_status_bar_translation_x)
+    private val translationXOut: Int = resources.getDimensionPixelSize(
+            R.dimen.ongoing_appops_chip_animation_out_status_bar_translation_x)
+
+    override fun onSystemEventAnimationBegin(): Animator {
+        val moveOut = ValueAnimator.ofFloat(0f, 1f).setDuration(383)
+        moveOut.interpolator = STATUS_BAR_X_MOVE_OUT
+        moveOut.addUpdateListener { animation: ValueAnimator ->
+            animatedView.translationX = -(translationXIn * animation.animatedValue as Float)
+        }
+        val alphaOut = ValueAnimator.ofFloat(1f, 0f).setDuration(133)
+        alphaOut.interpolator = null
+        alphaOut.addUpdateListener { animation: ValueAnimator ->
+            animatedView.alpha = animation.animatedValue as Float
+        }
+
+        val animSet = AnimatorSet()
+        animSet.playTogether(moveOut, alphaOut)
+        return animSet
+    }
+
+    override fun onSystemEventAnimationFinish(hasPersistentDot: Boolean): Animator {
+        animatedView.translationX = translationXOut.toFloat()
+        val moveIn = ValueAnimator.ofFloat(1f, 0f).setDuration(467)
+        moveIn.startDelay = 33
+        moveIn.interpolator = STATUS_BAR_X_MOVE_IN
+        moveIn.addUpdateListener { animation: ValueAnimator ->
+            animatedView.translationX = translationXOut * animation.animatedValue as Float
+        }
+        val alphaIn = ValueAnimator.ofFloat(0f, 1f).setDuration(167)
+        alphaIn.startDelay = 67
+        alphaIn.interpolator = null
+        alphaIn.addUpdateListener { animation: ValueAnimator ->
+            animatedView.alpha = animation.animatedValue as Float
+        }
+
+        val animatorSet = AnimatorSet()
+        animatorSet.playTogether(moveIn, alphaIn)
+
+        return animatorSet
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt
index 909261f..0d52f46 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt
@@ -17,11 +17,12 @@
 package com.android.systemui.statusbar.phone.userswitcher
 
 import android.content.Intent
+import android.os.UserHandle
 import android.view.View
-import com.android.systemui.animation.ActivityLaunchAnimator
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
 import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.FalsingManager
 
 import com.android.systemui.qs.user.UserSwitchDialogController
 import com.android.systemui.user.UserSwitcherActivity
@@ -38,7 +39,8 @@
     private val featureController: StatusBarUserSwitcherFeatureController,
     private val userSwitcherDialogController: UserSwitchDialogController,
     private val featureFlags: FeatureFlags,
-    private val activityStarter: ActivityStarter
+    private val activityStarter: ActivityStarter,
+    private val falsingManager: FalsingManager
 ) : ViewController<StatusBarUserSwitcherContainer>(view),
         StatusBarUserSwitcherController {
     private val listener = object : CurrentUserChipInfoUpdatedListener {
@@ -57,17 +59,21 @@
         }
     }
 
-    override fun onViewAttached() {
+    public override fun onViewAttached() {
         tracker.addCallback(listener)
         featureController.addCallback(featureFlagListener)
         mView.setOnClickListener { view: View ->
+            if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+                return@setOnClickListener
+            }
+
             if (featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)) {
                 val intent = Intent(context, UserSwitcherActivity::class.java)
                 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
 
                 activityStarter.startActivity(intent, true /* dismissShade */,
-                        ActivityLaunchAnimator.Controller.fromView(view, null),
-                        true /* showOverlockscreenwhenlocked */)
+                        null /* ActivityLaunchAnimator.Controller */,
+                        true /* showOverlockscreenwhenlocked */, UserHandle.SYSTEM)
             } else {
                 userSwitcherDialogController.showDialog(view)
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index 978564f..189dca6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -207,6 +207,8 @@
 
     private void setKeyguardFadingAway(boolean keyguardFadingAway) {
         if (mKeyguardFadingAway != keyguardFadingAway) {
+            Trace.traceCounter(Trace.TRACE_TAG_APP, "keyguardFadingAway",
+                    keyguardFadingAway ? 1 : 0);
             mKeyguardFadingAway = keyguardFadingAway;
             ArrayList<Callback> callbacks = new ArrayList<>(mCallbacks);
             for (int i = 0; i < callbacks.size(); i++) {
@@ -217,7 +219,7 @@
 
     @Override
     public void notifyKeyguardDoneFading() {
-        mKeyguardGoingAway = false;
+        notifyKeyguardGoingAway(false);
         setKeyguardFadingAway(false);
     }
 
@@ -318,7 +320,11 @@
 
     @Override
     public void notifyKeyguardGoingAway(boolean keyguardGoingAway) {
-        mKeyguardGoingAway = keyguardGoingAway;
+        if (mKeyguardGoingAway != keyguardGoingAway) {
+            Trace.traceCounter(Trace.TRACE_TAG_APP, "keyguardGoingAway",
+                    keyguardGoingAway ? 1 : 0);
+            mKeyguardGoingAway = keyguardGoingAway;
+        }
     }
 
     @Override
@@ -368,6 +374,8 @@
         pw.println("  mTrusted: " + mTrusted);
         pw.println("  mDebugUnlocked: " + mDebugUnlocked);
         pw.println("  mFaceAuthEnabled: " + mFaceAuthEnabled);
+        pw.println("  isKeyguardFadingAway: " + isKeyguardFadingAway());
+        pw.println("  isKeyguardGoingAway: " + isKeyguardGoingAway());
     }
 
     private class UpdateMonitorCallback extends KeyguardUpdateMonitorCallback {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.kt
index 31ef2f6..d5f2d21 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.kt
@@ -20,7 +20,7 @@
 import android.content.res.Configuration
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.statusbar.CommandQueue
-import com.android.systemui.util.Utils
+import com.android.systemui.util.LargeScreenUtils
 import javax.inject.Inject
 
 /**
@@ -42,7 +42,8 @@
     init {
         isLandscape =
             context.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
-        shouldUseSplitNotificationShade = Utils.shouldUseSplitNotificationShade(context.resources)
+        shouldUseSplitNotificationShade =
+                LargeScreenUtils.shouldUseSplitNotificationShade(context.resources)
         configController.addCallback(this)
     }
 
@@ -73,7 +74,7 @@
             needToRecompute = true
         }
 
-        val newSplitShadeFlag = Utils.shouldUseSplitNotificationShade(context.resources)
+        val newSplitShadeFlag = LargeScreenUtils.shouldUseSplitNotificationShade(context.resources)
         if (newSplitShadeFlag != shouldUseSplitNotificationShade) {
             shouldUseSplitNotificationShade = newSplitShadeFlag
             needToRecompute = true
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 48949f92..006edca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -22,8 +22,6 @@
 import android.animation.AnimatorListenerAdapter;
 import android.app.ActivityManager;
 import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.RemoteInput;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.ColorStateList;
@@ -75,7 +73,6 @@
 import com.android.systemui.R;
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry.EditedSuggestionInfo;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 import com.android.systemui.statusbar.phone.LightBarController;
@@ -111,21 +108,15 @@
     private ProgressBar mProgressBar;
     private ImageView mDelete;
     private ImageView mDeleteBg;
-    // TODO(b/193539698): remove reveal param fields, turn them into parameters where needed
-    private int mRevealCx;
-    private int mRevealCy;
-    private int mRevealR;
     private boolean mColorized;
     private int mTint;
     private boolean mResetting;
+    @Nullable private RevealParams mRevealParams;
 
     // TODO(b/193539698): move these to a Controller
     private RemoteInputController mController;
     private final UiEventLogger mUiEventLogger;
     private NotificationEntry mEntry;
-    private PendingIntent mPendingIntent;
-    private RemoteInput mRemoteInput;
-    private RemoteInput[] mRemoteInputs;
     private boolean mRemoved;
     private NotificationViewWrapper mWrapper;
 
@@ -397,9 +388,8 @@
         // During removal, we get reattached and lose focus. Not hiding in that
         // case to prevent flicker.
         if (!mRemoved) {
-            if (animate && mRevealR > 0) {
-                Animator reveal = ViewAnimationUtils.createCircularReveal(
-                        this, mRevealCx, mRevealCy, mRevealR, 0);
+            if (animate && mRevealParams != null && mRevealParams.radius > 0) {
+                Animator reveal = mRevealParams.createCircularHideAnimator(this);
                 reveal.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
                 reveal.setDuration(StackStateAnimator.ANIMATION_DURATION_CLOSE_REMOTE_INPUT);
                 reveal.addListener(new AnimatorListenerAdapter() {
@@ -454,30 +444,12 @@
         mController.removeSpinning(mEntry.getKey(), mToken);
     }
 
-    public void setPendingIntent(PendingIntent pendingIntent) {
-        mPendingIntent = pendingIntent;
+    public void setHintText(CharSequence hintText) {
+        mEditText.setHint(hintText);
     }
 
-    /**
-     * Sets the remote input for this view.
-     *
-     * @param remoteInputs The remote inputs that need to be sent to the app.
-     * @param remoteInput The remote input that needs to be activated.
-     * @param editedSuggestionInfo The smart reply that should be inserted in the remote input, or
-     *         {@code null} if the user is not editing a smart reply.
-     */
-    public void setRemoteInput(RemoteInput[] remoteInputs, RemoteInput remoteInput,
-            @Nullable EditedSuggestionInfo editedSuggestionInfo) {
-        mRemoteInputs = remoteInputs;
-        mRemoteInput = remoteInput;
-        mEditText.setHint(mRemoteInput.getLabel());
-        mEditText.setSupportedMimeTypes(remoteInput.getAllowedDataTypes());
-
-        mEntry.editedSuggestionInfo = editedSuggestionInfo;
-        if (editedSuggestionInfo != null) {
-            mEntry.remoteInputText = editedSuggestionInfo.originalText;
-            mEntry.remoteInputAttachment = null;
-        }
+    public void setSupportedMimeTypes(Collection<String> mimeTypes) {
+        mEditText.setSupportedMimeTypes(mimeTypes);
     }
 
     /** Populates the text field of the remote input with the given content. */
@@ -486,9 +458,8 @@
     }
 
     public void focusAnimated() {
-        if (getVisibility() != VISIBLE) {
-            Animator animator = ViewAnimationUtils.createCircularReveal(
-                    this, mRevealCx, mRevealCy, 0, mRevealR);
+        if (getVisibility() != VISIBLE && mRevealParams != null) {
+            Animator animator = mRevealParams.createCircularRevealAnimator(this);
             animator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
             animator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
             animator.start();
@@ -587,30 +558,12 @@
         return mEditText.isFocused() && mEditText.isEnabled();
     }
 
-    // TODO(b/193539698): move this to the controller
-    public void stealFocusFrom(RemoteInputView other) {
-        other.close();
-        setPendingIntent(other.mPendingIntent);
-        setRemoteInput(other.mRemoteInputs, other.mRemoteInput, mEntry.editedSuggestionInfo);
-        setRevealParameters(other.mRevealCx, other.mRevealCy, other.mRevealR);
-        getController().setPendingIntent(other.mPendingIntent);
-        getController().setRemoteInput(other.mRemoteInput);
-        getController().setRemoteInputs(other.mRemoteInputs);
-        focus();
-    }
-
-    public PendingIntent getPendingIntent() {
-        return mPendingIntent;
-    }
-
     public void setRemoved() {
         mRemoved = true;
     }
 
-    public void setRevealParameters(int cx, int cy, int r) {
-        mRevealCx = cx;
-        mRevealCy = cy;
-        mRevealR = r;
+    public void setRevealParameters(@Nullable RevealParams revealParams) {
+        mRevealParams = revealParams;
     }
 
     @Override
@@ -938,4 +891,24 @@
         }
 
     }
+
+    public static class RevealParams {
+        final int centerX;
+        final int centerY;
+        final int radius;
+
+        public RevealParams(int centerX, int centerY, int radius) {
+            this.centerX = centerX;
+            this.centerY = centerY;
+            this.radius = radius;
+        }
+
+        Animator createCircularHideAnimator(View view) {
+            return ViewAnimationUtils.createCircularReveal(view, centerX, centerY, radius, 0);
+        }
+
+        Animator createCircularRevealAnimator(View view) {
+            return ViewAnimationUtils.createCircularReveal(view, centerX, centerY, 0, radius);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
index ef0a5b4..f845101 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
@@ -33,7 +33,9 @@
 import com.android.systemui.statusbar.NotificationRemoteInputManager
 import com.android.systemui.statusbar.RemoteInputController
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntry.EditedSuggestionInfo
 import com.android.systemui.statusbar.policy.RemoteInputView.NotificationRemoteInputEvent
+import com.android.systemui.statusbar.policy.RemoteInputView.RevealParams
 import com.android.systemui.statusbar.policy.dagger.RemoteInputViewScope
 import javax.inject.Inject
 
@@ -41,6 +43,8 @@
     fun bind()
     fun unbind()
 
+    val isActive: Boolean
+
     /**
      * A [NotificationRemoteInputManager.BouncerChecker] that will be used to determine if the
      * device needs to be unlocked before sending the RemoteInput.
@@ -55,6 +59,14 @@
     /** Other [RemoteInput]s from the notification associated with this Controller. */
     var remoteInputs: Array<RemoteInput>?
 
+    var revealParams: RevealParams?
+
+    /**
+     * Sets the smart reply that should be inserted in the remote input, or `null` if the user is
+     * not editing a smart reply.
+     */
+    fun setEditedSuggestionInfo(info: EditedSuggestionInfo?)
+
     /**
      * Tries to find an action in {@param actions} that matches the current pending intent
      * of this view and updates its state to that of the found action
@@ -68,6 +80,19 @@
 
     /** Unregisters a listener previously registered via [addOnSendRemoteInputListener] */
     fun removeOnSendRemoteInputListener(listener: OnSendRemoteInputListener)
+
+    fun close()
+
+    fun focus()
+
+    fun stealFocusFrom(other: RemoteInputViewController) {
+        other.close()
+        remoteInput = other.remoteInput
+        remoteInputs = other.remoteInputs
+        revealParams = other.revealParams
+        pendingIntent = other.pendingIntent
+        focus()
+    }
 }
 
 /** Listener for send events  */
@@ -100,15 +125,41 @@
 
     private var isBound = false
 
-    override var pendingIntent: PendingIntent? = null
     override var bouncerChecker: NotificationRemoteInputManager.BouncerChecker? = null
+
     override var remoteInput: RemoteInput? = null
+        set(value) {
+            field = value
+            value?.takeIf { isBound }?.let {
+                view.setHintText(it.label)
+                view.setSupportedMimeTypes(it.allowedDataTypes)
+            }
+        }
+
+    override var pendingIntent: PendingIntent? = null
     override var remoteInputs: Array<RemoteInput>? = null
 
+    override var revealParams: RevealParams? = null
+        set(value) {
+            field = value
+            if (isBound) {
+                view.setRevealParameters(value)
+            }
+        }
+
+    override val isActive: Boolean get() = view.isActive
+
     override fun bind() {
         if (isBound) return
         isBound = true
 
+        // TODO: refreshUI method?
+        remoteInput?.let {
+            view.setHintText(it.label)
+            view.setSupportedMimeTypes(it.allowedDataTypes)
+        }
+        view.setRevealParameters(revealParams)
+
         view.addOnEditTextFocusChangedListener(onFocusChangeListener)
         view.addOnSendRemoteInputListener(onSendRemoteInputListener)
     }
@@ -121,6 +172,14 @@
         view.removeOnSendRemoteInputListener(onSendRemoteInputListener)
     }
 
+    override fun setEditedSuggestionInfo(info: EditedSuggestionInfo?) {
+        entry.editedSuggestionInfo = info
+        if (info != null) {
+            entry.remoteInputText = info.originalText
+            entry.remoteInputAttachment = null
+        }
+    }
+
     override fun updatePendingIntentFromActions(actions: Array<Notification.Action>?): Boolean {
         actions ?: return false
         val current: Intent = pendingIntent?.intent ?: return false
@@ -132,8 +191,7 @@
             pendingIntent = actionIntent
             remoteInput = input
             remoteInputs = inputs
-            view.pendingIntent = actionIntent
-            view.setRemoteInput(inputs, input, null /* editedSuggestionInfo */)
+            setEditedSuggestionInfo(null)
             return true
         }
         return false
@@ -148,6 +206,14 @@
         onSendListeners.remove(listener)
     }
 
+    override fun close() {
+        view.close()
+    }
+
+    override fun focus() {
+        view.focus()
+    }
+
     private val onFocusChangeListener = View.OnFocusChangeListener { _, hasFocus ->
         remoteInputQuickSettingsDisabler.setRemoteInputActive(hasFocus)
     }
@@ -217,11 +283,12 @@
      * @return returns intent with granted URI permissions that should be used immediately
      */
     private fun prepareRemoteInput(remoteInput: RemoteInput): Intent =
-            if (entry.remoteInputAttachment == null) prepareRemoteInputFromText(remoteInput)
-            else prepareRemoteInputFromData(
-                    remoteInput,
-                    entry.remoteInputMimeType,
-                    entry.remoteInputUri)
+        if (entry.remoteInputAttachment == null)
+            prepareRemoteInputFromText(remoteInput)
+        else prepareRemoteInputFromData(
+                remoteInput,
+                entry.remoteInputMimeType,
+                entry.remoteInputUri)
 
     private fun prepareRemoteInputFromText(remoteInput: RemoteInput): Intent {
         val results = Bundle()
@@ -232,11 +299,7 @@
         view.clearAttachment()
         entry.remoteInputUri = null
         entry.remoteInputMimeType = null
-        if (entry.editedSuggestionInfo == null) {
-            RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_FREE_FORM_INPUT)
-        } else {
-            RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_CHOICE)
-        }
+        RemoteInput.setResultsSource(fillInIntent, remoteInputResultsSource)
         return fillInIntent
     }
 
@@ -266,11 +329,12 @@
         entry.remoteInputText = fullText
 
         // mirror prepareRemoteInputFromText for text input
-        if (entry.editedSuggestionInfo == null) {
-            RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_FREE_FORM_INPUT)
-        } else if (entry.remoteInputAttachment == null) {
-            RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_CHOICE)
-        }
+        RemoteInput.setResultsSource(fillInIntent, remoteInputResultsSource)
         return fillInIntent
     }
+
+    private val remoteInputResultsSource
+        get() = entry.editedSuggestionInfo
+                ?.let { RemoteInput.SOURCE_CHOICE }
+                ?: RemoteInput.SOURCE_FREE_FORM_INPUT
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 763f041..8396639 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -51,6 +51,7 @@
 import android.view.View;
 import android.view.WindowManagerGlobal;
 import android.widget.BaseAdapter;
+import android.widget.Toast;
 
 import androidx.annotation.Nullable;
 
@@ -59,6 +60,8 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.util.LatencyTracker;
 import com.android.settingslib.RestrictedLockUtilsInternal;
+import com.android.settingslib.users.UserCreatingDialog;
+import com.android.settingslib.utils.ThreadUtils;
 import com.android.systemui.Dumpable;
 import com.android.systemui.GuestResumeSessionReceiver;
 import com.android.systemui.Prefs;
@@ -89,6 +92,7 @@
 import java.util.List;
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
 
 import javax.inject.Inject;
 
@@ -447,14 +451,6 @@
         mResumeUserOnGuestLogout = resume;
     }
 
-    public void logoutCurrentUser() {
-        int currentUser = mUserTracker.getUserId();
-        if (currentUser != UserHandle.USER_SYSTEM) {
-            pauseRefreshUsers();
-            ActivityManager.logoutCurrentUser();
-        }
-    }
-
     /**
      * Returns whether the current user is a system user.
      */
@@ -490,26 +486,25 @@
 
     @VisibleForTesting
     void onUserListItemClicked(UserRecord record, DialogShower dialogShower) {
-        int id;
         if (record.isGuest && record.info == null) {
             // No guest user. Create one.
-            int guestId = createGuest();
-            if (guestId == UserHandle.USER_NULL) {
-                // This may happen if we haven't reloaded the user list yet.
-                return;
-            }
-            mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_ADD);
-            id = guestId;
+            createGuestAsync(guestId -> {
+                // guestId may be USER_NULL if we haven't reloaded the user list yet.
+                if (guestId != UserHandle.USER_NULL) {
+                    mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_ADD);
+                    onUserListItemClicked(guestId, record, dialogShower);
+                }
+            });
         } else if (record.isAddUser) {
             showAddUserDialog(dialogShower);
-            return;
         } else if (record.isAddSupervisedUser) {
             startSupervisedUserActivity();
-            return;
         } else {
-            id = record.info.id;
+            onUserListItemClicked(record.info.id, record, dialogShower);
         }
+    }
 
+    private void onUserListItemClicked(int id, UserRecord record, DialogShower dialogShower) {
         int currUserId = mUserTracker.getUserId();
         if (currUserId == id) {
             if (record.isGuest) {
@@ -517,7 +512,6 @@
             }
             return;
         }
-
         if (UserManager.isGuestUserEphemeral()) {
             // If switching from guest, we want to bring up the guest exit dialog instead of switching
             UserInfo currUserInfo = mUserManager.getUserInfo(currUserId);
@@ -711,8 +705,7 @@
         if (mUsers.isEmpty()) return null;
         UserRecord item = mUsers.stream().filter(x -> x.isCurrent).findFirst().orElse(null);
         if (item == null || item.info == null) return null;
-        if (item.isGuest) return mContext.getString(
-                com.android.settingslib.R.string.guest_nickname);
+        if (item.isGuest) return mContext.getString(com.android.internal.R.string.guest_name);
         return item.info.name;
     }
 
@@ -769,29 +762,30 @@
             return;
         }
 
-        try {
-            if (targetUserId == UserHandle.USER_NULL) {
-                // Create a new guest in the foreground, and then immediately switch to it
-                int newGuestId = createGuest();
+        if (targetUserId == UserHandle.USER_NULL) {
+            // Create a new guest in the foreground, and then immediately switch to it
+            createGuestAsync(newGuestId -> {
                 if (newGuestId == UserHandle.USER_NULL) {
                     Log.e(TAG, "Could not create new guest, switching back to system user");
                     switchToUserId(UserHandle.USER_SYSTEM);
                     mUserManager.removeUser(currentUser.id);
-                    WindowManagerGlobal.getWindowManagerService().lockNow(/* options= */ null);
+                    try {
+                        WindowManagerGlobal.getWindowManagerService().lockNow(/* options= */ null);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Couldn't remove guest because ActivityManager "
+                                + "or WindowManager is dead");
+                    }
                     return;
                 }
                 switchToUserId(newGuestId);
                 mUserManager.removeUser(currentUser.id);
-            } else {
-                if (mGuestUserAutoCreated) {
-                    mGuestIsResetting.set(true);
-                }
-                switchToUserId(targetUserId);
-                mUserManager.removeUser(currentUser.id);
+            });
+        } else {
+            if (mGuestUserAutoCreated) {
+                mGuestIsResetting.set(true);
             }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Couldn't remove guest because ActivityManager or WindowManager is dead");
-            return;
+            switchToUserId(targetUserId);
+            mUserManager.removeUser(currentUser.id);
         }
     }
 
@@ -840,6 +834,24 @@
         }
     }
 
+    private void createGuestAsync(Consumer<Integer> callback) {
+        final Dialog guestCreationProgressDialog =
+                new UserCreatingDialog(mContext, /* isGuest= */true);
+        guestCreationProgressDialog.show();
+
+        // userManager.createGuest will block the thread so post is needed for the dialog to show
+        ThreadUtils.postOnMainThread(() -> {
+            final int guestId = createGuest();
+            guestCreationProgressDialog.dismiss();
+            if (guestId == UserHandle.USER_NULL) {
+                Toast.makeText(mContext,
+                        com.android.settingslib.R.string.add_guest_failed,
+                        Toast.LENGTH_SHORT).show();
+            }
+            callback.accept(guestId);
+        });
+    }
+
     /**
      * Creates a guest user and return its multi-user user ID.
      *
@@ -949,7 +961,7 @@
                             : com.android.settingslib.R.string.guest_exit_guest);
                 } else {
                     if (item.info != null) {
-                        return context.getString(com.android.settingslib.R.string.guest_nickname);
+                        return context.getString(com.android.internal.R.string.guest_name);
                     } else {
                         if (mController.mGuestUserAutoCreated) {
                             // If mGuestIsResetting=true, we expect the guest user to be created
@@ -961,7 +973,7 @@
                             return context.getString(
                                     mController.mGuestIsResetting.get()
                                             ? com.android.settingslib.R.string.guest_resetting
-                                            : com.android.settingslib.R.string.guest_nickname);
+                                            : com.android.internal.R.string.guest_name);
                         } else {
                             return context.getString(
                                     com.android.settingslib.R.string.guest_new_guest);
@@ -969,7 +981,7 @@
                     }
                 }
             } else if (item.isAddUser) {
-                return context.getString(R.string.user_add_user);
+                return context.getString(com.android.settingslib.R.string.user_add_user);
             } else if (item.isAddSupervisedUser) {
                 return context.getString(R.string.add_user_supervised);
             } else {
@@ -1136,7 +1148,7 @@
             super(context);
             setTitle(mGuestUserAutoCreated
                     ? com.android.settingslib.R.string.guest_reset_guest_dialog_title
-                    : R.string.guest_exit_guest_dialog_title);
+                    : com.android.settingslib.R.string.guest_remove_guest_dialog_title);
             setMessage(context.getString(R.string.guest_exit_guest_dialog_message));
             setButton(DialogInterface.BUTTON_NEUTRAL,
                     context.getString(android.R.string.cancel), this);
@@ -1173,8 +1185,8 @@
 
         public AddUserDialog(Context context) {
             super(context);
-            setTitle(R.string.user_add_user_title);
-            setMessage(context.getString(R.string.user_add_user_message_short));
+            setTitle(com.android.settingslib.R.string.user_add_user_title);
+            setMessage(com.android.settingslib.R.string.user_add_user_message_short);
             setButton(DialogInterface.BUTTON_NEUTRAL,
                     context.getString(android.R.string.cancel), this);
             setButton(DialogInterface.BUTTON_POSITIVE,
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index fb80551..c06b8e6 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -38,6 +38,7 @@
 import android.content.om.OverlayIdentifier;
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.graphics.Color;
 import android.net.Uri;
@@ -53,6 +54,7 @@
 import android.util.TypedValue;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.graphics.ColorUtils;
 import com.android.systemui.CoreStartable;
@@ -114,10 +116,12 @@
     private final boolean mIsMonetEnabled;
     private final UserTracker mUserTracker;
     private final DeviceProvisionedController mDeviceProvisionedController;
+    private final Resources mResources;
     // Current wallpaper colors associated to a user.
     private final SparseArray<WallpaperColors> mCurrentColors = new SparseArray<>();
     private final WallpaperManager mWallpaperManager;
-    private ColorScheme mColorScheme;
+    @VisibleForTesting
+    protected ColorScheme mColorScheme;
     // If fabricated overlays were already created for the current theme.
     private boolean mNeedsOverlayCreation;
     // Dominant color extracted from wallpaper, NOT the color used on the overlay
@@ -344,7 +348,7 @@
             SecureSettings secureSettings, WallpaperManager wallpaperManager,
             UserManager userManager, DeviceProvisionedController deviceProvisionedController,
             UserTracker userTracker, DumpManager dumpManager, FeatureFlags featureFlags,
-            WakefulnessLifecycle wakefulnessLifecycle) {
+            @Main Resources resources, WakefulnessLifecycle wakefulnessLifecycle) {
         super(context);
 
         mIsMonetEnabled = featureFlags.isEnabled(Flags.MONET);
@@ -358,6 +362,7 @@
         mSecureSettings = secureSettings;
         mWallpaperManager = wallpaperManager;
         mUserTracker = userTracker;
+        mResources = resources;
         mWakefulnessLifecycle = wakefulnessLifecycle;
         dumpManager.registerDumpable(TAG, this);
     }
@@ -466,8 +471,13 @@
         mMainWallpaperColor = mainColor;
 
         if (mIsMonetEnabled) {
+            mThemeStyle = fetchThemeStyleFromSetting();
             mSecondaryOverlay = getOverlay(mMainWallpaperColor, ACCENT, mThemeStyle);
             mNeutralOverlay = getOverlay(mMainWallpaperColor, NEUTRAL, mThemeStyle);
+            if (colorSchemeIsApplied()) {
+                Log.d(TAG, "Skipping overlay creation. Theme was already: " + mColorScheme);
+                return;
+            }
             mNeedsOverlayCreation = true;
             if (DEBUG) {
                 Log.d(TAG, "fetched overlays. accent: " + mSecondaryOverlay
@@ -493,7 +503,7 @@
      * Given a color candidate, return an overlay definition.
      */
     protected @Nullable FabricatedOverlay getOverlay(int color, int type, Style style) {
-        boolean nightMode = (mContext.getResources().getConfiguration().uiMode
+        boolean nightMode = (mResources.getConfiguration().uiMode
                 & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
 
         mColorScheme = new ColorScheme(color, nightMode, style);
@@ -525,6 +535,23 @@
         return overlay.build();
     }
 
+    /**
+     * Checks if the color scheme in mColorScheme matches the current system palettes.
+     */
+    private boolean colorSchemeIsApplied() {
+        return mResources.getColor(
+                android.R.color.system_accent1_500, mContext.getTheme())
+                        == mColorScheme.getAccent1().get(6)
+                && mResources.getColor(android.R.color.system_accent2_500, mContext.getTheme())
+                        == mColorScheme.getAccent2().get(6)
+                && mResources.getColor(android.R.color.system_accent3_500, mContext.getTheme())
+                        == mColorScheme.getAccent3().get(6)
+                && mResources.getColor(android.R.color.system_neutral1_500, mContext.getTheme())
+                        == mColorScheme.getNeutral1().get(6)
+                && mResources.getColor(android.R.color.system_neutral2_500, mContext.getTheme())
+                        == mColorScheme.getNeutral2().get(6);
+    }
+
     private void updateThemeOverlays() {
         final int currentUser = mUserTracker.getUserId();
         final String overlayPackageJson = mSecureSettings.getStringForUser(
@@ -532,7 +559,6 @@
                 currentUser);
         if (DEBUG) Log.d(TAG, "updateThemeOverlays. Setting: " + overlayPackageJson);
         final Map<String, OverlayIdentifier> categoryToPackage = new ArrayMap<>();
-        Style newStyle = mThemeStyle;
         if (!TextUtils.isEmpty(overlayPackageJson)) {
             try {
                 JSONObject object = new JSONObject(overlayPackageJson);
@@ -543,25 +569,11 @@
                         categoryToPackage.put(category, identifier);
                     }
                 }
-
-                try {
-                    newStyle = Style.valueOf(
-                            object.getString(ThemeOverlayApplier.OVERLAY_CATEGORY_THEME_STYLE));
-                } catch (IllegalArgumentException e) {
-                    newStyle = Style.TONAL_SPOT;
-                }
             } catch (JSONException e) {
                 Log.i(TAG, "Failed to parse THEME_CUSTOMIZATION_OVERLAY_PACKAGES.", e);
             }
         }
 
-        if (mIsMonetEnabled && newStyle != mThemeStyle) {
-            mThemeStyle = newStyle;
-            mNeutralOverlay = getOverlay(mMainWallpaperColor, NEUTRAL, mThemeStyle);
-            mSecondaryOverlay = getOverlay(mMainWallpaperColor, ACCENT, mThemeStyle);
-            mNeedsOverlayCreation = true;
-        }
-
         // Let's generate system overlay if the style picker decided to override it.
         OverlayIdentifier systemPalette = categoryToPackage.get(OVERLAY_CATEGORY_SYSTEM_PALETTE);
         if (mIsMonetEnabled && systemPalette != null && systemPalette.getPackageName() != null) {
@@ -626,6 +638,24 @@
         }
     }
 
+    private Style fetchThemeStyleFromSetting() {
+        Style style = mThemeStyle;
+        final String overlayPackageJson = mSecureSettings.getStringForUser(
+                Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
+                mUserTracker.getUserId());
+        if (!TextUtils.isEmpty(overlayPackageJson)) {
+            try {
+                JSONObject object = new JSONObject(overlayPackageJson);
+                style = Style.valueOf(
+                        object.getString(ThemeOverlayApplier.OVERLAY_CATEGORY_THEME_STYLE));
+            } catch (JSONException | IllegalArgumentException e) {
+                Log.i(TAG, "Failed to parse THEME_CUSTOMIZATION_OVERLAY_PACKAGES.", e);
+                style = Style.TONAL_SPOT;
+            }
+        }
+        return style;
+    }
+
     @Override
     public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
         pw.println("mSystemColors=" + mCurrentColors);
diff --git a/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java b/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java
index c9de966..cc6bf6a 100644
--- a/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java
@@ -110,7 +110,7 @@
                 },
                 null,
                 defaultUserName,
-                getString(R.string.user_add_user),
+                getString(com.android.settingslib.R.string.user_add_user),
                 this::addUserNow,
                 this::finish
         );
@@ -134,7 +134,7 @@
         mSetupUserDialog.dismiss();
 
         userName = (userName == null || userName.trim().isEmpty())
-                ? getString(R.string.user_new_user_name)
+                ? getString(com.android.settingslib.R.string.user_new_user_name)
                 : userName;
 
         mUserCreator.createUser(userName, userIcon,
diff --git a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
index c0d7925..9e9b746 100644
--- a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
@@ -23,7 +23,6 @@
 import android.graphics.drawable.BitmapDrawable
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.GradientDrawable
-import android.graphics.drawable.InsetDrawable
 import android.graphics.drawable.LayerDrawable
 import android.os.Bundle
 import android.os.UserManager
@@ -149,8 +148,8 @@
         }
 
         private fun getDrawable(item: UserRecord): Drawable {
-            var drawable = if (item.isCurrent && item.isGuest) {
-                getDrawable(R.drawable.ic_avatar_guest_user)
+            var drawable = if (item.isGuest) {
+                getDrawable(R.drawable.ic_account_circle)
             } else {
                 findUserIcon(item)
             }
@@ -168,7 +167,7 @@
             val ld = getDrawable(R.drawable.user_switcher_icon_large).mutate()
                 as LayerDrawable
             if (item == userSwitcherController.getCurrentUserRecord()) {
-                (ld.getDrawable(1) as GradientDrawable).apply {
+                (ld.findDrawableByLayerId(R.id.ring) as GradientDrawable).apply {
                     val stroke = resources
                         .getDimensionPixelSize(R.dimen.user_switcher_icon_selected_width)
                     val color = Utils.getColorAttrDefaultColor(
@@ -180,15 +179,7 @@
                 }
             }
 
-            ld.addLayer(
-                InsetDrawable(
-                    drawable,
-                    resources.getDimensionPixelSize(
-                        R.dimen.user_switcher_icon_large_margin
-                    )
-                )
-            )
-
+            ld.setDrawableByLayerId(R.id.user_avatar, drawable)
             return ld
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/util/LargeScreenUtils.kt b/packages/SystemUI/src/com/android/systemui/util/LargeScreenUtils.kt
new file mode 100644
index 0000000..8b29310
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/LargeScreenUtils.kt
@@ -0,0 +1,26 @@
+package com.android.systemui.util
+
+import android.content.res.Resources
+import com.android.systemui.R
+
+object LargeScreenUtils {
+
+    /**
+     * Returns true if the device should use the split notification shade, based on orientation and
+     * screen width.
+     */
+    @JvmStatic
+    fun shouldUseSplitNotificationShade(resources: Resources): Boolean {
+        return resources.getBoolean(R.bool.config_use_split_notification_shade)
+    }
+
+    /**
+     * Returns true if we should use large screen shade header:
+     * [com.android.systemui.statusbar.phone.LargeScreenShadeHeaderController]
+     * That should be true when we have enough horizontal space to show all info in one row.
+     */
+    @JvmStatic
+    fun shouldUseLargeScreenShadeHeader(resources: Resources): Boolean {
+        return resources.getBoolean(R.bool.config_use_large_screen_shade_header)
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java
index 7e3bce5..8e5e1d2 100644
--- a/packages/SystemUI/src/com/android/systemui/util/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java
@@ -25,12 +25,10 @@
 import android.provider.Settings;
 import android.view.ContextThemeWrapper;
 import android.view.DisplayCutout;
-import android.view.View;
 
 import com.android.internal.policy.SystemBarUtils;
 import com.android.systemui.R;
 import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.statusbar.CommandQueue;
 
 import java.util.List;
 import java.util.function.Consumer;
@@ -51,58 +49,6 @@
     }
 
     /**
-     * Sets the visibility of an UI element according to the DISABLE_* flags in
-     * {@link android.app.StatusBarManager}.
-     */
-    public static class DisableStateTracker implements CommandQueue.Callbacks,
-            View.OnAttachStateChangeListener {
-        private final int mMask1;
-        private final int mMask2;
-        private final CommandQueue mCommandQueue;
-        private View mView;
-        private boolean mDisabled;
-
-        public DisableStateTracker(int disableMask, int disable2Mask, CommandQueue commandQueue) {
-            mMask1 = disableMask;
-            mMask2 = disable2Mask;
-            mCommandQueue = commandQueue;
-        }
-
-        @Override
-        public void onViewAttachedToWindow(View v) {
-            mView = v;
-            mCommandQueue.addCallback(this);
-        }
-
-        @Override
-        public void onViewDetachedFromWindow(View v) {
-            mCommandQueue.removeCallback(this);
-            mView = null;
-        }
-
-        /**
-         * Sets visibility of this {@link View} given the states passed from
-         * {@link com.android.systemui.statusbar.CommandQueue.Callbacks#disable(int, int, int)}.
-         */
-        @Override
-        public void disable(int displayId, int state1, int state2, boolean animate) {
-            if (displayId != mView.getDisplay().getDisplayId()) {
-                return;
-            }
-            final boolean disabled = ((state1 & mMask1) != 0) || ((state2 & mMask2) != 0);
-            if (disabled == mDisabled) return;
-            mDisabled = disabled;
-            mView.setVisibility(disabled ? View.GONE : View.VISIBLE);
-        }
-
-        /** @return {@code true} if and only if this {@link View} is currently disabled */
-        public boolean isDisabled() {
-            return mDisabled;
-        }
-    }
-
-
-    /**
      * Returns {@code true} iff the package {@code packageName} is a headless remote display
      * provider, i.e, that the package holds the privileged {@code REMOTE_DISPLAY_PROVIDER}
      * permission and that it doesn't host a launcher icon.
@@ -151,17 +97,6 @@
     }
 
     /**
-     * Allow recommendations from smartspace to show in media controls.
-     * Requires {@link #useQsMediaPlayer(Context)} to be enabled.
-     * On by default, but can be disabled by setting to 0
-     */
-    public static boolean allowMediaRecommendations(Context context) {
-        int flag = Settings.Secure.getInt(context.getContentResolver(),
-                Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION, 1);
-        return useQsMediaPlayer(context) && flag > 0;
-    }
-
-    /**
      * Returns true if the device should use the collapsed layout for the media player when in
      * landscape (or seascape) orientation
      */
@@ -170,14 +105,6 @@
     }
 
     /**
-     * Returns true if the device should use the split notification shade, based on orientation and
-     * screen width.
-     */
-    public static boolean shouldUseSplitNotificationShade(Resources resources) {
-        return resources.getBoolean(R.bool.config_use_split_notification_shade);
-    }
-
-    /**
      * Returns the color provided at the specified {@param attrIndex} in {@param a} if it exists,
      * otherwise, returns the color from the private attribute {@param privAttrId}.
      */
@@ -197,33 +124,6 @@
     }
 
     /**
-     * Gets the {@link R.dimen#split_shade_header_height}.
-     *
-     * It should be fine to not ignore cutouts as split shade might not want to react to them:
-     * for split shade header, which is only on bigger screens, either cutout won't be a problem
-     * (it's usually centered and in split shade that's likely empty area) or we probably want to
-     * handle it differently.
-     */
-    public static int getSplitShadeStatusBarHeight(Context context) {
-        return context.getResources().getDimensionPixelSize(R.dimen.split_shade_header_height);
-    }
-
-    /**
-     * Gets the {@link R.dimen#qs_header_system_icons_area_height}.
-     *
-     * It's the same as {@link com.android.internal.R.dimen#quick_qs_offset_height} except for
-     * sw600dp-land.
-     */
-    public static int getQsHeaderSystemIconsAreaHeight(Context context) {
-        final Resources res = context.getResources();
-        if (Utils.shouldUseSplitNotificationShade(res)) {
-            return res.getDimensionPixelSize(R.dimen.qs_header_system_icons_area_height);
-        } else {
-            return SystemBarUtils.getQuickQsOffsetHeight(context);
-        }
-    }
-
-    /**
      * Gets the {@link R.dimen#status_bar_header_height_keyguard}.
      */
     public static int getStatusBarHeaderHeightKeyguard(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/AnimationUtil.kt b/packages/SystemUI/src/com/android/systemui/util/animation/AnimationUtil.kt
new file mode 100644
index 0000000..c0538c1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/AnimationUtil.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.systemui.util.animation
+
+import kotlin.math.roundToLong
+
+/** A generic util class for animations in SysUI. */
+class AnimationUtil {
+    companion object {
+        /**
+         * Returns the number of milliseconds there are in [numFrames] for a 60 fps device.
+         *
+         * Note that this method can be used on any device, not just 60 fps devices. Animation
+         * lengths are typically specified in terms of number of frames for a 60 fps device, and
+         * the value "5 frames" is often more meaningful than "83ms". This method allows us to
+         * write animation code in terms of the more meaningful "5" number.
+         *
+         * @param numFrames must be >= 0.
+         */
+        fun getMsForFrames(numFrames: Int): Long {
+            if (numFrames < 0) {
+                throw IllegalArgumentException("numFrames must be >= 0")
+            }
+            return (numFrames * 1000f / 60f).roundToLong()
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java
index 5aaf7f6..1bf5f07 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java
@@ -303,6 +303,7 @@
     default boolean putInt(String name, int value) {
         return putIntForUser(name, value, getUserId());
     }
+
     /** See {@link #putInt(String, int)}. */
     default boolean putIntForUser(String name, int value, int userHandle) {
         return putStringForUser(name, Integer.toString(value), userHandle);
@@ -310,6 +311,76 @@
 
     /**
      * Convenience function for retrieving a single secure settings value
+     * as a boolean.  Note that internally setting values are always
+     * stored as strings; this function converts the string to a boolean
+     * for you.  The default value will be returned if the setting is
+     * not defined or not a boolean.
+     *
+     * @param name The name of the setting to retrieve.
+     * @param def Value to return if the setting is not defined.
+     *
+     * @return The setting's current value, or 'def' if it is not defined
+     * or not a valid boolean.
+     */
+    default boolean getBool(String name, boolean def) {
+        return getBoolForUser(name, def, getUserId());
+    }
+
+    /** See {@link #getBool(String, boolean)}. */
+    default boolean getBoolForUser(String name, boolean def, int userHandle) {
+        return getIntForUser(name, def ? 1 : 0, userHandle) != 0;
+    }
+
+    /**
+     * Convenience function for retrieving a single secure settings value
+     * as a boolean.  Note that internally setting values are always
+     * stored as strings; this function converts the string to a boolean
+     * for you.
+     * <p>
+     * This version does not take a default value.  If the setting has not
+     * been set, or the string value is not a number,
+     * it throws {@link Settings.SettingNotFoundException}.
+     *
+     * @param name The name of the setting to retrieve.
+     *
+     * @throws Settings.SettingNotFoundException Thrown if a setting by the given
+     * name can't be found or the setting value is not a boolean.
+     *
+     * @return The setting's current value.
+     */
+    default boolean getBool(String name) throws Settings.SettingNotFoundException {
+        return getBoolForUser(name, getUserId());
+    }
+
+    /** See {@link #getBool(String)}. */
+    default boolean getBoolForUser(String name, int userHandle)
+            throws Settings.SettingNotFoundException {
+        return getIntForUser(name, userHandle) != 0;
+    }
+
+    /**
+     * Convenience function for updating a single settings value as a
+     * boolean. This will either create a new entry in the table if the
+     * given name does not exist, or modify the value of the existing row
+     * with that name.  Note that internally setting values are always
+     * stored as strings, so this function converts the given value to a
+     * string before storing it.
+     *
+     * @param name The name of the setting to modify.
+     * @param value The new value for the setting.
+     * @return true if the value was set, false on database errors
+     */
+    default boolean putBool(String name, boolean value) {
+        return putBoolForUser(name, value, getUserId());
+    }
+
+    /** See {@link #putBool(String, boolean)}. */
+    default boolean putBoolForUser(String name, boolean value, int userHandle) {
+        return putIntForUser(name, value ? 1 : 0, userHandle);
+    }
+
+    /**
+     * Convenience function for retrieving a single secure settings value
      * as a {@code long}.  Note that internally setting values are always
      * stored as strings; this function converts the string to a {@code long}
      * for you.  The default value will be returned if the setting is
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
index 7072890..3c869e7 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
@@ -33,6 +33,7 @@
 import com.android.systemui.R;
 import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.util.settings.SecureSettings;
@@ -64,6 +65,7 @@
     private final Context mContext;
     private final Executor mExecutor;
     private final Executor mCallbackExecutor;
+    private final Executor mBgExecutor;
     private final SecureSettings mSecureSettings;
     private final SystemClock mClock;
 
@@ -80,12 +82,14 @@
             Context context,
             @Main Executor executor,
             @CallbackExecutor Executor callbackExecutor,
+            @Background Executor bgExecutor,
             SecureSettings secureSettings,
             QuickAccessWalletClient quickAccessWalletClient,
             SystemClock clock) {
         mContext = context;
         mExecutor = executor;
         mCallbackExecutor = callbackExecutor;
+        mBgExecutor = bgExecutor;
         mSecureSettings = secureSettings;
         mQuickAccessWalletClient = quickAccessWalletClient;
         mClock = clock;
@@ -182,7 +186,7 @@
      * Re-create the {@link QuickAccessWalletClient} of the controller.
      */
     public void reCreateWalletClient() {
-        mQuickAccessWalletClient = QuickAccessWalletClient.create(mContext);
+        mQuickAccessWalletClient = QuickAccessWalletClient.create(mContext, mBgExecutor);
         mQawClientCreatedTimeMillis = mClock.elapsedRealtime();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/dagger/WalletModule.java b/packages/SystemUI/src/com/android/systemui/wallet/dagger/WalletModule.java
index c1f5516..2c901d2 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/dagger/WalletModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/dagger/WalletModule.java
@@ -21,8 +21,11 @@
 import android.service.quickaccesswallet.QuickAccessWalletClient;
 
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.wallet.ui.WalletActivity;
 
+import java.util.concurrent.Executor;
+
 import dagger.Binds;
 import dagger.Module;
 import dagger.Provides;
@@ -45,7 +48,8 @@
     /** */
     @SysUISingleton
     @Provides
-    public static QuickAccessWalletClient provideQuickAccessWalletClient(Context context) {
-        return QuickAccessWalletClient.create(context);
+    public static QuickAccessWalletClient provideQuickAccessWalletClient(Context context,
+            @Background Executor bgExecutor) {
+        return QuickAccessWalletClient.create(context, bgExecutor);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
index 92e7f2d..89c3100 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
@@ -122,7 +122,7 @@
         getActionBar().setHomeActionContentDescription(R.string.accessibility_desc_close);
         WalletView walletView = requireViewById(R.id.wallet_view);
 
-        mWalletClient = QuickAccessWalletClient.create(this);
+        mWalletClient = QuickAccessWalletClient.create(this, mExecutor);
         mWalletScreenController = new WalletScreenController(
                 this,
                 walletView,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt
new file mode 100644
index 0000000..6266bf1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt
@@ -0,0 +1,71 @@
+/*
+ * 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.keyguard
+
+import android.test.suitebuilder.annotation.SmallTest
+import android.testing.AndroidTestingRunner
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class BouncerPanelExpansionCalculatorTest : SysuiTestCase() {
+    @Test
+    fun testGetHostViewScaledExpansion() {
+        assertThat(BouncerPanelExpansionCalculator.getHostViewScaledExpansion(1f))
+                .isEqualTo(1f)
+        assertThat(BouncerPanelExpansionCalculator.getHostViewScaledExpansion(0.9f))
+                .isEqualTo(1f)
+        assertThat(BouncerPanelExpansionCalculator.getHostViewScaledExpansion(0.59f))
+                .isEqualTo(0f)
+        assertThat(BouncerPanelExpansionCalculator.getHostViewScaledExpansion(0f))
+                .isEqualTo(0f)
+        assertEquals(BouncerPanelExpansionCalculator
+                .getHostViewScaledExpansion(0.8f), 2f / 3f, 0.01f)
+    }
+
+    @Test
+    fun testGetBackScrimScaledExpansion() {
+        assertThat(BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(1f))
+                .isEqualTo(1f)
+        assertEquals(BouncerPanelExpansionCalculator
+                .getBackScrimScaledExpansion(0.95f), 1f / 2f, 0.01f)
+        assertThat(BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(0.9f))
+                .isEqualTo(0f)
+        assertThat(BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(0.5f))
+                .isEqualTo(0f)
+        assertThat(BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(0f))
+                .isEqualTo(0f)
+    }
+
+    @Test
+    fun testGetKeyguardClockScaledExpansion() {
+        assertThat(BouncerPanelExpansionCalculator.getKeyguardClockScaledExpansion(1f))
+                .isEqualTo(1f)
+        assertEquals(BouncerPanelExpansionCalculator
+                .getKeyguardClockScaledExpansion(0.8f), 1f / 3f, 0.01f)
+        assertThat(BouncerPanelExpansionCalculator.getKeyguardClockScaledExpansion(0.7f))
+                .isEqualTo(0f)
+        assertThat(BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(0.5f))
+                .isEqualTo(0f)
+        assertThat(BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(0f))
+                .isEqualTo(0f)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
index a7197cc..1518ea1 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
@@ -84,4 +84,10 @@
         mMessageAreaController.setMessage("");
         verify(mKeyguardMessageArea).setMessage("");
     }
+
+    @Test
+    public void testSetBouncerVisible() {
+        mMessageAreaController.setBouncerShowing(true);
+        verify(mKeyguardMessageArea).setBouncerShowing(true);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java
index 31fb25a..013c298 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java
@@ -40,7 +40,7 @@
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         mKeyguardMessageArea = new KeyguardMessageArea(mContext, null);
-        mKeyguardMessageArea.setBouncerVisible(true);
+        mKeyguardMessageArea.setBouncerShowing(true);
     }
 
     @Test
@@ -53,7 +53,7 @@
 
     @Test
     public void testHiddenWhenBouncerHidden() {
-        mKeyguardMessageArea.setBouncerVisible(false);
+        mKeyguardMessageArea.setBouncerShowing(false);
         mKeyguardMessageArea.setVisibility(View.INVISIBLE);
         mKeyguardMessageArea.setMessage("oobleck");
         assertThat(mKeyguardMessageArea.getVisibility()).isEqualTo(View.INVISIBLE);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
index e980eb7..8e1e42a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
@@ -88,6 +88,6 @@
     fun onPause_clearsTextField() {
         mKeyguardPatternViewController.init()
         mKeyguardPatternViewController.onPause()
-        verify(mKeyguardMessageAreaController).setMessage(R.string.keyguard_enter_your_pattern)
+        verify(mKeyguardMessageAreaController).setMessage("")
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index 6736bfd..14c903c 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -34,6 +34,7 @@
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.graphics.Insets;
+import android.provider.Settings;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.Gravity;
@@ -204,10 +205,14 @@
         mKeyguardSecurityContainer.updatePositionByTouchX(
                 mKeyguardSecurityContainer.getWidth() - 1f);
 
+        verify(mGlobalSettings).putInt(Settings.Global.ONE_HANDED_KEYGUARD_SIDE,
+                Settings.Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT);
         verify(mSecurityViewFlipper).setTranslationX(
                 mKeyguardSecurityContainer.getWidth() - mSecurityViewFlipper.getWidth());
 
         mKeyguardSecurityContainer.updatePositionByTouchX(1f);
+        verify(mGlobalSettings).putInt(Settings.Global.ONE_HANDED_KEYGUARD_SIDE,
+                Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT);
 
         verify(mSecurityViewFlipper).setTranslationX(0.0f);
     }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
index 2fc9122..1753157 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -112,4 +112,13 @@
         mKeyguardUpdateMonitorCallbackCaptor.getValue().onUserSwitchComplete(0);
         verify(mKeyguardClockSwitchController).refreshFormat();
     }
+
+    @Test
+    public void setTranslationYExcludingMedia_forwardsCallToView() {
+        float translationY = 123f;
+
+        mController.setTranslationYExcludingMedia(translationY);
+
+        verify(mKeyguardStatusView).setChildrenTranslationYExcludingMediaView(translationY);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt
new file mode 100644
index 0000000..ce44f4d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt
@@ -0,0 +1,55 @@
+package com.android.keyguard
+
+import android.test.suitebuilder.annotation.SmallTest
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.children
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper(setAsMainLooper = true)
+class KeyguardStatusViewTest : SysuiTestCase() {
+
+    private lateinit var keyguardStatusView: KeyguardStatusView
+    private val mediaView: View
+        get() = keyguardStatusView.findViewById(R.id.status_view_media_container)
+    private val statusViewContainer: ViewGroup
+        get() = keyguardStatusView.findViewById(R.id.status_view_container)
+    private val childrenExcludingMedia
+        get() = statusViewContainer.children.filter { it != mediaView }
+
+    @Before
+    fun setUp() {
+        keyguardStatusView = LayoutInflater.from(context)
+                .inflate(R.layout.keyguard_status_view, /* root= */ null) as KeyguardStatusView
+    }
+
+    @Test
+    fun setChildrenTranslationYExcludingMediaView_mediaViewIsNotTranslated() {
+        val translationY = 1234f
+
+        keyguardStatusView.setChildrenTranslationYExcludingMediaView(translationY)
+
+        assertThat(mediaView.translationY).isEqualTo(0)
+    }
+
+    @Test
+    fun setChildrenTranslationYExcludingMediaView_childrenAreTranslated() {
+        val translationY = 1234f
+
+        keyguardStatusView.setChildrenTranslationYExcludingMediaView(translationY)
+
+        childrenExcludingMedia.forEach {
+            assertThat(it.translationY).isEqualTo(translationY)
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index 70f3251..ec92adb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -48,7 +48,6 @@
 import android.content.res.TypedArray;
 import android.graphics.Insets;
 import android.graphics.PixelFormat;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.VectorDrawable;
 import android.hardware.display.DisplayManager;
@@ -58,6 +57,7 @@
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 import android.util.RotationUtils;
+import android.util.Size;
 import android.view.Display;
 import android.view.DisplayCutout;
 import android.view.View;
@@ -73,6 +73,7 @@
 import com.android.systemui.decor.OverlayWindow;
 import com.android.systemui.decor.PrivacyDotCornerDecorProviderImpl;
 import com.android.systemui.decor.PrivacyDotDecorProviderFactory;
+import com.android.systemui.decor.RoundedCornerResDelegate;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.events.PrivacyDotViewController;
 import com.android.systemui.tuner.TunerService;
@@ -95,8 +96,6 @@
 @SmallTest
 public class ScreenDecorationsTest extends SysuiTestCase {
 
-    private static final Rect ZERO_RECT = new Rect();
-
     private ScreenDecorations mScreenDecorations;
     private WindowManager mWindowManager;
     private DisplayManager mDisplayManager;
@@ -424,7 +423,7 @@
 
     @Test
     public void testRoundingRadius_NoCutout() {
-        final Point testRadiusPoint = new Point(1, 1);
+        final Size testRadiusPoint = new Size(1, 1);
         setupResources(1 /* radius */, 1 /* radiusTop */, 1 /* radiusBottom */,
                 0 /* roundedPadding */, false /* multipleRadius */,
                 false /* fillCutout */, true /* privacyDot */);
@@ -433,9 +432,9 @@
 
         mScreenDecorations.start();
         // Size of corner view should same as rounded_corner_radius{_top|_bottom}
-        assertThat(mScreenDecorations.mRoundedDefault).isEqualTo(testRadiusPoint);
-        assertThat(mScreenDecorations.mRoundedDefaultTop).isEqualTo(testRadiusPoint);
-        assertThat(mScreenDecorations.mRoundedDefaultBottom).isEqualTo(testRadiusPoint);
+        final RoundedCornerResDelegate resDelegate = mScreenDecorations.mRoundedCornerResDelegate;
+        assertThat(resDelegate.getTopRoundedSize()).isEqualTo(testRadiusPoint);
+        assertThat(resDelegate.getBottomRoundedSize()).isEqualTo(testRadiusPoint);
     }
 
     @Test
@@ -454,17 +453,17 @@
         View rightRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView()
                 .findViewById(R.id.right);
         verify(mScreenDecorations, atLeastOnce())
-                .setSize(leftRoundedCorner, new Point(testTopRadius, testTopRadius));
+                .setSize(leftRoundedCorner, new Size(testTopRadius, testTopRadius));
         verify(mScreenDecorations, atLeastOnce())
-                .setSize(rightRoundedCorner, new Point(testTopRadius, testTopRadius));
+                .setSize(rightRoundedCorner, new Size(testTopRadius, testTopRadius));
         leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView()
                 .findViewById(R.id.left);
         rightRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView()
                 .findViewById(R.id.right);
         verify(mScreenDecorations, atLeastOnce())
-                .setSize(leftRoundedCorner, new Point(testBottomRadius, testBottomRadius));
+                .setSize(leftRoundedCorner, new Size(testBottomRadius, testBottomRadius));
         verify(mScreenDecorations, atLeastOnce())
-                .setSize(rightRoundedCorner, new Point(testBottomRadius, testBottomRadius));
+                .setSize(rightRoundedCorner, new Size(testBottomRadius, testBottomRadius));
     }
 
     @Test
@@ -480,8 +479,8 @@
                 .when(mScreenDecorations).getCutout();
 
         mScreenDecorations.start();
-        final Point topRadius = new Point(testTopRadius, testTopRadius);
-        final Point bottomRadius = new Point(testBottomRadius, testBottomRadius);
+        final Size topRadius = new Size(testTopRadius, testTopRadius);
+        final Size bottomRadius = new Size(testBottomRadius, testBottomRadius);
         View leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].getRootView()
                 .findViewById(R.id.left);
         boolean isTop = mScreenDecorations.isTopRoundedCorner(BOUNDS_POSITION_LEFT, R.id.left);
@@ -510,7 +509,7 @@
     @Test
     public void testRoundingMultipleRadius_NoCutout_NoPrivacyDot() {
         final VectorDrawable d = (VectorDrawable) mContext.getDrawable(R.drawable.rounded);
-        final Point multipleRadiusSize = new Point(d.getIntrinsicWidth(), d.getIntrinsicHeight());
+        final Size multipleRadiusSize = new Size(d.getIntrinsicWidth(), d.getIntrinsicHeight());
         setupResources(9999 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 9999 /* roundedPadding */, true /* multipleRadius */,
                 false /* fillCutout */, false /* privacyDot */);
@@ -536,15 +535,15 @@
         verify(mDotViewController, never()).initialize(any(), any(), any(), any());
 
         // Size of corner view should exactly match max(width, height) of R.drawable.rounded
-        assertThat(mScreenDecorations.mRoundedDefault).isEqualTo(multipleRadiusSize);
-        assertThat(mScreenDecorations.mRoundedDefaultTop).isEqualTo(multipleRadiusSize);
-        assertThat(mScreenDecorations.mRoundedDefaultBottom).isEqualTo(multipleRadiusSize);
+        final RoundedCornerResDelegate resDelegate = mScreenDecorations.mRoundedCornerResDelegate;
+        assertThat(resDelegate.getTopRoundedSize()).isEqualTo(multipleRadiusSize);
+        assertThat(resDelegate.getBottomRoundedSize()).isEqualTo(multipleRadiusSize);
     }
 
     @Test
     public void testRoundingMultipleRadius_NoCutout_PrivacyDot() {
         final VectorDrawable d = (VectorDrawable) mContext.getDrawable(R.drawable.rounded);
-        final Point multipleRadiusSize = new Point(d.getIntrinsicWidth(), d.getIntrinsicHeight());
+        final Size multipleRadiusSize = new Size(d.getIntrinsicWidth(), d.getIntrinsicHeight());
         setupResources(9999 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 9999 /* roundedPadding */, true /* multipleRadius */,
                 false /* fillCutout */, true /* privacyDot */);
@@ -571,9 +570,9 @@
                 isA(View.class), isA(View.class), isA(View.class), isA(View.class));
 
         // Size of corner view should exactly match max(width, height) of R.drawable.rounded
-        assertThat(mScreenDecorations.mRoundedDefault).isEqualTo(multipleRadiusSize);
-        assertThat(mScreenDecorations.mRoundedDefaultTop).isEqualTo(multipleRadiusSize);
-        assertThat(mScreenDecorations.mRoundedDefaultBottom).isEqualTo(multipleRadiusSize);
+        final RoundedCornerResDelegate resDelegate = mScreenDecorations.mRoundedCornerResDelegate;
+        assertThat(resDelegate.getTopRoundedSize()).isEqualTo(multipleRadiusSize);
+        assertThat(resDelegate.getBottomRoundedSize()).isEqualTo(multipleRadiusSize);
     }
 
     @Test
@@ -944,12 +943,15 @@
                 false /* fillCutout */, true /* privacyDot */);
 
         mScreenDecorations.start();
-        assertEquals(mScreenDecorations.mRoundedDefault, new Point(20, 20));
+        final RoundedCornerResDelegate resDelegate = mScreenDecorations.mRoundedCornerResDelegate;
+        assertEquals(resDelegate.getTopRoundedSize(), new Size(20, 20));
+        assertEquals(resDelegate.getBottomRoundedSize(), new Size(20, 20));
 
         when(mContext.getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.rounded_corner_radius)).thenReturn(5);
         mScreenDecorations.onConfigurationChanged(null);
-        assertEquals(mScreenDecorations.mRoundedDefault, new Point(5, 5));
+        assertEquals(resDelegate.getTopRoundedSize(), new Size(5, 5));
+        assertEquals(resDelegate.getBottomRoundedSize(), new Size(5, 5));
     }
 
     @Test
@@ -959,9 +961,9 @@
                 false /* fillCutout */, true /* privacyDot */);
 
         mScreenDecorations.start();
-        assertEquals(new Point(0, 0), mScreenDecorations.mRoundedDefault);
-        assertEquals(new Point(10, 10), mScreenDecorations.mRoundedDefaultTop);
-        assertEquals(new Point(0, 0), mScreenDecorations.mRoundedDefaultBottom);
+        final RoundedCornerResDelegate resDelegate = mScreenDecorations.mRoundedCornerResDelegate;
+        assertEquals(new Size(10, 10), resDelegate.getTopRoundedSize());
+        assertEquals(new Size(0, 0), resDelegate.getBottomRoundedSize());
     }
 
     @Test
@@ -971,9 +973,9 @@
                 false /* fillCutout */, true /* privacyDot */);
 
         mScreenDecorations.start();
-        assertEquals(new Point(0, 0), mScreenDecorations.mRoundedDefault);
-        assertEquals(new Point(0, 0), mScreenDecorations.mRoundedDefaultTop);
-        assertEquals(new Point(20, 20), mScreenDecorations.mRoundedDefaultBottom);
+        final RoundedCornerResDelegate resDelegate = mScreenDecorations.mRoundedCornerResDelegate;
+        assertEquals(new Size(0, 0), resDelegate.getTopRoundedSize());
+        assertEquals(new Size(20, 20), resDelegate.getBottomRoundedSize());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index 7a0db1f..8c79277 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -208,6 +208,11 @@
         }
     }
 
+    /** Delegates to {@link android.testing.TestableResources#addOverride(int, Object)}. */
+    protected void overrideResource(int resourceId, Object value) {
+        mContext.getOrCreateTestableResources().addOverride(resourceId, value);
+    }
+
     public static final class EmptyRunnable implements Runnable {
         public void run() {
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index a49c4d7..ee150ca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -80,6 +80,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Answers;
@@ -172,11 +173,10 @@
 
     @Test
     public void enableWindowMagnification_notifySourceBoundsChanged() {
-        mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
-                    Float.NaN, /* magnificationFrameOffsetRatioX= */ 0,
-                    /* magnificationFrameOffsetRatioY= */ 0, null);
-        });
+        mInstrumentation.runOnMainSync(
+                () -> mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+                        Float.NaN, /* magnificationFrameOffsetRatioX= */ 0,
+                /* magnificationFrameOffsetRatioY= */ 0, null));
 
         // Waits for the surface created
         verify(mWindowMagnifierCallback, timeout(LAYOUT_CHANGE_TIMEOUT_MS)).onSourceBoundsChanged(
@@ -184,6 +184,16 @@
     }
 
     @Test
+    public void enableWindowMagnification_disabled_notifySourceBoundsChanged() {
+        enableWindowMagnification_notifySourceBoundsChanged();
+        mInstrumentation.runOnMainSync(
+                () -> mWindowMagnificationController.deleteWindowMagnification(null));
+        Mockito.reset(mWindowMagnifierCallback);
+
+        enableWindowMagnification_notifySourceBoundsChanged();
+    }
+
+    @Test
     public void enableWindowMagnification_withAnimation_schedulesFrame() {
         mInstrumentation.runOnMainSync(() -> {
             mWindowMagnificationController.enableWindowMagnification(2.0f, 10,
@@ -293,6 +303,7 @@
         verify(mSfVsyncFrameProvider, atLeastOnce()).postFrameCallback(any());
     }
 
+    @Ignore("b/224717753")
     @Test
     public void moveWindowMagnifierToPositionWithAnimation_expectedValuesAndInvokeCallback()
             throws InterruptedException {
@@ -327,6 +338,7 @@
         assertEquals(mWindowMagnificationController.getCenterY(), targetCenterY, 0);
     }
 
+    @Ignore("b/224717753")
     @Test
     public void moveWindowMagnifierToPositionMultipleTimes_expectedValuesAndInvokeCallback()
             throws InterruptedException {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
new file mode 100644
index 0000000..8eb0918
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
@@ -0,0 +1,277 @@
+package com.android.systemui.animation
+
+import android.animation.ObjectAnimator
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.View
+import android.view.ViewGroup
+import android.widget.LinearLayout
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertNotNull
+import junit.framework.Assert.assertNull
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class ViewHierarchyAnimatorTest : SysuiTestCase() {
+    companion object {
+        private const val TEST_DURATION = 1000L
+        private val TEST_INTERPOLATOR = Interpolators.LINEAR
+    }
+
+    private lateinit var rootView: LinearLayout
+
+    @Before
+    fun setUp() {
+        rootView = LinearLayout(mContext)
+    }
+
+    @After
+    fun tearDown() {
+        ViewHierarchyAnimator.stopAnimating(rootView)
+    }
+
+    @Test
+    fun respectsAnimationParameters() {
+        rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+        ViewHierarchyAnimator.animate(
+            rootView, interpolator = TEST_INTERPOLATOR, duration = TEST_DURATION
+        )
+        rootView.layout(0 /* l */, 0 /* t */, 100 /* r */, 100 /* b */)
+
+        assertNotNull(rootView.getTag(R.id.tag_animator))
+        val animator = rootView.getTag(R.id.tag_animator) as ObjectAnimator
+        assertEquals(animator.interpolator, TEST_INTERPOLATOR)
+        assertEquals(animator.duration, TEST_DURATION)
+    }
+
+    @Test
+    fun animatesFromStartToEnd() {
+        rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+        ViewHierarchyAnimator.animate(rootView)
+        // Change all bounds.
+        rootView.layout(0 /* l */, 15 /* t */, 70 /* r */, 80 /* b */)
+
+        assertNotNull(rootView.getTag(R.id.tag_animator))
+        // The initial values should be those of the previous layout.
+        checkBounds(rootView, l = 10, t = 10, r = 50, b = 50)
+        endAnimation(rootView)
+        assertNull(rootView.getTag(R.id.tag_animator))
+        // The end values should be those of the latest layout.
+        checkBounds(rootView, l = 0, t = 15, r = 70, b = 80)
+    }
+
+    @Test
+    fun animatesSuccessiveLayoutChanges() {
+        rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+        ViewHierarchyAnimator.animate(rootView)
+        // Change all bounds.
+        rootView.layout(0 /* l */, 15 /* t */, 70 /* r */, 80 /* b */)
+
+        assertNotNull(rootView.getTag(R.id.tag_animator))
+        endAnimation(rootView)
+        assertNull(rootView.getTag(R.id.tag_animator))
+        checkBounds(rootView, l = 0, t = 15, r = 70, b = 80)
+
+        // Change only top and right.
+        rootView.layout(0 /* l */, 20 /* t */, 60 /* r */, 80 /* b */)
+
+        assertNotNull(rootView.getTag(R.id.tag_animator))
+        endAnimation(rootView)
+        assertNull(rootView.getTag(R.id.tag_animator))
+        checkBounds(rootView, l = 0, t = 20, r = 60, b = 80)
+
+        // Change all bounds again.
+        rootView.layout(5 /* l */, 25 /* t */, 55 /* r */, 95 /* b */)
+
+        assertNotNull(rootView.getTag(R.id.tag_animator))
+        endAnimation(rootView)
+        assertNull(rootView.getTag(R.id.tag_animator))
+        checkBounds(rootView, l = 5, t = 25, r = 55, b = 95)
+    }
+
+    @Test
+    fun animatesFromPreviousAnimationProgress() {
+        rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+        ViewHierarchyAnimator.animateNextUpdate(rootView, interpolator = TEST_INTERPOLATOR)
+        // Change all bounds.
+        rootView.layout(0 /* l */, 20 /* t */, 70 /* r */, 80 /* b */)
+
+        assertNotNull(rootView.getTag(R.id.tag_animator))
+        advanceAnimation(rootView, fraction = 0.5f)
+        checkBounds(rootView, l = 5, t = 15, r = 60, b = 65)
+
+        // Change all bounds again.
+        rootView.layout(25 /* l */, 25 /* t */, 55 /* r */, 60 /* b */)
+
+        assertNotNull(rootView.getTag(R.id.tag_animator))
+        checkBounds(rootView, l = 5, t = 15, r = 60, b = 65)
+        endAnimation(rootView)
+        assertNull(rootView.getTag(R.id.tag_animator))
+        checkBounds(rootView, l = 25, t = 25, r = 55, b = 60)
+    }
+
+    @Test
+    fun animatesRootAndChildren() {
+        val firstChild = View(mContext)
+        rootView.addView(firstChild)
+        val secondChild = View(mContext)
+        rootView.addView(secondChild)
+        rootView.layout(0 /* l */, 0 /* t */, 150 /* r */, 100 /* b */)
+        firstChild.layout(0 /* l */, 0 /* t */, 100 /* r */, 100 /* b */)
+        secondChild.layout(100 /* l */, 0 /* t */, 150 /* r */, 100 /* b */)
+
+        ViewHierarchyAnimator.animate(rootView)
+        // Change all bounds.
+        rootView.layout(10 /* l */, 20 /* t */, 200 /* r */, 120 /* b */)
+        firstChild.layout(10 /* l */, 20 /* t */, 150 /* r */, 120 /* b */)
+        secondChild.layout(150 /* l */, 20 /* t */, 200 /* r */, 120 /* b */)
+
+        assertNotNull(rootView.getTag(R.id.tag_animator))
+        // The initial values should be those of the previous layout.
+        checkBounds(rootView, l = 0, t = 0, r = 150, b = 100)
+        checkBounds(firstChild, l = 0, t = 0, r = 100, b = 100)
+        checkBounds(secondChild, l = 100, t = 0, r = 150, b = 100)
+        endAnimation(rootView)
+        assertNull(rootView.getTag(R.id.tag_animator))
+        // The end values should be those of the latest layout.
+        checkBounds(rootView, l = 10, t = 20, r = 200, b = 120)
+        checkBounds(firstChild, l = 10, t = 20, r = 150, b = 120)
+        checkBounds(secondChild, l = 150, t = 20, r = 200, b = 120)
+    }
+
+    @Test
+    fun doesNotAnimateInvisibleViews() {
+        rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+        ViewHierarchyAnimator.animate(rootView)
+        // GONE.
+        rootView.visibility = View.GONE
+        rootView.layout(0 /* l */, 15 /* t */, 55 /* r */, 80 /* b */)
+
+        assertNull(rootView.getTag(R.id.tag_animator))
+        checkBounds(rootView, l = 0, t = 15, r = 55, b = 80)
+
+        // INVISIBLE.
+        rootView.visibility = View.INVISIBLE
+        rootView.layout(0 /* l */, 20 /* t */, 0 /* r */, 20 /* b */)
+    }
+
+    @Test
+    fun doesNotAnimateUnchangingBounds() {
+        rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+        ViewHierarchyAnimator.animate(rootView)
+        // No bounds are changed.
+        rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+        assertNull(rootView.getTag(R.id.tag_animator))
+        checkBounds(rootView, l = 10, t = 10, r = 50, b = 50)
+
+        // Change only right and bottom.
+        rootView.layout(10 /* l */, 10 /* t */, 70 /* r */, 80 /* b */)
+
+        assertNotNull(rootView.getTag(R.id.tag_animator))
+        endAnimation(rootView)
+        assertNull(rootView.getTag(R.id.tag_animator))
+        checkBounds(rootView, l = 10, t = 10, r = 70, b = 80)
+    }
+
+    @Test
+    fun doesNotAnimateExcludedBounds() {
+        rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+        ViewHierarchyAnimator.animate(
+            rootView,
+            bounds = setOf(ViewHierarchyAnimator.Bound.LEFT, ViewHierarchyAnimator.Bound.TOP),
+            interpolator = TEST_INTERPOLATOR
+        )
+        // Change all bounds.
+        rootView.layout(0 /* l */, 20 /* t */, 70 /* r */, 80 /* b */)
+
+        assertNotNull(rootView.getTag(R.id.tag_animator))
+        advanceAnimation(rootView, 0.5f)
+        checkBounds(rootView, l = 5, t = 15, r = 70, b = 80)
+        endAnimation(rootView)
+        assertNull(rootView.getTag(R.id.tag_animator))
+        checkBounds(rootView, l = 0, t = 20, r = 70, b = 80)
+    }
+
+    @Test
+    fun stopsAnimatingAfterSingleLayout() {
+        rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+        ViewHierarchyAnimator.animateNextUpdate(rootView)
+        // Change all bounds.
+        rootView.layout(0 /* l */, 15 /* t */, 70 /* r */, 80 /* b */)
+
+        assertNotNull(rootView.getTag(R.id.tag_animator))
+        endAnimation(rootView)
+        assertNull(rootView.getTag(R.id.tag_animator))
+        checkBounds(rootView, l = 0, t = 15, r = 70, b = 80)
+
+        // Change all bounds again.
+        rootView.layout(10 /* l */, 10 /* t */, 50/* r */, 50 /* b */)
+
+        assertNull(rootView.getTag(R.id.tag_animator))
+        checkBounds(rootView, l = 10, t = 10, r = 50, b = 50)
+    }
+
+    @Test
+    fun stopsAnimatingWhenInstructed() {
+        rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+        ViewHierarchyAnimator.animate(rootView)
+        // Change all bounds.
+        rootView.layout(0 /* l */, 15 /* t */, 70 /* r */, 80 /* b */)
+
+        assertNotNull(rootView.getTag(R.id.tag_animator))
+        endAnimation(rootView)
+        assertNull(rootView.getTag(R.id.tag_animator))
+        checkBounds(rootView, l = 0, t = 15, r = 70, b = 80)
+
+        ViewHierarchyAnimator.stopAnimating(rootView)
+        // Change all bounds again.
+        rootView.layout(10 /* l */, 10 /* t */, 50/* r */, 50 /* b */)
+
+        assertNull(rootView.getTag(R.id.tag_animator))
+        checkBounds(rootView, l = 10, t = 10, r = 50, b = 50)
+    }
+
+    private fun checkBounds(v: View, l: Int, t: Int, r: Int, b: Int) {
+        assertEquals(l, v.left)
+        assertEquals(t, v.top)
+        assertEquals(r, v.right)
+        assertEquals(b, v.bottom)
+    }
+
+    private fun advanceAnimation(rootView: View, fraction: Float) {
+        (rootView.getTag(R.id.tag_animator) as? ObjectAnimator)?.setCurrentFraction(fraction)
+
+        if (rootView is ViewGroup) {
+            for (i in 0 until rootView.childCount) {
+                advanceAnimation(rootView.getChildAt(i), fraction)
+            }
+        }
+    }
+
+    private fun endAnimation(rootView: View) {
+        (rootView.getTag(R.id.tag_animator) as? ObjectAnimator)?.end()
+
+        if (rootView is ViewGroup) {
+            for (i in 0 until rootView.childCount) {
+                endAnimation(rootView.getChildAt(i))
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
index 9418b50..f99b20d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
@@ -42,6 +42,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 
+import org.junit.After;
 import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
@@ -50,7 +51,6 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
-@Ignore
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
 @SmallTest
@@ -66,6 +66,11 @@
 
     private AuthBiometricView mBiometricView;
 
+    @After
+    public void tearDown() {
+        destroyDialog();
+    }
+
     @Test
     public void testOnAuthenticationSucceeded_noConfirmationRequired_sendsActionAuthenticated() {
         initDialog(false /* allowDeviceCredential */, mCallback);
@@ -245,6 +250,7 @@
         // TODO: Test dialog size. Should move requireConfirmation to buildBiometricPromptBundle
 
         // Create new dialog and restore the previous state into it
+        destroyDialog();
         initDialog(false /* allowDeviceCredential */, mCallback, state, 10000);
         mBiometricView.mAnimationDurationHideDialog = 10000;
         mBiometricView.setRequireConfirmation(requireConfirmation);
@@ -304,6 +310,12 @@
         waitForIdleSync();
     }
 
+    private void destroyDialog() {
+        if (mBiometricView != null && mBiometricView.isAttachedToWindow()) {
+            ViewUtils.detachView(mBiometricView);
+        }
+    }
+
     @Override
     protected void waitForIdleSync() {
         TestableLooper.get(this).processAllMessages();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index cfac965..42c3c7f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -82,7 +82,6 @@
 import com.android.systemui.util.concurrency.FakeExecution;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -100,7 +99,6 @@
 
 import javax.inject.Provider;
 
-@Ignore
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
 @SmallTest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index ec2c1de..a95da62 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -114,12 +114,13 @@
     }
 
     @Test
-    fun testFingerprintTrigger_Ripple() {
+    fun testFingerprintTrigger_KeyguardVisible_Ripple() {
         // GIVEN fp exists, keyguard is visible, user doesn't need strong auth
         val fpsLocation = PointF(5f, 5f)
         `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
         controller.onViewAttached()
         `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true)
+        `when`(keyguardUpdateMonitor.isDreaming).thenReturn(false)
         `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false)
 
         // WHEN fingerprint authenticated
@@ -136,7 +137,30 @@
     }
 
     @Test
-    fun testFingerprintTrigger_KeyguardNotVisible_NoRipple() {
+    fun testFingerprintTrigger_Dreaming_Ripple() {
+        // GIVEN fp exists, keyguard is visible, user doesn't need strong auth
+        val fpsLocation = PointF(5f, 5f)
+        `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
+        controller.onViewAttached()
+        `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(false)
+        `when`(keyguardUpdateMonitor.isDreaming).thenReturn(true)
+        `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false)
+
+        // WHEN fingerprint authenticated
+        val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
+        verify(keyguardUpdateMonitor).registerCallback(captor.capture())
+        captor.value.onBiometricAuthenticated(
+                0 /* userId */,
+                BiometricSourceType.FINGERPRINT /* type */,
+                false /* isStrongBiometric */)
+
+        // THEN update sensor location and show ripple
+        verify(rippleView).setFingerprintSensorLocation(fpsLocation, -1f)
+        verify(rippleView).startUnlockedRipple(any())
+    }
+
+    @Test
+    fun testFingerprintTrigger_KeyguardNotVisible_NotDreaming_NoRipple() {
         // GIVEN fp exists & user doesn't need strong auth
         val fpsLocation = PointF(5f, 5f)
         `when`(authController.udfpsSensorLocation).thenReturn(fpsLocation)
@@ -145,6 +169,7 @@
 
         // WHEN keyguard is NOT visible & fingerprint authenticated
         `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(false)
+        `when`(keyguardUpdateMonitor.isDreaming).thenReturn(false)
         val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
         verify(keyguardUpdateMonitor).registerCallback(captor.capture())
         captor.value.onBiometricAuthenticated(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
index ef82c3e..fd49766 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -61,6 +61,8 @@
 import org.mockito.junit.MockitoJUnit
 import org.mockito.Mockito.`when` as whenever
 
+private const val REQUEST_ID = 2L
+
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
 @RunWithLooper(setAsMainLooper = true)
@@ -119,7 +121,7 @@
             statusBarStateController, panelExpansionStateManager, statusBarKeyguardViewManager,
             keyguardUpdateMonitor, dialogManager, dumpManager, transitionController,
             configurationController, systemClock, keyguardStateController,
-            unlockedScreenOffAnimationController, sensorProps, hbmProvider, reason,
+            unlockedScreenOffAnimationController, sensorProps, hbmProvider, REQUEST_ID, reason,
             controllerCallback, onTouch, activityLaunchAnimator)
         block()
     }
@@ -263,6 +265,12 @@
         controllerOverlay.hide()
         verify(udfpsView).stopIllumination()
     }
+
+    @Test
+    fun matchesRequestIds() = withReason(REASON_AUTH_BP) {
+        assertThat(controllerOverlay.matchesRequestId(REQUEST_ID)).isTrue()
+        assertThat(controllerOverlay.matchesRequestId(REQUEST_ID + 1)).isFalse()
+    }
 }
 
 private class EnrollListener(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 1856fda..406ed5c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -48,6 +49,7 @@
 import android.testing.TestableLooper.RunWithLooper;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
+import android.view.View;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
 
@@ -64,8 +66,8 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.phone.SystemUIDialogManager;
 import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
@@ -101,6 +103,7 @@
     // Use this for inputs going into SystemUI. Use UdfpsController.mUdfpsSensorId for things
     // leaving SystemUI.
     private static final int TEST_UDFPS_SENSOR_ID = 1;
+    private static final long TEST_REQUEST_ID = 70;
 
     @Rule
     public MockitoRule rule = MockitoJUnit.rule();
@@ -188,6 +191,7 @@
     @Captor private ArgumentCaptor<IUdfpsOverlayController> mOverlayCaptor;
     private IUdfpsOverlayController mOverlayController;
     @Captor private ArgumentCaptor<UdfpsView.OnTouchListener> mTouchListenerCaptor;
+    @Captor private ArgumentCaptor<View.OnHoverListener> mHoverListenerCaptor;
     @Captor private ArgumentCaptor<Runnable> mOnIlluminatedRunnableCaptor;
     @Captor private ArgumentCaptor<ScreenLifecycle.Observer> mScreenObserverCaptor;
     private ScreenLifecycle.Observer mScreenObserver;
@@ -276,7 +280,7 @@
 
     @Test
     public void dozeTimeTick() throws RemoteException {
-        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
         mFgExecutor.runAllReady();
         mUdfpsController.dozeTimeTick();
@@ -291,7 +295,7 @@
         when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
 
         // GIVEN that the overlay is showing
-        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
         mFgExecutor.runAllReady();
 
@@ -314,7 +318,7 @@
         when(mStatusBarStateController.isDozing()).thenReturn(true);
 
         // GIVEN that the overlay is showing
-        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
         mFgExecutor.runAllReady();
 
@@ -337,7 +341,7 @@
         when(mStatusBarStateController.isDozing()).thenReturn(false);
 
         // GIVEN that the overlay is showing
-        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
         mFgExecutor.runAllReady();
 
@@ -360,7 +364,7 @@
                 (UdfpsAnimationViewController) mock(UdfpsEnrollViewController.class));
 
         // GIVEN that the overlay is showing
-        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
                 BiometricOverlayConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback);
         mFgExecutor.runAllReady();
 
@@ -375,25 +379,42 @@
     }
 
     @Test
-    public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice() throws RemoteException {
+    public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice()
+            throws RemoteException {
+        onActionMoveTouch_whenCanDismissLockScreen_entersDevice(false /* stale */);
+    }
+
+    @Test
+    public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice_ignoreStale()
+            throws RemoteException {
+        onActionMoveTouch_whenCanDismissLockScreen_entersDevice(true /* stale */);
+    }
+
+    public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice(boolean stale)
+            throws RemoteException {
         // GIVEN can dismiss lock screen and the current animation is an UdfpsKeyguardViewController
         when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
         when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
         when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
 
         // GIVEN that the overlay is showing
-        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
         mFgExecutor.runAllReady();
 
         // WHEN ACTION_MOVE is received
         verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
         MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
+        if (stale) {
+            mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
+            mFgExecutor.runAllReady();
+        }
         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
         moveEvent.recycle();
 
         // THEN notify keyguard authenticate to dismiss the keyguard
-        verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(anyBoolean());
+        verify(mStatusBarKeyguardViewManager, stale ? never() : times(1))
+                .notifyKeyguardAuthenticated(anyBoolean());
     }
 
     @Test
@@ -404,7 +425,7 @@
         when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
 
         // GIVEN that the overlay is showing
-        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
         mFgExecutor.runAllReady();
 
@@ -425,7 +446,7 @@
     @Test
     public void hideUdfpsOverlay_resetsAltAuthBouncerWhenShowing() throws RemoteException {
         // GIVEN overlay was showing and the udfps bouncer is showing
-        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
         when(mStatusBarKeyguardViewManager.isShowingAlternateAuth()).thenReturn(true);
 
@@ -439,7 +460,7 @@
 
     @Test
     public void testSubscribesToOrientationChangesWhenShowingOverlay() throws Exception {
-        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
         mFgExecutor.runAllReady();
 
@@ -458,7 +479,7 @@
         when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
 
         // GIVEN that the overlay is showing
-        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
         mFgExecutor.runAllReady();
         // WHEN ACTION_DOWN is received
@@ -470,8 +491,9 @@
         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
         moveEvent.recycle();
         // THEN FingerprintManager is notified about onPointerDown
-        verify(mFingerprintManager).onPointerDown(eq(mUdfpsController.mSensorProps.sensorId), eq(0),
-                eq(0), eq(0f), eq(0f));
+        verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
+                eq(mUdfpsController.mSensorProps.sensorId),
+                eq(0), eq(0), eq(0f), eq(0f));
         verify(mLatencyTracker).onActionStart(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
         // AND illumination begins
         verify(mUdfpsView).startIllumination(mOnIlluminatedRunnableCaptor.capture());
@@ -479,14 +501,15 @@
         // AND onIlluminatedRunnable notifies FingerprintManager about onUiReady
         mOnIlluminatedRunnableCaptor.getValue().run();
         InOrder inOrder = inOrder(mFingerprintManager, mLatencyTracker);
-        inOrder.verify(mFingerprintManager).onUiReady(eq(mUdfpsController.mSensorProps.sensorId));
+        inOrder.verify(mFingerprintManager).onUiReady(
+                eq(TEST_REQUEST_ID), eq(mUdfpsController.mSensorProps.sensorId));
         inOrder.verify(mLatencyTracker).onActionEnd(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
     }
 
     @Test
     public void aodInterrupt() throws RemoteException {
         // GIVEN that the overlay is showing and screen is on and fp is running
-        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
         mScreenObserver.onScreenTurnedOn();
         mFgExecutor.runAllReady();
@@ -497,14 +520,15 @@
         // AND onIlluminatedRunnable that notifies FingerprintManager is set
         verify(mUdfpsView).startIllumination(mOnIlluminatedRunnableCaptor.capture());
         mOnIlluminatedRunnableCaptor.getValue().run();
-        verify(mFingerprintManager).onPointerDown(eq(mUdfpsController.mSensorProps.sensorId), eq(0),
-                eq(0), eq(3f) /* minor */, eq(2f) /* major */);
+        verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
+                eq(mUdfpsController.mSensorProps.sensorId),
+                eq(0), eq(0), eq(3f) /* minor */, eq(2f) /* major */);
     }
 
     @Test
     public void cancelAodInterrupt() throws RemoteException {
         // GIVEN AOD interrupt
-        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
         mScreenObserver.onScreenTurnedOn();
         mFgExecutor.runAllReady();
@@ -520,7 +544,7 @@
     @Test
     public void aodInterruptTimeout() throws RemoteException {
         // GIVEN AOD interrupt
-        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
         mScreenObserver.onScreenTurnedOn();
         mFgExecutor.runAllReady();
@@ -537,7 +561,7 @@
     @Test
     public void aodInterruptScreenOff() throws RemoteException {
         // GIVEN screen off
-        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
         mScreenObserver.onScreenTurnedOff();
         mFgExecutor.runAllReady();
@@ -553,7 +577,7 @@
     @Test
     public void aodInterrupt_fingerprintNotRunning() throws RemoteException {
         // GIVEN showing overlay
-        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD,
                 mUdfpsOverlayControllerCallback);
         mScreenObserver.onScreenTurnedOn();
@@ -568,23 +592,24 @@
     }
 
     @Test
-    public void playHapticOnTouchUdfpsArea() throws RemoteException {
+    public void playHapticOnTouchUdfpsArea_a11yTouchExplorationEnabled() throws RemoteException {
         // Configure UdfpsView to accept the ACTION_DOWN event
         when(mUdfpsView.isIlluminationRequested()).thenReturn(false);
         when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
 
-        // GIVEN that the overlay is showing
-        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+        // GIVEN that the overlay is showing and a11y touch exploration enabled
+        when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true);
+        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
         mFgExecutor.runAllReady();
 
-        // WHEN ACTION_DOWN is received
-        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
-        MotionEvent downEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
-        downEvent.recycle();
-        MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
-        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+        // WHEN ACTION_HOVER is received
+        verify(mUdfpsView).setOnHoverListener(mHoverListenerCaptor.capture());
+        MotionEvent enterEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0, 0, 0);
+        mHoverListenerCaptor.getValue().onHover(mUdfpsView, enterEvent);
+        enterEvent.recycle();
+        MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_MOVE, 0, 0, 0);
+        mHoverListenerCaptor.getValue().onHover(mUdfpsView, moveEvent);
         moveEvent.recycle();
 
         // THEN tick haptic is played
@@ -600,4 +625,34 @@
         assertEquals(VibrationAttributes.USAGE_COMMUNICATION_REQUEST,
                 UdfpsController.VIBRATION_ATTRIBUTES.getUsage());
     }
+
+    @Test
+    public void noHapticOnTouchUdfpsArea_a11yTouchExplorationDisabled() throws RemoteException {
+        // Configure UdfpsView to accept the ACTION_DOWN event
+        when(mUdfpsView.isIlluminationRequested()).thenReturn(false);
+        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+
+        // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
+        when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
+        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
+                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+        mFgExecutor.runAllReady();
+
+        // WHEN ACTION_DOWN is received
+        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+        MotionEvent downEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
+        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
+        downEvent.recycle();
+        MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
+        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+        moveEvent.recycle();
+
+        // THEN NO haptic played
+        verify(mVibrator, never()).vibrate(
+                anyInt(),
+                anyString(),
+                any(),
+                anyString(),
+                any());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
new file mode 100644
index 0000000..b536bfd
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
@@ -0,0 +1,139 @@
+/*
+ * 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.systemui.decor
+
+import android.content.res.TypedArray
+import android.graphics.drawable.VectorDrawable
+import android.testing.AndroidTestingRunner
+import android.testing.TestableResources
+import android.util.Size
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class RoundedCornerResDelegateTest : SysuiTestCase() {
+
+    private lateinit var roundedCornerResDelegate: RoundedCornerResDelegate
+    @Mock private lateinit var mockTypedArray: TypedArray
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+    }
+
+    @Test
+    fun testReloadAllAndDefaultRadius() {
+        mContext.orCreateTestableResources.addOverrides(
+                mockTypeArray = mockTypedArray,
+                radius = 3,
+                radiusTop = 0,
+                radiusBottom = 4,
+                multipleRadius = false)
+
+        roundedCornerResDelegate = RoundedCornerResDelegate(mContext.resources, null)
+
+        assertEquals(Size(3, 3), roundedCornerResDelegate.topRoundedSize)
+        assertEquals(Size(4, 4), roundedCornerResDelegate.bottomRoundedSize)
+        assertEquals(false, roundedCornerResDelegate.isMultipleRadius)
+
+        mContext.orCreateTestableResources.addOverrides(
+                mockTypeArray = mockTypedArray,
+                radius = 5,
+                radiusTop = 6,
+                radiusBottom = 0)
+
+        roundedCornerResDelegate.reloadAll("test")
+
+        assertEquals(Size(6, 6), roundedCornerResDelegate.topRoundedSize)
+        assertEquals(Size(5, 5), roundedCornerResDelegate.bottomRoundedSize)
+    }
+
+    @Test
+    fun testUpdateTuningSizeFactor() {
+        mContext.orCreateTestableResources.addOverrides(
+                mockTypeArray = mockTypedArray,
+                radiusTop = 0,
+                radiusBottom = 0,
+                multipleRadius = false)
+
+        roundedCornerResDelegate = RoundedCornerResDelegate(mContext.resources, null)
+
+        val factor = 5
+        roundedCornerResDelegate.updateTuningSizeFactor(factor)
+        val length = (factor * mContext.resources.displayMetrics.density).toInt()
+
+        assertEquals(Size(length, length), roundedCornerResDelegate.topRoundedSize)
+        assertEquals(Size(length, length), roundedCornerResDelegate.bottomRoundedSize)
+    }
+
+    @Test
+    fun testReadDefaultRadiusWhen0() {
+        mContext.orCreateTestableResources.addOverrides(
+                mockTypeArray = mockTypedArray,
+                radius = 3,
+                radiusTop = 0,
+                radiusBottom = 0,
+                multipleRadius = false)
+
+        roundedCornerResDelegate = RoundedCornerResDelegate(mContext.resources, null)
+
+        assertEquals(Size(3, 3), roundedCornerResDelegate.topRoundedSize)
+        assertEquals(Size(3, 3), roundedCornerResDelegate.bottomRoundedSize)
+    }
+
+    @Test
+    fun testReadMultipleRadius() {
+        val d = mContext.getDrawable(R.drawable.rounded) as VectorDrawable
+        val multipleRadiusSize = Size(d.intrinsicWidth, d.intrinsicHeight)
+        mContext.orCreateTestableResources.addOverrides(
+                mockTypeArray = mockTypedArray,
+                multipleRadius = true)
+        roundedCornerResDelegate = RoundedCornerResDelegate(mContext.resources, null)
+        assertEquals(multipleRadiusSize, roundedCornerResDelegate.topRoundedSize)
+        assertEquals(multipleRadiusSize, roundedCornerResDelegate.bottomRoundedSize)
+    }
+}
+
+private fun TestableResources.addOverrides(
+    mockTypeArray: TypedArray,
+    radius: Int? = null,
+    radiusTop: Int? = null,
+    radiusBottom: Int? = null,
+    multipleRadius: Boolean? = null
+) {
+    addOverride(com.android.internal.R.array.config_displayUniqueIdArray, arrayOf<String>())
+    addOverride(com.android.internal.R.array.config_roundedCornerRadiusArray, mockTypeArray)
+    addOverride(com.android.internal.R.array.config_roundedCornerTopRadiusArray, mockTypeArray)
+    addOverride(com.android.internal.R.array.config_roundedCornerBottomRadiusArray, mockTypeArray)
+    addOverride(R.array.config_roundedCornerDrawableArray, mockTypeArray)
+    addOverride(R.array.config_roundedCornerTopDrawableArray, mockTypeArray)
+    addOverride(R.array.config_roundedCornerBottomDrawableArray, mockTypeArray)
+    addOverride(R.array.config_roundedCornerMultipleRadiusArray, mockTypeArray)
+    radius?.let { addOverride(com.android.internal.R.dimen.rounded_corner_radius, it) }
+    radiusTop?.let { addOverride(com.android.internal.R.dimen.rounded_corner_radius_top, it) }
+    radiusBottom?.let { addOverride(com.android.internal.R.dimen.rounded_corner_radius_bottom, it) }
+    multipleRadius?.let { addOverride(R.bool.config_roundedCornerMultipleRadius, it) }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
index badafa4..f4b378e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
@@ -27,6 +27,7 @@
 import static com.android.systemui.doze.DozeMachine.State.FINISH;
 import static com.android.systemui.doze.DozeMachine.State.INITIALIZED;
 import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotSame;
@@ -468,37 +469,39 @@
     public void transitionToDoze_shouldClampBrightness_afterTimeout_clampsToDim() {
         when(mWakefulnessLifecycle.getLastSleepReason()).thenReturn(
                 PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
-        when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true);
         when(mDozeParameters.shouldClampToDimBrightness()).thenReturn(true);
 
         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
-        mScreen.transitionTo(INITIALIZED, DOZE);
 
         // If we're dozing after a timeout, and playing the unlocked screen animation, we should
         // stay at or below dim brightness, because the screen dims just before timeout.
         assertTrue(mServiceFake.screenBrightness <= DIM_BRIGHTNESS);
+
+        // Once we transition to Doze, use the doze brightness
+        mScreen.transitionTo(INITIALIZED, DOZE);
+        assertEquals(mServiceFake.screenBrightness, DEFAULT_BRIGHTNESS);
     }
 
     @Test
     public void transitionToDoze_shouldClampBrightness_notAfterTimeout_doesNotClampToDim() {
         when(mWakefulnessLifecycle.getLastSleepReason()).thenReturn(
                 PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON);
-        when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true);
         when(mDozeParameters.shouldClampToDimBrightness()).thenReturn(true);
 
         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
-        mScreen.transitionTo(INITIALIZED, DOZE);
 
         // If we're playing the unlocked screen off animation after a power button press, we should
         // leave the brightness alone.
         assertEquals(mServiceFake.screenBrightness, DEFAULT_BRIGHTNESS);
+
+        mScreen.transitionTo(INITIALIZED, DOZE);
+        assertEquals(mServiceFake.screenBrightness, DEFAULT_BRIGHTNESS);
     }
 
     @Test
     public void transitionToDoze_noClampBrightness_afterTimeout_noScreenOff_doesNotClampToDim() {
         when(mWakefulnessLifecycle.getLastSleepReason()).thenReturn(
                 PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
-        when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(false);
         when(mDozeParameters.shouldClampToDimBrightness()).thenReturn(false);
 
         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
@@ -514,11 +517,9 @@
                 PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
         when(mWakefulnessLifecycle.getWakefulness()).thenReturn(
                 WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP);
-        when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(false);
         when(mDozeParameters.shouldClampToDimBrightness()).thenReturn(false);
 
         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
-        mScreen.transitionTo(INITIALIZED, DOZE);
 
         assertTrue(mServiceFake.screenBrightness <= DIM_BRIGHTNESS);
     }
@@ -529,7 +530,6 @@
                 PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON);
         when(mWakefulnessLifecycle.getWakefulness()).thenReturn(
                 WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP);
-        when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(false);
         when(mDozeParameters.shouldClampToDimBrightness()).thenReturn(false);
 
         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
index ff9e13a..fa6288f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -16,9 +16,11 @@
 
 package com.android.systemui.dreams;
 
-import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -26,13 +28,17 @@
 import android.os.Handler;
 import android.testing.AndroidTestingRunner;
 import android.view.ViewGroup;
+import android.view.ViewRootImpl;
 import android.view.ViewTreeObserver;
 
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dreams.complication.ComplicationHostViewController;
+import com.android.systemui.statusbar.BlurUtils;
+import com.android.systemui.statusbar.phone.KeyguardBouncer;
+import com.android.systemui.statusbar.phone.KeyguardBouncer.BouncerExpansionCallback;
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -44,7 +50,6 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
-    private static final int DREAM_OVERLAY_NOTIFICATIONS_DRAG_AREA_HEIGHT = 100;
     private static final int MAX_BURN_IN_OFFSET = 20;
     private static final long BURN_IN_PROTECTION_UPDATE_INTERVAL = 10;
     private static final long MILLIS_UNTIL_FULL_JITTER = 240 * 1000;
@@ -70,23 +75,36 @@
     @Mock
     Handler mHandler;
 
+    @Mock
+    BlurUtils mBlurUtils;
+
+    @Mock
+    StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+
+    @Mock
+    KeyguardBouncer mBouncer;
+
+    @Mock
+    ViewRootImpl mViewRoot;
+
     DreamOverlayContainerViewController mController;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
 
-        when(mResources.getDimensionPixelSize(
-                R.dimen.dream_overlay_notifications_drag_area_height)).thenReturn(
-                        DREAM_OVERLAY_NOTIFICATIONS_DRAG_AREA_HEIGHT);
         when(mDreamOverlayContainerView.getResources()).thenReturn(mResources);
         when(mDreamOverlayContainerView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
+        when(mStatusBarKeyguardViewManager.getBouncer()).thenReturn(mBouncer);
+        when(mDreamOverlayContainerView.getViewRootImpl()).thenReturn(mViewRoot);
 
         mController = new DreamOverlayContainerViewController(
                 mDreamOverlayContainerView,
                 mComplicationHostViewController,
                 mDreamOverlayContentView,
                 mDreamOverlayStatusBarViewController,
+                mStatusBarKeyguardViewManager,
+                mBlurUtils,
                 mHandler,
                 MAX_BURN_IN_OFFSET,
                 BURN_IN_PROTECTION_UPDATE_INTERVAL,
@@ -100,13 +118,6 @@
     }
 
     @Test
-    public void testSetsDreamOverlayNotificationsDragAreaHeight() {
-        assertEquals(
-                mController.getDreamOverlayNotificationsDragAreaHeight(),
-                DREAM_OVERLAY_NOTIFICATIONS_DRAG_AREA_HEIGHT);
-    }
-
-    @Test
     public void testBurnInProtectionStartsWhenContentViewAttached() {
         mController.onViewAttached();
         verify(mHandler).postDelayed(any(Runnable.class), eq(BURN_IN_PROTECTION_UPDATE_INTERVAL));
@@ -138,4 +149,34 @@
         runnableCaptor.getValue().run();
         verify(mHandler).postDelayed(runnableCaptor.getValue(), BURN_IN_PROTECTION_UPDATE_INTERVAL);
     }
+
+    @Test
+    public void testBouncerAnimation_doesNotApply() {
+        final ArgumentCaptor<BouncerExpansionCallback> bouncerExpansionCaptor =
+                ArgumentCaptor.forClass(BouncerExpansionCallback.class);
+        mController.onViewAttached();
+        verify(mBouncer).addBouncerExpansionCallback(bouncerExpansionCaptor.capture());
+
+        bouncerExpansionCaptor.getValue().onExpansionChanged(0.5f);
+        verify(mBlurUtils, never()).applyBlur(eq(mViewRoot), anyInt(), eq(false));
+        verify(mDreamOverlayContainerView, never()).setAlpha(anyFloat());
+    }
+
+    @Test
+    public void testBouncerAnimation_updateBlurAndAlpha() {
+        final ArgumentCaptor<BouncerExpansionCallback> bouncerExpansionCaptor =
+                ArgumentCaptor.forClass(BouncerExpansionCallback.class);
+        mController.onViewAttached();
+        verify(mBouncer).addBouncerExpansionCallback(bouncerExpansionCaptor.capture());
+
+        final float blurRadius = 1337f;
+        when(mBlurUtils.blurRadiusOfRatio(anyFloat())).thenReturn(blurRadius);
+
+        bouncerExpansionCaptor.getValue().onStartingToShow();
+        final float bouncerHideAmount = 0.1f;
+        bouncerExpansionCaptor.getValue().onExpansionChanged(bouncerHideAmount);
+        verify(mBlurUtils).blurRadiusOfRatio(1 - bouncerHideAmount);
+        verify(mBlurUtils).applyBlur(mViewRoot, (int) blurRadius, false);
+        verify(mDreamOverlayContainerView).setAlpha(bouncerHideAmount);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java
new file mode 100644
index 0000000..c861221
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.systemui.dreams;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class DreamOverlayNotificationCountProviderTest extends SysuiTestCase {
+    @Mock
+    NotificationListener mNotificationListener;
+    @Mock
+    DreamOverlayNotificationCountProvider.Callback mCallback;
+    @Mock
+    StatusBarNotification mNotification1;
+    @Mock
+    StatusBarNotification mNotification2;
+    @Mock
+    NotificationListenerService.RankingMap mRankingMap;
+
+    private DreamOverlayNotificationCountProvider mProvider;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+
+        when(mNotification1.getKey()).thenReturn("key1");
+        when(mNotification2.getKey()).thenReturn("key2");
+
+        final StatusBarNotification[] notifications = {mNotification1};
+        when(mNotificationListener.getActiveNotifications()).thenReturn(notifications);
+        mProvider = new DreamOverlayNotificationCountProvider(mNotificationListener);
+        mProvider.addCallback(mCallback);
+    }
+
+    @Test
+    public void testPostingNotificationCallsCallbackWithNotificationCount() {
+        final ArgumentCaptor<NotificationHandler> handlerArgumentCaptor =
+                ArgumentCaptor.forClass(NotificationHandler.class);
+        verify(mNotificationListener).addNotificationHandler(handlerArgumentCaptor.capture());
+        handlerArgumentCaptor.getValue().onNotificationPosted(mNotification2, mRankingMap);
+        verify(mCallback).onNotificationCountChanged(2);
+    }
+
+    @Test
+    public void testRemovingNotificationCallsCallbackWithZeroNotificationCount() {
+        final ArgumentCaptor<NotificationHandler> handlerArgumentCaptor =
+                ArgumentCaptor.forClass(NotificationHandler.class);
+        verify(mNotificationListener).addNotificationHandler(handlerArgumentCaptor.capture());
+        handlerArgumentCaptor.getValue().onNotificationRemoved(mNotification1, mRankingMap);
+        verify(mCallback).onNotificationCountChanged(0);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
index 3657192..f567b55 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
@@ -38,6 +38,7 @@
 import androidx.lifecycle.LifecycleRegistry;
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.logging.UiEventLogger;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dreams.complication.DreamPreviewComplication;
@@ -104,6 +105,9 @@
     @Mock
     ViewGroup mDreamOverlayContainerViewParent;
 
+    @Mock
+    UiEventLogger mUiEventLogger;
+
     DreamOverlayService mService;
 
     @Before
@@ -129,7 +133,22 @@
                 mDreamOverlayComponentFactory,
                 mStateController,
                 mKeyguardUpdateMonitor,
-                mPreviewComplication);
+                mPreviewComplication,
+                mUiEventLogger);
+    }
+
+    @Test
+    public void testOnStartMetricsLogged() throws Exception {
+        final IBinder proxy = mService.onBind(new Intent());
+        final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
+
+        // Inform the overlay service of dream starting.
+        overlay.startDream(mWindowParams, mDreamOverlayCallback);
+        mMainExecutor.runAllReady();
+
+        verify(mUiEventLogger).log(DreamOverlayService.DreamOverlayEvent.DREAM_OVERLAY_ENTER_START);
+        verify(mUiEventLogger).log(
+                DreamOverlayService.DreamOverlayEvent.DREAM_OVERLAY_COMPLETE_START);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
index a32ff80..4915ded 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
@@ -31,15 +31,12 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
 import android.provider.Settings;
-import android.service.notification.NotificationListenerService;
-import android.service.notification.StatusBarNotification;
 import android.testing.AndroidTestingRunner;
 
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
 import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.ZenModeController;
@@ -53,6 +50,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.concurrent.Executor;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
@@ -82,13 +81,11 @@
     @Mock
     IndividualSensorPrivacyController mSensorPrivacyController;
     @Mock
-    StatusBarNotification mStatusBarNotification;
-    @Mock
-    NotificationListenerService.RankingMap mRankingMap;
-    @Mock
-    NotificationListener mNotificationListener;
-    @Mock
     ZenModeController mZenModeController;
+    @Mock
+    DreamOverlayNotificationCountProvider mDreamOverlayNotificationCountProvider;
+
+    private final Executor mMainExecutor = Runnable::run;
 
     DreamOverlayStatusBarViewController mController;
 
@@ -102,13 +99,14 @@
         mController = new DreamOverlayStatusBarViewController(
                 mView,
                 mResources,
+                mMainExecutor,
                 mConnectivityManager,
                 mTouchSession,
                 mAlarmManager,
                 mNextAlarmController,
                 mDateFormatUtil,
                 mSensorPrivacyController,
-                mNotificationListener,
+                mDreamOverlayNotificationCountProvider,
                 mZenModeController);
     }
 
@@ -118,6 +116,7 @@
         verify(mNextAlarmController).addCallback(any());
         verify(mSensorPrivacyController).addCallback(any());
         verify(mZenModeController).addCallback(any());
+        verify(mDreamOverlayNotificationCountProvider).addCallback(any());
     }
 
     @Test
@@ -134,7 +133,8 @@
                 .thenReturn(false);
         when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(mNetworkCapabilities);
         mController.onViewAttached();
-        verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true);
+        verify(mView).showIcon(
+                DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true, null);
     }
 
     @Test
@@ -143,13 +143,16 @@
                 .thenReturn(true);
         when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(mNetworkCapabilities);
         mController.onViewAttached();
-        verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false);
+        verify(mView).showIcon(
+                DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false, null);
     }
 
     @Test
     public void testOnViewAttachedShowsWifiIconWhenNetworkCapabilitiesUnavailable() {
         when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(null);
         mController.onViewAttached();
+        verify(mView).showIcon(
+                DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true, null);
     }
 
     @Test
@@ -176,7 +179,8 @@
         when(mSensorPrivacyController.isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA))
                 .thenReturn(true);
         mController.onViewAttached();
-        verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, true);
+        verify(mView).showIcon(
+                DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, true, null);
     }
 
     @Test
@@ -186,22 +190,32 @@
         when(mSensorPrivacyController.isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA))
                 .thenReturn(false);
         mController.onViewAttached();
-        verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, false);
+        verify(mView).showIcon(
+                DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, false, null);
     }
 
     @Test
     public void testOnViewAttachedShowsNotificationsIconWhenNotificationsExist() {
-        StatusBarNotification[] notifications = { mStatusBarNotification };
-        when(mNotificationListener.getActiveNotifications()).thenReturn(notifications);
         mController.onViewAttached();
+
+        final ArgumentCaptor<DreamOverlayNotificationCountProvider.Callback> callbackCapture =
+                ArgumentCaptor.forClass(DreamOverlayNotificationCountProvider.Callback.class);
+        verify(mDreamOverlayNotificationCountProvider).addCallback(callbackCapture.capture());
+        callbackCapture.getValue().onNotificationCountChanged(1);
+
         verify(mView).showIcon(
                 eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(true), any());
     }
 
     @Test
     public void testOnViewAttachedHidesNotificationsIconWhenNoNotificationsExist() {
-        when(mNotificationListener.getActiveNotifications()).thenReturn(null);
         mController.onViewAttached();
+
+        final ArgumentCaptor<DreamOverlayNotificationCountProvider.Callback> callbackCapture =
+                ArgumentCaptor.forClass(DreamOverlayNotificationCountProvider.Callback.class);
+        verify(mDreamOverlayNotificationCountProvider).addCallback(callbackCapture.capture());
+        callbackCapture.getValue().onNotificationCountChanged(0);
+
         verify(mView).showIcon(
                 eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(false), isNull());
     }
@@ -211,7 +225,8 @@
         when(mZenModeController.getZen()).thenReturn(
                 Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
         mController.onViewAttached();
-        verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, true);
+        verify(mView).showIcon(
+                DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, true, null);
     }
 
     @Test
@@ -219,7 +234,8 @@
         when(mZenModeController.getZen()).thenReturn(
                 Settings.Global.ZEN_MODE_OFF);
         mController.onViewAttached();
-        verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false);
+        verify(mView).showIcon(
+                DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false, null);
     }
 
     @Test
@@ -235,6 +251,7 @@
         verify(mNextAlarmController).removeCallback(any());
         verify(mSensorPrivacyController).removeCallback(any());
         verify(mZenModeController).removeCallback(any());
+        verify(mDreamOverlayNotificationCountProvider).removeCallback(any());
     }
 
     @Test
@@ -250,7 +267,9 @@
                 ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
         verify(mConnectivityManager).registerNetworkCallback(any(), callbackCapture.capture());
         callbackCapture.getValue().onAvailable(mNetwork);
-        verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false);
+
+        verify(mView).showIcon(
+                DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false, null);
     }
 
     @Test
@@ -266,7 +285,9 @@
                 ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
         verify(mConnectivityManager).registerNetworkCallback(any(), callbackCapture.capture());
         callbackCapture.getValue().onLost(mNetwork);
-        verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true);
+
+        verify(mView).showIcon(
+                DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true, null);
     }
 
     @Test
@@ -283,20 +304,19 @@
         when(mNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))
                 .thenReturn(true);
         callbackCapture.getValue().onCapabilitiesChanged(mNetwork, mNetworkCapabilities);
-        verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false);
+
+        verify(mView).showIcon(
+                DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false, null);
     }
 
     @Test
     public void testNotificationsIconShownWhenNotificationAdded() {
         mController.onViewAttached();
 
-        StatusBarNotification[] notifications = { mStatusBarNotification };
-        when(mNotificationListener.getActiveNotifications()).thenReturn(notifications);
-
-        final ArgumentCaptor<NotificationListener.NotificationHandler> callbackCapture =
-                ArgumentCaptor.forClass(NotificationListener.NotificationHandler.class);
-        verify(mNotificationListener).addNotificationHandler(callbackCapture.capture());
-        callbackCapture.getValue().onNotificationPosted(mStatusBarNotification, mRankingMap);
+        final ArgumentCaptor<DreamOverlayNotificationCountProvider.Callback> callbackCapture =
+                ArgumentCaptor.forClass(DreamOverlayNotificationCountProvider.Callback.class);
+        verify(mDreamOverlayNotificationCountProvider).addCallback(callbackCapture.capture());
+        callbackCapture.getValue().onNotificationCountChanged(1);
 
         verify(mView).showIcon(
                 eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(true), any());
@@ -304,15 +324,12 @@
 
     @Test
     public void testNotificationsIconHiddenWhenLastNotificationRemoved() {
-        StatusBarNotification[] notifications = { mStatusBarNotification };
-        when(mNotificationListener.getActiveNotifications()).thenReturn(notifications)
-                .thenReturn(null);
         mController.onViewAttached();
 
-        final ArgumentCaptor<NotificationListener.NotificationHandler> callbackCapture =
-                ArgumentCaptor.forClass(NotificationListener.NotificationHandler.class);
-        verify(mNotificationListener).addNotificationHandler(callbackCapture.capture());
-        callbackCapture.getValue().onNotificationPosted(mStatusBarNotification, mRankingMap);
+        final ArgumentCaptor<DreamOverlayNotificationCountProvider.Callback> callbackCapture =
+                ArgumentCaptor.forClass(DreamOverlayNotificationCountProvider.Callback.class);
+        verify(mDreamOverlayNotificationCountProvider).addCallback(callbackCapture.capture());
+        callbackCapture.getValue().onNotificationCountChanged(0);
 
         verify(mView).showIcon(
                 eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(false), any());
@@ -333,7 +350,8 @@
         callbackCapture.getValue().onSensorBlockedChanged(
                 SensorPrivacyManager.Sensors.MICROPHONE, true);
 
-        verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, true);
+        verify(mView).showIcon(
+                DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, true, null);
     }
 
     @Test
@@ -350,7 +368,8 @@
         callbackCapture.getValue().onSensorBlockedChanged(
                 SensorPrivacyManager.Sensors.MICROPHONE, false);
 
-        verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, false);
+        verify(mView).showIcon(
+                DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, false, null);
     }
 
     @Test
@@ -364,7 +383,8 @@
         verify(mZenModeController).addCallback(callbackCapture.capture());
         callbackCapture.getValue().onZenChanged(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS);
 
-        verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, true);
+        verify(mView).showIcon(
+                DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, true, null);
     }
 
     @Test
@@ -373,12 +393,12 @@
                 .thenReturn(Settings.Global.ZEN_MODE_OFF);
         mController.onViewAttached();
 
-
         final ArgumentCaptor<ZenModeController.Callback> callbackCapture =
                 ArgumentCaptor.forClass(ZenModeController.Callback.class);
         verify(mZenModeController).addCallback(callbackCapture.capture());
         callbackCapture.getValue().onZenChanged(Settings.Global.ZEN_MODE_OFF);
 
-        verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false);
+        verify(mView).showIcon(
+                DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false, null);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java
index d1d9ec3..35bcfcd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java
@@ -18,6 +18,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -414,4 +415,37 @@
             assertThat(lp.endToEnd == ConstraintLayout.LayoutParams.PARENT_ID).isTrue();
         });
     }
+
+    /**
+     * Ensures a second removal of a complication is a no-op.
+     */
+    @Test
+    public void testDoubleRemoval() {
+        final ComplicationLayoutEngine engine =
+                new ComplicationLayoutEngine(mLayout, 0, mTouchSession, 0, 0);
+
+        final ViewInfo firstViewInfo = new ViewInfo(
+                new ComplicationLayoutParams(
+                        100,
+                        100,
+                        ComplicationLayoutParams.POSITION_TOP
+                                | ComplicationLayoutParams.POSITION_END,
+                        ComplicationLayoutParams.DIRECTION_DOWN,
+                        0),
+                Complication.CATEGORY_STANDARD,
+                mLayout);
+
+        engine.addComplication(firstViewInfo.id, firstViewInfo.view, firstViewInfo.lp,
+                firstViewInfo.category);
+        verify(mLayout).addView(firstViewInfo.view);
+
+        assertThat(engine.removeComplication(firstViewInfo.id)).isTrue();
+        verify(firstViewInfo.view).getParent();
+        verify(mLayout).removeView(firstViewInfo.view);
+
+        Mockito.clearInvocations(mLayout, firstViewInfo.view);
+        assertThat(engine.removeComplication(firstViewInfo.id)).isFalse();
+        verify(firstViewInfo.view, never()).getParent();
+        verify(mLayout, never()).removeView(firstViewInfo.view);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockDateComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockDateComplicationTest.java
index b02c506..86aa14d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockDateComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockDateComplicationTest.java
@@ -15,11 +15,16 @@
  */
 package com.android.systemui.dreams.complication;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.testing.AndroidTestingRunner;
+import android.view.View;
 
 import androidx.test.filters.SmallTest;
 
@@ -32,6 +37,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import javax.inject.Provider;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 public class DreamClockDateComplicationTest extends SysuiTestCase {
@@ -45,9 +52,28 @@
     @Mock
     private DreamClockDateComplication mComplication;
 
+    @Mock
+    private Provider<DreamClockDateComplication.DreamClockDateViewHolder>
+            mDreamClockDateViewHolderProvider;
+
+    @Mock
+    private DreamClockDateComplication.DreamClockDateViewHolder
+            mDreamClockDateViewHolder;
+
+    @Mock
+    private ComplicationViewModel mComplicationViewModel;
+
+    @Mock
+    private View mView;
+
+    @Mock
+    private ComplicationLayoutParams mLayoutParams;
+
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
+        when(mDreamClockDateViewHolderProvider.get()).thenReturn(mDreamClockDateViewHolder);
+
     }
 
     /**
@@ -63,4 +89,40 @@
         registrant.start();
         verify(mDreamOverlayStateController).addComplication(eq(mComplication));
     }
+
+    /**
+     * Verifies {@link DreamClockDateComplication} has the required type.
+     */
+    @Test
+    public void testComplicationRequiredTypeAvailability() {
+        final DreamClockDateComplication complication =
+                new DreamClockDateComplication(mDreamClockDateViewHolderProvider);
+        assertEquals(Complication.COMPLICATION_TYPE_DATE,
+                complication.getRequiredTypeAvailability());
+    }
+
+    /**
+     * Verifies {@link DreamClockDateComplication.DreamClockDateViewHolder} is obtainable from its
+     * provider when the complication creates view.
+     */
+    @Test
+    public void testComplicationViewHolderProviderOnCreateView() {
+        final DreamClockDateComplication complication =
+                new DreamClockDateComplication(mDreamClockDateViewHolderProvider);
+        final Complication.ViewHolder viewHolder = complication.createView(mComplicationViewModel);
+        verify(mDreamClockDateViewHolderProvider).get();
+        assertThat(viewHolder).isEqualTo(mDreamClockDateViewHolder);
+    }
+
+    /**
+     * Verifies {@link DreamClockDateComplication.DreamClockDateViewHolder} has the intended view
+     * and layout parameters from constructor.
+     */
+    @Test
+    public void testComplicationViewHolderContentAccessors() {
+        final DreamClockDateComplication.DreamClockDateViewHolder viewHolder =
+                new DreamClockDateComplication.DreamClockDateViewHolder(mView, mLayoutParams);
+        assertThat(viewHolder.getView()).isEqualTo(mView);
+        assertThat(viewHolder.getLayoutParams()).isEqualTo(mLayoutParams);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java
index 088b4d5..314a30b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java
@@ -15,11 +15,16 @@
  */
 package com.android.systemui.dreams.complication;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.testing.AndroidTestingRunner;
+import android.view.View;
 
 import androidx.test.filters.SmallTest;
 
@@ -32,6 +37,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import javax.inject.Provider;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 public class DreamClockTimeComplicationTest extends SysuiTestCase {
@@ -45,9 +52,27 @@
     @Mock
     private DreamClockTimeComplication mComplication;
 
+    @Mock
+    private Provider<DreamClockTimeComplication.DreamClockTimeViewHolder>
+            mDreamClockTimeViewHolderProvider;
+
+    @Mock
+    private DreamClockTimeComplication.DreamClockTimeViewHolder
+            mDreamClockTimeViewHolder;
+
+    @Mock
+    private ComplicationViewModel mComplicationViewModel;
+
+    @Mock
+    private View mView;
+
+    @Mock
+    private ComplicationLayoutParams mLayoutParams;
+
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
+        when(mDreamClockTimeViewHolderProvider.get()).thenReturn(mDreamClockTimeViewHolder);
     }
 
     /**
@@ -63,4 +88,40 @@
         registrant.start();
         verify(mDreamOverlayStateController).addComplication(eq(mComplication));
     }
+
+    /**
+     * Verifies {@link DreamClockTimeComplication} has the required type.
+     */
+    @Test
+    public void testComplicationRequiredTypeAvailability() {
+        final DreamClockTimeComplication complication =
+                new DreamClockTimeComplication(mDreamClockTimeViewHolderProvider);
+        assertEquals(Complication.COMPLICATION_TYPE_TIME,
+                complication.getRequiredTypeAvailability());
+    }
+
+    /**
+     * Verifies {@link DreamClockTimeComplication.DreamClockTimeViewHolder} is obtainable from its
+     * provider when the complication creates view.
+     */
+    @Test
+    public void testComplicationViewHolderProviderOnCreateView() {
+        final DreamClockTimeComplication complication =
+                new DreamClockTimeComplication(mDreamClockTimeViewHolderProvider);
+        final Complication.ViewHolder viewHolder = complication.createView(mComplicationViewModel);
+        verify(mDreamClockTimeViewHolderProvider).get();
+        assertThat(viewHolder).isEqualTo(mDreamClockTimeViewHolder);
+    }
+
+    /**
+     * Verifies {@link DreamClockTimeComplication.DreamClockTimeViewHolder} has the intended view
+     * and layout parameters from constructor.
+     */
+    @Test
+    public void testComplicationViewHolderContentAccessors() {
+        final DreamClockTimeComplication.DreamClockTimeViewHolder viewHolder =
+                new DreamClockTimeComplication.DreamClockTimeViewHolder(mView, mLayoutParams);
+        assertThat(viewHolder.getView()).isEqualTo(mView);
+        assertThat(viewHolder.getLayoutParams()).isEqualTo(mLayoutParams);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
index 6e01541..b08dd57 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
@@ -31,6 +31,7 @@
 import android.testing.AndroidTestingRunner;
 import android.util.DisplayMetrics;
 import android.view.GestureDetector;
+import android.view.GestureDetector.OnGestureListener;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 
@@ -39,8 +40,8 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.shared.system.InputChannelCompat;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
+import com.android.systemui.statusbar.phone.KeyguardBouncer;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.wm.shell.animation.FlingAnimationUtils;
 
@@ -111,9 +112,12 @@
                 mFlingAnimationUtilsClosing,
                 TOUCH_REGION);
 
+        when(mCentralSurfaces.isBouncerShowing()).thenReturn(false);
         when(mCentralSurfaces.getDisplayHeight()).thenReturn((float) SCREEN_HEIGHT_PX);
+        when(mCentralSurfaces.isBouncerShowing()).thenReturn(false);
         when(mValueAnimatorCreator.create(anyFloat(), anyFloat())).thenReturn(mValueAnimator);
         when(mVelocityTrackerFactory.obtain()).thenReturn(mVelocityTracker);
+        when(mFlingAnimationUtils.getMinVelocityPxPerSecond()).thenReturn(Float.MAX_VALUE);
     }
 
     /**
@@ -154,7 +158,73 @@
      * Makes sure expansion amount is proportional to scroll.
      */
     @Test
-    public void testExpansionAmount() {
+    public void testExpansionAmount_whenBouncerHidden_setsCorrectValue() {
+        mTouchHandler.onSessionStart(mTouchSession);
+        ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerCaptor =
+                ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class);
+        verify(mTouchSession).registerGestureListener(gestureListenerCaptor.capture());
+
+        final OnGestureListener gestureListener = gestureListenerCaptor.getValue();
+        when(mCentralSurfaces.isBouncerShowing()).thenReturn(false);
+        verifyScroll(.3f, Direction.UP, true, gestureListener);
+
+        // Ensure that subsequent gestures are treated as expanding even if the bouncer state
+        // changes.
+        when(mCentralSurfaces.isBouncerShowing()).thenReturn(true);
+        verifyScroll(.7f, Direction.UP, true, gestureListener);
+    }
+
+    /**
+     * Makes sure collapse amount is proportional to scroll.
+     */
+    @Test
+    public void testCollapseAmount() {
+        mTouchHandler.onSessionStart(mTouchSession);
+        ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerCaptor =
+                ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class);
+        verify(mTouchSession).registerGestureListener(gestureListenerCaptor.capture());
+
+        final OnGestureListener gestureListener = gestureListenerCaptor.getValue();
+        when(mCentralSurfaces.isBouncerShowing()).thenReturn(true);
+        verifyScroll(.3f, Direction.DOWN, false, gestureListener);
+
+        // Ensure that subsequent gestures are treated as collapsing even if the bouncer state
+        // changes.
+        when(mCentralSurfaces.isBouncerShowing()).thenReturn(false);
+        verifyScroll(.7f, Direction.DOWN, false, gestureListener);
+    }
+
+    private enum Direction {
+        DOWN,
+        UP,
+    }
+
+    private void verifyScroll(float percent, Direction direction, boolean expanding,
+            android.view.GestureDetector.OnGestureListener gestureListener) {
+
+        final float distanceY = SCREEN_HEIGHT_PX * percent;
+
+        final MotionEvent event1 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,
+                0, direction == Direction.UP ? SCREEN_HEIGHT_PX : 0, 0);
+        final MotionEvent event2 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,
+                0, direction == Direction.UP ? SCREEN_HEIGHT_PX - distanceY : distanceY, 0);
+
+        assertThat(gestureListener.onScroll(event1, event2, 0, distanceY))
+                .isTrue();
+
+        // Ensure correct expansion passed in.
+        verify(mStatusBarKeyguardViewManager)
+                .onPanelExpansionChanged(
+                        eq(expanding ? 1 - percent : percent), eq(false), eq(true));
+    }
+
+    /**
+     * Makes sure expansion amount is proportional to scroll.
+     */
+    @Test
+    public void testExpansionAmount_whenBouncerShown_setsCorrectValue() {
+        when(mCentralSurfaces.isBouncerShowing()).thenReturn(true);
+
         mTouchHandler.onSessionStart(mTouchSession);
         ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerCaptor =
                 ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class);
@@ -166,9 +236,9 @@
         final MotionEvent event1 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,
                 0, SCREEN_HEIGHT_PX, 0);
         final MotionEvent event2 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,
-                0, SCREEN_HEIGHT_PX  - distanceY, 0);
+                0, SCREEN_HEIGHT_PX - distanceY, 0);
 
-        assertThat(gestureListenerCaptor.getValue().onScroll(event1, event2, 0 , distanceY))
+        assertThat(gestureListenerCaptor.getValue().onScroll(event1, event2, 0, distanceY))
                 .isTrue();
 
         // Ensure only called once
@@ -177,7 +247,7 @@
 
         // Ensure correct expansion passed in.
         verify(mStatusBarKeyguardViewManager)
-                .onPanelExpansionChanged(eq(1 - scrollAmount), eq(false), eq(true));
+                .onPanelExpansionChanged(eq(scrollAmount), eq(false), eq(true));
     }
 
     private void swipeToPosition(float position, float velocityY) {
@@ -196,9 +266,9 @@
         final MotionEvent event1 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,
                 0, SCREEN_HEIGHT_PX, 0);
         final MotionEvent event2 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,
-                0, SCREEN_HEIGHT_PX  - distanceY, 0);
+                0, SCREEN_HEIGHT_PX - distanceY, 0);
 
-        assertThat(gestureListenerCaptor.getValue().onScroll(event1, event2, 0 , distanceY))
+        assertThat(gestureListenerCaptor.getValue().onScroll(event1, event2, 0, distanceY))
                 .isTrue();
 
         final MotionEvent upEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP,
@@ -212,14 +282,18 @@
      * down.
      */
     @Test
-    public void testCollapseOnThreshold() {
+    public void testSwipeBelowThreshold_collapsesBouncer() {
         final float swipeUpPercentage = .3f;
-        swipeToPosition(swipeUpPercentage, -1);
+        final float expansion = 1 - swipeUpPercentage;
+        // The upward velocity is ignored.
+        final float velocityY = -1;
+        swipeToPosition(swipeUpPercentage, velocityY);
 
-        verify(mValueAnimatorCreator).create(eq(1 - swipeUpPercentage),
-                eq(KeyguardBouncer.EXPANSION_VISIBLE));
-        verify(mFlingAnimationUtilsClosing).apply(eq(mValueAnimator), anyFloat(), anyFloat(),
-                anyFloat(), anyFloat());
+        verify(mValueAnimatorCreator).create(eq(expansion), eq(KeyguardBouncer.EXPANSION_HIDDEN));
+        verify(mFlingAnimationUtilsClosing).apply(eq(mValueAnimator),
+                eq(SCREEN_HEIGHT_PX * expansion),
+                eq(SCREEN_HEIGHT_PX * KeyguardBouncer.EXPANSION_HIDDEN),
+                eq(velocityY), eq((float) SCREEN_HEIGHT_PX));
         verify(mValueAnimator).start();
     }
 
@@ -227,14 +301,59 @@
      * Tests that ending a swipe above the set expansion threshold will continue the expansion.
      */
     @Test
-    public void testExpandOnThreshold() {
+    public void testSwipeAboveThreshold_expandsBouncer() {
         final float swipeUpPercentage = .7f;
-        swipeToPosition(swipeUpPercentage, 1);
+        final float expansion = 1 - swipeUpPercentage;
+        // The downward velocity is ignored.
+        final float velocityY = 1;
+        swipeToPosition(swipeUpPercentage, velocityY);
 
-        verify(mValueAnimatorCreator).create(eq(1 - swipeUpPercentage),
-                eq(KeyguardBouncer.EXPANSION_HIDDEN));
-        verify(mFlingAnimationUtils).apply(eq(mValueAnimator), anyFloat(), anyFloat(),
-                anyFloat(), anyFloat());
+        verify(mValueAnimatorCreator).create(eq(expansion), eq(KeyguardBouncer.EXPANSION_VISIBLE));
+        verify(mFlingAnimationUtils).apply(eq(mValueAnimator), eq(SCREEN_HEIGHT_PX * expansion),
+                eq(SCREEN_HEIGHT_PX * KeyguardBouncer.EXPANSION_VISIBLE),
+                eq(velocityY), eq((float) SCREEN_HEIGHT_PX));
+        verify(mValueAnimator).start();
+    }
+
+    /**
+     * Tests that swiping down with a speed above the set threshold leads to bouncer collapsing
+     * down.
+     */
+    @Test
+    public void testSwipeDownVelocityAboveMin_collapsesBouncer() {
+        when(mFlingAnimationUtils.getMinVelocityPxPerSecond()).thenReturn((float) 0);
+
+        // The swipe amount above the set expansion threshold is ignored.
+        final float swipeUpPercentage = .7f;
+        final float expansion = 1 - swipeUpPercentage;
+        final float velocityY = 1;
+        swipeToPosition(swipeUpPercentage, velocityY);
+
+        verify(mValueAnimatorCreator).create(eq(expansion), eq(KeyguardBouncer.EXPANSION_HIDDEN));
+        verify(mFlingAnimationUtilsClosing).apply(eq(mValueAnimator),
+                eq(SCREEN_HEIGHT_PX * expansion),
+                eq(SCREEN_HEIGHT_PX * KeyguardBouncer.EXPANSION_HIDDEN),
+                eq(velocityY), eq((float) SCREEN_HEIGHT_PX));
+        verify(mValueAnimator).start();
+    }
+
+    /**
+     * Tests that swiping up with a speed above the set threshold will continue the expansion.
+     */
+    @Test
+    public void testSwipeUpVelocityAboveMin_expandsBouncer() {
+        when(mFlingAnimationUtils.getMinVelocityPxPerSecond()).thenReturn((float) 0);
+
+        // The swipe amount below the set expansion threshold is ignored.
+        final float swipeUpPercentage = .3f;
+        final float expansion = 1 - swipeUpPercentage;
+        final float velocityY = -1;
+        swipeToPosition(swipeUpPercentage, velocityY);
+
+        verify(mValueAnimatorCreator).create(eq(expansion), eq(KeyguardBouncer.EXPANSION_VISIBLE));
+        verify(mFlingAnimationUtils).apply(eq(mValueAnimator), eq(SCREEN_HEIGHT_PX * expansion),
+                eq(SCREEN_HEIGHT_PX * KeyguardBouncer.EXPANSION_VISIBLE),
+                eq(velocityY), eq((float) SCREEN_HEIGHT_PX));
         verify(mValueAnimator).start();
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitorTest.java
index 29f56e0..a807407 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitorTest.java
@@ -345,6 +345,26 @@
     }
 
     @Test
+    public void testPop() {
+        final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class);
+        final DreamTouchHandler.TouchSession.Callback callback =
+                Mockito.mock(DreamTouchHandler.TouchSession.Callback.class);
+
+        final Environment environment = new Environment(Stream.of(touchHandler)
+                .collect(Collectors.toCollection(HashSet::new)));
+
+        final InputEvent initialEvent = Mockito.mock(InputEvent.class);
+        environment.publishInputEvent(initialEvent);
+
+        final DreamTouchHandler.TouchSession session = captureSession(touchHandler);
+        session.registerCallback(callback);
+        session.pop();
+        environment.executeAll();
+
+        verify(callback).onRemoved();
+    }
+
+    @Test
     public void testPause() {
         final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
index 23a5b2b..50b779c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
@@ -67,9 +67,14 @@
     private lateinit var mBroadcastReceiver: BroadcastReceiver
     private lateinit var mClearCacheAction: Consumer<Int>
 
+    private val teamfoodableFlagA = BooleanFlag(500, false, true)
+    private val teamfoodableFlagB = BooleanFlag(501, true, true)
+
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
+        mFlagMap.put(teamfoodableFlagA.id, teamfoodableFlagA)
+        mFlagMap.put(teamfoodableFlagB.id, teamfoodableFlagB)
         mFeatureFlagsDebug = FeatureFlagsDebug(
             mFlagManager,
             mMockContext,
@@ -77,7 +82,7 @@
             mSystemProperties,
             mResources,
             mDumpManager,
-            { mFlagMap },
+            mFlagMap,
             mBarService
         )
         verify(mFlagManager).onSettingsChangedAction = any()
@@ -93,12 +98,50 @@
 
     @Test
     fun testReadBooleanFlag() {
+        // Remember that the TEAMFOOD flag is id#1 and has special behavior.
         whenever(mFlagManager.readFlagValue<Boolean>(eq(3), any())).thenReturn(true)
         whenever(mFlagManager.readFlagValue<Boolean>(eq(4), any())).thenReturn(false)
-        assertThat(mFeatureFlagsDebug.isEnabled(BooleanFlag(1, false))).isFalse()
         assertThat(mFeatureFlagsDebug.isEnabled(BooleanFlag(2, true))).isTrue()
         assertThat(mFeatureFlagsDebug.isEnabled(BooleanFlag(3, false))).isTrue()
         assertThat(mFeatureFlagsDebug.isEnabled(BooleanFlag(4, true))).isFalse()
+        assertThat(mFeatureFlagsDebug.isEnabled(BooleanFlag(5, false))).isFalse()
+    }
+
+    @Test
+    fun testTeamFoodFlag_False() {
+        whenever(mFlagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(false)
+        assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isFalse()
+        assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isTrue()
+
+        // Regular boolean flags should still test the same.
+        // Only our teamfoodableFlag should change.
+        testReadBooleanFlag()
+    }
+
+    @Test
+    fun testTeamFoodFlag_True() {
+        whenever(mFlagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(true)
+        assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isTrue()
+        assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isTrue()
+
+        // Regular boolean flags should still test the same.
+        // Only our teamfoodableFlag should change.
+        testReadBooleanFlag()
+    }
+
+    @Test
+    fun testTeamFoodFlag_Overridden() {
+        whenever(mFlagManager.readFlagValue<Boolean>(eq(teamfoodableFlagA.id), any()))
+                .thenReturn(true)
+        whenever(mFlagManager.readFlagValue<Boolean>(eq(teamfoodableFlagB.id), any()))
+                .thenReturn(false)
+        whenever(mFlagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(true)
+        assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isTrue()
+        assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isFalse()
+
+        // Regular boolean flags should still test the same.
+        // Only our teamfoodableFlag should change.
+        testReadBooleanFlag()
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
index 1484c9d..fcfef4a4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
@@ -52,8 +52,6 @@
     private lateinit var statusBarStateController: SysuiStatusBarStateController
     @Mock
     private lateinit var configurationController: ConfigurationController
-    @Mock
-    private lateinit var mediaFlags: MediaFlags
 
     @Mock
     private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager
@@ -73,15 +71,13 @@
                 .thenReturn(true)
         whenever(mediaHost.hostView).thenReturn(hostView)
         hostView.layoutParams = FrameLayout.LayoutParams(100, 100)
-        whenever(mediaFlags.useMediaSessionLayout()).thenReturn(false)
         keyguardMediaController = KeyguardMediaController(
             mediaHost,
             bypassController,
             statusBarStateController,
             notificationLockscreenUserManager,
             context,
-            configurationController,
-            mediaFlags
+            configurationController
         )
         keyguardMediaController.attachSinglePaneContainer(mediaContainerView)
         keyguardMediaController.useSplitShade = false
@@ -157,22 +153,7 @@
     }
 
     @Test
-    fun testNotificationLayout_collapsedPlayer() {
-        verify(mediaHost).expansion = MediaHostState.COLLAPSED
-    }
-
-    @Test
-    fun testSessionLayout_expandedPlayer() {
-        whenever(mediaFlags.useMediaSessionLayout()).thenReturn(true)
-        keyguardMediaController = KeyguardMediaController(
-            mediaHost,
-            bypassController,
-            statusBarStateController,
-            notificationLockscreenUserManager,
-            context,
-            configurationController,
-            mediaFlags
-        )
+    fun testMediaHost_expandedPlayer() {
         verify(mediaHost).expansion = MediaHostState.EXPANDED
     }
 }
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 dcbe0ab..daf81bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
@@ -37,7 +37,6 @@
 import org.mockito.Mock
 import org.mockito.MockitoAnnotations
 import javax.inject.Provider
-import org.mockito.Mockito.`when` as whenever
 
 private val DATA = MediaData(
     userId = -1,
@@ -83,7 +82,6 @@
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
-        whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
         mediaCarouselController = MediaCarouselController(
             context,
             mediaControlPanelFactory,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index cb68d81..04609ad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -16,10 +16,12 @@
 
 package com.android.systemui.media
 
+import org.mockito.Mockito.`when` as whenever
 import android.content.Intent
 import android.graphics.Color
+import android.graphics.drawable.Animatable2
+import android.graphics.drawable.AnimatedVectorDrawable
 import android.graphics.drawable.GradientDrawable
-import android.graphics.drawable.Icon
 import android.graphics.drawable.RippleDrawable
 import android.media.MediaMetadata
 import android.media.session.MediaSession
@@ -35,6 +37,7 @@
 import android.widget.ImageView
 import android.widget.SeekBar
 import android.widget.TextView
+import androidx.constraintlayout.widget.Barrier
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.lifecycle.LiveData
 import androidx.test.filters.SmallTest
@@ -58,12 +61,12 @@
 import org.mockito.ArgumentCaptor
 import org.mockito.ArgumentMatchers.anyLong
 import org.mockito.Mock
+import org.mockito.Mockito.any
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.never
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 import org.mockito.junit.MockitoJUnit
-import org.mockito.Mockito.`when` as whenever
 
 private const val KEY = "TEST_KEY"
 private const val APP = "APP"
@@ -89,8 +92,7 @@
     @Mock private lateinit var activityStarter: ActivityStarter
     @Mock private lateinit var broadcastSender: BroadcastSender
 
-    @Mock private lateinit var holder: PlayerViewHolder
-    @Mock private lateinit var sessionHolder: PlayerSessionViewHolder
+    @Mock private lateinit var viewHolder: MediaViewHolder
     @Mock private lateinit var view: TransitionLayout
     @Mock private lateinit var seekBarViewModel: SeekBarViewModel
     @Mock private lateinit var seekBarData: LiveData<SeekBarViewModel.Progress>
@@ -101,7 +103,6 @@
     @Mock private lateinit var mediaOutputDialogFactory: MediaOutputDialogFactory
     @Mock private lateinit var mediaCarouselController: MediaCarouselController
     @Mock private lateinit var falsingManager: FalsingManager
-    @Mock private lateinit var mediaFlags: MediaFlags
     private lateinit var appIcon: ImageView
     private lateinit var albumView: ImageView
     private lateinit var titleText: TextView
@@ -122,10 +123,10 @@
     private lateinit var actionPlayPause: ImageButton
     private lateinit var actionNext: ImageButton
     private lateinit var actionPrev: ImageButton
+    private lateinit var actionsTopBarrier: Barrier
     @Mock private lateinit var longPressText: TextView
     @Mock private lateinit var handler: Handler
-    private lateinit var settings: View
-    private lateinit var settingsText: TextView
+    private lateinit var settings: ImageButton
     private lateinit var cancel: View
     private lateinit var cancelText: TextView
     private lateinit var dismiss: FrameLayout
@@ -147,7 +148,7 @@
 
         player = MediaControlPanel(context, bgExecutor, activityStarter, broadcastSender,
             mediaViewController, seekBarViewModel, Lazy { mediaDataManager },
-            mediaOutputDialogFactory, mediaCarouselController, falsingManager, mediaFlags, clock)
+            mediaOutputDialogFactory, mediaCarouselController, falsingManager, clock)
         whenever(seekBarViewModel.progress).thenReturn(seekBarData)
 
         // Set up mock views for the players
@@ -163,8 +164,7 @@
         seekBar = SeekBar(context)
         elapsedTimeView = TextView(context)
         totalTimeView = TextView(context)
-        settings = View(context)
-        settingsText = TextView(context)
+        settings = ImageButton(context)
         cancel = View(context)
         cancelText = TextView(context)
         dismiss = FrameLayout(context)
@@ -180,8 +180,22 @@
         actionPrev = ImageButton(context).also { it.setId(R.id.actionPrev) }
         actionNext = ImageButton(context).also { it.setId(R.id.actionNext) }
 
-        initPlayerHolderMocks()
-        initSessionHolderMocks()
+        actionsTopBarrier =
+            Barrier(context).also {
+                it.id = R.id.media_action_barrier_top
+                it.referencedIds =
+                    intArrayOf(
+                        actionPrev.id,
+                        seekBar.id,
+                        actionNext.id,
+                        action0.id,
+                        action1.id,
+                        action2.id,
+                        action3.id,
+                        action4.id)
+            }
+
+        initMediaViewHolderMocks()
 
         // Create media session
         val metadataBuilder = MediaMetadata.Builder().apply {
@@ -215,15 +229,12 @@
                 device = device,
                 active = true,
                 resumeAction = null)
-
-        whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(false)
-        whenever(mediaFlags.useMediaSessionLayout()).thenReturn(false)
     }
 
     /**
-     * Initialize elements common to both view holders
+     * Initialize elements in media view holder
      */
-    private fun initMediaViewHolderMocks(viewHolder: MediaViewHolder) {
+    private fun initMediaViewHolderMocks() {
         whenever(viewHolder.player).thenReturn(view)
         whenever(viewHolder.appIcon).thenReturn(appIcon)
         whenever(viewHolder.albumView).thenReturn(albumView)
@@ -237,6 +248,12 @@
         whenever(viewHolder.seekBar).thenReturn(seekBar)
 
         // Action buttons
+        whenever(viewHolder.actionPlayPause).thenReturn(actionPlayPause)
+        whenever(viewHolder.getAction(R.id.actionPlayPause)).thenReturn(actionPlayPause)
+        whenever(viewHolder.actionNext).thenReturn(actionNext)
+        whenever(viewHolder.getAction(R.id.actionNext)).thenReturn(actionNext)
+        whenever(viewHolder.actionPrev).thenReturn(actionPrev)
+        whenever(viewHolder.getAction(R.id.actionPrev)).thenReturn(actionPrev)
         whenever(viewHolder.action0).thenReturn(action0)
         whenever(viewHolder.getAction(R.id.action0)).thenReturn(action0)
         whenever(viewHolder.action1).thenReturn(action1)
@@ -252,32 +269,12 @@
         whenever(viewHolder.longPressText).thenReturn(longPressText)
         whenever(longPressText.handler).thenReturn(handler)
         whenever(viewHolder.settings).thenReturn(settings)
-        whenever(viewHolder.settingsText).thenReturn(settingsText)
         whenever(viewHolder.cancel).thenReturn(cancel)
         whenever(viewHolder.cancelText).thenReturn(cancelText)
         whenever(viewHolder.dismiss).thenReturn(dismiss)
         whenever(viewHolder.dismissText).thenReturn(dismissText)
-    }
 
-    /** Mock view holder for the notification player */
-    private fun initPlayerHolderMocks() {
-        initMediaViewHolderMocks(holder)
-
-        whenever(holder.elapsedTimeView).thenReturn(elapsedTimeView)
-        whenever(holder.totalTimeView).thenReturn(totalTimeView)
-    }
-
-    /** Mock view holder for session player */
-    private fun initSessionHolderMocks() {
-        initMediaViewHolderMocks(sessionHolder)
-
-        // Semantic action buttons
-        whenever(sessionHolder.actionPlayPause).thenReturn(actionPlayPause)
-        whenever(sessionHolder.getAction(R.id.actionPlayPause)).thenReturn(actionPlayPause)
-        whenever(sessionHolder.actionNext).thenReturn(actionNext)
-        whenever(sessionHolder.getAction(R.id.actionNext)).thenReturn(actionNext)
-        whenever(sessionHolder.actionPrev).thenReturn(actionPrev)
-        whenever(sessionHolder.getAction(R.id.actionPrev)).thenReturn(actionPrev)
+        whenever(viewHolder.actionsTopBarrier).thenReturn(actionsTopBarrier)
     }
 
     @After
@@ -294,57 +291,17 @@
     }
 
     @Test
-    fun bindSemanticActionsOldLayout() {
-        whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
-        whenever(mediaFlags.useMediaSessionLayout()).thenReturn(false)
-
-        val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play)
+    fun bindSemanticActions() {
+        val icon = context.getDrawable(android.R.drawable.ic_media_play)
+        val bg = context.getDrawable(R.drawable.qs_media_round_button_background)
         val semanticActions = MediaButton(
-            playOrPause = MediaAction(icon, Runnable {}, "play"),
-            nextOrCustom = MediaAction(icon, Runnable {}, "next"),
-            custom0 = MediaAction(icon, null, "custom 0"),
-            custom1 = MediaAction(icon, null, "custom 1")
+            playOrPause = MediaAction(icon, Runnable {}, "play", bg),
+            nextOrCustom = MediaAction(icon, Runnable {}, "next", bg),
+            custom0 = MediaAction(icon, null, "custom 0", bg),
+            custom1 = MediaAction(icon, null, "custom 1", bg)
         )
         val state = mediaData.copy(semanticActions = semanticActions)
-
-        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
-        player.bindPlayer(state, PACKAGE)
-
-        verify(expandedSet).setVisibility(R.id.action0, ConstraintSet.VISIBLE)
-        assertThat(action0.contentDescription).isEqualTo("custom 0")
-        assertThat(action0.isEnabled()).isFalse()
-
-        verify(expandedSet).setVisibility(R.id.action1, ConstraintSet.INVISIBLE)
-        assertThat(action1.isEnabled()).isFalse()
-
-        verify(expandedSet).setVisibility(R.id.action2, ConstraintSet.VISIBLE)
-        assertThat(action2.isEnabled()).isTrue()
-        assertThat(action2.contentDescription).isEqualTo("play")
-
-        verify(expandedSet).setVisibility(R.id.action3, ConstraintSet.VISIBLE)
-        assertThat(action3.isEnabled()).isTrue()
-        assertThat(action3.contentDescription).isEqualTo("next")
-
-        verify(expandedSet).setVisibility(R.id.action4, ConstraintSet.VISIBLE)
-        assertThat(action4.contentDescription).isEqualTo("custom 1")
-        assertThat(action4.isEnabled()).isFalse()
-    }
-
-    @Test
-    fun bindSemanticActionsNewLayout() {
-        whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
-        whenever(mediaFlags.useMediaSessionLayout()).thenReturn(true)
-
-        val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play)
-        val semanticActions = MediaButton(
-                playOrPause = MediaAction(icon, Runnable {}, "play"),
-                nextOrCustom = MediaAction(icon, Runnable {}, "next"),
-                custom0 = MediaAction(icon, null, "custom 0"),
-                custom1 = MediaAction(icon, null, "custom 1")
-        )
-        val state = mediaData.copy(semanticActions = semanticActions)
-
-        player.attachPlayer(sessionHolder, MediaViewController.TYPE.PLAYER_SESSION)
+        player.attachPlayer(viewHolder)
         player.bindPlayer(state, PACKAGE)
 
         assertThat(actionPrev.isEnabled()).isFalse()
@@ -380,23 +337,50 @@
     }
 
     @Test
-    fun bindNotificationActionsNewLayout() {
-        whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
-        whenever(mediaFlags.useMediaSessionLayout()).thenReturn(true)
+    fun bind_seekBarDisabled_seekBarVisibilityIsSetToInvisible() {
+        whenever(seekBarViewModel.getEnabled()).thenReturn(false)
 
-        val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play)
+        val icon = context.getDrawable(android.R.drawable.ic_media_play)
+        val semanticActions = MediaButton(
+            playOrPause = MediaAction(icon, Runnable {}, "play", null),
+            nextOrCustom = MediaAction(icon, Runnable {}, "next", null)
+        )
+        val state = mediaData.copy(semanticActions = semanticActions)
+
+        player.attachPlayer(viewHolder)
+        player.bindPlayer(state, PACKAGE)
+
+        verify(expandedSet).setVisibility(R.id.media_progress_bar, ConstraintSet.INVISIBLE)
+    }
+
+    @Test
+    fun bind_seekBarDisabled_noActions_seekBarVisibilityIsSetToGone() {
+        whenever(seekBarViewModel.getEnabled()).thenReturn(false)
+
+        val state = mediaData.copy(semanticActions = MediaButton())
+
+        player.attachPlayer(viewHolder)
+        player.bindPlayer(state, PACKAGE)
+
+        verify(expandedSet).setVisibility(R.id.media_progress_bar, ConstraintSet.INVISIBLE)
+    }
+
+    @Test
+    fun bindNotificationActions() {
+        val icon = context.getDrawable(android.R.drawable.ic_media_play)
+        val bg = context.getDrawable(R.drawable.qs_media_round_button_background)
         val actions = listOf(
-            MediaAction(icon, Runnable {}, "previous"),
-            MediaAction(icon, Runnable {}, "play"),
-            MediaAction(icon, null, "next"),
-            MediaAction(icon, null, "custom 0"),
-            MediaAction(icon, Runnable {}, "custom 1")
+            MediaAction(icon, Runnable {}, "previous", bg),
+            MediaAction(icon, Runnable {}, "play", bg),
+            MediaAction(icon, null, "next", bg),
+            MediaAction(icon, null, "custom 0", bg),
+            MediaAction(icon, Runnable {}, "custom 1", bg)
         )
         val state = mediaData.copy(actions = actions,
             actionsToShowInCompact = listOf(1, 2),
             semanticActions = null)
 
-        player.attachPlayer(sessionHolder, MediaViewController.TYPE.PLAYER_SESSION)
+        player.attachPlayer(viewHolder)
         player.bindPlayer(state, PACKAGE)
 
         // Verify semantic actions are hidden
@@ -432,8 +416,74 @@
     }
 
     @Test
+    fun bindAnimatedSemanticActions() {
+        val mockAvd0 = mock(AnimatedVectorDrawable::class.java)
+        val mockAvd1 = mock(AnimatedVectorDrawable::class.java)
+        val mockAvd2 = mock(AnimatedVectorDrawable::class.java)
+        whenever(mockAvd0.mutate()).thenReturn(mockAvd0)
+        whenever(mockAvd1.mutate()).thenReturn(mockAvd1)
+        whenever(mockAvd2.mutate()).thenReturn(mockAvd2)
+
+        val icon = context.getDrawable(R.drawable.ic_media_play)
+        val bg = context.getDrawable(R.drawable.ic_media_play_container)
+        val semanticActions0 = MediaButton(
+                playOrPause = MediaAction(mockAvd0, Runnable {}, "play", null))
+        val semanticActions1 = MediaButton(
+                playOrPause = MediaAction(mockAvd1, Runnable {}, "pause", null))
+        val semanticActions2 = MediaButton(
+                playOrPause = MediaAction(mockAvd2, Runnable {}, "loading", null))
+        val state0 = mediaData.copy(semanticActions = semanticActions0)
+        val state1 = mediaData.copy(semanticActions = semanticActions1)
+        val state2 = mediaData.copy(semanticActions = semanticActions2)
+
+        player.attachPlayer(viewHolder)
+        player.bindPlayer(state0, PACKAGE)
+
+        // Validate first binding
+        assertThat(actionPlayPause.isEnabled()).isTrue()
+        assertThat(actionPlayPause.contentDescription).isEqualTo("play")
+        verify(collapsedSet).setVisibility(R.id.actionPlayPause, ConstraintSet.VISIBLE)
+        assertThat(actionPlayPause.hasOnClickListeners()).isTrue()
+
+        // Trigger animation & update mock
+        actionPlayPause.performClick()
+        verify(mockAvd0, times(1)).start()
+        whenever(mockAvd0.isRunning()).thenReturn(true)
+
+        // Validate states no longer bind
+        player.bindPlayer(state1, PACKAGE)
+        player.bindPlayer(state2, PACKAGE)
+        assertThat(actionPlayPause.contentDescription).isEqualTo("play")
+
+        // Complete animation and run callbacks
+        whenever(mockAvd0.isRunning()).thenReturn(false)
+        val captor = ArgumentCaptor.forClass(Animatable2.AnimationCallback::class.java)
+        verify(mockAvd0, times(1)).registerAnimationCallback(captor.capture())
+        verify(mockAvd1, never())
+            .registerAnimationCallback(any(Animatable2.AnimationCallback::class.java))
+        verify(mockAvd2, never())
+            .registerAnimationCallback(any(Animatable2.AnimationCallback::class.java))
+        captor.getValue().onAnimationEnd(mockAvd0)
+
+        // Validate correct state was bound
+        assertThat(actionPlayPause.contentDescription).isEqualTo("loading")
+        verify(mockAvd0, times(1))
+            .registerAnimationCallback(any(Animatable2.AnimationCallback::class.java))
+        verify(mockAvd1, times(1)
+            ).registerAnimationCallback(any(Animatable2.AnimationCallback::class.java))
+        verify(mockAvd2, times(1))
+            .registerAnimationCallback(any(Animatable2.AnimationCallback::class.java))
+        verify(mockAvd0, times(1))
+            .unregisterAnimationCallback(any(Animatable2.AnimationCallback::class.java))
+        verify(mockAvd1, times(1))
+            .unregisterAnimationCallback(any(Animatable2.AnimationCallback::class.java))
+        verify(mockAvd2, never())
+            .unregisterAnimationCallback(any(Animatable2.AnimationCallback::class.java))
+    }
+
+    @Test
     fun bindText() {
-        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
+        player.attachPlayer(viewHolder)
         player.bindPlayer(mediaData, PACKAGE)
         assertThat(titleText.getText()).isEqualTo(TITLE)
         assertThat(artistText.getText()).isEqualTo(ARTIST)
@@ -441,7 +491,7 @@
 
     @Test
     fun bindDevice() {
-        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
+        player.attachPlayer(viewHolder)
         player.bindPlayer(mediaData, PACKAGE)
         assertThat(seamlessText.getText()).isEqualTo(DEVICE_NAME)
         assertThat(seamless.contentDescription).isEqualTo(DEVICE_NAME)
@@ -451,7 +501,7 @@
     @Test
     fun bindDisabledDevice() {
         seamless.id = 1
-        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
+        player.attachPlayer(viewHolder)
         val state = mediaData.copy(device = disabledDevice)
         player.bindPlayer(state, PACKAGE)
         assertThat(seamless.isEnabled()).isFalse()
@@ -462,7 +512,7 @@
     @Test
     fun bindNullDevice() {
         val fallbackString = context.getResources().getString(R.string.media_seamless_other_device)
-        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
+        player.attachPlayer(viewHolder)
         val state = mediaData.copy(device = null)
         player.bindPlayer(state, PACKAGE)
         assertThat(seamless.isEnabled()).isTrue()
@@ -472,7 +522,7 @@
 
     @Test
     fun bindDeviceResumptionPlayer() {
-        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
+        player.attachPlayer(viewHolder)
         val state = mediaData.copy(resumption = true)
         player.bindPlayer(state, PACKAGE)
         assertThat(seamlessText.getText()).isEqualTo(DEVICE_NAME)
@@ -481,32 +531,32 @@
 
     @Test
     fun longClick_gutsClosed() {
-        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
+        player.attachPlayer(viewHolder)
         whenever(mediaViewController.isGutsVisible).thenReturn(false)
 
         val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
-        verify(holder.player).setOnLongClickListener(captor.capture())
+        verify(viewHolder.player).setOnLongClickListener(captor.capture())
 
-        captor.value.onLongClick(holder.player)
+        captor.value.onLongClick(viewHolder.player)
         verify(mediaViewController).openGuts()
     }
 
     @Test
     fun longClick_gutsOpen() {
-        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
+        player.attachPlayer(viewHolder)
         whenever(mediaViewController.isGutsVisible).thenReturn(true)
 
         val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
-        verify(holder.player).setOnLongClickListener(captor.capture())
+        verify(viewHolder.player).setOnLongClickListener(captor.capture())
 
-        captor.value.onLongClick(holder.player)
+        captor.value.onLongClick(viewHolder.player)
         verify(mediaViewController, never()).openGuts()
         verify(mediaViewController).closeGuts(false)
     }
 
     @Test
     fun cancelButtonClick_animation() {
-        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
+        player.attachPlayer(viewHolder)
 
         cancel.callOnClick()
 
@@ -515,7 +565,7 @@
 
     @Test
     fun settingsButtonClick() {
-        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
+        player.attachPlayer(viewHolder)
 
         settings.callOnClick()
 
@@ -528,7 +578,7 @@
     @Test
     fun dismissButtonClick() {
         val mediaKey = "key for dismissal"
-        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
+        player.attachPlayer(viewHolder)
         val state = mediaData.copy(notificationKey = KEY)
         player.bindPlayer(state, mediaKey)
 
@@ -540,7 +590,7 @@
     @Test
     fun dismissButtonDisabled() {
         val mediaKey = "key for dismissal"
-        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
+        player.attachPlayer(viewHolder)
         val state = mediaData.copy(isClearable = false, notificationKey = KEY)
         player.bindPlayer(state, mediaKey)
 
@@ -552,7 +602,7 @@
         val mediaKey = "key for dismissal"
         whenever(mediaDataManager.dismissMediaData(eq(mediaKey), anyLong())).thenReturn(false)
 
-        player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
+        player.attachPlayer(viewHolder)
         val state = mediaData.copy(notificationKey = KEY)
         player.bindPlayer(state, mediaKey)
 
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 925ae30..066f49a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.statusbar.SbnBuilder
 import com.android.systemui.tuner.TunerService
 import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.capture
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.time.FakeSystemClock
@@ -167,7 +168,7 @@
         whenever(mediaSmartspaceTarget.featureType).thenReturn(SmartspaceTarget.FEATURE_MEDIA)
         whenever(mediaSmartspaceTarget.iconGrid).thenReturn(listOf(mediaRecommendationItem))
         whenever(mediaSmartspaceTarget.creationTimeMillis).thenReturn(1234L)
-        whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(false)
+        whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(false)
     }
 
     @After
@@ -594,7 +595,7 @@
     @Test
     fun testPlaybackActions_noState_usesNotification() {
         val desc = "Notification Action"
-        whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
+        whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
         whenever(controller.playbackState).thenReturn(null)
 
         val notifWithAction = SbnBuilder().run {
@@ -621,7 +622,7 @@
     @Test
     fun testPlaybackActions_hasPrevNext() {
         val customDesc = arrayOf("custom 1", "custom 2", "custom 3", "custom 4")
-        whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
+        whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
         val stateActions = PlaybackState.ACTION_PLAY or
                 PlaybackState.ACTION_SKIP_TO_PREVIOUS or
                 PlaybackState.ACTION_SKIP_TO_NEXT
@@ -669,7 +670,7 @@
     @Test
     fun testPlaybackActions_noPrevNext_usesCustom() {
         val customDesc = arrayOf("custom 1", "custom 2", "custom 3", "custom 4", "custom 5")
-        whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
+        whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
         val stateActions = PlaybackState.ACTION_PLAY
         val stateBuilder = PlaybackState.Builder()
                 .setActions(stateActions)
@@ -707,7 +708,7 @@
     @Test
     fun testPlaybackActions_reservedSpace() {
         val customDesc = arrayOf("custom 1", "custom 2", "custom 3", "custom 4")
-        whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
+        whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
         val stateActions = PlaybackState.ACTION_PLAY
         val stateBuilder = PlaybackState.Builder()
                 .setActions(stateActions)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
index b359ae5..203eb47 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
@@ -117,9 +117,9 @@
                 dreamOverlayStateController)
         verify(wakefulnessLifecycle).addObserver(wakefullnessObserver.capture())
         verify(statusBarStateController).addCallback(statusBarCallback.capture())
-        setupHost(lockHost, MediaHierarchyManager.LOCATION_LOCKSCREEN)
-        setupHost(qsHost, MediaHierarchyManager.LOCATION_QS)
-        setupHost(qqsHost, MediaHierarchyManager.LOCATION_QQS)
+        setupHost(lockHost, MediaHierarchyManager.LOCATION_LOCKSCREEN, LOCKSCREEN_TOP)
+        setupHost(qsHost, MediaHierarchyManager.LOCATION_QS, QS_TOP)
+        setupHost(qqsHost, MediaHierarchyManager.LOCATION_QQS, QQS_TOP)
         `when`(statusBarStateController.state).thenReturn(StatusBarState.SHADE)
         `when`(mediaCarouselController.mediaCarouselScrollHandler)
                 .thenReturn(mediaCarouselScrollHandler)
@@ -130,9 +130,9 @@
         clearInvocations(mediaCarouselController)
     }
 
-    private fun setupHost(host: MediaHost, location: Int) {
+    private fun setupHost(host: MediaHost, location: Int, top: Int) {
         `when`(host.location).thenReturn(location)
-        `when`(host.currentBounds).thenReturn(Rect())
+        `when`(host.currentBounds).thenReturn(Rect(0, top, 0, top))
         `when`(host.hostView).thenReturn(uniqueObjectHostView)
         `when`(host.visible).thenReturn(true)
         mediaHiearchyManager.register(host)
@@ -223,6 +223,18 @@
     }
 
     @Test
+    fun calculateTransformationType_onLockSplitShade_goingToFullShade_mediaInvisible_returnsFade() {
+        enableSplitShade()
+        goToLockscreen()
+        expandQS()
+        whenever(lockHost.visible).thenReturn(false)
+        mediaHiearchyManager.setTransitionToFullShadeAmount(10000f)
+
+        val transformType = mediaHiearchyManager.calculateTransformationType()
+        assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
+    }
+
+    @Test
     fun calculateTransformationType_onLockShade_inSplitShade_notExpanding_returnsFade() {
         enableSplitShade()
         goToLockscreen()
@@ -257,6 +269,20 @@
         verify(mediaCarouselController).closeGuts()
     }
 
+    @Test
+    fun getGuidedTransformationTranslationY_notInGuidedTransformation_returnsNegativeNumber() {
+        assertThat(mediaHiearchyManager.getGuidedTransformationTranslationY()).isLessThan(0)
+    }
+
+    @Test
+    fun getGuidedTransformationTranslationY_inGuidedTransformation_returnsCurrentTranslation() {
+        enterGuidedTransformation()
+
+        val expectedTranslation = LOCKSCREEN_TOP - QS_TOP
+        assertThat(mediaHiearchyManager.getGuidedTransformationTranslationY())
+                .isEqualTo(expectedTranslation)
+    }
+
     private fun enableSplitShade() {
         context.getOrCreateTestableResources().addOverride(
             R.bool.config_use_split_notification_shade, true
@@ -284,4 +310,16 @@
     private fun expandQS() {
         mediaHiearchyManager.qsExpansion = 1.0f
     }
+
+    private fun enterGuidedTransformation() {
+        mediaHiearchyManager.qsExpansion = 1.0f
+        goToLockscreen()
+        mediaHiearchyManager.setTransitionToFullShadeAmount(123f)
+    }
+
+    companion object {
+        private const val QQS_TOP = 123
+        private const val QS_TOP = 456
+        private const val LOCKSCREEN_TOP = 789
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaViewControllerTest.kt
new file mode 100644
index 0000000..b7d5ba1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaViewControllerTest.kt
@@ -0,0 +1,55 @@
+package com.android.systemui.media
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.animation.MeasurementInput
+import com.android.systemui.util.animation.TransitionLayout
+import com.android.systemui.util.animation.TransitionViewState
+import junit.framework.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests for {@link MediaViewController}.
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class MediaViewControllerTest : SysuiTestCase() {
+    private val configurationController =
+            com.android.systemui.statusbar.phone.ConfigurationControllerImpl(context)
+    private val mediaHostStatesManager = MediaHostStatesManager()
+    private val mediaViewController =
+            MediaViewController(context, configurationController, mediaHostStatesManager)
+    private val mediaHostStateHolder = MediaHost.MediaHostStateHolder()
+    private var transitionLayout = TransitionLayout(context, /* attrs */ null, /* defStyleAttr */ 0)
+
+    @Before
+    fun setUp() {
+        mediaViewController.attach(transitionLayout, MediaViewController.TYPE.PLAYER)
+    }
+
+    @Test
+    fun testObtainViewState_applySquishFraction_toTransitionViewState_height() {
+        transitionLayout.measureState = TransitionViewState().apply {
+            this.height = 100
+        }
+        mediaHostStateHolder.expansion = 1f
+        val widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY)
+        val heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY)
+        mediaHostStateHolder.measurementInput =
+                MeasurementInput(widthMeasureSpec, heightMeasureSpec)
+
+        // Test no squish
+        mediaHostStateHolder.squishFraction = 1f
+        assertTrue(mediaViewController.obtainViewState(mediaHostStateHolder)!!.height == 100)
+
+        // Test half squish
+        mediaHostStateHolder.squishFraction = 0.5f
+        assertTrue(mediaViewController.obtainViewState(mediaHostStateHolder)!!.height == 50)
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaViewHolderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaViewHolderTest.kt
new file mode 100644
index 0000000..ee32793
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaViewHolderTest.kt
@@ -0,0 +1,24 @@
+package com.android.systemui.media
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.LayoutInflater
+import android.widget.FrameLayout
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class MediaViewHolderTest : SysuiTestCase() {
+
+    @Test
+    fun create_succeeds() {
+        val inflater = LayoutInflater.from(context)
+        val parent = FrameLayout(context)
+
+        MediaViewHolder.create(inflater, parent)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/PlayerViewHolderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/PlayerViewHolderTest.kt
deleted file mode 100644
index d6849bf..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/media/PlayerViewHolderTest.kt
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.media
-
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import android.view.LayoutInflater
-import android.view.ViewGroup
-import android.widget.FrameLayout
-
-import androidx.test.filters.SmallTest
-
-import com.android.systemui.SysuiTestCase
-import com.google.common.truth.Truth.assertThat
-
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-
-/**
- * Tests for PlayerViewHolder.
- */
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@TestableLooper.RunWithLooper
-class PlayerViewHolderTest : SysuiTestCase() {
-
-    private lateinit var inflater: LayoutInflater
-    private lateinit var parent: ViewGroup
-
-    @Before
-    fun setUp() {
-        inflater = LayoutInflater.from(context)
-        parent = FrameLayout(context)
-    }
-
-    @Test
-    fun create() {
-        val holder = PlayerViewHolder.create(inflater, parent)
-        assertThat(holder.player).isNotNull()
-    }
-
-    @Test
-    fun backgroundIsIlluminationDrawable() {
-        val holder = PlayerViewHolder.create(inflater, parent)
-        assertThat(holder.player.background as IlluminationDrawable).isNotNull()
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
index 7ac15125..e719e84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
@@ -43,7 +43,7 @@
     private val enabledHeight = 2
 
     private lateinit var observer: SeekBarObserver
-    @Mock private lateinit var mockHolder: PlayerViewHolder
+    @Mock private lateinit var mockHolder: MediaViewHolder
     @Mock private lateinit var mockSquigglyProgress: SquigglyProgress
     private lateinit var seekBarView: SeekBar
     private lateinit var elapsedTimeView: TextView
@@ -53,7 +53,6 @@
 
     @Before
     fun setUp() {
-
         context.orCreateTestableResources
             .addOverride(R.dimen.qs_media_enabled_seekbar_height, enabledHeight)
         context.orCreateTestableResources
@@ -64,23 +63,19 @@
         elapsedTimeView = TextView(context)
         totalTimeView = TextView(context)
         whenever(mockHolder.seekBar).thenReturn(seekBarView)
-        whenever(mockHolder.elapsedTimeView).thenReturn(elapsedTimeView)
-        whenever(mockHolder.totalTimeView).thenReturn(totalTimeView)
 
-        observer = SeekBarObserver(mockHolder, false /* useSessionLayout */)
+        observer = SeekBarObserver(mockHolder)
     }
 
     @Test
     fun seekBarGone() {
         // WHEN seek bar is disabled
         val isEnabled = false
-        val data = SeekBarViewModel.Progress(isEnabled, false, false, null, 0)
+        val data = SeekBarViewModel.Progress(isEnabled, false, false, false, null, 0)
         observer.onChanged(data)
         // THEN seek bar shows just a thin line with no text
         assertThat(seekBarView.isEnabled()).isFalse()
         assertThat(seekBarView.getThumb().getAlpha()).isEqualTo(0)
-        assertThat(elapsedTimeView.getText()).isEqualTo("")
-        assertThat(totalTimeView.getText()).isEqualTo("")
         assertThat(seekBarView.contentDescription).isEqualTo("")
         assertThat(seekBarView.maxHeight).isEqualTo(disabledHeight)
     }
@@ -89,25 +84,21 @@
     fun seekBarVisible() {
         // WHEN seek bar is enabled
         val isEnabled = true
-        val data = SeekBarViewModel.Progress(isEnabled, true, false, 3000, 12000)
+        val data = SeekBarViewModel.Progress(isEnabled, true, false, false, 3000, 12000)
         observer.onChanged(data)
         // THEN seek bar is visible and thick
         assertThat(seekBarView.getVisibility()).isEqualTo(View.VISIBLE)
-        assertThat(elapsedTimeView.getVisibility()).isEqualTo(View.VISIBLE)
-        assertThat(totalTimeView.getVisibility()).isEqualTo(View.VISIBLE)
         assertThat(seekBarView.maxHeight).isEqualTo(enabledHeight)
     }
 
     @Test
     fun seekBarProgress() {
         // WHEN part of the track has been played
-        val data = SeekBarViewModel.Progress(true, true, true, 3000, 120000)
+        val data = SeekBarViewModel.Progress(true, true, true, false, 3000, 120000)
         observer.onChanged(data)
         // THEN seek bar shows the progress
         assertThat(seekBarView.progress).isEqualTo(3000)
         assertThat(seekBarView.max).isEqualTo(120000)
-        assertThat(elapsedTimeView.getText()).isEqualTo("00:03")
-        assertThat(totalTimeView.getText()).isEqualTo("02:00")
 
         val desc = context.getString(R.string.controls_media_seekbar_description, "00:03", "02:00")
         assertThat(seekBarView.contentDescription).isEqualTo(desc)
@@ -117,7 +108,7 @@
     fun seekBarDisabledWhenSeekNotAvailable() {
         // WHEN seek is not available
         val isSeekAvailable = false
-        val data = SeekBarViewModel.Progress(true, isSeekAvailable, false, 3000, 120000)
+        val data = SeekBarViewModel.Progress(true, isSeekAvailable, false, false, 3000, 120000)
         observer.onChanged(data)
         // THEN seek bar is not enabled
         assertThat(seekBarView.isEnabled()).isFalse()
@@ -127,27 +118,51 @@
     fun seekBarEnabledWhenSeekNotAvailable() {
         // WHEN seek is available
         val isSeekAvailable = true
-        val data = SeekBarViewModel.Progress(true, isSeekAvailable, false, 3000, 120000)
+        val data = SeekBarViewModel.Progress(true, isSeekAvailable, false, false, 3000, 120000)
         observer.onChanged(data)
         // THEN seek bar is not enabled
         assertThat(seekBarView.isEnabled()).isTrue()
     }
 
     @Test
-    fun seekBarPlaying() {
+    fun seekBarPlayingNotScrubbing() {
         // WHEN playing
         val isPlaying = true
-        val data = SeekBarViewModel.Progress(true, true, isPlaying, 3000, 120000)
+        val isScrubbing = false
+        val data = SeekBarViewModel.Progress(true, true, isPlaying, isScrubbing, 3000, 120000)
         observer.onChanged(data)
         // THEN progress drawable is animating
         verify(mockSquigglyProgress).animate = true
     }
 
     @Test
-    fun seekBarNotPlaying() {
-        // WHEN not playing
+    fun seekBarNotPlayingNotScrubbing() {
+        // WHEN not playing & not scrubbing
         val isPlaying = false
-        val data = SeekBarViewModel.Progress(true, true, isPlaying, 3000, 120000)
+        val isScrubbing = false
+        val data = SeekBarViewModel.Progress(true, true, isPlaying, isScrubbing, 3000, 120000)
+        observer.onChanged(data)
+        // THEN progress drawable is not animating
+        verify(mockSquigglyProgress).animate = false
+    }
+
+    @Test
+    fun seekBarPlayingScrubbing() {
+        // WHEN playing & scrubbing
+        val isPlaying = true
+        val isScrubbing = true
+        val data = SeekBarViewModel.Progress(true, true, isPlaying, isScrubbing, 3000, 120000)
+        observer.onChanged(data)
+        // THEN progress drawable is not animating
+        verify(mockSquigglyProgress).animate = false
+    }
+
+    @Test
+    fun seekBarNotPlayingScrubbing() {
+        // WHEN playing & scrubbing
+        val isPlaying = false
+        val isScrubbing = true
+        val data = SeekBarViewModel.Progress(true, true, isPlaying, isScrubbing, 3000, 120000)
         observer.onChanged(data)
         // THEN progress drawable is not animating
         verify(mockSquigglyProgress).animate = false
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
index ccce577..b9a69bb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
@@ -81,6 +81,9 @@
         whenever(packageManager.getApplicationIcon(PACKAGE_NAME)).thenReturn(appIconFromPackageName)
         whenever(applicationInfo.loadLabel(packageManager)).thenReturn(APP_NAME)
         whenever(packageManager.getApplicationInfo(
+            any(), any<PackageManager.ApplicationInfoFlags>()
+        )).thenThrow(PackageManager.NameNotFoundException())
+        whenever(packageManager.getApplicationInfo(
             eq(PACKAGE_NAME), any<PackageManager.ApplicationInfoFlags>()
         )).thenReturn(applicationInfo)
         context.setMockPackageManager(packageManager)
@@ -191,6 +194,28 @@
     }
 
     @Test
+    fun setIcon_nullAppIconDrawableAndNullPackageName_stillHasIcon() {
+        controllerCommon.displayChip(getState())
+        val chipView = getChipView()
+
+        controllerCommon.setIcon(chipView, appPackageName = null, appIconDrawableOverride = null)
+
+        assertThat(chipView.getAppIconView().drawable).isNotNull()
+    }
+
+    @Test
+    fun setIcon_nullAppIconDrawableAndInvalidPackageName_stillHasIcon() {
+        controllerCommon.displayChip(getState())
+        val chipView = getChipView()
+
+        controllerCommon.setIcon(
+            chipView, appPackageName = "fakePackageName", appIconDrawableOverride = null
+        )
+
+        assertThat(chipView.getAppIconView().drawable).isNotNull()
+    }
+
+    @Test
     fun setIcon_nullAppIconDrawable_iconIsFromPackageName() {
         controllerCommon.displayChip(getState())
         val chipView = getChipView()
@@ -201,7 +226,7 @@
     }
 
     @Test
-    fun displayChip_hasAppIconDrawable_iconIsDrawable() {
+    fun setIcon_hasAppIconDrawable_iconIsDrawable() {
         controllerCommon.displayChip(getState())
         val chipView = getChipView()
 
@@ -212,7 +237,29 @@
     }
 
     @Test
-    fun displayChip_nullAppName_iconContentDescriptionIsFromPackageName() {
+    fun setIcon_nullAppNameAndNullPackageName_stillHasContentDescription() {
+        controllerCommon.displayChip(getState())
+        val chipView = getChipView()
+
+        controllerCommon.setIcon(chipView, appPackageName = null, appNameOverride = null)
+
+        assertThat(chipView.getAppIconView().contentDescription.toString()).isNotEmpty()
+    }
+
+    @Test
+    fun setIcon_nullAppNameAndInvalidPackageName_stillHasContentDescription() {
+        controllerCommon.displayChip(getState())
+        val chipView = getChipView()
+
+        controllerCommon.setIcon(
+            chipView, appPackageName = "fakePackageName", appNameOverride = null
+        )
+
+        assertThat(chipView.getAppIconView().contentDescription.toString()).isNotEmpty()
+    }
+
+    @Test
+    fun setIcon_nullAppName_iconContentDescriptionIsFromPackageName() {
         controllerCommon.displayChip(getState())
         val chipView = getChipView()
 
@@ -222,7 +269,7 @@
     }
 
     @Test
-    fun displayChip_hasAppName_iconContentDescriptionIsAppNameOverride() {
+    fun setIcon_hasAppName_iconContentDescriptionIsAppNameOverride() {
         controllerCommon.displayChip(getState())
         val chipView = getChipView()
 
@@ -233,6 +280,21 @@
     }
 
     @Test
+    fun setIcon_iconSizeMatchesGetIconSize() {
+        controllerCommon.displayChip(getState())
+        val chipView = getChipView()
+
+        controllerCommon.setIcon(chipView, PACKAGE_NAME)
+        chipView.measure(
+            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
+            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
+        )
+
+        assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(ICON_SIZE)
+        assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(ICON_SIZE)
+    }
+
+    @Test
     fun tapGestureDetected_outsideViewBounds_viewHidden() {
         controllerCommon.displayChip(getState())
         whenever(viewUtil.touchIsWithinView(any(), any(), any())).thenReturn(false)
@@ -297,6 +359,8 @@
         override fun updateChipView(chipInfo: ChipInfo, currentChipView: ViewGroup) {
 
         }
+
+        override fun getIconSize(isAppIcon: Boolean): Int? = ICON_SIZE
     }
 
     inner class ChipInfo : ChipInfoCommon {
@@ -307,3 +371,4 @@
 private const val PACKAGE_NAME = "com.android.systemui"
 private const val APP_NAME = "Fake App Name"
 private const val TIMEOUT_MS = 10000L
+private const val ICON_SIZE = 47
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
index 355d3fe..067607f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
@@ -174,12 +174,47 @@
         verify(logger).logStateChange(any(), any())
     }
 
+    @Test
+    fun setIcon_isAppIcon_usesAppIconSize() {
+        controllerReceiver.displayChip(getChipReceiverInfo())
+        val chipView = getChipView()
+
+        controllerReceiver.setIcon(chipView, PACKAGE_NAME)
+        chipView.measure(
+            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
+            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
+        )
+
+        val expectedSize = controllerReceiver.getIconSize(isAppIcon = true)
+        assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(expectedSize)
+        assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(expectedSize)
+    }
+
+    @Test
+    fun setIcon_notAppIcon_usesGenericIconSize() {
+        controllerReceiver.displayChip(getChipReceiverInfo())
+        val chipView = getChipView()
+
+        controllerReceiver.setIcon(chipView, appPackageName = null)
+        chipView.measure(
+            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
+            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
+        )
+
+        val expectedSize = controllerReceiver.getIconSize(isAppIcon = false)
+        assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(expectedSize)
+        assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(expectedSize)
+    }
+
     private fun getChipView(): ViewGroup {
         val viewCaptor = ArgumentCaptor.forClass(View::class.java)
         verify(windowManager).addView(viewCaptor.capture(), any())
         return viewCaptor.value as ViewGroup
     }
 
+    private fun getChipReceiverInfo(): ChipReceiverInfo =
+        ChipReceiverInfo(routeInfo, null, null)
+
     private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon)
 }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java
index 6df56e9..51088b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java
@@ -123,7 +123,7 @@
                 Style.VIBRANT /* style */);
         int neutralMid = colorScheme.getNeutral1().get(colorScheme.getNeutral1().size() / 2);
         Cam cam = Cam.fromInt(neutralMid);
-        Assert.assertEquals(cam.getChroma(), 8.0, 1.0);
+        Assert.assertTrue(cam.getChroma() <= 8.0);
     }
 
     @Test
@@ -133,7 +133,7 @@
                 Style.EXPRESSIVE /* style */);
         int neutralMid = colorScheme.getNeutral1().get(colorScheme.getNeutral1().size() / 2);
         Cam cam = Cam.fromInt(neutralMid);
-        Assert.assertEquals(cam.getChroma(), 12.0, 1.0);
+        Assert.assertTrue(cam.getChroma() <= 8.0);
     }
 
     /**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
index 634d9e4..edcf479 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
@@ -16,8 +16,18 @@
 
 package com.android.systemui.navigationbar;
 
+import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
+import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
+
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -45,10 +55,15 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Optional;
 
 import dagger.Lazy;
 
+/**
+ * Tests for {@link NavBarHelper}.
+ */
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class NavBarHelperTest extends SysuiTestCase {
@@ -77,7 +92,11 @@
     DumpManager mDumpManager;
     @Mock
     NavBarHelper.NavbarTaskbarStateUpdater mNavbarTaskbarStateUpdater;
+    private AccessibilityManager.AccessibilityServicesStateChangeListener
+            mAccessibilityServicesStateChangeListener;
 
+    private static final int ACCESSIBILITY_BUTTON_CLICKABLE_STATE =
+            SYSUI_STATE_A11Y_BUTTON_CLICKABLE | SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
     private NavBarHelper mNavBarHelper;
 
     @Before
@@ -87,6 +106,9 @@
         when(mAssistManager.getAssistInfoForUser(anyInt())).thenReturn(mAssistantComponent);
         when(mUserTracker.getUserId()).thenReturn(1);
 
+        doAnswer((invocation) -> mAccessibilityServicesStateChangeListener =
+                invocation.getArgument(0)).when(
+                mAccessibilityManager).addAccessibilityServicesStateChangeListener(any());
         mNavBarHelper = new NavBarHelper(mContext, mAccessibilityManager,
                 mAccessibilityButtonModeObserver, mAccessibilityButtonTargetObserver,
                 mSystemActions, mOverviewProxyService, mAssistManagerLazy,
@@ -183,4 +205,42 @@
         verify(mNavbarTaskbarStateUpdater, times(1))
                 .updateAssistantAvailable(anyBoolean());
     }
+
+    @Test
+    public void initNavBarHelper_buttonModeNavBar_a11yButtonClickableState() {
+        when(mAccessibilityManager.getAccessibilityShortcutTargets(
+                AccessibilityManager.ACCESSIBILITY_BUTTON)).thenReturn(createFakeShortcutTargets());
+
+        mNavBarHelper.init();
+
+        assertThat(mNavBarHelper.getA11yButtonState()).isEqualTo(
+                ACCESSIBILITY_BUTTON_CLICKABLE_STATE);
+    }
+
+    @Test
+    public void initAccessibilityStateWithFloatingMenuModeAndTargets_disableClickableState() {
+        when(mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()).thenReturn(
+                ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU);
+        mNavBarHelper.init();
+
+        assertThat(mNavBarHelper.getA11yButtonState()).isEqualTo(/* disable_clickable_state */ 0);
+    }
+
+    @Test
+    public void onA11yServicesStateChangedWithMultipleServices_a11yButtonClickableState() {
+        when(mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()).thenReturn(
+                ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
+
+        when(mAccessibilityManager.getAccessibilityShortcutTargets(
+                AccessibilityManager.ACCESSIBILITY_BUTTON)).thenReturn(createFakeShortcutTargets());
+        mAccessibilityServicesStateChangeListener.onAccessibilityServicesStateChanged(
+                mAccessibilityManager);
+
+        assertThat(mNavBarHelper.getA11yButtonState()).isEqualTo(
+                ACCESSIBILITY_BUTTON_CLICKABLE_STATE);
+    }
+
+    private List<String> createFakeShortcutTargets() {
+        return new ArrayList<>(List.of("a", "b", "c", "d"));
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
index bb42c12..4e3bdea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
@@ -75,7 +75,7 @@
     @Mock
     private CommandQueue mCommandQueue;
     @Mock
-    private NavigationBar.Factory mNavigationBarFactory;
+    private NavigationBarComponent.Factory mNavigationBarFactory;
 
     @Before
     public void setUp() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index eb1e1a2..f5b006d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -29,8 +29,6 @@
 import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.HOME_BUTTON_LONG_PRESS_DURATION_MS;
 import static com.android.systemui.navigationbar.NavigationBar.NavBarActionEvent.NAVBAR_ASSIST_LONGPRESS;
 
-import static com.google.common.truth.Truth.assertThat;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -54,7 +52,6 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
-import android.provider.Settings;
 import android.telecom.TelecomManager;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -82,26 +79,31 @@
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.model.SysUiState;
+import com.android.systemui.navigationbar.buttons.ButtonDispatcher;
+import com.android.systemui.navigationbar.buttons.DeadZone;
 import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.settings.UserTracker;
+import com.android.systemui.shared.rotation.RotationButtonController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
 import com.android.systemui.statusbar.phone.AutoHideController;
+import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.LightBarController;
+import com.android.systemui.statusbar.phone.LightBarTransitionsController;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
 import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.DeviceConfigProxyFake;
 import com.android.systemui.utils.leaks.LeakCheckedTest;
 import com.android.wm.shell.back.BackAnimation;
 import com.android.wm.shell.pip.Pip;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -122,12 +124,34 @@
 
     private SysuiTestableContext mSysuiTestableContextExternal;
     @Mock
+    NavigationBarFrame mNavigationBarFrame;
+    @Mock
+    NavigationBarView mNavigationBarView;
+    @Mock
+    ButtonDispatcher mHomeButton;
+    @Mock
+    ButtonDispatcher mRecentsButton;
+    @Mock
+    ButtonDispatcher mAccessibilityButton;
+    @Mock
+    ButtonDispatcher mImeSwitchButton;
+    @Mock
+    ButtonDispatcher mBackButton;
+    @Mock
+    NavigationBarTransitions mNavigationBarTransitions;
+    @Mock
+    RotationButtonController mRotationButtonController;
+    @Mock
+    LightBarTransitionsController mLightBarTransitionsController;
+    @Mock
     private SystemActions mSystemActions;
     @Mock
     private OverviewProxyService mOverviewProxyService;
     @Mock
     private StatusBarStateController mStatusBarStateController;
     @Mock
+    private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+    @Mock
     private NavigationModeController mNavigationModeController;
     @Mock
     private CommandQueue mCommandQueue;
@@ -160,7 +184,10 @@
     @Mock
     private AssistManager mAssistManager;
     @Mock
+    private DeadZone mDeadZone;
+    @Mock
     private CentralSurfaces mCentralSurfaces;
+    private DeviceConfigProxyFake mDeviceConfigProxyFake = new DeviceConfigProxyFake();
 
     @Rule
     public final LeakCheckedTest.SysuiLeakCheck mLeakCheck = new LeakCheckedTest.SysuiLeakCheck();
@@ -173,6 +200,17 @@
                 .thenReturn(mEdgeBackGestureHandler);
         when(mLightBarcontrollerFactory.create(any(Context.class))).thenReturn(mLightBarController);
         when(mAutoHideControllerFactory.create(any(Context.class))).thenReturn(mAutoHideController);
+        when(mNavigationBarView.getHomeButton()).thenReturn(mHomeButton);
+        when(mNavigationBarView.getRecentsButton()).thenReturn(mRecentsButton);
+        when(mNavigationBarView.getAccessibilityButton()).thenReturn(mAccessibilityButton);
+        when(mNavigationBarView.getImeSwitchButton()).thenReturn(mImeSwitchButton);
+        when(mNavigationBarView.getBackButton()).thenReturn(mBackButton);
+        when(mNavigationBarView.getBarTransitions()).thenReturn(mNavigationBarTransitions);
+        when(mNavigationBarView.getRotationButtonController())
+                .thenReturn(mRotationButtonController);
+        when(mNavigationBarView.getLightTransitionsController())
+                .thenReturn(mLightBarTransitionsController);
+        when(mStatusBarKeyguardViewManager.isNavBarVisible()).thenReturn(true);
         setupSysuiDependency();
         // This class inflates views that call Dependency.get, thus these injections are still
         // necessary.
@@ -197,12 +235,6 @@
         });
     }
 
-    @After
-    public void tearDown() throws Exception {
-        DeviceConfig.resetToDefaults(
-                Settings.RESET_MODE_PACKAGE_DEFAULTS, DeviceConfig.NAMESPACE_SYSTEMUI);
-    }
-
     private void setupSysuiDependency() {
         Display display = new Display(DisplayManagerGlobal.getInstance(), EXTERNAL_DISPLAY_ID,
                 new DisplayInfo(), DEFAULT_DISPLAY_ADJUSTMENTS);
@@ -228,8 +260,8 @@
 
     @Test
     public void testHomeLongPress() {
-        mNavigationBar.onViewAttachedToWindow(mNavigationBar
-                .createView(null, /* initialVisibility= */ true));
+        mNavigationBar.init();
+        mNavigationBar.onViewAttached();
         mNavigationBar.onHomeLongClick(mNavigationBar.getView());
 
         verify(mUiEventLogger, times(1)).log(NAVBAR_ASSIST_LONGPRESS);
@@ -237,13 +269,14 @@
 
     @Test
     public void testHomeLongPressWithCustomDuration() throws Exception {
-        DeviceConfig.setProperties(
-                new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_SYSTEMUI)
-                    .setLong(HOME_BUTTON_LONG_PRESS_DURATION_MS, 100)
-                    .build());
+        mDeviceConfigProxyFake.setProperty(
+                DeviceConfig.NAMESPACE_SYSTEMUI,
+                HOME_BUTTON_LONG_PRESS_DURATION_MS,
+                "100",
+                false);
         when(mNavBarHelper.getLongPressHomeEnabled()).thenReturn(true);
-        mNavigationBar.onViewAttachedToWindow(mNavigationBar
-                .createView(null, /* initialVisibility= */ true));
+        mNavigationBar.init();
+        mNavigationBar.onViewAttached();
 
         mNavigationBar.onHomeTouch(mNavigationBar.getView(), MotionEvent.obtain(
                 /*downTime=*/SystemClock.uptimeMillis(),
@@ -265,8 +298,8 @@
 
     @Test
     public void testRegisteredWithDispatcher() {
-        mNavigationBar.onViewAttachedToWindow(mNavigationBar
-                .createView(null, /* initialVisibility= */ true));
+        mNavigationBar.init();
+        mNavigationBar.onViewAttached();
         verify(mBroadcastDispatcher).registerReceiverWithHandler(
                 any(BroadcastReceiver.class),
                 any(IntentFilter.class),
@@ -286,8 +319,8 @@
         doReturn(true).when(mockShadeWindowView).isAttachedToWindow();
         doNothing().when(defaultNavBar).checkNavBarModes();
         doNothing().when(externalNavBar).checkNavBarModes();
-        defaultNavBar.createView(null, /* initialVisibility= */ true);
-        externalNavBar.createView(null, /* initialVisibility= */ true);
+        defaultNavBar.init();
+        externalNavBar.init();
 
         defaultNavBar.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE,
                 BACK_DISPOSITION_DEFAULT, true);
@@ -321,7 +354,7 @@
         doReturn(mockShadeWindowView).when(mCentralSurfaces).getNotificationShadeWindowView();
         doReturn(true).when(mockShadeWindowView).isAttachedToWindow();
         doNothing().when(mNavigationBar).checkNavBarModes();
-        mNavigationBar.createView(null, /* initialVisibility= */ true);
+        mNavigationBar.init();
         WindowInsets windowInsets = new WindowInsets.Builder().setVisible(ime(), false).build();
         doReturn(windowInsets).when(mockShadeWindowView).getRootWindowInsets();
 
@@ -357,11 +390,11 @@
 
     @Test
     public void testA11yEventAfterDetach() {
-        View v = mNavigationBar.createView(null, /* initialVisibility= */ true);
-        mNavigationBar.onViewAttachedToWindow(v);
+        mNavigationBar.init();
+        mNavigationBar.onViewAttached();
         verify(mNavBarHelper).registerNavTaskStateUpdater(any(
                 NavBarHelper.NavbarTaskbarStateUpdater.class));
-        mNavigationBar.onViewDetachedFromWindow(v);
+        mNavigationBar.onViewDetached();
         verify(mNavBarHelper).removeNavTaskStateUpdater(any(
                 NavBarHelper.NavbarTaskbarStateUpdater.class));
 
@@ -371,31 +404,40 @@
 
     @Test
     public void testCreateView_initiallyVisible_viewIsVisible() {
-        mNavigationBar.createView(null, /* initialVisibility= */ true);
+        when(mStatusBarKeyguardViewManager.isNavBarVisible()).thenReturn(true);
+        mNavigationBar.init();
+        mNavigationBar.onViewAttached();
 
-        assertThat(mNavigationBar.getView().getVisibility()).isEqualTo(View.VISIBLE);
+        verify(mNavigationBarView).setVisibility(View.VISIBLE);
     }
 
     @Test
     public void testCreateView_initiallyNotVisible_viewIsNotVisible() {
-        mNavigationBar.createView(null, /* initialVisibility= */ false);
+        when(mStatusBarKeyguardViewManager.isNavBarVisible()).thenReturn(false);
+        mNavigationBar.init();
+        mNavigationBar.onViewAttached();
 
-        assertThat(mNavigationBar.getView().getVisibility()).isEqualTo(View.INVISIBLE);
+        verify(mNavigationBarView).setVisibility(View.INVISIBLE);
     }
 
     private NavigationBar createNavBar(Context context) {
         DeviceProvisionedController deviceProvisionedController =
                 mock(DeviceProvisionedController.class);
         when(deviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
-        NavigationBar.Factory factory = new NavigationBar.Factory(
+        return spy(new NavigationBar(
+                mNavigationBarView,
+                mNavigationBarFrame,
+                null,
+                context,
+                mWindowManager,
                 () -> mAssistManager,
                 mock(AccessibilityManager.class),
                 deviceProvisionedController,
                 new MetricsLogger(),
                 mOverviewProxyService,
                 mNavigationModeController,
-                mock(AccessibilityButtonModeObserver.class),
                 mStatusBarStateController,
+                mStatusBarKeyguardViewManager,
                 mMockSysUiState,
                 mBroadcastDispatcher,
                 mCommandQueue,
@@ -415,8 +457,9 @@
                 mAutoHideControllerFactory,
                 Optional.of(mTelecomManager),
                 mInputMethodManager,
-                Optional.of(mock(BackAnimation.class)));
-        return spy(factory.create(context));
+                mDeadZone,
+                mDeviceConfigProxyFake,
+                Optional.of(mock(BackAnimation.class))));
     }
 
     private void processAllMessages() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
index 3508226..38b448f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
@@ -19,8 +19,11 @@
 import android.app.ActivityManager
 import android.content.Context
 import android.content.Intent
+import android.content.pm.ActivityInfo
 import android.content.pm.ApplicationInfo
 import android.content.pm.PackageManager
+import android.content.pm.PackageManager.ResolveInfoFlags
+import android.content.pm.ResolveInfo
 import android.content.pm.UserInfo
 import android.os.Process.SYSTEM_UID
 import android.os.UserHandle
@@ -648,6 +651,77 @@
         }
     }
 
+    @Test
+    fun testCorrectIntentSubAttribution() {
+        val usage = createMockPermGroupUsage(
+                attributionTag = TEST_ATTRIBUTION_TAG,
+                attributionLabel = "TEST_LABEL"
+        )
+
+        val activityInfo = createMockActivityInfo()
+        val resolveInfo = createMockResolveInfo(activityInfo)
+        `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
+        `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>()))
+                .thenAnswer { resolveInfo }
+        controller.showDialog(context)
+        exhaustExecutors()
+
+        dialogProvider.list?.let { list ->
+            val navigationIntent = list.get(0).navigationIntent!!
+            assertThat(navigationIntent.action).isEqualTo(Intent.ACTION_MANAGE_PERMISSION_USAGE)
+            assertThat(navigationIntent.getStringExtra(Intent.EXTRA_PERMISSION_GROUP_NAME))
+                    .isEqualTo(PERM_CAMERA)
+            assertThat(navigationIntent.getStringArrayExtra(Intent.EXTRA_ATTRIBUTION_TAGS))
+                    .isEqualTo(arrayOf(TEST_ATTRIBUTION_TAG.toString()))
+            assertThat(navigationIntent.getBooleanExtra(Intent.EXTRA_SHOWING_ATTRIBUTION, false))
+                    .isTrue()
+        }
+    }
+
+    @Test
+    fun testDefaultIntentOnMissingAttributionLabel() {
+        val usage = createMockPermGroupUsage(
+                attributionTag = TEST_ATTRIBUTION_TAG
+        )
+
+        val activityInfo = createMockActivityInfo()
+        val resolveInfo = createMockResolveInfo(activityInfo)
+        `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
+        `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>()))
+                .thenAnswer { resolveInfo }
+        controller.showDialog(context)
+        exhaustExecutors()
+
+        dialogProvider.list?.let { list ->
+            assertThat(isIntentEqual(list.get(0).navigationIntent!!,
+                    controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)))
+                    .isTrue()
+        }
+    }
+
+    @Test
+    fun testDefaultIntentOnIncorrectPermission() {
+        val usage = createMockPermGroupUsage(
+                attributionTag = TEST_ATTRIBUTION_TAG
+        )
+
+        val activityInfo = createMockActivityInfo(
+                permission = "INCORRECT_PERMISSION"
+        )
+        val resolveInfo = createMockResolveInfo(activityInfo)
+        `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
+        `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>()))
+                .thenAnswer { resolveInfo }
+        controller.showDialog(context)
+        exhaustExecutors()
+
+        dialogProvider.list?.let { list ->
+            assertThat(isIntentEqual(list.get(0).navigationIntent!!,
+                    controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)))
+                    .isTrue()
+        }
+    }
+
     private fun exhaustExecutors() {
         FakeExecutor.exhaustExecutors(backgroundExecutor, uiExecutor)
     }
@@ -680,6 +754,24 @@
         return user * UserHandle.PER_USER_RANGE + nextUid++
     }
 
+    private fun createMockResolveInfo(
+        activityInfo: ActivityInfo? = null
+    ): ResolveInfo {
+        val resolveInfo = mock(ResolveInfo::class.java)
+        resolveInfo.activityInfo = activityInfo
+        return resolveInfo
+    }
+
+    private fun createMockActivityInfo(
+        permission: String = android.Manifest.permission.START_VIEW_PERMISSION_USAGE,
+        className: String = "TEST_CLASS_NAME"
+    ): ActivityInfo {
+        val activityInfo = mock(ActivityInfo::class.java)
+        activityInfo.permission = permission
+        activityInfo.name = className
+        return activityInfo
+    }
+
     private fun createMockPermGroupUsage(
         packageName: String = TEST_PACKAGE_NAME,
         uid: Int = generateUidForUser(USER_ID),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSContainerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSContainerImplTest.kt
new file mode 100644
index 0000000..bf82e90
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSContainerImplTest.kt
@@ -0,0 +1,80 @@
+package com.android.systemui.qs
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.View
+import android.widget.FrameLayout
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.qs.customize.QSCustomizer
+import com.android.systemui.util.mockito.eq
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+@SmallTest
+class QSContainerImplTest : SysuiTestCase() {
+
+    @Mock
+    private lateinit var quickStatusBarHeader: QuickStatusBarHeader
+    @Mock
+    private lateinit var qsCustomizer: QSCustomizer
+    @Mock
+    private lateinit var qsPanelContainer: NonInterceptingScrollView
+    @Mock
+    private lateinit var qsPanelController: QSPanelController
+    @Mock
+    private lateinit var quickStatusBarHeaderController: QuickStatusBarHeaderController
+
+    private lateinit var qsContainer: QSContainerImpl
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        qsContainer = QSContainerImpl(mContext, null)
+
+        setUpMockView(quickStatusBarHeader, R.id.header)
+        setUpMockView(qsCustomizer, R.id.qs_customize)
+        setUpMockView(qsPanelContainer, R.id.expanded_qs_scroll_view)
+
+        qsContainer.onFinishInflate()
+    }
+
+    private fun setUpMockView(view: View, id: Int) {
+        whenever(view.findViewById<View>(id)).thenReturn(view)
+        whenever(view.layoutParams).thenReturn(FrameLayout.LayoutParams(0, 0))
+        qsContainer.addView(view)
+    }
+
+    @Test
+    fun testContainerBottomPadding() {
+        qsContainer.updateResources(
+            qsPanelController,
+            quickStatusBarHeaderController,
+            /* newFooter */ false
+        )
+        verify(qsPanelContainer).setPaddingRelative(anyInt(), anyInt(), anyInt(), eq(0))
+
+        qsContainer.updateResources(
+            qsPanelController,
+            quickStatusBarHeaderController,
+            /* newFooter */ true
+        )
+        verify(qsPanelContainer)
+            .setPaddingRelative(
+                anyInt(),
+                anyInt(),
+                anyInt(),
+                eq(mContext.resources.getDimensionPixelSize(R.dimen.new_footer_height))
+            )
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
index ac1e86f..1b48a16 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
@@ -8,7 +8,6 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.media.MediaFlags
 import com.android.systemui.media.MediaHost
 import com.android.systemui.media.MediaHostState
 import com.android.systemui.plugins.FalsingManager
@@ -49,7 +48,6 @@
     @Mock private lateinit var brightnessSliderFactory: BrightnessSliderController.Factory
     @Mock private lateinit var falsingManager: FalsingManager
     @Mock private lateinit var featureFlags: FeatureFlags
-    @Mock private lateinit var mediaFlags: MediaFlags
     @Mock private lateinit var mediaHost: MediaHost
 
     private lateinit var controller: QSPanelController
@@ -79,8 +77,7 @@
             brightnessControllerFactory,
             brightnessSliderFactory,
             falsingManager,
-            featureFlags,
-            mediaFlags
+            featureFlags
         )
     }
 
@@ -90,45 +87,12 @@
     }
 
     @Test
-    fun onInit_notSplitShade_newMediaLayoutAvailable_setsMediaAsExpanded() {
-        setSplitShadeEnabled(false)
-        whenever(mediaFlags.useMediaSessionLayout()).thenReturn(true)
-
+    fun onInit_setsMediaAsExpanded() {
         controller.onInit()
 
         verify(mediaHost).expansion = MediaHostState.EXPANDED
     }
 
-    @Test
-    fun onInit_notSplitShade_newMediaLayoutNotAvailable_setsMediaAsExpanded() {
-        setSplitShadeEnabled(false)
-        whenever(mediaFlags.useMediaSessionLayout()).thenReturn(false)
-
-        controller.onInit()
-
-        verify(mediaHost).expansion = MediaHostState.EXPANDED
-    }
-
-    @Test
-    fun onInit_inSplitShade_newMediaLayoutAvailable_setsMediaAsExpanded() {
-        setSplitShadeEnabled(true)
-        whenever(mediaFlags.useMediaSessionLayout()).thenReturn(true)
-
-        controller.onInit()
-
-        verify(mediaHost).expansion = MediaHostState.EXPANDED
-    }
-
-    @Test
-    fun onInit_inSplitShade_newMediaLayoutNotAvailable_setsMediaAsCollapsed() {
-        setSplitShadeEnabled(true)
-        whenever(mediaFlags.useMediaSessionLayout()).thenReturn(false)
-
-        controller.onInit()
-
-        verify(mediaHost).expansion = MediaHostState.COLLAPSED
-    }
-
     private fun setSplitShadeEnabled(enabled: Boolean) {
         mContext.orCreateTestableResources
             .addOverride(R.bool.config_use_split_notification_shade, enabled)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
index 5213a30..04bbd60 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
@@ -137,20 +137,6 @@
         assertThat(mQsPanel.indexOfChild(mQsPanel.mSecurityFooter)).isEqualTo(-1)
     }
 
-    @Test
-    fun testBottomPadding() {
-        mQsPanel.setUseNewFooter(false)
-
-        mQsPanel.updatePadding()
-        assertThat(mQsPanel.paddingBottom).isEqualTo(0)
-
-        mQsPanel.setUseNewFooter(true)
-
-        mQsPanel.updatePadding()
-        assertThat(mQsPanel.paddingBottom)
-                .isEqualTo(mContext.resources.getDimensionPixelSize(R.dimen.new_footer_height))
-    }
-
     private fun getNewOrientationConfig(@Configuration.Orientation newOrientation: Int) =
             context.resources.configuration.apply { orientation = newOrientation }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
index 62915b8..1f28210 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
@@ -23,7 +23,6 @@
 import com.android.internal.logging.testing.UiEventLoggerFake
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
-import com.android.systemui.media.MediaFlags
 import com.android.systemui.media.MediaHost
 import com.android.systemui.media.MediaHostState
 import com.android.systemui.plugins.qs.QSTile
@@ -58,8 +57,6 @@
     @Mock
     private lateinit var mediaHost: MediaHost
     @Mock
-    private lateinit var mediaFlags: MediaFlags
-    @Mock
     private lateinit var metricsLogger: MetricsLogger
     private val uiEventLogger = UiEventLoggerFake()
     @Mock
@@ -85,7 +82,6 @@
         `when`(quickQSPanel.dumpableTag).thenReturn("")
         `when`(quickQSPanel.resources).thenReturn(mContext.resources)
         `when`(qsTileHost.createTileView(any(), any(), anyBoolean())).thenReturn(tileView)
-        `when`(mediaFlags.useMediaSessionLayout()).thenReturn(false)
 
         controller = TestQuickQSPanelController(
                 quickQSPanel,
@@ -94,7 +90,6 @@
                 false,
                 mediaHost,
                 true,
-                mediaFlags,
                 metricsLogger,
                 uiEventLogger,
                 qsLogger,
@@ -131,20 +126,17 @@
 
     @Test
     fun testMediaExpansionUpdatedWhenConfigurationChanged() {
-        `when`(mediaFlags.useMediaSessionLayout()).thenReturn(true)
-
         // times(2) because both controller and base controller are registering their listeners
         verify(quickQSPanel, times(2)).addOnConfigurationChangedListener(captor.capture())
 
-        captor.allValues.forEach { it.onConfigurationChange(Configuration.EMPTY) }
+        // verify that media starts in the expanded state by default
         verify(mediaHost).expansion = MediaHostState.EXPANDED
 
         // Rotate device, verify media size updated
         controller.setRotation(RotationUtils.ROTATION_LANDSCAPE)
         captor.allValues.forEach { it.onConfigurationChange(Configuration.EMPTY) }
 
-        // times(2) because init will have set to collapsed because the flag was off
-        verify(mediaHost, times(2)).expansion = MediaHostState.COLLAPSED
+        verify(mediaHost).expansion = MediaHostState.COLLAPSED
     }
 
     class TestQuickQSPanelController(
@@ -154,13 +146,12 @@
         usingMediaPlayer: Boolean,
         mediaHost: MediaHost,
         usingCollapsedLandscapeMedia: Boolean,
-        mediaFlags: MediaFlags,
         metricsLogger: MetricsLogger,
         uiEventLogger: UiEventLoggerFake,
         qsLogger: QSLogger,
         dumpManager: DumpManager
     ) : QuickQSPanelController(view, qsTileHost, qsCustomizerController, usingMediaPlayer,
-        mediaHost, usingCollapsedLandscapeMedia, mediaFlags, metricsLogger, uiEventLogger, qsLogger,
+        mediaHost, usingCollapsedLandscapeMedia, metricsLogger, uiEventLogger, qsLogger,
         dumpManager) {
 
         private var rotation = RotationUtils.ROTATION_NONE
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index 19a9863..6b7e5b93 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -20,21 +20,18 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.os.Handler;
-import android.os.Looper;
+import android.os.RemoteException;
 import android.os.UserHandle;
-import android.service.quicksettings.TileService;
+import android.service.quicksettings.IQSTileService;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -49,6 +46,7 @@
 import com.android.systemui.qs.tileimpl.QSFactoryImpl;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.AutoTileManager;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -68,17 +66,25 @@
 import java.util.ArrayList;
 import java.util.Optional;
 
+import javax.inject.Provider;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
 public class TileServicesTest extends SysuiTestCase {
     private static int NUM_FAKES = TileServices.DEFAULT_MAX_BOUND * 2;
 
+    private static final ComponentName TEST_COMPONENT =
+            ComponentName.unflattenFromString("pkg/.cls");
+
     private TileServices mTileService;
+    private TestableLooper mTestableLooper;
     private ArrayList<TileServiceManager> mManagers;
     @Mock
     private BroadcastDispatcher mBroadcastDispatcher;
     @Mock
+    private CommandQueue mCommandQueue;
+    @Mock
     private StatusBarIconController mStatusBarIconController;
     @Mock
     private QSFactoryImpl mQSFactory;
@@ -116,17 +122,20 @@
         MockitoAnnotations.initMocks(this);
         mDependency.injectMockDependency(BluetoothController.class);
         mManagers = new ArrayList<>();
+        mTestableLooper = TestableLooper.get(this);
 
         when(mTileServiceRequestControllerBuilder.create(any()))
                 .thenReturn(mTileServiceRequestController);
         when(mTileLifecycleManagerFactory.create(any(Intent.class), any(UserHandle.class)))
                 .thenReturn(mTileLifecycleManager);
 
+        Provider<Handler> provider = () -> new Handler(mTestableLooper.getLooper());
+
         QSTileHost host = new QSTileHost(mContext,
                 mStatusBarIconController,
                 mQSFactory,
-                new Handler(),
-                Looper.myLooper(),
+                provider.get(),
+                mTestableLooper.getLooper(),
                 mPluginManager,
                 mTunerService,
                 () -> mAutoTileManager,
@@ -140,8 +149,8 @@
                 mock(CustomTileStatePersister.class),
                 mTileServiceRequestControllerBuilder,
                 mTileLifecycleManagerFactory);
-        mTileService = new TestTileServices(host, Looper.getMainLooper(), mBroadcastDispatcher,
-                mUserTracker, mKeyguardStateController);
+        mTileService = new TestTileServices(host, provider, mBroadcastDispatcher,
+                mUserTracker, mKeyguardStateController, mCommandQueue);
     }
 
     @After
@@ -152,24 +161,6 @@
     }
 
     @Test
-    public void testActiveTileListenerRegisteredOnAllUsers() {
-        ArgumentCaptor<IntentFilter> captor = ArgumentCaptor.forClass(IntentFilter.class);
-        verify(mBroadcastDispatcher).registerReceiver(any(), captor.capture(), any(), eq(
-                UserHandle.ALL));
-        assertTrue(captor.getValue().hasAction(TileService.ACTION_REQUEST_LISTENING));
-    }
-
-    @Test
-    public void testBadComponentName_doesntCrash() {
-        ArgumentCaptor<BroadcastReceiver> captor = ArgumentCaptor.forClass(BroadcastReceiver.class);
-        verify(mBroadcastDispatcher).registerReceiver(captor.capture(), any(), any(), eq(
-                UserHandle.ALL));
-        Intent intent = new Intent(TileService.ACTION_REQUEST_LISTENING)
-                .putExtra(Intent.EXTRA_COMPONENT_NAME, "abc");
-        captor.getValue().onReceive(mContext, intent);
-    }
-
-    @Test
     public void testRecalculateBindAllowance() {
         // Add some fake tiles.
         for (int i = 0; i < NUM_FAKES; i++) {
@@ -225,11 +216,36 @@
         }
     }
 
+    @Test
+    public void testRegisterCommand() {
+        verify(mCommandQueue).addCallback(any());
+    }
+
+    @Test
+    public void testRequestListeningStatusCommand() throws RemoteException {
+        ArgumentCaptor<CommandQueue.Callbacks> captor =
+                ArgumentCaptor.forClass(CommandQueue.Callbacks.class);
+        verify(mCommandQueue).addCallback(captor.capture());
+
+        CustomTile mockTile = mock(CustomTile.class);
+        when(mockTile.getComponent()).thenReturn(TEST_COMPONENT);
+
+        TileServiceManager manager = mTileService.getTileWrapper(mockTile);
+        when(manager.isActiveTile()).thenReturn(true);
+        when(manager.getTileService()).thenReturn(mock(IQSTileService.class));
+
+        captor.getValue().requestTileServiceListeningState(TEST_COMPONENT);
+        mTestableLooper.processAllMessages();
+        verify(manager).setBindRequested(true);
+        verify(manager.getTileService()).onStartListening();
+    }
+
     private class TestTileServices extends TileServices {
-        TestTileServices(QSTileHost host, Looper looper,
+        TestTileServices(QSTileHost host, Provider<Handler> handlerProvider,
                 BroadcastDispatcher broadcastDispatcher, UserTracker userTracker,
-                KeyguardStateController keyguardStateController) {
-            super(host, looper, broadcastDispatcher, userTracker, keyguardStateController);
+                KeyguardStateController keyguardStateController, CommandQueue commandQueue) {
+            super(host, handlerProvider, broadcastDispatcher, userTracker, keyguardStateController,
+                    commandQueue);
         }
 
         @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java
index 8297850..b652aee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java
@@ -104,8 +104,6 @@
         assertEquals(state.label, mContext.getString(R.string.qr_code_scanner_title));
         assertEquals(state.contentDescription, mContext.getString(R.string.qr_code_scanner_title));
         assertEquals(state.icon, QSTileImpl.ResourceIcon.get(R.drawable.ic_qr_code_scanner));
-        assertEquals(state.secondaryLabel,
-                mContext.getString(R.string.qr_code_scanner_description));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
index d3bb241..f306fd6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
@@ -4,14 +4,19 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableResources;
@@ -30,6 +35,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.Spy;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
@@ -40,6 +46,7 @@
 @RunWith(AndroidTestingRunner.class)
 public class InternetAdapterTest extends SysuiTestCase {
 
+    private static final String WIFI_KEY = "Wi-Fi_Key";
     private static final String WIFI_TITLE = "Wi-Fi Title";
     private static final String WIFI_SUMMARY = "Wi-Fi Summary";
     private static final int GEAR_ICON_RES_ID = R.drawable.ic_settings_24dp;
@@ -47,6 +54,8 @@
 
     @Rule
     public MockitoRule mRule = MockitoJUnit.rule();
+    @Spy
+    private Context mSpyContext = mContext;
 
     @Mock
     private WifiEntry mInternetWifiEntry;
@@ -74,6 +83,7 @@
         when(mInternetWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
         when(mInternetWifiEntry.isDefaultNetwork()).thenReturn(true);
         when(mInternetWifiEntry.hasInternetAccess()).thenReturn(true);
+        when(mWifiEntry.getKey()).thenReturn(WIFI_KEY);
         when(mWifiEntry.getTitle()).thenReturn(WIFI_TITLE);
         when(mWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
 
@@ -197,6 +207,66 @@
     }
 
     @Test
+    public void viewHolderShouldEnabled_wifiCanConnect_returnTrue() {
+        when(mWifiEntry.canConnect()).thenReturn(true);
+
+        assertThat(mViewHolder.shouldEnabled(mWifiEntry)).isTrue();
+    }
+
+    @Test
+    public void viewHolderShouldEnabled_wifiCanNotConnect_returnFalse() {
+        when(mWifiEntry.canConnect()).thenReturn(false);
+
+        assertThat(mViewHolder.shouldEnabled(mWifiEntry)).isFalse();
+    }
+
+    @Test
+    public void viewHolderShouldEnabled_wifiCanNotConnectButCanDisconnect_returnTrue() {
+        when(mWifiEntry.canConnect()).thenReturn(false);
+        when(mWifiEntry.canConnect()).thenReturn(true);
+
+        assertThat(mViewHolder.shouldEnabled(mWifiEntry)).isTrue();
+    }
+
+    @Test
+    public void viewHolderShouldEnabled_wifiCanNotConnectButIsSaved_returnTrue() {
+        when(mWifiEntry.canConnect()).thenReturn(false);
+        when(mWifiEntry.isSaved()).thenReturn(true);
+
+        assertThat(mViewHolder.shouldEnabled(mWifiEntry)).isTrue();
+    }
+
+    @Test
+    public void viewHolderOnWifiClick_wifiShouldEditBeforeConnect_startActivity() {
+        when(mWifiEntry.shouldEditBeforeConnect()).thenReturn(true);
+        mViewHolder = mInternetAdapter.onCreateViewHolder(new LinearLayout(mSpyContext), 0);
+        doNothing().when(mSpyContext).startActivity(any());
+
+        mViewHolder.onWifiClick(mWifiEntry, mock(View.class));
+
+        verify(mSpyContext).startActivity(any());
+    }
+
+    @Test
+    public void viewHolderOnWifiClick_wifiCanConnect_connectWifi() {
+        when(mWifiEntry.canConnect()).thenReturn(true);
+
+        mViewHolder.onWifiClick(mWifiEntry, mock(View.class));
+
+        verify(mInternetDialogController).connect(mWifiEntry);
+    }
+
+    @Test
+    public void viewHolderOnWifiClick_wifiCanNotConnectButIsSaved_launchWifiDetailsSetting() {
+        when(mWifiEntry.canConnect()).thenReturn(false);
+        when(mWifiEntry.isSaved()).thenReturn(true);
+
+        mViewHolder.onWifiClick(mWifiEntry, mock(View.class));
+
+        verify(mInternetDialogController).launchWifiDetailsSetting(anyString(), any());
+    }
+
+    @Test
     public void viewHolderUpdateEndIcon_wifiConnected_updateGearIcon() {
         mTestableResources.addOverride(GEAR_ICON_RES_ID, mGearIcon);
 
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 a2959e2..633a9c3 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
@@ -385,18 +385,16 @@
     }
 
     @Test
-    public void launchWifiNetworkDetailsSetting_withNoWifiEntryKey_doNothing() {
-        mInternetDialogController.launchWifiNetworkDetailsSetting(null /* key */,
-                mDialogLaunchView);
+    public void launchWifiDetailsSetting_withNoWifiEntryKey_doNothing() {
+        mInternetDialogController.launchWifiDetailsSetting(null /* key */, mDialogLaunchView);
 
         verify(mActivityStarter, never())
                 .postStartActivityDismissingKeyguard(any(Intent.class), anyInt());
     }
 
     @Test
-    public void launchWifiNetworkDetailsSetting_withWifiEntryKey_startActivity() {
-        mInternetDialogController.launchWifiNetworkDetailsSetting("wifi_entry_key",
-                mDialogLaunchView);
+    public void launchWifiDetailsSetting_withWifiEntryKey_startActivity() {
+        mInternetDialogController.launchWifiDetailsSetting("wifi_entry_key", mDialogLaunchView);
 
         verify(mActivityStarter).postStartActivityDismissingKeyguard(any(Intent.class), anyInt(),
                 any());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 3c1a73e..a2a02cd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -51,6 +51,7 @@
 import android.app.IActivityManager;
 import android.app.Instrumentation;
 import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyResourcesManager;
 import android.app.trust.TrustManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -126,6 +127,8 @@
     @Mock
     private DevicePolicyManager mDevicePolicyManager;
     @Mock
+    private DevicePolicyResourcesManager mDevicePolicyResourcesManager;
+    @Mock
     private ViewGroup mIndicationArea;
     @Mock
     private KeyguardStateController mKeyguardStateController;
@@ -210,12 +213,14 @@
                 .thenReturn(mIndicationAreaBottom);
         when(mIndicationArea.findViewById(R.id.keyguard_indication_text)).thenReturn(mTextView);
 
+        when(mDevicePolicyManager.getResources()).thenReturn(mDevicePolicyResourcesManager);
         when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser())
                 .thenReturn(DEVICE_OWNER_COMPONENT);
         when(mDevicePolicyManager.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
                 .thenReturn(DEVICE_OWNER_TYPE_DEFAULT);
-        when(mDevicePolicyManager.getString(anyString(), any())).thenReturn(mDisclosureGeneric);
-        when(mDevicePolicyManager.getString(anyString(), any(), anyString()))
+        when(mDevicePolicyResourcesManager.getString(anyString(), any()))
+                .thenReturn(mDisclosureGeneric);
+        when(mDevicePolicyResourcesManager.getString(anyString(), any(), anyString()))
                 .thenReturn(mDisclosureWithOrganization);
 
         mWakeLock = new WakeLockFake();
@@ -226,6 +231,10 @@
     @After
     public void tearDown() throws Exception {
         mTextView.setAnimationsEnabled(true);
+        if (mController != null) {
+            mController.destroy();
+            mController = null;
+        }
     }
 
     private void createController() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index 067caa9..fc19d13 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -1,5 +1,6 @@
 package com.android.systemui.statusbar
 
+import org.mockito.Mockito.`when` as whenever
 import android.test.suitebuilder.annotation.SmallTest
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
@@ -18,11 +19,11 @@
 import com.android.systemui.statusbar.notification.stack.AmbientState
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.phone.CentralSurfaces
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.phone.LSShadeTransitionLogger
 import com.android.systemui.statusbar.phone.NotificationPanelViewController
 import com.android.systemui.statusbar.phone.ScrimController
-import com.android.systemui.statusbar.phone.CentralSurfaces
 import com.android.systemui.statusbar.policy.FakeConfigurationController
 import org.junit.After
 import org.junit.Assert.assertFalse
@@ -37,13 +38,14 @@
 import org.mockito.ArgumentMatchers.anyFloat
 import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.ArgumentMatchers.anyLong
+import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mock
 import org.mockito.Mockito
 import org.mockito.Mockito.clearInvocations
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyZeroInteractions
 import org.mockito.junit.MockitoJUnit
-import org.mockito.Mockito.`when` as whenever
 
 private fun <T> anyObject(): T {
     return Mockito.anyObject<T>()
@@ -74,6 +76,8 @@
     @Mock lateinit var expandHelperCallback: ExpandHelper.Callback
     @Mock lateinit var mCentralSurfaces: CentralSurfaces
     @Mock lateinit var qS: QS
+    @Mock lateinit var singleShadeOverScroller: SingleShadeLockScreenOverScroller
+    @Mock lateinit var splitShadeOverScroller: SplitShadeLockScreenOverScroller
     @JvmField @Rule val mockito = MockitoJUnit.rule()
 
     private val configurationController = FakeConfigurationController()
@@ -103,7 +107,9 @@
             context = context,
             configurationController = configurationController,
             falsingManager = falsingManager,
-            dumpManager = dumpManager
+            dumpManager = dumpManager,
+            splitShadeOverScrollerFactory = { _, _ -> splitShadeOverScroller },
+            singleShadeOverScrollerFactory = { singleShadeOverScroller }
         )
         whenever(nsslController.view).thenReturn(stackscroller)
         whenever(nsslController.expandHelperCallback).thenReturn(expandHelperCallback)
@@ -228,9 +234,9 @@
     fun testDragDownAmountDoesntCallOutInLockedDownShade() {
         whenever(nsslController.isInLockedDownShade).thenReturn(true)
         transitionController.dragDownAmount = 10f
-        verify(nsslController, never()).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
+        verify(nsslController, never()).setTransitionToFullShadeAmount(anyFloat())
         verify(mediaHierarchyManager, never()).setTransitionToFullShadeAmount(anyFloat())
-        verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat())
+        verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
         verify(notificationPanelController, never()).setTransitionToFullShadeAmount(anyFloat(),
                 anyBoolean(), anyLong())
         verify(qS, never()).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
@@ -239,9 +245,9 @@
     @Test
     fun testDragDownAmountCallsOut() {
         transitionController.dragDownAmount = 10f
-        verify(nsslController).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
+        verify(nsslController).setTransitionToFullShadeAmount(anyFloat())
         verify(mediaHierarchyManager).setTransitionToFullShadeAmount(anyFloat())
-        verify(scrimController).setTransitionToFullShadeProgress(anyFloat())
+        verify(scrimController).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
         verify(notificationPanelController).setTransitionToFullShadeAmount(anyFloat(),
                 anyBoolean(), anyLong())
         verify(qS).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
@@ -249,14 +255,68 @@
     }
 
     @Test
-    fun testDragDownAmount_depthDistanceIsZero_doesNotSetProgress() {
+    fun testDragDownAmount_depthDistanceIsZero_setsProgressToZero() {
         context.getOrCreateTestableResources()
             .addOverride(R.dimen.lockscreen_shade_depth_controller_transition_distance, 0)
         configurationController.notifyConfigurationChanged()
 
         transitionController.dragDownAmount = 10f
 
-        verify(depthController, never()).transitionToFullShadeProgress
+        verify(depthController).transitionToFullShadeProgress = 0f
+    }
+
+    @Test
+    fun testDragDownAmount_depthDistanceNonZero_setsProgressBasedOnDistance() {
+        context.getOrCreateTestableResources()
+            .addOverride(R.dimen.lockscreen_shade_depth_controller_transition_distance, 100)
+        configurationController.notifyConfigurationChanged()
+
+        transitionController.dragDownAmount = 10f
+
+        verify(depthController).transitionToFullShadeProgress = 0.1f
+    }
+
+    @Test
+    fun setDragAmount_setsKeyguardTransitionProgress() {
+        transitionController.dragDownAmount = 10f
+
+        verify(notificationPanelController).setKeyguardTransitionProgress(anyFloat(), anyInt())
+    }
+
+    @Test
+    fun setDragAmount_setsKeyguardAlphaBasedOnDistance() {
+        val alphaDistance = context.resources.getDimensionPixelSize(
+                R.dimen.lockscreen_shade_npvc_keyguard_content_alpha_transition_distance)
+        transitionController.dragDownAmount = 10f
+
+        val expectedAlpha = 1 - 10f / alphaDistance
+        verify(notificationPanelController)
+                .setKeyguardTransitionProgress(eq(expectedAlpha), anyInt())
+    }
+
+    @Test
+    fun setDragAmount_notInSplitShade_setsKeyguardTranslationToZero() {
+        val mediaTranslationY = 123
+        disableSplitShade()
+        whenever(mediaHierarchyManager.getGuidedTransformationTranslationY())
+                .thenReturn(mediaTranslationY)
+
+        transitionController.dragDownAmount = 10f
+
+        verify(notificationPanelController).setKeyguardTransitionProgress(anyFloat(), eq(0))
+    }
+
+    @Test
+    fun setDragAmount_inSplitShade_setsKeyguardTranslationBasedOnMediaTranslation() {
+        val mediaTranslationY = 123
+        enableSplitShade()
+        whenever(mediaHierarchyManager.getGuidedTransformationTranslationY())
+                .thenReturn(mediaTranslationY)
+
+        transitionController.dragDownAmount = 10f
+
+        verify(notificationPanelController)
+                .setKeyguardTransitionProgress(anyFloat(), eq(mediaTranslationY))
     }
 
     @Test
@@ -267,6 +327,75 @@
     }
 
     @Test
+    fun setDragAmount_setsScrimProgressBasedOnScrimDistance() {
+        val distance = 10
+        context.orCreateTestableResources
+                .addOverride(R.dimen.lockscreen_shade_scrim_transition_distance, distance)
+        configurationController.notifyConfigurationChanged()
+
+        transitionController.dragDownAmount = 5f
+
+        verify(scrimController).transitionToFullShadeProgress(
+                progress = eq(0.5f),
+                lockScreenNotificationsProgress = anyFloat()
+        )
+    }
+
+    @Test
+    fun setDragAmount_setsNotificationsScrimProgressBasedOnNotificationsScrimDistanceAndDelay() {
+        val distance = 100
+        val delay = 10
+        context.orCreateTestableResources.addOverride(
+                R.dimen.lockscreen_shade_notifications_scrim_transition_distance, distance)
+        context.orCreateTestableResources.addOverride(
+                R.dimen.lockscreen_shade_notifications_scrim_transition_delay, delay)
+        configurationController.notifyConfigurationChanged()
+
+        transitionController.dragDownAmount = 20f
+
+        verify(scrimController).transitionToFullShadeProgress(
+                progress = anyFloat(),
+                lockScreenNotificationsProgress = eq(0.1f)
+        )
+    }
+
+    @Test
+    fun setDragAmount_dragAmountLessThanNotifDelayDistance_setsNotificationsScrimProgressToZero() {
+        val distance = 100
+        val delay = 50
+        context.orCreateTestableResources.addOverride(
+                R.dimen.lockscreen_shade_notifications_scrim_transition_distance, distance)
+        context.orCreateTestableResources.addOverride(
+                R.dimen.lockscreen_shade_notifications_scrim_transition_delay, delay)
+        configurationController.notifyConfigurationChanged()
+
+        transitionController.dragDownAmount = 20f
+
+        verify(scrimController).transitionToFullShadeProgress(
+                progress = anyFloat(),
+                lockScreenNotificationsProgress = eq(0f)
+        )
+    }
+
+    @Test
+    fun setDragAmount_dragAmountMoreThanTotalDistance_setsNotificationsScrimProgressToOne() {
+        val distance = 100
+        val delay = 50
+        context.orCreateTestableResources.addOverride(
+                R.dimen.lockscreen_shade_notifications_scrim_transition_distance, distance)
+        context.orCreateTestableResources.addOverride(
+                R.dimen.lockscreen_shade_notifications_scrim_transition_delay, delay)
+        configurationController.notifyConfigurationChanged()
+
+        transitionController.dragDownAmount = 999999f
+
+        verify(scrimController).transitionToFullShadeProgress(
+                progress = anyFloat(),
+                lockScreenNotificationsProgress = eq(1f)
+        )
+    }
+
+    @Test
     fun setDragDownAmount_inSplitShade_setsValueOnMediaHierarchyManager() {
         enableSplitShade()
 
@@ -275,10 +404,72 @@
         verify(mediaHierarchyManager).setTransitionToFullShadeAmount(10f)
     }
 
+    @Test
+    fun setDragAmount_notInSplitShade_forwardsToSingleShadeOverScroller() {
+        disableSplitShade()
+
+        transitionController.dragDownAmount = 10f
+
+        verify(singleShadeOverScroller).expansionDragDownAmount = 10f
+        verifyZeroInteractions(splitShadeOverScroller)
+    }
+
+    @Test
+    fun setDragAmount_inSplitShade_forwardsToSplitShadeOverScroller() {
+        enableSplitShade()
+
+        transitionController.dragDownAmount = 10f
+
+        verify(splitShadeOverScroller).expansionDragDownAmount = 10f
+        verifyZeroInteractions(singleShadeOverScroller)
+    }
+
+    @Test
+    fun setDragDownAmount_inSplitShade_setsKeyguardStatusBarAlphaBasedOnDistance() {
+        val alphaDistance = context.resources.getDimensionPixelSize(
+            R.dimen.lockscreen_shade_npvc_keyguard_content_alpha_transition_distance)
+        val dragDownAmount = 10f
+        enableSplitShade()
+
+        transitionController.dragDownAmount = dragDownAmount
+
+        val expectedAlpha = 1 - dragDownAmount / alphaDistance
+        verify(notificationPanelController).setKeyguardStatusBarAlpha(expectedAlpha)
+    }
+
+    @Test
+    fun setDragDownAmount_notInSplitShade_setsKeyguardStatusBarAlphaToMinusOne() {
+        disableSplitShade()
+
+        transitionController.dragDownAmount = 10f
+
+        verify(notificationPanelController).setKeyguardStatusBarAlpha(-1f)
+    }
+
     private fun enableSplitShade() {
-        context.getOrCreateTestableResources().addOverride(
-            R.bool.config_use_split_notification_shade, true
-        )
+        setSplitShadeEnabled(true)
+    }
+
+    private fun disableSplitShade() {
+        setSplitShadeEnabled(false)
+    }
+
+    private fun setSplitShadeEnabled(enabled: Boolean) {
+        overrideResource(R.bool.config_use_split_notification_shade, enabled)
         configurationController.notifyConfigurationChanged()
     }
+
+    /**
+     * Wrapper around [ScrimController.transitionToFullShadeProgress] that has named parameters for
+     * clarify and easier refactoring of parameter names.
+     */
+    private fun ScrimController.transitionToFullShadeProgress(
+        progress: Float,
+        lockScreenNotificationsProgress: Float
+    ) {
+        scrimController.setTransitionToFullShadeProgress(
+                progress,
+                lockScreenNotificationsProgress
+        )
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt
new file mode 100644
index 0000000..2606be5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt
@@ -0,0 +1,56 @@
+package com.android.systemui.statusbar
+
+import org.mockito.Mockito.`when` as whenever
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.policy.FakeConfigurationController
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.intThat
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class SingleShadeLockScreenOverScrollerTest : SysuiTestCase() {
+
+    @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
+    @Mock private lateinit var nsslController: NotificationStackScrollLayoutController
+
+    private lateinit var overScroller: SingleShadeLockScreenOverScroller
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        whenever(nsslController.height).thenReturn(1800)
+        overScroller =
+            SingleShadeLockScreenOverScroller(
+                FakeConfigurationController(),
+                context,
+                statusBarStateController,
+                nsslController
+            )
+    }
+
+    @Test
+    fun setDragDownAmount_onKeyguard_overScrolls() {
+        whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+
+        overScroller.expansionDragDownAmount = 10f
+
+        verify(nsslController).setOverScrollAmount(intThat { it > 0 })
+    }
+
+    @Test
+    fun setDragDownAmount_notOnKeyguard_doesNotOverScroll() {
+        whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE)
+
+        overScroller.expansionDragDownAmount = 10f
+
+        verify(nsslController).setOverScrollAmount(0)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScrollerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScrollerTest.kt
new file mode 100644
index 0000000..9d5099c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScrollerTest.kt
@@ -0,0 +1,124 @@
+package com.android.systemui.statusbar
+
+import org.mockito.Mockito.`when` as whenever
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.qs.QS
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.phone.ScrimController
+import com.android.systemui.statusbar.policy.FakeConfigurationController
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.atLeast
+import org.mockito.Mockito.intThat
+import org.mockito.Mockito.reset
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.Mockito.verifyZeroInteractions
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+@TestableLooper.RunWithLooper
+class SplitShadeLockScreenOverScrollerTest : SysuiTestCase() {
+
+    private val configurationController = FakeConfigurationController()
+
+    @Mock private lateinit var scrimController: ScrimController
+    @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
+    @Mock private lateinit var qS: QS
+    @Mock private lateinit var nsslController: NotificationStackScrollLayoutController
+
+    private lateinit var overScroller: SplitShadeLockScreenOverScroller
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        whenever(nsslController.height).thenReturn(1800)
+
+        overScroller =
+            SplitShadeLockScreenOverScroller(
+                configurationController,
+                context,
+                scrimController,
+                statusBarStateController,
+                qS,
+                nsslController)
+    }
+
+    @Test
+    fun setDragDownAmount_onKeyguard_appliesOverScroll() {
+        whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+
+        setDragAmount(1000f)
+
+        verifyOverScrollPerformed()
+    }
+
+    @Test
+    fun setDragDownAmount_notOnKeyguard_doesNotApplyOverScroll() {
+        whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE)
+
+        setDragAmount(1000f)
+
+        verifyZeroInteractions(qS)
+        verifyZeroInteractions(scrimController)
+        verifyZeroInteractions(nsslController)
+    }
+
+    @Test
+    fun setDragAmount_onKeyguard_thenNotOnKeyguard_resetsOverScrollToZero() {
+        whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+        setDragAmount(1000f)
+        verifyOverScrollPerformed()
+        reset(qS, scrimController, nsslController)
+
+        whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE)
+        setDragAmount(999f)
+        verifyOverScrollResetToZero()
+    }
+
+    @Test
+    fun setDragAmount_onKeyguard_thenNotOnKeyguard_multipleTimes_resetsOverScrollToZeroOnlyOnce() {
+        whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+        setDragAmount(1000f)
+        whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE)
+        setDragAmount(999f)
+        reset(qS, scrimController, nsslController)
+
+        setDragAmount(998f)
+        setDragAmount(997f)
+        setDragAmount(996f)
+        verifyNoMoreOverScrollChanges()
+    }
+
+    private fun verifyOverScrollPerformed() {
+        verify(qS).setOverScrollAmount(intThat { it > 0 })
+        verify(scrimController).setNotificationsOverScrollAmount(intThat { it > 0 })
+        verify(nsslController).setOverScrollAmount(intThat { it > 0 })
+    }
+
+    private fun verifyOverScrollResetToZero() {
+        // Might be more than once as the animator might have multiple values close to zero that
+        // round down to zero.
+        verify(qS, atLeast(1)).setOverScrollAmount(0)
+        verify(scrimController, atLeast(1)).setNotificationsOverScrollAmount(0)
+        verify(nsslController, atLeast(1)).setOverScrollAmount(0)
+    }
+
+    private fun verifyNoMoreOverScrollChanges() {
+        verifyNoMoreInteractions(qS)
+        verifyNoMoreInteractions(scrimController)
+        verifyNoMoreInteractions(nsslController)
+    }
+
+    private fun setDragAmount(dragDownAmount: Float) {
+        overScroller.expansionDragDownAmount = dragDownAmount
+        overScroller.finishAnimations()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
index 3a60c04..9f82a567 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
@@ -31,6 +31,7 @@
     @Mock lateinit var notificationListContainer: NotificationListContainer
     @Mock lateinit var headsUpManager: HeadsUpManagerPhone
     @Mock lateinit var jankMonitor: InteractionJankMonitor
+    @Mock lateinit var onFinishAnimationCallback: Runnable
 
     private lateinit var notificationTestHelper: NotificationTestHelper
     private lateinit var notification: ExpandableNotificationRow
@@ -52,7 +53,8 @@
                 notificationListContainer,
                 headsUpManager,
                 notification,
-                jankMonitor
+                jankMonitor,
+                onFinishAnimationCallback
         )
     }
 
@@ -61,7 +63,7 @@
     }
 
     @Test
-    fun testHunIsRemovedIfWeDontAnimateLaunch() {
+    fun testHunIsRemovedAndCallbackIsInvokedIfWeDontAnimateLaunch() {
         flagNotificationAsHun()
         controller.onIntentStarted(willAnimate = false)
 
@@ -69,10 +71,11 @@
         assertFalse(notification.entry.isExpandAnimationRunning)
         verify(headsUpManager).removeNotification(
                 notificationKey, true /* releaseImmediately */, true /* animate */)
+        verify(onFinishAnimationCallback).run()
     }
 
     @Test
-    fun testHunIsRemovedWhenAnimationIsCancelled() {
+    fun testHunIsRemovedAndCallbackIsInvokedWhenAnimationIsCancelled() {
         flagNotificationAsHun()
         controller.onLaunchAnimationCancelled()
 
@@ -80,10 +83,11 @@
         assertFalse(notification.entry.isExpandAnimationRunning)
         verify(headsUpManager).removeNotification(
                 notificationKey, true /* releaseImmediately */, true /* animate */)
+        verify(onFinishAnimationCallback).run()
     }
 
     @Test
-    fun testHunIsRemovedWhenAnimationEnds() {
+    fun testHunIsRemovedAndCallbackIsInvokedWhenAnimationEnds() {
         flagNotificationAsHun()
         controller.onLaunchAnimationEnd(isExpandingFullyAbove = true)
 
@@ -91,6 +95,7 @@
         assertFalse(notification.entry.isExpandAnimationRunning)
         verify(headsUpManager).removeNotification(
                 notificationKey, true /* releaseImmediately */, false /* animate */)
+        verify(onFinishAnimationCallback).run()
     }
 
     @Test
@@ -99,4 +104,4 @@
 
         assertTrue(notification.entry.isExpandAnimationRunning)
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index f470715..dd0c758 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -1173,6 +1173,29 @@
     }
 
     @Test
+    public void testStabilizeGroupsAlwaysAllowsGroupChangeFromDeletedGroupToRoot() {
+        // GIVEN a group w/ summary and two children
+        addGroupSummary(0, PACKAGE_1, GROUP_1);
+        addGroupChild(1, PACKAGE_1, GROUP_1);
+        addGroupChild(2, PACKAGE_1, GROUP_1);
+        dispatchBuild();
+
+        // GIVEN visual stability manager doesn't allow any group changes
+        mStabilityManager.setAllowGroupChanges(false);
+
+        // WHEN we run the pipeline with the summary and one child removed
+        mEntrySet.remove(2);
+        mEntrySet.remove(0);
+        dispatchBuild();
+
+        // THEN all that remains is the one child at top-level, despite no group change allowed by
+        // visual stability manager.
+        verifyBuiltList(
+                notif(0)
+        );
+    }
+
+    @Test
     public void testStabilizeGroupsDoesNotAllowGroupingExistingNotifications() {
         // GIVEN one group child without a summary yet
         addGroupChild(0, PACKAGE_1, GROUP_1);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
index 144eefb..699f77f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
@@ -170,11 +170,41 @@
     }
 
     @Test
+    fun testCancelAndReAddStickyNotification() {
+        whenever(mHeadsUpManager.isSticky(anyString())).thenReturn(true)
+        addHUN(mEntry)
+        whenever(mHeadsUpManager.canRemoveImmediately(anyString())).thenReturn(false, true, false)
+        whenever(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L)
+        assertTrue(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0))
+        addHUN(mEntry)
+        assertFalse(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0))
+        mExecutor.advanceClockToLast()
+        mExecutor.runAllReady()
+        assertTrue(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0))
+        verify(mHeadsUpManager, times(0)).removeNotification(anyString(), eq(false))
+        verify(mHeadsUpManager, times(0)).removeNotification(anyString(), eq(true))
+    }
+
+    @Test
+    fun hunNotRemovedWhenExtensionCancelled() {
+        whenever(mHeadsUpManager.isSticky(anyString())).thenReturn(true)
+        addHUN(mEntry)
+        whenever(mHeadsUpManager.canRemoveImmediately(anyString())).thenReturn(false)
+        whenever(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L)
+        assertTrue(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0))
+        mNotifLifetimeExtender.cancelLifetimeExtension(mEntry)
+        mExecutor.advanceClockToLast()
+        mExecutor.runAllReady()
+        verify(mHeadsUpManager, times(0)).removeNotification(anyString(), any())
+    }
+
+    @Test
     fun testCancelUpdatedStickyNotification() {
         whenever(mHeadsUpManager.isSticky(anyString())).thenReturn(true)
         addHUN(mEntry)
         whenever(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L, 500L)
         assertTrue(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0))
+        addHUN(mEntry)
         mExecutor.advanceClockToLast()
         mExecutor.runAllReady()
         verify(mHeadsUpManager, times(0)).removeNotification(anyString(), eq(false))
@@ -305,6 +335,7 @@
         mHuns.add(entry)
         whenever(mHeadsUpManager.topEntry).thenReturn(entry)
         mOnHeadsUpChangedListener.onHeadsUpStateChanged(entry, true)
+        mNotifLifetimeExtender.cancelLifetimeExtension(entry)
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
index d094749..52bacd2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
@@ -16,18 +16,8 @@
 
 package com.android.systemui.statusbar.notification.collection.coordinator;
 
-import static android.app.Notification.VISIBILITY_PUBLIC;
-import static android.app.Notification.VISIBILITY_SECRET;
-import static android.app.NotificationManager.IMPORTANCE_HIGH;
-import static android.app.NotificationManager.IMPORTANCE_MIN;
-
-import static com.android.systemui.statusbar.notification.collection.EntryUtilKt.modifyEntry;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
 import android.os.Handler;
 import android.os.UserHandle;
@@ -39,40 +29,41 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.RankingBuilder;
 import com.android.systemui.statusbar.notification.SectionHeaderVisibilityProvider;
-import com.android.systemui.statusbar.notification.collection.GroupEntry;
-import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
+import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import org.junit.Before;
-import org.junit.Test;
+import org.junit.Ignore;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+/**
+ * TODO(b/224771204) Create test cases
+ */
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
+@Ignore
 public class KeyguardCoordinatorTest extends SysuiTestCase {
     private static final int NOTIF_USER_ID = 0;
     private static final int CURR_USER_ID = 1;
 
     @Mock private Handler mMainHandler;
     @Mock private KeyguardStateController mKeyguardStateController;
-    @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
     @Mock private BroadcastDispatcher mBroadcastDispatcher;
     @Mock private StatusBarStateController mStatusBarStateController;
     @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @Mock private HighPriorityProvider mHighPriorityProvider;
     @Mock private SectionHeaderVisibilityProvider mSectionHeaderVisibilityProvider;
     @Mock private NotifPipeline mNotifPipeline;
+    @Mock private KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
 
     private NotificationEntry mEntry;
     private NotifFilter mKeyguardFilter;
@@ -81,9 +72,9 @@
     public void setup() {
         MockitoAnnotations.initMocks(this);
         KeyguardCoordinator keyguardCoordinator = new KeyguardCoordinator(
-                mContext, mMainHandler, mKeyguardStateController, mLockscreenUserManager,
-                mBroadcastDispatcher, mStatusBarStateController,
-                mKeyguardUpdateMonitor, mHighPriorityProvider, mSectionHeaderVisibilityProvider);
+                mStatusBarStateController,
+                mKeyguardUpdateMonitor, mHighPriorityProvider, mSectionHeaderVisibilityProvider,
+                mKeyguardNotificationVisibilityProvider);
 
         mEntry = new NotificationEntryBuilder()
                 .setUser(new UserHandle(NOTIF_USER_ID))
@@ -94,171 +85,4 @@
         verify(mNotifPipeline, times(1)).addFinalizeFilter(filterCaptor.capture());
         mKeyguardFilter = filterCaptor.getValue();
     }
-
-    @Test
-    public void unfilteredState() {
-        // GIVEN an 'unfiltered-keyguard-showing' state
-        setupUnfilteredState(mEntry);
-
-        // THEN don't filter out the entry
-        assertFalse(mKeyguardFilter.shouldFilterOut(mEntry, 0));
-    }
-
-    @Test
-    public void keyguardNotShowing() {
-        // GIVEN the lockscreen isn't showing
-        setupUnfilteredState(mEntry);
-        when(mKeyguardStateController.isShowing()).thenReturn(false);
-
-        // THEN don't filter out the entry
-        assertFalse(mKeyguardFilter.shouldFilterOut(mEntry, 0));
-    }
-
-    @Test
-    public void doNotShowLockscreenNotifications() {
-        // GIVEN an 'unfiltered-keyguard-showing' state
-        setupUnfilteredState(mEntry);
-
-        // WHEN we shouldn't show any lockscreen notifications
-        when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false);
-
-        // THEN filter out the entry
-        assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
-    }
-
-    @Test
-    public void lockdown() {
-        // GIVEN an 'unfiltered-keyguard-showing' state
-        setupUnfilteredState(mEntry);
-
-        // WHEN the notification's user is in lockdown:
-        when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(true);
-
-        // THEN filter out the entry
-        assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
-    }
-
-    @Test
-    public void publicMode_settingsDisallow() {
-        // GIVEN an 'unfiltered-keyguard-showing' state
-        setupUnfilteredState(mEntry);
-
-        // WHEN the notification's user is in public mode and settings are configured to disallow
-        // notifications in public mode
-        when(mLockscreenUserManager.isLockscreenPublicMode(NOTIF_USER_ID)).thenReturn(true);
-        when(mLockscreenUserManager.userAllowsNotificationsInPublic(NOTIF_USER_ID))
-                .thenReturn(false);
-
-        // THEN filter out the entry
-        assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
-    }
-
-    @Test
-    public void publicMode_notifDisallowed() {
-        // GIVEN an 'unfiltered-keyguard-showing' state
-        setupUnfilteredState(mEntry);
-
-        // WHEN the notification's user is in public mode and settings are configured to disallow
-        // notifications in public mode
-        when(mLockscreenUserManager.isLockscreenPublicMode(CURR_USER_ID)).thenReturn(true);
-        mEntry.setRanking(new RankingBuilder()
-                .setKey(mEntry.getKey())
-                .setVisibilityOverride(VISIBILITY_SECRET).build());
-
-        // THEN filter out the entry
-        assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
-    }
-
-    @Test
-    public void doesNotExceedThresholdToShow() {
-        // GIVEN an 'unfiltered-keyguard-showing' state
-        setupUnfilteredState(mEntry);
-
-        // WHEN the notification doesn't exceed the threshold to show on the lockscreen
-        mEntry.setRanking(new RankingBuilder()
-                .setKey(mEntry.getKey())
-                .setImportance(IMPORTANCE_MIN)
-                .build());
-        when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
-
-        // THEN filter out the entry
-        assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
-    }
-
-    @Test
-    public void summaryExceedsThresholdToShow() {
-        // GIVEN the notification doesn't exceed the threshold to show on the lockscreen
-        // but it's part of a group (has a parent)
-        final NotificationEntry entryWithParent = new NotificationEntryBuilder()
-                .setUser(new UserHandle(NOTIF_USER_ID))
-                .build();
-
-        final GroupEntry parent = new GroupEntryBuilder()
-                .setKey("test_group_key")
-                .setSummary(new NotificationEntryBuilder()
-                        .setImportance(IMPORTANCE_HIGH)
-                        .build())
-                .addChild(entryWithParent)
-                .build();
-
-        setupUnfilteredState(entryWithParent);
-        entryWithParent.setRanking(new RankingBuilder()
-                .setKey(entryWithParent.getKey())
-                .setImportance(IMPORTANCE_MIN)
-                .build());
-
-        // WHEN its parent does exceed threshold tot show on the lockscreen
-        when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(true);
-
-        // THEN don't filter out the entry
-        assertFalse(mKeyguardFilter.shouldFilterOut(entryWithParent, 0));
-
-        // WHEN its parent doesn't exceed threshold to show on lockscreen
-        when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(false);
-        modifyEntry(parent.getSummary(), builder -> builder
-                .setImportance(IMPORTANCE_MIN)
-                .done());
-
-        // THEN filter out the entry
-        assertTrue(mKeyguardFilter.shouldFilterOut(entryWithParent, 0));
-    }
-
-    /**
-     * setup a state where the notification will not be filtered by the
-     * KeyguardNotificationCoordinator when the keyguard is showing.
-     */
-    private void setupUnfilteredState(NotificationEntry entry) {
-        // keyguard is showing
-        when(mKeyguardStateController.isShowing()).thenReturn(true);
-
-        // show notifications on the lockscreen
-        when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(true);
-
-        // neither the current user nor the notification's user is in lockdown
-        when(mLockscreenUserManager.getCurrentUserId()).thenReturn(CURR_USER_ID);
-        when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(false);
-        when(mKeyguardUpdateMonitor.isUserInLockdown(CURR_USER_ID)).thenReturn(false);
-
-        // not in public mode
-        when(mLockscreenUserManager.isLockscreenPublicMode(CURR_USER_ID)).thenReturn(false);
-        when(mLockscreenUserManager.isLockscreenPublicMode(NOTIF_USER_ID)).thenReturn(false);
-
-        // entry's ranking - should show on all lockscreens
-        // + priority of the notification exceeds the threshold to be shown on the lockscreen
-        entry.setRanking(new RankingBuilder()
-                .setKey(mEntry.getKey())
-                .setVisibilityOverride(VISIBILITY_PUBLIC)
-                .setImportance(IMPORTANCE_HIGH)
-                .build());
-
-        // settings allows notifications in public mode
-        when(mLockscreenUserManager.userAllowsNotificationsInPublic(CURR_USER_ID)).thenReturn(true);
-        when(mLockscreenUserManager.userAllowsNotificationsInPublic(NOTIF_USER_ID))
-                .thenReturn(true);
-
-        // notification doesn't have a summary
-
-        // notification is high priority, so it shouldn't be filtered
-        when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(true);
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
new file mode 100644
index 0000000..4e07d59
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
@@ -0,0 +1,461 @@
+/*
+ * 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.systemui.statusbar.notification.interruption;
+
+import static android.app.Notification.VISIBILITY_PUBLIC;
+import static android.app.Notification.VISIBILITY_SECRET;
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.app.NotificationManager.IMPORTANCE_MIN;
+
+import static com.android.systemui.statusbar.notification.collection.EntryUtilKt.modifyEntry;
+import static com.android.systemui.util.mockito.KotlinMockitoHelpersKt.argThat;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.CoreStartable;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.RankingBuilder;
+import com.android.systemui.statusbar.notification.collection.GroupEntry;
+import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.settings.FakeSettings;
+import com.android.systemui.util.settings.GlobalSettings;
+import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.utils.os.FakeHandler;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Map;
+import java.util.function.Consumer;
+
+import dagger.BindsInstance;
+import dagger.Component;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class KeyguardNotificationVisibilityProviderTest  extends SysuiTestCase {
+    private static final int NOTIF_USER_ID = 0;
+    private static final int CURR_USER_ID = 1;
+
+    @Mock private KeyguardStateController mKeyguardStateController;
+    @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
+    @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    @Mock private HighPriorityProvider mHighPriorityProvider;
+    @Mock private StatusBarStateController mStatusBarStateController;
+    @Mock private BroadcastDispatcher mBroadcastDispatcher;
+    private final FakeSettings mFakeSettings = new FakeSettings();
+
+    private KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
+    private NotificationEntry mEntry;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        TestComponent component =
+                DaggerKeyguardNotificationVisibilityProviderTest_TestComponent
+                        .factory()
+                        .create(
+                                mContext,
+                                new FakeHandler(TestableLooper.get(this).getLooper()),
+                                mKeyguardStateController,
+                                mLockscreenUserManager,
+                                mKeyguardUpdateMonitor,
+                                mHighPriorityProvider,
+                                mStatusBarStateController,
+                                mBroadcastDispatcher,
+                                mFakeSettings,
+                                mFakeSettings);
+        mKeyguardNotificationVisibilityProvider = component.getProvider();
+        for (CoreStartable startable : component.getCoreStartables().values()) {
+            startable.start();
+        }
+        mEntry = new NotificationEntryBuilder()
+                .setUser(new UserHandle(NOTIF_USER_ID))
+                .build();
+    }
+
+    @Test
+    public void notifyListeners_onUnlockedChanged() {
+        ArgumentCaptor<KeyguardStateController.Callback> callbackCaptor =
+                ArgumentCaptor.forClass(KeyguardStateController.Callback.class);
+        verify(mKeyguardStateController).addCallback(callbackCaptor.capture());
+        KeyguardStateController.Callback callback = callbackCaptor.getValue();
+
+        Consumer<String> listener = mock(Consumer.class);
+        mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
+
+        callback.onUnlockedChanged();
+
+        verify(listener).accept(anyString());
+    }
+
+    @Test
+    public void notifyListeners_onKeyguardShowingChanged() {
+        ArgumentCaptor<KeyguardStateController.Callback> callbackCaptor =
+                ArgumentCaptor.forClass(KeyguardStateController.Callback.class);
+        verify(mKeyguardStateController).addCallback(callbackCaptor.capture());
+        KeyguardStateController.Callback callback = callbackCaptor.getValue();
+
+        Consumer<String> listener = mock(Consumer.class);
+        mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
+
+        callback.onKeyguardShowingChanged();
+
+        verify(listener).accept(anyString());
+    }
+
+    @Test
+    public void notifyListeners_onStrongAuthStateChanged() {
+        ArgumentCaptor<KeyguardUpdateMonitorCallback> callbackCaptor =
+                ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
+        verify(mKeyguardUpdateMonitor).registerCallback(callbackCaptor.capture());
+        KeyguardUpdateMonitorCallback callback = callbackCaptor.getValue();
+
+        Consumer<String> listener = mock(Consumer.class);
+        mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
+
+        callback.onStrongAuthStateChanged(0);
+
+        verify(listener).accept(anyString());
+    }
+
+    @Test
+    public void notifyListeners_onStatusBarStateChanged() {
+        ArgumentCaptor<StatusBarStateController.StateListener> callbackCaptor =
+                ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
+        verify(mStatusBarStateController).addCallback(callbackCaptor.capture());
+        StatusBarStateController.StateListener callback = callbackCaptor.getValue();
+
+        Consumer<String> listener = mock(Consumer.class);
+        mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
+
+        callback.onStateChanged(0);
+
+        verify(listener).accept(anyString());
+    }
+
+    @Test
+    public void notifyListeners_onReceiveUserSwitchBroadcast() {
+        ArgumentCaptor<BroadcastReceiver> callbackCaptor =
+                ArgumentCaptor.forClass(BroadcastReceiver.class);
+        verify(mBroadcastDispatcher).registerReceiver(
+                callbackCaptor.capture(),
+                argThat(intentFilter -> intentFilter.hasAction(Intent.ACTION_USER_SWITCHED)),
+                isNull(),
+                isNull(),
+                eq(Context.RECEIVER_EXPORTED));
+        BroadcastReceiver callback = callbackCaptor.getValue();
+
+        Consumer<String> listener = mock(Consumer.class);
+        mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
+
+        when(mKeyguardStateController.isShowing()).thenReturn(true);
+        callback.onReceive(mContext, new Intent(Intent.ACTION_USER_SWITCHED));
+
+        verify(listener).accept(anyString());
+    }
+
+    @Test
+    public void notifyListeners_onSettingChange_lockScreenShowNotifs() {
+        when(mKeyguardStateController.isShowing()).thenReturn(true);
+        Consumer<String> listener = mock(Consumer.class);
+        mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
+
+        mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, true);
+
+        verify(listener).accept(anyString());
+    }
+
+    @Test
+    public void notifyListeners_onSettingChange_lockScreenAllowPrivateNotifs() {
+        when(mKeyguardStateController.isShowing()).thenReturn(true);
+        Consumer<String> listener = mock(Consumer.class);
+        mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
+
+        mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, true);
+
+        verify(listener).accept(anyString());
+    }
+
+    @Test
+    public void notifyListeners_onSettingChange_zenMode() {
+        when(mKeyguardStateController.isShowing()).thenReturn(true);
+        Consumer<String> listener = mock(Consumer.class);
+        mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
+
+        mFakeSettings.putBool(Settings.Global.ZEN_MODE, true);
+
+        verify(listener).accept(anyString());
+    }
+
+    @Test
+    public void notifyListeners_onSettingChange_lockScreenShowSilentNotifs() {
+        when(mKeyguardStateController.isShowing()).thenReturn(true);
+        Consumer<String> listener = mock(Consumer.class);
+        mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
+
+        mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, true);
+
+        verify(listener).accept(anyString());
+    }
+
+    @Test
+    public void unfilteredState() {
+        // GIVEN an 'unfiltered-keyguard-showing' state
+        setupUnfilteredState(mEntry);
+
+        // THEN don't filter out the entry
+        assertFalse(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
+    }
+
+    @Test
+    public void keyguardNotShowing() {
+        // GIVEN the lockscreen isn't showing
+        setupUnfilteredState(mEntry);
+        when(mKeyguardStateController.isShowing()).thenReturn(false);
+
+        // THEN don't filter out the entry
+        assertFalse(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
+    }
+
+    @Test
+    public void doNotShowLockscreenNotifications() {
+        // GIVEN an 'unfiltered-keyguard-showing' state
+        setupUnfilteredState(mEntry);
+
+        // WHEN we shouldn't show any lockscreen notifications
+        when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false);
+
+        // THEN filter out the entry
+        assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
+    }
+
+    @Test
+    public void lockdown() {
+        // GIVEN an 'unfiltered-keyguard-showing' state
+        setupUnfilteredState(mEntry);
+
+        // WHEN the notification's user is in lockdown:
+        when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(true);
+
+        // THEN filter out the entry
+        assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
+    }
+
+    @Test
+    public void publicMode_settingsDisallow() {
+        // GIVEN an 'unfiltered-keyguard-showing' state
+        setupUnfilteredState(mEntry);
+
+        // WHEN the notification's user is in public mode and settings are configured to disallow
+        // notifications in public mode
+        when(mLockscreenUserManager.isLockscreenPublicMode(NOTIF_USER_ID)).thenReturn(true);
+        when(mLockscreenUserManager.userAllowsNotificationsInPublic(NOTIF_USER_ID))
+                .thenReturn(false);
+
+        // THEN filter out the entry
+        assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
+    }
+
+    @Test
+    public void publicMode_notifDisallowed() {
+        // GIVEN an 'unfiltered-keyguard-showing' state
+        setupUnfilteredState(mEntry);
+
+        // WHEN the notification's user is in public mode and settings are configured to disallow
+        // notifications in public mode
+        when(mLockscreenUserManager.isLockscreenPublicMode(CURR_USER_ID)).thenReturn(true);
+        mEntry.setRanking(new RankingBuilder()
+                .setKey(mEntry.getKey())
+                .setVisibilityOverride(VISIBILITY_SECRET).build());
+
+        // THEN filter out the entry
+        assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
+    }
+
+    @Test
+    public void doesNotExceedThresholdToShow() {
+        // GIVEN an 'unfiltered-keyguard-showing' state
+        setupUnfilteredState(mEntry);
+
+        // WHEN the notification doesn't exceed the threshold to show on the lockscreen
+        mEntry.setRanking(new RankingBuilder()
+                .setKey(mEntry.getKey())
+                .setImportance(IMPORTANCE_MIN)
+                .build());
+        when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
+
+        // THEN filter out the entry
+        assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
+    }
+
+    @Test
+    public void showSilentOnLockscreenSetting() {
+        // GIVEN an 'unfiltered-keyguard-showing' state
+        setupUnfilteredState(mEntry);
+
+        // WHEN the notification is not high priority and not ambient
+        mEntry.setRanking(new RankingBuilder()
+                .setKey(mEntry.getKey())
+                .setImportance(IMPORTANCE_LOW)
+                .build());
+        when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
+
+        // WHEN the show silent notifs on lockscreen setting is true
+        mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, true);
+
+        // THEN do not filter out the entry
+        assertFalse(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
+    }
+
+    @Test
+    public void summaryExceedsThresholdToShow() {
+        // GIVEN the notification doesn't exceed the threshold to show on the lockscreen
+        // but it's part of a group (has a parent)
+        final NotificationEntry entryWithParent = new NotificationEntryBuilder()
+                .setUser(new UserHandle(NOTIF_USER_ID))
+                .build();
+
+        final GroupEntry parent = new GroupEntryBuilder()
+                .setKey("test_group_key")
+                .setSummary(new NotificationEntryBuilder()
+                        .setImportance(IMPORTANCE_HIGH)
+                        .build())
+                .addChild(entryWithParent)
+                .build();
+
+        setupUnfilteredState(entryWithParent);
+        entryWithParent.setRanking(new RankingBuilder()
+                .setKey(entryWithParent.getKey())
+                .setImportance(IMPORTANCE_MIN)
+                .build());
+
+        // WHEN its parent does exceed threshold tot show on the lockscreen
+        mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, false);
+        when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(true);
+
+        // THEN don't filter out the entry
+        assertFalse(
+                mKeyguardNotificationVisibilityProvider.shouldHideNotification(entryWithParent));
+
+        // WHEN its parent doesn't exceed threshold to show on lockscreen
+        when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(false);
+        modifyEntry(parent.getSummary(), builder -> builder
+                .setImportance(IMPORTANCE_MIN)
+                .done());
+
+        // THEN filter out the entry
+        assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(entryWithParent));
+    }
+
+    /**
+     * setup a state where the notification will not be filtered by the
+     * KeyguardNotificationCoordinator when the keyguard is showing.
+     */
+    private void setupUnfilteredState(NotificationEntry entry) {
+        // keyguard is showing
+        when(mKeyguardStateController.isShowing()).thenReturn(true);
+
+        // show notifications on the lockscreen
+        when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(true);
+
+        // neither the current user nor the notification's user is in lockdown
+        when(mLockscreenUserManager.getCurrentUserId()).thenReturn(CURR_USER_ID);
+        when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(false);
+        when(mKeyguardUpdateMonitor.isUserInLockdown(CURR_USER_ID)).thenReturn(false);
+
+        // not in public mode
+        when(mLockscreenUserManager.isLockscreenPublicMode(CURR_USER_ID)).thenReturn(false);
+        when(mLockscreenUserManager.isLockscreenPublicMode(NOTIF_USER_ID)).thenReturn(false);
+
+        // entry's ranking - should show on all lockscreens
+        // + priority of the notification exceeds the threshold to be shown on the lockscreen
+        entry.setRanking(new RankingBuilder()
+                .setKey(mEntry.getKey())
+                .setVisibilityOverride(VISIBILITY_PUBLIC)
+                .setImportance(IMPORTANCE_HIGH)
+                .build());
+
+        // settings allows notifications in public mode
+        when(mLockscreenUserManager.userAllowsNotificationsInPublic(CURR_USER_ID)).thenReturn(true);
+        when(mLockscreenUserManager.userAllowsNotificationsInPublic(NOTIF_USER_ID))
+                .thenReturn(true);
+
+        // notification doesn't have a summary
+
+        // notification is high priority, so it shouldn't be filtered
+        when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(true);
+    }
+
+    @SysUISingleton
+    @Component(modules = { KeyguardNotificationVisibilityProviderModule.class })
+    interface TestComponent {
+        KeyguardNotificationVisibilityProvider getProvider();
+        Map<Class<?>, CoreStartable> getCoreStartables();
+
+        @Component.Factory
+        interface Factory {
+            TestComponent create(
+                    @BindsInstance Context context,
+                    @BindsInstance @Main Handler handler,
+                    @BindsInstance KeyguardStateController keyguardStateController,
+                    @BindsInstance NotificationLockscreenUserManager lockscreenUserManager,
+                    @BindsInstance KeyguardUpdateMonitor keyguardUpdateMonitor,
+                    @BindsInstance HighPriorityProvider highPriorityProvider,
+                    @BindsInstance StatusBarStateController statusBarStateController,
+                    @BindsInstance BroadcastDispatcher broadcastDispatcher,
+                    @BindsInstance SecureSettings secureSettings,
+                    @BindsInstance GlobalSettings globalSettings
+            );
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index 2e1297b..8a2dc26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
@@ -30,6 +30,9 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.Notification;
@@ -48,6 +51,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationFilter;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -86,6 +90,10 @@
     BatteryController mBatteryController;
     @Mock
     Handler mMockHandler;
+    @Mock
+    NotifPipelineFlags mFlags;
+    @Mock
+    KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
 
     private NotificationInterruptStateProviderImpl mNotifInterruptionStateProvider;
 
@@ -104,8 +112,9 @@
                         mStatusBarStateController,
                         mHeadsUpManager,
                         mLogger,
-                        mMockHandler);
-
+                        mMockHandler,
+                        mFlags,
+                        mKeyguardNotificationVisibilityProvider);
         mNotifInterruptionStateProvider.mUseHeadsUp = true;
     }
 
@@ -194,6 +203,16 @@
     }
 
     @Test
+    public void testDoNotRunFilterOnNewPipeline() {
+        when(mFlags.isNewPipelineEnabled()).thenReturn(true);
+        // WHEN this entry should be filtered out
+        NotificationEntry entry  = createNotification(IMPORTANCE_DEFAULT);
+        mNotifInterruptionStateProvider.shouldHeadsUp(entry);
+        verify(mFlags, times(1)).isNewPipelineEnabled();
+        verify(mNotificationFilter, times(0)).shouldFilterOut(eq(entry));
+    }
+
+    @Test
     public void testShouldNotHeadsUp_suppressedForGroups() throws RemoteException {
         // GIVEN state for "heads up when awake" is true
         ensureStateForHeadsUpWhenAwake();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index 7fc5ece..251ac7d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -41,6 +41,7 @@
 import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.NotificationMessagingUtil;
 import com.android.systemui.R;
@@ -87,6 +88,7 @@
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
 import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder;
+import com.android.systemui.statusbar.policy.SmartReplyConstants;
 import com.android.systemui.statusbar.policy.SmartReplyStateInflater;
 import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
 import com.android.systemui.util.concurrency.FakeExecutor;
@@ -252,13 +254,17 @@
                 .thenAnswer((Answer<ExpandableNotificationRowController>) invocation ->
                         new ExpandableNotificationRowController(
                                 viewCaptor.getValue(),
-                                mListContainer,
-                                mock(RemoteInputViewSubcomponent.Factory.class),
                                 mock(ActivatableNotificationViewController.class),
+                                mock(RemoteInputViewSubcomponent.Factory.class),
+                                mock(MetricsLogger.class),
+                                mListContainer,
                                 mNotificationMediaManager,
+                                mock(SmartReplyConstants.class),
+                                mock(SmartReplyController.class),
                                 mock(PluginManager.class),
                                 new FakeSystemClock(),
-                                "FOOBAR", "FOOBAR",
+                                "FOOBAR",
+                                "FOOBAR",
                                 mKeyguardBypassController,
                                 mGroupMembershipManager,
                                 mGroupExpansionManager,
@@ -275,8 +281,7 @@
                                 mock(FeatureFlags.class),
                                 mPeopleNotificationIdentifier,
                                 Optional.of(mock(BubblesManager.class)),
-                                mock(ExpandableNotificationRowDragController.class)
-                        ));
+                                mock(ExpandableNotificationRowDragController.class)));
 
         when(mNotificationRowComponentBuilder.activatableNotificationView(any()))
                 .thenReturn(mNotificationRowComponentBuilder);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 72f8f70..1ecb09b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -44,6 +44,7 @@
 import android.view.LayoutInflater;
 import android.widget.RemoteViews;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.TestableDependency;
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.classifier.FalsingManagerFake;
@@ -54,6 +55,7 @@
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.SmartReplyController;
 import com.android.systemui.statusbar.notification.ConversationNotificationProcessor;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -73,6 +75,7 @@
 import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
 import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
 import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder;
+import com.android.systemui.statusbar.policy.SmartReplyConstants;
 import com.android.systemui.statusbar.policy.SmartReplyStateInflater;
 import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
 import com.android.systemui.tests.R;
@@ -505,7 +508,10 @@
                 mPeopleNotificationIdentifier,
                 mOnUserInteractionCallback,
                 Optional.of(mock(BubblesManager.class)),
-                mock(NotificationGutsManager.class));
+                mock(NotificationGutsManager.class),
+                mock(MetricsLogger.class),
+                mock(SmartReplyConstants.class),
+                mock(SmartReplyController.class));
 
         row.setAboveShelfChangedListener(aboveShelf -> { });
         mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index bf16e0a..c9de608 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -134,6 +134,7 @@
     @Mock private InteractionJankMonitor mJankMonitor;
     @Mock private StackStateLogger mStackLogger;
     @Mock private NotificationStackScrollLogger mLogger;
+    @Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
 
     @Captor
     private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor;
@@ -186,7 +187,8 @@
                 mShadeController,
                 mJankMonitor,
                 mStackLogger,
-                mLogger
+                mLogger,
+                mNotificationStackSizeCalculator
         );
 
         when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index eafcc35..7a92b96 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -103,6 +103,7 @@
     @Mock private NotificationStackScrollLayoutController mStackScrollLayoutController;
     @Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
     @Mock private NotificationShelf mNotificationShelf;
+    @Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
 
     @Before
     @UiThreadTest
@@ -138,7 +139,8 @@
         // holds a copy of the CUT's instances of these KeyguardBypassController, so they still
         // refer to the CUT's member variables, not the spy's member variables.
         mStackScrollerInternal = new NotificationStackScrollLayout(getContext(), null);
-        mStackScrollerInternal.initView(getContext(), mNotificationSwipeHelper);
+        mStackScrollerInternal.initView(getContext(), mNotificationSwipeHelper,
+                mNotificationStackSizeCalculator);
         mStackScroller = spy(mStackScrollerInternal);
         mStackScroller.setShelfController(notificationShelfController);
         mStackScroller.setCentralSurfaces(mCentralSurfaces);
@@ -161,17 +163,6 @@
     }
 
     @Test
-    public void testUpdateStackEndHeight_forEndOfStackHeightAnimation() {
-        final float nsslHeight = 10f;
-        final float bottomMargin = 1f;
-        final float topPadding = 1f;
-
-        mStackScroller.updateStackEndHeight(nsslHeight, bottomMargin, topPadding);
-        final float stackEndHeight = nsslHeight - bottomMargin - topPadding;
-        assertTrue(mAmbientState.getStackEndHeight() == stackEndHeight);
-    }
-
-    @Test
     public void testUpdateStackHeight_withDozeAmount_whenDozeChanging() {
         final float dozeAmount = 0.5f;
         mAmbientState.setDozeAmount(dozeAmount);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
new file mode 100644
index 0000000..9a4e10c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
@@ -0,0 +1,208 @@
+/*
+ * 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.systemui.statusbar.notification.stack
+
+import android.service.notification.StatusBarNotification
+import android.testing.AndroidTestingRunner
+import android.view.View.VISIBLE
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.StatusBarState.KEYGUARD
+import com.android.systemui.statusbar.StatusBarState.SHADE
+import com.android.systemui.statusbar.SysuiStatusBarStateController
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.ExpandableView
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.nullable
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class NotificationStackSizeCalculatorTest : SysuiTestCase() {
+
+    @Mock private lateinit var sysuiStatusBarStateController: SysuiStatusBarStateController
+
+    @Mock private lateinit var stackLayout: NotificationStackScrollLayout
+
+    private val testableResources = mContext.getOrCreateTestableResources()
+
+    private lateinit var sizeCalculator: NotificationStackSizeCalculator
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        whenever(stackLayout.calculateGapHeight(nullable(), nullable(), any()))
+            .thenReturn(GAP_HEIGHT)
+        with(testableResources) {
+            addOverride(R.integer.keyguard_max_notification_count, -1)
+            addOverride(R.dimen.notification_divider_height, NOTIFICATION_PADDING.toInt())
+        }
+
+        sizeCalculator =
+            NotificationStackSizeCalculator(
+                statusBarStateController = sysuiStatusBarStateController,
+                testableResources.resources)
+    }
+
+    @Test
+    fun computeMaxKeyguardNotifications_zeroSpace_returnZero() {
+        val rows = listOf(createMockRow(height = ROW_HEIGHT))
+
+        val maxNotifications =
+            computeMaxKeyguardNotifications(rows, availableSpace = 0f, shelfHeight = 0f)
+
+        assertThat(maxNotifications).isEqualTo(0)
+    }
+
+    @Test
+    fun computeMaxKeyguardNotifications_infiniteSpace_returnsAll() {
+        val numberOfRows = 30
+        val rows = createLockscreenRows(numberOfRows)
+
+        val maxNotifications = computeMaxKeyguardNotifications(rows, Float.MAX_VALUE)
+
+        assertThat(maxNotifications).isEqualTo(numberOfRows)
+    }
+
+    @Test
+    fun computeMaxKeyguardNotifications_spaceForOne_returnsOne() {
+        val rowHeight = ROW_HEIGHT
+        val totalSpaceForEachRow = GAP_HEIGHT + rowHeight
+        val shelfHeight =
+            totalSpaceForEachRow / 2 // In this way shelf absence will not leave room for another.
+        val spaceForOne = totalSpaceForEachRow
+        val rows =
+            listOf(
+                createMockRow(rowHeight),
+                createMockRow(rowHeight))
+
+        val maxNotifications =
+            computeMaxKeyguardNotifications(
+                rows, availableSpace = spaceForOne, shelfHeight = shelfHeight)
+
+        assertThat(maxNotifications).isEqualTo(1)
+    }
+
+    @Test
+    fun computeMaxKeyguardNotifications_spaceForOne_shelfUsableForLastNotification_returnsTwo() {
+        val rowHeight = ROW_HEIGHT
+        val totalSpaceForEachRow = GAP_HEIGHT + rowHeight
+        val shelfHeight = totalSpaceForEachRow + NOTIFICATION_PADDING
+        val spaceForOne = totalSpaceForEachRow
+        val rows =
+            listOf(
+                createMockRow(rowHeight),
+                createMockRow(rowHeight))
+
+        val maxNotifications =
+            computeMaxKeyguardNotifications(
+                rows, availableSpace = spaceForOne, shelfHeight = shelfHeight)
+
+        assertThat(maxNotifications).isEqualTo(1)
+    }
+
+    @Test
+    fun computeMaxKeyguardNotifications_spaceForTwo_returnsTwo() {
+        val rowHeight = ROW_HEIGHT
+        val totalSpaceForEachRow = GAP_HEIGHT + rowHeight
+        val spaceForTwo = totalSpaceForEachRow * 2 + NOTIFICATION_PADDING
+        val rows =
+            listOf(
+                createMockRow(rowHeight),
+                createMockRow(rowHeight),
+                createMockRow(rowHeight))
+
+        val maxNotifications = computeMaxKeyguardNotifications(rows, spaceForTwo, shelfHeight = 0f)
+
+        assertThat(maxNotifications).isEqualTo(2)
+    }
+
+    @Test
+    fun computeHeight_returnsLessThanAvailableSpaceUsedToCalculateMaxNotifications() {
+        val rowHeight = ROW_HEIGHT
+        val shelfHeight = SHELF_HEIGHT
+        val totalSpaceForEachRow = GAP_HEIGHT + rowHeight + NOTIFICATION_PADDING
+        val availableSpace = totalSpaceForEachRow * 2
+        val rows =
+            listOf(
+                createMockRow(rowHeight),
+                createMockRow(rowHeight),
+                createMockRow(rowHeight))
+
+        val maxNotifications = computeMaxKeyguardNotifications(rows, availableSpace, shelfHeight)
+        assertThat(maxNotifications).isEqualTo(2)
+
+        val height = sizeCalculator.computeHeight(stackLayout, maxNotifications, SHELF_HEIGHT)
+        assertThat(height).isAtMost(availableSpace + SHELF_HEIGHT)
+    }
+
+    private fun computeMaxKeyguardNotifications(
+        rows: List<ExpandableView>,
+        availableSpace: Float,
+        shelfHeight: Float = SHELF_HEIGHT
+    ): Int {
+        setupChildren(rows)
+        return sizeCalculator.computeMaxKeyguardNotifications(
+            stackLayout, availableSpace, shelfHeight)
+    }
+
+    private fun setupChildren(children: List<ExpandableView>) {
+        whenever(stackLayout.getChildAt(any())).thenAnswer { invocation ->
+            val inx = invocation.getArgument<Int>(0)
+            return@thenAnswer children[inx]
+        }
+        whenever(stackLayout.childCount).thenReturn(children.size)
+    }
+
+    private fun createLockscreenRows(number: Int): List<ExpandableNotificationRow> =
+        (1..number).map { createMockRow() }.toList()
+
+    private fun createMockRow(
+        height: Float = ROW_HEIGHT,
+        isRemoved: Boolean = false,
+        visibility: Int = VISIBLE,
+    ): ExpandableNotificationRow {
+        val row = mock(ExpandableNotificationRow::class.java)
+        val entry = mock(NotificationEntry::class.java)
+        val sbn = mock(StatusBarNotification::class.java)
+        whenever(entry.sbn).thenReturn(sbn)
+        whenever(row.entry).thenReturn(entry)
+        whenever(row.isRemoved).thenReturn(isRemoved)
+        whenever(row.visibility).thenReturn(visibility)
+        whenever(row.getMinHeight(any())).thenReturn(height.toInt())
+        whenever(row.intrinsicHeight).thenReturn(height.toInt())
+        return row
+    }
+
+    /** Default dimensions for tests that don't overwrite them. */
+    companion object {
+        const val GAP_HEIGHT = 12f
+        const val NOTIFICATION_PADDING = 3f
+        const val SHELF_HEIGHT = 14f
+        const val ROW_HEIGHT = SHELF_HEIGHT * 3
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index ed144fa..142c2c1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -408,7 +408,7 @@
     @Test
     public void onFinishedGoingToSleep_authenticatesWhenPending() {
         when(mUpdateMonitor.isGoingToSleep()).thenReturn(true);
-        mBiometricUnlockController.onFinishedGoingToSleep(-1);
+        mBiometricUnlockController.mWakefulnessObserver.onFinishedGoingToSleep();
         verify(mHandler, never()).post(any());
 
         ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
@@ -416,7 +416,7 @@
         // value of isUnlockingWithBiometricAllowed()
         mBiometricUnlockController.onBiometricAuthenticated(1 /* userId */,
                 BiometricSourceType.FACE, true /* isStrongBiometric */);
-        mBiometricUnlockController.onFinishedGoingToSleep(-1);
+        mBiometricUnlockController.mWakefulnessObserver.onFinishedGoingToSleep();
         verify(mHandler).post(captor.capture());
         captor.getValue().run();
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesTest.java
index 3810783..c72f895 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesTest.java
@@ -131,6 +131,7 @@
 import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
 import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
 import com.android.systemui.statusbar.notification.init.NotificationsController;
+import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
@@ -309,7 +310,9 @@
                         mDreamManager, mAmbientDisplayConfiguration, mNotificationFilter,
                         mStatusBarStateController, mBatteryController, mHeadsUpManager,
                         mock(NotificationInterruptLogger.class),
-                        new Handler(TestableLooper.get(this).getLooper()));
+                        new Handler(TestableLooper.get(this).getLooper()),
+                        mock(NotifPipelineFlags.class),
+                        mock(KeyguardNotificationVisibilityProvider.class));
 
         mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class));
         mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class));
@@ -994,9 +997,12 @@
                 BatteryController batteryController,
                 HeadsUpManager headsUpManager,
                 NotificationInterruptLogger logger,
-                Handler mainHandler) {
+                Handler mainHandler,
+                NotifPipelineFlags flags,
+                KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider) {
             super(contentResolver, powerManager, dreamManager, ambientDisplayConfiguration, filter,
-                    batteryController, controller, headsUpManager, logger, mainHandler);
+                    batteryController, controller, headsUpManager, logger, mainHandler,
+                    flags, keyguardNotificationVisibilityProvider);
             mUseHeadsUp = true;
         }
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index f391eff..4986792 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.android.systemui.statusbar.phone.KeyguardBouncer.EXPANSION_HIDDEN;
+import static com.android.systemui.statusbar.phone.KeyguardBouncer.EXPANSION_VISIBLE;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -24,9 +27,11 @@
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
+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.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.verifyZeroInteractions;
@@ -53,6 +58,7 @@
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
+import com.android.systemui.statusbar.phone.KeyguardBouncer.BouncerExpansionCallback;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import org.junit.Assert;
@@ -62,6 +68,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
@@ -79,7 +86,7 @@
     @Mock
     private KeyguardHostViewController mKeyguardHostViewController;
     @Mock
-    private KeyguardBouncer.BouncerExpansionCallback mExpansionCallback;
+    private BouncerExpansionCallback mExpansionCallback;
     @Mock
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @Mock
@@ -197,11 +204,11 @@
         mBouncer.ensureView();
         mBouncer.setExpansion(0.5f);
 
-        mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
+        mBouncer.setExpansion(EXPANSION_HIDDEN);
         verify(mFalsingCollector).onBouncerHidden();
         verify(mExpansionCallback).onFullyHidden();
 
-        mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
+        mBouncer.setExpansion(EXPANSION_VISIBLE);
         verify(mFalsingCollector).onBouncerShown();
         verify(mExpansionCallback).onFullyShown();
 
@@ -410,11 +417,11 @@
     @Test
     public void testInTransit_whenTranslation() {
         mBouncer.show(true);
-        mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
+        mBouncer.setExpansion(EXPANSION_HIDDEN);
         assertThat(mBouncer.inTransit()).isFalse();
         mBouncer.setExpansion(0.5f);
         assertThat(mBouncer.inTransit()).isTrue();
-        mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
+        mBouncer.setExpansion(EXPANSION_VISIBLE);
         assertThat(mBouncer.inTransit()).isFalse();
     }
 
@@ -435,4 +442,37 @@
 
         verify(mKeyguardHostViewController).updateKeyguardPosition(1.0f);
     }
+
+    @Test
+    public void testExpansion_notifiesCallback() {
+        mBouncer.ensureView();
+        mBouncer.setExpansion(0.5f);
+
+        final BouncerExpansionCallback callback = mock(BouncerExpansionCallback.class);
+        mBouncer.addBouncerExpansionCallback(callback);
+
+        mBouncer.setExpansion(EXPANSION_HIDDEN);
+        verify(callback).onFullyHidden();
+        verify(callback).onExpansionChanged(EXPANSION_HIDDEN);
+
+        Mockito.clearInvocations(callback);
+        mBouncer.setExpansion(EXPANSION_VISIBLE);
+        verify(callback).onFullyShown();
+        verify(callback).onExpansionChanged(EXPANSION_VISIBLE);
+
+        Mockito.clearInvocations(callback);
+        float bouncerHideAmount = 0.9f;
+        // Ensure the callback only triggers once despite multiple calls to setExpansion
+        // with the same value.
+        mBouncer.setExpansion(bouncerHideAmount);
+        mBouncer.setExpansion(bouncerHideAmount);
+        verify(callback, times(1)).onStartingToHide();
+        verify(callback, times(1)).onExpansionChanged(bouncerHideAmount);
+
+        Mockito.clearInvocations(callback);
+        mBouncer.removeBouncerExpansionCallback(callback);
+        bouncerHideAmount = 0.5f;
+        mBouncer.setExpansion(bouncerHideAmount);
+        verify(callback, never()).onExpansionChanged(bouncerHideAmount);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
index 1827c7f..6d3a5fe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
@@ -279,7 +279,7 @@
     public void notifPaddingMakesUpToFullMarginInSplitShade() {
         when(mResources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin))
                 .thenReturn(100);
-        when(mResources.getDimensionPixelSize(R.dimen.split_shade_header_height))
+        when(mResources.getDimensionPixelSize(R.dimen.large_screen_shade_header_height))
                 .thenReturn(70);
         mClockPositionAlgorithm.loadDimens(mResources);
         givenLockScreen();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
index 7de3545..39d5a16 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -343,6 +343,28 @@
         assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.INVISIBLE);
     }
 
+    @Test
+    public void setAlpha_explicitAlpha_setsExplicitAlpha() {
+        mController.onViewAttached();
+        updateStateToKeyguard();
+
+        mController.setAlpha(0.5f);
+
+        assertThat(mKeyguardStatusBarView.getAlpha()).isEqualTo(0.5f);
+    }
+
+    @Test
+    public void setAlpha_explicitAlpha_thenMinusOneAlpha_setsAlphaBasedOnDefaultCriteria() {
+        mController.onViewAttached();
+        updateStateToKeyguard();
+
+        mController.setAlpha(0.5f);
+        mController.setAlpha(-1f);
+
+        assertThat(mKeyguardStatusBarView.getAlpha()).isGreaterThan(0);
+        assertThat(mKeyguardStatusBarView.getAlpha()).isNotEqualTo(0.5f);
+    }
+
     // TODO(b/195442899): Add more tests for #updateViewState once CLs are finalized.
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SplitShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LargeScreenShadeHeaderControllerTest.kt
similarity index 89%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SplitShadeHeaderControllerTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LargeScreenShadeHeaderControllerTest.kt
index 2b1826e..b086d68 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SplitShadeHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LargeScreenShadeHeaderControllerTest.kt
@@ -27,7 +27,7 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
-class SplitShadeHeaderControllerTest : SysuiTestCase() {
+class LargeScreenShadeHeaderControllerTest : SysuiTestCase() {
 
     @Mock private lateinit var view: View
     @Mock private lateinit var statusIcons: StatusIconContainer
@@ -43,7 +43,7 @@
     @JvmField @Rule val mockitoRule = MockitoJUnit.rule()
     var viewVisibility = View.GONE
 
-    private lateinit var splitShadeHeaderController: SplitShadeHeaderController
+    private lateinit var mLargeScreenShadeHeaderController: LargeScreenShadeHeaderController
     private lateinit var carrierIconSlots: List<String>
 
     @Before
@@ -62,7 +62,7 @@
         }
         whenever(view.visibility).thenAnswer { _ -> viewVisibility }
         whenever(featureFlags.isEnabled(Flags.COMBINED_QS_HEADERS)).thenReturn(false)
-        splitShadeHeaderController = SplitShadeHeaderController(
+        mLargeScreenShadeHeaderController = LargeScreenShadeHeaderController(
                 view,
                 statusBarIconController,
                 privacyIconsController,
@@ -76,11 +76,11 @@
     }
 
     @Test
-    fun setVisible_onlyInSplitShade() {
+    fun setVisible_onlyWhenActive() {
         makeShadeVisible()
         assertThat(viewVisibility).isEqualTo(View.VISIBLE)
 
-        splitShadeHeaderController.splitShadeMode = false
+        mLargeScreenShadeHeaderController.active = false
         assertThat(viewVisibility).isEqualTo(View.GONE)
     }
 
@@ -94,7 +94,7 @@
     @Test
     fun shadeExpandedFraction_updatesAlpha() {
         makeShadeVisible()
-        splitShadeHeaderController.shadeExpandedFraction = 0.5f
+        mLargeScreenShadeHeaderController.shadeExpandedFraction = 0.5f
         verify(view).setAlpha(ShadeInterpolation.getContentAlpha(0.5f))
     }
 
@@ -117,7 +117,7 @@
     }
 
     private fun makeShadeVisible() {
-        splitShadeHeaderController.splitShadeMode = true
-        splitShadeHeaderController.shadeExpanded = true
+        mLargeScreenShadeHeaderController.active = true
+        mLargeScreenShadeHeaderController.shadeExpanded = true
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
index 4bac08e..22bf6c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
@@ -104,7 +104,6 @@
 import com.android.systemui.statusbar.KeyguardAffordanceView;
 import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -119,12 +118,12 @@
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
 import com.android.systemui.statusbar.notification.stack.AmbientState;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator;
 import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController;
@@ -174,8 +173,6 @@
     @Mock
     private NotificationShelfController mNotificationShelfController;
     @Mock
-    private NotificationGroupManagerLegacy mGroupManager;
-    @Mock
     private KeyguardStatusBarView mKeyguardStatusBar;
     @Mock
     private KeyguardUserSwitcherView mUserSwitcherView;
@@ -200,10 +197,6 @@
     @Mock
     private DynamicPrivacyController mDynamicPrivacyController;
     @Mock
-    private ShadeController mShadeController;
-    @Mock
-    private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
-    @Mock
     private NotificationEntryManager mNotificationEntryManager;
     @Mock
     private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
@@ -295,7 +288,7 @@
     @Mock
     private SecureSettings mSecureSettings;
     @Mock
-    private SplitShadeHeaderController mSplitShadeHeaderController;
+    private LargeScreenShadeHeaderController mLargeScreenShadeHeaderController;
     @Mock
     private ContentResolver mContentResolver;
     @Mock
@@ -336,6 +329,8 @@
     private SysUiState mSysUiState;
     @Mock
     private NotificationListContainer mNotificationListContainer;
+    @Mock
+    private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
     private NotificationPanelViewController.PanelEventsEmitter mPanelEventsEmitter;
     private Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
     private SysuiStatusBarStateController mStatusBarStateController;
@@ -466,7 +461,7 @@
                 mFeatureFlags,
                 coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
                 mFalsingManager, new FalsingCollectorFake(),
-                mNotificationLockscreenUserManager, mNotificationEntryManager,
+                mNotificationEntryManager,
                 mKeyguardStateController,
                 mStatusBarStateController,
                 mStatusBarWindowStateController,
@@ -484,7 +479,6 @@
                 mKeyguardUserSwitcherComponentFactory,
                 mKeyguardStatusBarViewComponentFactory,
                 mLockscreenShadeTransitionController,
-                mGroupManager,
                 mNotificationAreaController,
                 mAuthController,
                 mScrimController,
@@ -504,7 +498,7 @@
                 mRecordingController,
                 mExecutor,
                 mSecureSettings,
-                mSplitShadeHeaderController,
+                mLargeScreenShadeHeaderController,
                 mScreenOffAnimationController,
                 mLockscreenGestureLogger,
                 new PanelExpansionStateManager(),
@@ -516,7 +510,8 @@
                 mSysUiState,
                 mKeyguardUnlockAnimationController,
                 mNotificationListContainer,
-                mPanelEventsEmitter);
+                mPanelEventsEmitter,
+                mNotificationStackSizeCalculator);
         mNotificationPanelViewController.initDependencies(
                 mCentralSurfaces,
                 () -> {},
@@ -923,6 +918,35 @@
         verify(mKeyguardStatusViewController, never()).displayClock(LARGE, /* animate */ true);
     }
 
+    @Test
+    public void testLargeScreenHeaderMadeActiveForLargeScreen() {
+        mStatusBarStateController.setState(SHADE);
+        when(mResources.getBoolean(R.bool.config_use_large_screen_shade_header)).thenReturn(true);
+        mNotificationPanelViewController.updateResources();
+        verify(mLargeScreenShadeHeaderController).setActive(true);
+
+        when(mResources.getBoolean(R.bool.config_use_large_screen_shade_header)).thenReturn(false);
+        mNotificationPanelViewController.updateResources();
+        verify(mLargeScreenShadeHeaderController).setActive(false);
+    }
+
+    @Test
+    public void testUnlockAnimationDoesNotAffectScrim() {
+        mNotificationPanelViewController.onUnlockHintStarted();
+        verify(mScrimController).setExpansionAffectsAlpha(false);
+        mNotificationPanelViewController.onUnlockHintFinished();
+        verify(mScrimController).setExpansionAffectsAlpha(true);
+    }
+
+    @Test
+    public void setKeyguardStatusBarAlpha_setsAlphaOnKeyguardStatusBarController() {
+        float statusBarAlpha = 0.5f;
+
+        mNotificationPanelViewController.setKeyguardStatusBarAlpha(statusBarAlpha);
+
+        verify(mKeyguardStatusBarViewController).setAlpha(statusBarAlpha);
+    }
+
     private void triggerPositionClockAndNotifications() {
         mNotificationPanelViewController.closeQs();
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
index d65cc78..05a21db 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
@@ -1,12 +1,12 @@
 package com.android.systemui.statusbar.phone
 
-import android.annotation.IdRes
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.view.View
 import android.view.ViewGroup
 import android.view.WindowInsets
 import android.view.WindowManagerPolicyConstants
+import androidx.annotation.IdRes
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.test.filters.SmallTest
@@ -18,6 +18,8 @@
 import com.android.systemui.navigationbar.NavigationModeController.ModeChangedListener
 import com.android.systemui.recents.OverviewProxyService
 import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
@@ -31,6 +33,7 @@
 import org.mockito.Mockito.doNothing
 import org.mockito.Mockito.eq
 import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 import java.util.function.Consumer
@@ -71,8 +74,8 @@
     private lateinit var navigationModeCallback: ModeChangedListener
     private lateinit var taskbarVisibilityCallback: OverviewProxyListener
     private lateinit var windowInsetsCallback: Consumer<WindowInsets>
-
-    private val testableResources = mContext.orCreateTestableResources
+    private lateinit var delayableExecutor: FakeExecutor
+    private lateinit var fakeSystemClock: FakeSystemClock
 
     @Before
     fun setup() {
@@ -80,11 +83,14 @@
         mContext.ensureTestableResources()
         whenever(notificationsQSContainer.context).thenReturn(mContext)
         whenever(notificationsQSContainer.resources).thenReturn(mContext.resources)
+        fakeSystemClock = FakeSystemClock()
+        delayableExecutor = FakeExecutor(fakeSystemClock)
         controller = NotificationsQSContainerController(
                 notificationsQSContainer,
                 navigationModeController,
                 overviewProxyService,
-                featureFlags
+                featureFlags,
+                delayableExecutor
         )
 
         overrideResource(R.dimen.split_shade_notifications_scrim_margin_bottom, SCRIM_MARGIN)
@@ -105,10 +111,6 @@
         windowInsetsCallback = windowInsetsCallbackCaptor.value
     }
 
-    fun overrideResource(@IdRes id: Int, value: Any) {
-        mContext.orCreateTestableResources.addOverride(id, value)
-    }
-
     @Test
     fun testTaskbarVisibleInSplitShade() {
         enableSplitShade()
@@ -458,6 +460,49 @@
     }
 
     @Test
+    fun testSplitShadeLayout_qsFrameHasHorizontalMarginsOfZero() {
+        enableSplitShade()
+        controller.updateResources()
+        assertThat(getConstraintSetLayout(R.id.qs_frame).endMargin).isEqualTo(0)
+        assertThat(getConstraintSetLayout(R.id.qs_frame).startMargin).isEqualTo(0)
+    }
+
+    @Test
+    fun testLargeScreenLayout_qsAndNotifsTopMarginIsOfHeaderHeight() {
+        setLargeScreen()
+        val largeScreenHeaderHeight = 100
+        overrideResource(R.dimen.large_screen_shade_header_height, largeScreenHeaderHeight)
+
+        controller.updateResources()
+
+        assertThat(getConstraintSetLayout(R.id.qs_frame).topMargin)
+                .isEqualTo(largeScreenHeaderHeight)
+        assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).topMargin)
+                .isEqualTo(largeScreenHeaderHeight)
+    }
+
+    @Test
+    fun testSmallScreenLayout_qsAndNotifsTopMarginIsZero() {
+        setSmallScreen()
+        controller.updateResources()
+        assertThat(getConstraintSetLayout(R.id.qs_frame).topMargin).isEqualTo(0)
+        assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).topMargin)
+                .isEqualTo(0)
+    }
+
+    @Test
+    fun testSinglePaneShadeLayout_qsFrameHasHorizontalMarginsSetToCorrectValue() {
+        disableSplitShade()
+        controller.updateResources()
+        val notificationPanelMarginHorizontal = context.resources
+                .getDimensionPixelSize(R.dimen.notification_panel_margin_horizontal)
+        assertThat(getConstraintSetLayout(R.id.qs_frame).endMargin)
+                .isEqualTo(notificationPanelMarginHorizontal)
+        assertThat(getConstraintSetLayout(R.id.qs_frame).startMargin)
+                .isEqualTo(notificationPanelMarginHorizontal)
+    }
+
+    @Test
     fun testSinglePaneShadeLayout_isAlignedToParent() {
         disableSplitShade()
         controller.updateResources()
@@ -476,13 +521,32 @@
         container.addView(newViewWithId(1))
         container.addView(newViewWithId(View.NO_ID))
         val controller = NotificationsQSContainerController(container, navigationModeController,
-                overviewProxyService, featureFlags)
+                overviewProxyService, featureFlags, delayableExecutor)
         controller.updateResources()
 
         assertThat(container.getChildAt(0).id).isEqualTo(1)
         assertThat(container.getChildAt(1).id).isNotEqualTo(View.NO_ID)
     }
 
+    @Test
+    fun testWindowInsetDebounce() {
+        disableSplitShade()
+        useNewFooter(true)
+
+        given(taskbarVisible = false,
+            navigationMode = GESTURES_NAVIGATION,
+            insets = emptyInsets(),
+            applyImmediately = false)
+        fakeSystemClock.advanceTime(INSET_DEBOUNCE_MILLIS / 2)
+        windowInsetsCallback.accept(windowInsets().withStableBottom())
+
+        delayableExecutor.advanceClockToLast()
+        delayableExecutor.runAllReady()
+
+        verify(notificationsQSContainer, never()).setQSContainerPaddingBottom(0)
+        verify(notificationsQSContainer).setQSContainerPaddingBottom(STABLE_INSET_BOTTOM)
+    }
+
     private fun disableSplitShade() {
         setSplitShadeEnabled(false)
     }
@@ -496,15 +560,32 @@
         controller.updateResources()
     }
 
+    private fun setSmallScreen() {
+        setLargeScreenEnabled(false)
+    }
+
+    private fun setLargeScreen() {
+        setLargeScreenEnabled(true)
+    }
+
+    private fun setLargeScreenEnabled(enabled: Boolean) {
+        overrideResource(R.bool.config_use_large_screen_shade_header, enabled)
+    }
+
     private fun given(
         taskbarVisible: Boolean,
         navigationMode: Int,
-        insets: WindowInsets
+        insets: WindowInsets,
+        applyImmediately: Boolean = true
     ) {
         Mockito.clearInvocations(notificationsQSContainer)
         taskbarVisibilityCallback.onTaskbarStatusUpdated(taskbarVisible, false)
         navigationModeCallback.onNavigationModeChanged(navigationMode)
         windowInsetsCallback.accept(insets)
+        if (applyImmediately) {
+            delayableExecutor.advanceClockToLast()
+            delayableExecutor.runAllReady()
+        }
     }
 
     fun then(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt
index 093f926..7e245fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt
@@ -24,11 +24,13 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollectorFake
 import com.android.systemui.dock.DockManager
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController
 import com.android.systemui.lowlightclock.LowLightClockController
 import com.android.systemui.statusbar.LockscreenShadeTransitionController
 import com.android.systemui.statusbar.NotificationShadeDepthController
 import com.android.systemui.statusbar.NotificationShadeWindowController
 import com.android.systemui.statusbar.SysuiStatusBarStateController
+import com.android.systemui.statusbar.notification.stack.AmbientState
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
 import com.android.systemui.statusbar.phone.NotificationShadeWindowView.InteractionEventHandler
 import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager
@@ -71,6 +73,10 @@
     @Mock
     private lateinit var mNotificationShadeWindowController: NotificationShadeWindowController
     @Mock
+    private lateinit var mKeyguardUnlockAnimationController: KeyguardUnlockAnimationController
+    @Mock
+    private lateinit var mAmbientState: AmbientState
+    @Mock
     private lateinit var stackScrollLayoutController: NotificationStackScrollLayoutController
     @Mock
     private lateinit var mStatusBarKeyguardViewManager: StatusBarKeyguardViewManager
@@ -109,7 +115,9 @@
             mLockIconViewController,
             Optional.of(mLowLightClockController),
             mCentralSurfaces,
-            mNotificationShadeWindowController
+            mNotificationShadeWindowController,
+            mKeyguardUnlockAnimationController,
+            mAmbientState
         )
         mController.setupExpandedStatusBar()
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
index 62a1bcd..1d86fb1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
@@ -37,12 +37,14 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.dock.DockManager;
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.lowlightclock.LowLightClockController;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.notification.stack.AmbientState;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
@@ -83,6 +85,8 @@
     @Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
     @Mock private LockIconViewController mLockIconViewController;
     @Mock private LowLightClockController mLowLightClockController;
+    @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+    @Mock private AmbientState mAmbientState;
 
     @Captor private ArgumentCaptor<NotificationShadeWindowView.InteractionEventHandler>
             mInteractionEventHandlerCaptor;
@@ -117,7 +121,9 @@
                 mLockIconViewController,
                 Optional.of(mLowLightClockController),
                 mCentralSurfaces,
-                mNotificationShadeWindowController);
+                mNotificationShadeWindowController,
+                mKeyguardUnlockAnimationController,
+                mAmbientState);
         mController.setupExpandedStatusBar();
         mController.setDragDownHelper(mDragDownHelper);
     }
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 0b25467..134ad4b 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
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static com.android.systemui.statusbar.phone.ScrimController.KEYGUARD_SCRIM_ALPHA;
 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;
@@ -54,6 +53,7 @@
 import com.android.systemui.DejankUtils;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dock.DockManager;
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.scrim.ScrimView;
 import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -113,6 +113,8 @@
     private ConfigurationController mConfigurationController;
     @Mock
     private ScreenOffAnimationController mScreenOffAnimationController;
+    @Mock
+    private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
     // TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The
     //   event-dispatch-on-registration pattern caused some of these unit tests to fail.)
     @Mock
@@ -230,7 +232,8 @@
                 new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor,
                 mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()),
                 mScreenOffAnimationController,
-                mPanelExpansionStateManager);
+                mPanelExpansionStateManager,
+                mKeyguardUnlockAnimationController);
         mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
         mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
         mScrimController.setAnimatorListener(mAnimatorListener);
@@ -1263,19 +1266,63 @@
 
         mScrimController.setClipsQsScrim(true);
         float progress = 0.5f;
-        mScrimController.setTransitionToFullShadeProgress(progress);
+        float lsNotifProgress = 0.3f;
+        mScrimController.setTransitionToFullShadeProgress(progress, lsNotifProgress);
         assertEquals(MathUtils.lerp(keyguardAlpha, shadeLockedAlpha, progress),
                 mNotificationsScrim.getViewAlpha(), 0.2);
         progress = 0.0f;
-        mScrimController.setTransitionToFullShadeProgress(progress);
+        mScrimController.setTransitionToFullShadeProgress(progress, lsNotifProgress);
         assertEquals(MathUtils.lerp(keyguardAlpha, shadeLockedAlpha, progress),
                 mNotificationsScrim.getViewAlpha(), 0.2);
         progress = 1.0f;
-        mScrimController.setTransitionToFullShadeProgress(progress);
+        mScrimController.setTransitionToFullShadeProgress(progress, lsNotifProgress);
         assertEquals(MathUtils.lerp(keyguardAlpha, shadeLockedAlpha, progress),
                 mNotificationsScrim.getViewAlpha(), 0.2);
     }
 
+    @Test
+    public void notificationTransparency_followsNotificationScrimProgress() {
+        mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
+        mScrimController.setRawPanelExpansionFraction(1.0f);
+        finishAnimationsImmediately();
+        mScrimController.transitionTo(ScrimState.KEYGUARD);
+        mScrimController.setRawPanelExpansionFraction(1.0f);
+        finishAnimationsImmediately();
+
+        float progress = 0.5f;
+        float notifProgress = 0.3f;
+        mScrimController.setTransitionToFullShadeProgress(progress, notifProgress);
+
+        assertThat(mNotificationsScrim.getViewAlpha()).isEqualTo(notifProgress);
+    }
+
+    @Test
+    public void setNotificationsOverScrollAmount_setsTranslationYOnNotificationsScrim() {
+        int overScrollAmount = 10;
+
+        mScrimController.setNotificationsOverScrollAmount(overScrollAmount);
+
+        assertThat(mNotificationsScrim.getTranslationY()).isEqualTo(overScrollAmount);
+    }
+
+    @Test
+    public void setNotificationsOverScrollAmount_doesNotSetTranslationYOnBehindScrim() {
+        int overScrollAmount = 10;
+
+        mScrimController.setNotificationsOverScrollAmount(overScrollAmount);
+
+        assertThat(mScrimBehind.getTranslationY()).isEqualTo(0);
+    }
+
+    @Test
+    public void setNotificationsOverScrollAmount_doesNotSetTranslationYOnFrontScrim() {
+        int overScrollAmount = 10;
+
+        mScrimController.setNotificationsOverScrollAmount(overScrollAmount);
+
+        assertThat(mScrimInFront.getTranslationY()).isEqualTo(0);
+    }
+
     private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) {
         mScrimController.setRawPanelExpansionFraction(expansion);
         finishAnimationsImmediately();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index f4f55cc..29488f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -95,6 +95,8 @@
     @Mock
     private KeyguardMessageAreaController.Factory mKeyguardMessageAreaFactory;
     @Mock
+    private KeyguardMessageAreaController mKeyguardMessageAreaController;
+    @Mock
     private KeyguardBouncer mBouncer;
     @Mock
     private StatusBarKeyguardViewManager.AlternateAuthInterceptor mAlternateAuthInterceptor;
@@ -120,6 +122,8 @@
                 .thenReturn(mBouncer);
         when(mCentralSurfaces.getBouncerContainer()).thenReturn(mContainer);
         when(mContainer.findViewById(anyInt())).thenReturn(mKeyguardMessageArea);
+        when(mKeyguardMessageAreaFactory.create(any(KeyguardMessageArea.class)))
+                .thenReturn(mKeyguardMessageAreaController);
         mStatusBarKeyguardViewManager = new StatusBarKeyguardViewManager(
                 getContext(),
                 mViewMediatorCallback,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 27179fd..fa867e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -85,6 +85,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.Mockito;
@@ -188,10 +189,11 @@
         when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(false);
         when(mOnUserInteractionCallback.getGroupSummaryToDismiss(mNotificationRow.getEntry()))
                 .thenReturn(null);
-        when(mVisibilityProvider.obtain(anyString(), anyBoolean())).thenAnswer(
-                invocation-> NotificationVisibility.obtain(invocation.getArgument(0), 0, 1, false));
-        when(mVisibilityProvider.obtain(any(NotificationEntry.class), anyBoolean())).thenAnswer(
-                invocation-> NotificationVisibility.obtain(
+        when(mVisibilityProvider.obtain(anyString(), anyBoolean()))
+                .thenAnswer(invocation -> NotificationVisibility.obtain(
+                        invocation.getArgument(0), 0, 1, false));
+        when(mVisibilityProvider.obtain(any(NotificationEntry.class), anyBoolean()))
+                .thenAnswer(invocation -> NotificationVisibility.obtain(
                         invocation.<NotificationEntry>getArgument(0).getKey(), 0, 1, false));
 
         HeadsUpManagerPhone headsUpManager = mock(HeadsUpManagerPhone.class);
@@ -431,12 +433,29 @@
     }
 
     @Test
-    public void testNotifActivityStarterEventSourceFinishEvent_postPanelCollapse() {
+    public void testNotifActivityStarterEventSourceFinishEvent_postPanelCollapse()
+            throws Exception {
         NotifActivityLaunchEvents.Listener listener =
                 mock(NotifActivityLaunchEvents.Listener.class);
         mLaunchEventsEmitter.registerListener(listener);
         mNotificationActivityStarter
                 .onNotificationClicked(mNotificationRow.getEntry().getSbn(), mNotificationRow);
+        ArgumentCaptor<ActivityLaunchAnimator.Controller> controllerCaptor =
+                ArgumentCaptor.forClass(ActivityLaunchAnimator.Controller.class);
+        verify(mActivityLaunchAnimator).startPendingIntentWithAnimation(
+                controllerCaptor.capture(), anyBoolean(), any(), any());
+        controllerCaptor.getValue().onIntentStarted(false);
+        verify(listener).onFinishLaunchNotifActivity(mNotificationRow.getEntry());
+    }
+
+    @Test
+    public void testNotifActivityStarterEventSourceFinishEvent_postPanelCollapse_noAnimate() {
+        NotifActivityLaunchEvents.Listener listener =
+                mock(NotifActivityLaunchEvents.Listener.class);
+        mLaunchEventsEmitter.registerListener(listener);
+        when(mCentralSurfaces.shouldAnimateLaunch(anyBoolean())).thenReturn(false);
+        mNotificationActivityStarter
+                .onNotificationClicked(mNotificationRow.getEntry().getSbn(), mNotificationRow);
         verify(listener).onFinishLaunchNotifActivity(mNotificationRow.getEntry());
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
index 589aa03..6c83e9f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
@@ -14,10 +14,12 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
 import android.content.BroadcastReceiver;
@@ -43,7 +45,6 @@
 @SmallTest
 public class SystemUIDialogTest extends SysuiTestCase {
 
-    private SystemUIDialog mDialog;
     @Mock
     private BroadcastDispatcher mBroadcastDispatcher;
 
@@ -52,24 +53,37 @@
         MockitoAnnotations.initMocks(this);
 
         mDependency.injectTestDependency(BroadcastDispatcher.class, mBroadcastDispatcher);
-
-        mDialog = new SystemUIDialog(mContext);
     }
 
     @Test
     public void testRegisterReceiver() {
+        final SystemUIDialog dialog = new SystemUIDialog(mContext);
         final ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
                 ArgumentCaptor.forClass(BroadcastReceiver.class);
         final ArgumentCaptor<IntentFilter> intentFilterCaptor =
                 ArgumentCaptor.forClass(IntentFilter.class);
 
-        mDialog.show();
+        dialog.show();
         verify(mBroadcastDispatcher).registerReceiver(broadcastReceiverCaptor.capture(),
                 intentFilterCaptor.capture(), eq(null), any());
-
+        assertTrue(intentFilterCaptor.getValue().hasAction(Intent.ACTION_SCREEN_OFF));
         assertTrue(intentFilterCaptor.getValue().hasAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
 
-        mDialog.dismiss();
+        dialog.dismiss();
         verify(mBroadcastDispatcher).unregisterReceiver(eq(broadcastReceiverCaptor.getValue()));
     }
+
+
+    @Test
+    public void testNoRegisterReceiver() {
+        final SystemUIDialog dialog = new SystemUIDialog(mContext, false);
+
+        dialog.show();
+        verify(mBroadcastDispatcher, never()).registerReceiver(any(), any(), eq(null), any());
+        assertTrue(dialog.isShowing());
+
+        dialog.dismiss();
+        verify(mBroadcastDispatcher, never()).unregisterReceiver(any());
+        assertFalse(dialog.isShowing());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherControllerTest.kt
new file mode 100644
index 0000000..37c0f36
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherControllerTest.kt
@@ -0,0 +1,103 @@
+/*
+ * 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.systemui.statusbar.phone.userswitcher
+
+import android.content.Intent
+import android.os.UserHandle
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.qs.user.UserSwitchDialogController
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+@SmallTest
+class StatusBarUserSwitcherControllerTest : SysuiTestCase() {
+    @Mock
+    private lateinit var tracker: StatusBarUserInfoTracker
+
+    @Mock
+    private lateinit var featureController: StatusBarUserSwitcherFeatureController
+
+    @Mock
+    private lateinit var userSwitcherDialogController: UserSwitchDialogController
+
+    @Mock
+    private lateinit var featureFlags: FeatureFlags
+
+    @Mock
+    private lateinit var activityStarter: ActivityStarter
+
+    @Mock
+    private lateinit var falsingManager: FalsingManager
+
+    private lateinit var statusBarUserSwitcherContainer: StatusBarUserSwitcherContainer
+    private lateinit var controller: StatusBarUserSwitcherControllerImpl
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        statusBarUserSwitcherContainer = StatusBarUserSwitcherContainer(mContext, null)
+        statusBarUserSwitcherContainer
+        controller = StatusBarUserSwitcherControllerImpl(
+                statusBarUserSwitcherContainer,
+                tracker,
+                featureController,
+                userSwitcherDialogController,
+                featureFlags,
+                activityStarter,
+                falsingManager
+        )
+        controller.init()
+        controller.onViewAttached()
+    }
+
+    @Test
+    fun testFalsingManager() {
+        statusBarUserSwitcherContainer.callOnClick()
+        verify(falsingManager).isFalseTap(FalsingManager.LOW_PENALTY)
+    }
+
+    @Test
+    fun testStartActivity() {
+        `when`(featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)).thenReturn(false)
+        statusBarUserSwitcherContainer.callOnClick()
+        verify(userSwitcherDialogController).showDialog(any(View::class.java))
+        `when`(featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)).thenReturn(true)
+        statusBarUserSwitcherContainer.callOnClick()
+        verify(activityStarter).startActivity(any(Intent::class.java),
+                eq(true) /* dismissShade */,
+                eq(null) /* animationController */,
+                eq(true) /* showOverLockscreenWhenLocked */,
+                eq(UserHandle.SYSTEM))
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index 20a3fda..3a0a7c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -114,15 +114,13 @@
         mContext.unregisterReceiver(mReceiver);
     }
 
-    private void setTestPendingIntent(RemoteInputView view, RemoteInputViewController controller) {
+    private void setTestPendingIntent(RemoteInputViewController controller) {
         PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0,
                 new Intent(TEST_ACTION), PendingIntent.FLAG_MUTABLE);
         RemoteInput input = new RemoteInput.Builder(TEST_RESULT_KEY).build();
         RemoteInput[] inputs = {input};
 
-        view.setPendingIntent(pendingIntent);
         controller.setPendingIntent(pendingIntent);
-        view.setRemoteInput(inputs, input, null /* editedSuggestionInfo */);
         controller.setRemoteInput(input);
         controller.setRemoteInputs(inputs);
     }
@@ -137,7 +135,7 @@
         RemoteInputView view = RemoteInputView.inflate(mContext, null, row.getEntry(), mController);
         RemoteInputViewController controller = bindController(view, row.getEntry());
 
-        setTestPendingIntent(view, controller);
+        setTestPendingIntent(controller);
 
         view.focus();
 
@@ -177,7 +175,7 @@
         RemoteInputView view = RemoteInputView.inflate(mContext, null, row.getEntry(), mController);
         RemoteInputViewController controller = bindController(view, row.getEntry());
 
-        setTestPendingIntent(view, controller);
+        setTestPendingIntent(controller);
 
         view.focus();
 
@@ -235,7 +233,7 @@
         RemoteInputView view = RemoteInputView.inflate(mContext, null, row.getEntry(), mController);
         RemoteInputViewController controller = bindController(view, row.getEntry());
 
-        setTestPendingIntent(view, controller);
+        setTestPendingIntent(controller);
 
         // Open view, send a reply
         view.focus();
@@ -265,7 +263,7 @@
         RemoteInputView view = RemoteInputView.inflate(mContext, null, row.getEntry(), mController);
         RemoteInputViewController controller = bindController(view, row.getEntry());
 
-        setTestPendingIntent(view, controller);
+        setTestPendingIntent(controller);
 
         // Open view, attach an image
         view.focus();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index f804d83..b8f66fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -39,6 +39,7 @@
 import android.content.Intent;
 import android.content.om.FabricatedOverlay;
 import android.content.om.OverlayIdentifier;
+import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.graphics.Color;
 import android.os.Handler;
@@ -56,6 +57,7 @@
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.monet.ColorScheme;
 import com.android.systemui.monet.Style;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -108,6 +110,8 @@
     @Mock
     private FeatureFlags mFeatureFlags;
     @Mock
+    private Resources mResources;
+    @Mock
     private WakefulnessLifecycle mWakefulnessLifecycle;
     @Captor
     private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiver;
@@ -129,10 +133,20 @@
         when(mFeatureFlags.isEnabled(Flags.MONET)).thenReturn(true);
         when(mWakefulnessLifecycle.getWakefulness()).thenReturn(WAKEFULNESS_AWAKE);
         when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
-        mThemeOverlayController = new ThemeOverlayController(null /* context */,
+        when(mResources.getColor(eq(android.R.color.system_accent1_500), any()))
+                .thenReturn(Color.RED);
+        when(mResources.getColor(eq(android.R.color.system_accent2_500), any()))
+                .thenReturn(Color.GREEN);
+        when(mResources.getColor(eq(android.R.color.system_accent3_500), any()))
+                .thenReturn(Color.BLUE);
+        when(mResources.getColor(eq(android.R.color.system_neutral1_500), any()))
+                .thenReturn(Color.YELLOW);
+        when(mResources.getColor(eq(android.R.color.system_neutral2_500), any()))
+                .thenReturn(Color.BLACK);
+        mThemeOverlayController = new ThemeOverlayController(mContext,
                 mBroadcastDispatcher, mBgHandler, mMainExecutor, mBgExecutor, mThemeOverlayApplier,
                 mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController,
-                mUserTracker, mDumpManager, mFeatureFlags, mWakefulnessLifecycle) {
+                mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle) {
             @Nullable
             @Override
             protected FabricatedOverlay getOverlay(int color, int type, Style style) {
@@ -140,6 +154,7 @@
                 when(overlay.getIdentifier())
                         .thenReturn(new OverlayIdentifier(Integer.toHexString(color | 0xff000000)));
                 mCurrentStyle = style;
+                mColorScheme = new ColorScheme(color, false /* nightMode */, style);
                 return overlay;
             }
         };
@@ -643,16 +658,17 @@
 
         Executor executor = MoreExecutors.directExecutor();
 
-        mThemeOverlayController = new ThemeOverlayController(null /* context */,
+        mThemeOverlayController = new ThemeOverlayController(mContext,
                 mBroadcastDispatcher, mBgHandler, executor, executor, mThemeOverlayApplier,
                 mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController,
-                mUserTracker, mDumpManager, mFeatureFlags, mWakefulnessLifecycle) {
+                mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle) {
             @Nullable
             @Override
             protected FabricatedOverlay getOverlay(int color, int type, Style style) {
                 FabricatedOverlay overlay = mock(FabricatedOverlay.class);
                 when(overlay.getIdentifier())
                         .thenReturn(new OverlayIdentifier("com.thebest.livewallpaperapp.ever"));
+                mColorScheme = new ColorScheme(color, false /* nightMode */, style);
                 return overlay;
             }
 
@@ -679,16 +695,17 @@
                 .thenReturn(new WallpaperColors(Color.valueOf(Color.GRAY), null, null));
 
         Executor executor = MoreExecutors.directExecutor();
-        mThemeOverlayController = new ThemeOverlayController(null /* context */,
+        mThemeOverlayController = new ThemeOverlayController(mContext,
                 mBroadcastDispatcher, mBgHandler, executor, executor, mThemeOverlayApplier,
                 mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController,
-                mUserTracker, mDumpManager, mFeatureFlags, mWakefulnessLifecycle) {
+                mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle) {
             @Nullable
             @Override
             protected FabricatedOverlay getOverlay(int color, int type, Style style) {
                 FabricatedOverlay overlay = mock(FabricatedOverlay.class);
                 when(overlay.getIdentifier())
                         .thenReturn(new OverlayIdentifier(Integer.toHexString(color | 0xff000000)));
+                mColorScheme = new ColorScheme(color, false /* nightMode */, style);
                 return overlay;
             }
         };
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
new file mode 100644
index 0000000..5509a6ca
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
@@ -0,0 +1,221 @@
+/*
+ * 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.systemui.unfold.progress
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.systemui.unfold.updates.FOLD_UPDATE_START_OPENING
+import com.android.systemui.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE
+import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN
+import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_HALF_OPEN
+import com.android.systemui.unfold.updates.FOLD_UPDATE_START_CLOSING
+import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_CLOSED
+import com.android.systemui.unfold.util.TestFoldStateProvider
+import com.android.systemui.util.leak.ReferenceTestUtils.waitForCondition
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class PhysicsBasedUnfoldTransitionProgressProviderTest : SysuiTestCase() {
+
+    private val foldStateProvider: TestFoldStateProvider = TestFoldStateProvider()
+    private val listener = TestUnfoldProgressListener()
+    private lateinit var progressProvider: UnfoldTransitionProgressProvider
+
+    @Before
+    fun setUp() {
+        progressProvider = PhysicsBasedUnfoldTransitionProgressProvider(
+            foldStateProvider
+        )
+        progressProvider.addCallback(listener)
+    }
+
+    @Test
+    fun testUnfold_emitsIncreasingTransitionEvents() {
+        runOnMainThreadWithInterval(
+            { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_OPENING) },
+            { foldStateProvider.sendHingeAngleUpdate(10f) },
+            { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) },
+            { foldStateProvider.sendHingeAngleUpdate(90f) },
+            { foldStateProvider.sendHingeAngleUpdate(180f) },
+            { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) },
+        )
+
+        with(listener.ensureTransitionFinished()) {
+            assertIncreasingProgress()
+            assertFinishedWithUnfold()
+        }
+    }
+
+    @Test
+    fun testUnfold_screenAvailableOnlyAfterFullUnfold_emitsIncreasingTransitionEvents() {
+        runOnMainThreadWithInterval(
+            { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_OPENING) },
+            { foldStateProvider.sendHingeAngleUpdate(10f) },
+            { foldStateProvider.sendHingeAngleUpdate(90f) },
+            { foldStateProvider.sendHingeAngleUpdate(180f) },
+            { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) },
+            { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) },
+        )
+
+        with(listener.ensureTransitionFinished()) {
+            assertIncreasingProgress()
+            assertFinishedWithUnfold()
+        }
+    }
+
+    @Test
+    fun testFold_emitsDecreasingTransitionEvents() {
+        runOnMainThreadWithInterval(
+            { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_CLOSING) },
+            { foldStateProvider.sendHingeAngleUpdate(170f) },
+            { foldStateProvider.sendHingeAngleUpdate(90f) },
+            { foldStateProvider.sendHingeAngleUpdate(10f) },
+            { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_CLOSED) },
+        )
+
+        with(listener.ensureTransitionFinished()) {
+            assertDecreasingProgress()
+            assertFinishedWithFold()
+        }
+    }
+
+    @Test
+    fun testUnfoldAndStopUnfolding_finishesTheUnfoldTransition() {
+        runOnMainThreadWithInterval(
+            { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_OPENING) },
+            { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) },
+            { foldStateProvider.sendHingeAngleUpdate(10f) },
+            { foldStateProvider.sendHingeAngleUpdate(90f) },
+            { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN) },
+        )
+
+        with(listener.ensureTransitionFinished()) {
+            assertIncreasingProgress()
+            assertFinishedWithUnfold()
+        }
+    }
+
+    @Test
+    fun testFoldImmediatelyAfterUnfold_runsFoldAnimation() {
+        runOnMainThreadWithInterval(
+            { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_OPENING) },
+            { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) },
+            { foldStateProvider.sendHingeAngleUpdate(10f) },
+            { foldStateProvider.sendHingeAngleUpdate(90f) },
+            { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) },
+            { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_CLOSING) },
+            { foldStateProvider.sendHingeAngleUpdate(60f) },
+            { foldStateProvider.sendHingeAngleUpdate(10f) },
+            { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_CLOSED) },
+        )
+
+        with(listener.ensureTransitionFinished()) {
+            assertHasFoldAnimationAtTheEnd()
+        }
+    }
+
+    private class TestUnfoldProgressListener : TransitionProgressListener {
+
+        private val recordings: MutableList<UnfoldTransitionRecording> = arrayListOf()
+        private var currentRecording: UnfoldTransitionRecording? = null
+
+        override fun onTransitionStarted() {
+            assertWithMessage("Trying to start a transition when it is already in progress")
+                .that(currentRecording).isNull()
+
+            currentRecording = UnfoldTransitionRecording()
+        }
+
+        override fun onTransitionProgress(progress: Float) {
+            assertWithMessage("Received transition progress event when it's not started")
+                .that(currentRecording).isNotNull()
+            currentRecording!!.addProgress(progress)
+        }
+
+        override fun onTransitionFinished() {
+            assertWithMessage("Received transition finish event when it's not started")
+                .that(currentRecording).isNotNull()
+            recordings += currentRecording!!
+            currentRecording = null
+        }
+
+        fun ensureTransitionFinished(): UnfoldTransitionRecording {
+            waitForCondition { recordings.size == 1 }
+            return recordings.first()
+        }
+
+        class UnfoldTransitionRecording {
+            private val progressHistory: MutableList<Float> = arrayListOf()
+
+            fun addProgress(progress: Float) {
+                assertThat(progress).isAtMost(1.0f)
+                assertThat(progress).isAtLeast(0.0f)
+
+                progressHistory += progress
+            }
+
+            fun assertIncreasingProgress() {
+                assertThat(progressHistory.size).isGreaterThan(MIN_ANIMATION_EVENTS)
+                assertThat(progressHistory).isInOrder()
+            }
+
+            fun assertDecreasingProgress() {
+                assertThat(progressHistory.size).isGreaterThan(MIN_ANIMATION_EVENTS)
+                assertThat(progressHistory).isInOrder(Comparator.reverseOrder<Float>())
+            }
+
+            fun assertFinishedWithUnfold() {
+                assertThat(progressHistory).isNotEmpty()
+                assertThat(progressHistory.last()).isEqualTo(1.0f)
+            }
+
+            fun assertFinishedWithFold() {
+                assertThat(progressHistory).isNotEmpty()
+                assertThat(progressHistory.last()).isEqualTo(0.0f)
+            }
+
+            fun assertHasFoldAnimationAtTheEnd() {
+                // Check that there are at least a few decreasing events at the end
+                assertThat(progressHistory.size).isGreaterThan(MIN_ANIMATION_EVENTS)
+                assertThat(progressHistory.takeLast(MIN_ANIMATION_EVENTS))
+                    .isInOrder(Comparator.reverseOrder<Float>())
+                assertThat(progressHistory.last()).isEqualTo(0.0f)
+            }
+        }
+
+        private companion object {
+            private const val MIN_ANIMATION_EVENTS = 5
+        }
+    }
+
+    private fun runOnMainThreadWithInterval(vararg blocks: () -> Unit, intervalMillis: Long = 60) {
+        blocks.forEach {
+            InstrumentationRegistry.getInstrumentation().runOnMainSync {
+                it()
+            }
+            Thread.sleep(intervalMillis)
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
index f43dc6c..7ac2434 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
@@ -16,6 +16,11 @@
 
 package com.android.systemui.unfold.updates
 
+import android.app.ActivityManager
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME
+import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
+import android.app.WindowConfiguration.ActivityType
 import android.hardware.devicestate.DeviceStateManager
 import android.hardware.devicestate.DeviceStateManager.FoldStateListener
 import android.os.Handler
@@ -30,7 +35,6 @@
 import com.android.systemui.unfold.util.FoldableTestUtils
 import com.android.systemui.util.mockito.any
 import com.google.common.truth.Truth.assertThat
-import java.lang.Exception
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -51,6 +55,8 @@
 
     @Mock private lateinit var deviceStateManager: DeviceStateManager
 
+    @Mock private lateinit var activityManager: ActivityManager
+
     @Mock private lateinit var handler: Handler
 
     @Captor private lateinit var foldStateListenerCaptor: ArgumentCaptor<FoldStateListener>
@@ -80,6 +86,7 @@
                 hingeAngleProvider,
                 screenStatusProvider,
                 deviceStateManager,
+                activityManager,
                 context.mainExecutor,
                 handler)
 
@@ -113,6 +120,9 @@
             }
             null
         }
+
+        // By default, we're on launcher.
+        setupForegroundActivityType(ACTIVITY_TYPE_HOME)
     }
 
     @Test
@@ -258,6 +268,31 @@
         }
     }
 
+    @Test
+    fun startClosingEvent_whileNotOnLauncher_doesNotTriggerBeforeThreshold() {
+        setupForegroundActivityType(ACTIVITY_TYPE_STANDARD)
+        sendHingeAngleEvent(180)
+
+        sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
+
+        assertThat(foldUpdates).isEmpty()
+    }
+
+    @Test
+    fun startClosingEvent_whileNotOnLauncher_triggersAfterThreshold() {
+        setupForegroundActivityType(ACTIVITY_TYPE_STANDARD)
+        sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES)
+
+        sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES - 1)
+
+        assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
+    }
+
+    private fun setupForegroundActivityType(@ActivityType type: Int) {
+        val taskInfo = RunningTaskInfo().apply { topActivityType = type }
+        whenever(activityManager.getRunningTasks(1)).thenReturn(listOf(taskInfo))
+    }
+
     private fun simulateTimeout(waitTime: Long = HALF_OPENED_TIMEOUT_MILLIS) {
         val runnableDelay = scheduledRunnableDelay ?: throw Exception("No runnable scheduled.")
         if (waitTime >= runnableDelay) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt
new file mode 100644
index 0000000..dd307b4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt
@@ -0,0 +1,57 @@
+/*
+ * 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.systemui.unfold.util
+
+import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN
+import com.android.systemui.unfold.updates.FoldStateProvider
+import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
+import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdatesListener
+
+class TestFoldStateProvider : FoldStateProvider {
+
+    private val listeners: MutableList<FoldUpdatesListener> = arrayListOf()
+
+    override fun start() {
+    }
+
+    override fun stop() {
+        listeners.clear()
+    }
+
+    private var _isFullyOpened: Boolean = false
+
+    override val isFullyOpened: Boolean
+        get() = _isFullyOpened
+
+    override fun addCallback(listener: FoldUpdatesListener) {
+        listeners += listener
+    }
+
+    override fun removeCallback(listener: FoldUpdatesListener) {
+        listeners -= listener
+    }
+
+    fun sendFoldUpdate(@FoldUpdate update: Int) {
+        if (update == FOLD_UPDATE_FINISH_FULL_OPEN) {
+            _isFullyOpened = true
+        }
+        listeners.forEach { it.onFoldUpdate(update) }
+    }
+
+    fun sendHingeAngleUpdate(angle: Float) {
+        listeners.forEach { it.onHingeAngleUpdate(angle) }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt
new file mode 100644
index 0000000..92afb03
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt
@@ -0,0 +1,51 @@
+/*
+ * 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.systemui.util.animation
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import java.lang.IllegalArgumentException
+
+@SmallTest
+class AnimationUtilTest : SysuiTestCase() {
+    @Test
+    fun getMsForFrames_5frames_returns83() {
+        assertThat(AnimationUtil.getMsForFrames(5)).isEqualTo(83L)
+    }
+
+    @Test
+    fun getMsForFrames_7frames_returns117() {
+        assertThat(AnimationUtil.getMsForFrames(7)).isEqualTo(117L)
+    }
+
+    @Test
+    fun getMsForFrames_30frames_returns500() {
+        assertThat(AnimationUtil.getMsForFrames(30)).isEqualTo(500L)
+    }
+
+    @Test
+    fun getMsForFrames_60frames_returns1000() {
+        assertThat(AnimationUtil.getMsForFrames(60)).isEqualTo(1000L)
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun getMsForFrames_negativeFrames_throwsException() {
+        AnimationUtil.getMsForFrames(-1)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt b/packages/SystemUI/tests/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
index 0f1b65c..309acdf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
@@ -24,6 +24,7 @@
  */
 
 import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatcher
 import org.mockito.Mockito
 
 /**
@@ -44,6 +45,14 @@
 inline fun <reified T> any(): T = any(T::class.java)
 
 /**
+ * Returns Mockito.argThat() as nullable type to avoid java.lang.IllegalStateException when
+ * null is returned.
+ *
+ * Generic T is nullable because implicitly bounded by Any?.
+ */
+fun <T> argThat(matcher: ArgumentMatcher<T>): T = Mockito.argThat(matcher)
+
+/**
  * Kotlin type-inferred version of Mockito.nullable()
  */
 inline fun <reified T> nullable(): T? = Mockito.nullable(T::class.java)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
index d8aef66..6802745 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
@@ -100,6 +100,7 @@
                 mContext,
                 MoreExecutors.directExecutor(),
                 MoreExecutors.directExecutor(),
+                MoreExecutors.directExecutor(),
                 mSecureSettings,
                 mQuickAccessWalletClient,
                 mClock);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 82880fe..78ee9e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -98,6 +98,7 @@
 import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
 import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
+import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
@@ -343,7 +344,9 @@
                         mock(BatteryController.class),
                         mock(HeadsUpManager.class),
                         mock(NotificationInterruptLogger.class),
-                        mock(Handler.class)
+                        mock(Handler.class),
+                        mock(NotifPipelineFlags.class),
+                        mock(KeyguardNotificationVisibilityProvider.class)
                 );
 
         when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
index cc848bc3..fafe4b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -85,6 +85,7 @@
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
 import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
+import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
@@ -309,7 +310,9 @@
                         mock(BatteryController.class),
                         mock(HeadsUpManager.class),
                         mock(NotificationInterruptLogger.class),
-                        mock(Handler.class)
+                        mock(Handler.class),
+                        mock(NotifPipelineFlags.class),
+                        mock(KeyguardNotificationVisibilityProvider.class)
                 );
         when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(true);
         when(mShellTaskOrganizer.getExecutor()).thenReturn(syncExecutor);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java
index e698f1e..a7f0dc2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java
@@ -23,7 +23,9 @@
 import android.service.dreams.IDreamManager;
 
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
 import com.android.systemui.statusbar.policy.BatteryController;
@@ -42,7 +44,9 @@
             BatteryController batteryController,
             HeadsUpManager headsUpManager,
             NotificationInterruptLogger logger,
-            Handler mainHandler) {
+            Handler mainHandler,
+            NotifPipelineFlags flags,
+            KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider) {
         super(contentResolver,
                 powerManager,
                 dreamManager,
@@ -52,7 +56,9 @@
                 statusBarStateController,
                 headsUpManager,
                 logger,
-                mainHandler);
+                mainHandler,
+                flags,
+                keyguardNotificationVisibilityProvider);
         mUseHeadsUp = true;
     }
 }
diff --git a/packages/VpnDialogs/res/values-or/strings.xml b/packages/VpnDialogs/res/values-or/strings.xml
index 0604b47..4c5c259 100644
--- a/packages/VpnDialogs/res/values-or/strings.xml
+++ b/packages/VpnDialogs/res/values-or/strings.xml
@@ -29,7 +29,7 @@
     <string name="always_on_disconnected_message" msgid="555634519845992917">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> ସବୁ ସମୟରେ କନେକ୍ଟ ହୋଇ ରହିବା ପାଇଁ ସେଟଅପ୍‍ କରାଯାଇଛି। ଆପଣଙ୍କ ଫୋନ୍‍, <xliff:g id="VPN_APP_1">%1$s</xliff:g> ସହ କନେକ୍ଟ ନହେବା ପର୍ଯ୍ୟନ୍ତ ଏକ ପବ୍ଲିକ୍‍ ନେଟ୍‌ୱର୍କ ବ୍ୟବହାର କରିବ।"</string>
     <string name="always_on_disconnected_message_lockdown" msgid="4232225539869452120">"<xliff:g id="VPN_APP">%1$s</xliff:g> ସବୁ ସମୟରେ କନେକ୍ଟ ହୋଇରହିବାକୁ ସେଟଅପ୍‍ କରାଯାଇଛି, କିନ୍ତୁ ଏହା ବର୍ତ୍ତମାନ କନେକ୍ଟ କରିପାରୁ ନାହିଁ। VPN ପୁଣି କନେକ୍ଟ ନହେବା ପର୍ଯ୍ୟନ୍ତ ଆପଣଙ୍କର କୌଣସି କନେକ୍ସନ୍‌ ରହିବନାହିଁ।"</string>
     <string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string>
-    <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"VPN ସେଟିଂସ୍ ବଦଳାନ୍ତୁ"</string>
+    <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"VPN ସେଟିଂସ ବଦଳାନ୍ତୁ"</string>
     <string name="configure" msgid="4905518375574791375">"କନଫିଗର୍‍ କରନ୍ତୁ"</string>
     <string name="disconnect" msgid="971412338304200056">"ବିଚ୍ଛିନ୍ନ କରନ୍ତୁ"</string>
     <string name="open_app" msgid="3717639178595958667">"ଆପ୍‌ ଖୋଲନ୍ତୁ"</string>
diff --git a/proto/src/camera.proto b/proto/src/camera.proto
index 4082118..38d74e4 100644
--- a/proto/src/camera.proto
+++ b/proto/src/camera.proto
@@ -66,5 +66,5 @@
     // The dynamic range profile of the stream
     optional int64 dynamic_range_profile = 14;
     // The stream use case
-    optional int32 stream_use_case = 15;
+    optional int64 stream_use_case = 15;
 }
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 3f712dd..3801c24 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -2260,10 +2260,12 @@
     ACCOUNTS_WORK_PROFILE_SETTINGS = 401;
 
     // Settings -> Dev options -> Convert to file encryption
-    CONVERT_FBE = 402;
+    // DEPRECATED: this setting was removed in Android T.
+    CONVERT_FBE = 402 [deprecated=true];
 
     // Settings -> Dev options -> Convert to file encryption -> WIPE AND CONVERT...
-    CONVERT_FBE_CONFIRM = 403;
+    // DEPRECATED: this setting was removed in Android T.
+    CONVERT_FBE_CONFIRM = 403 [deprecated=true];
 
     // Settings -> Dev options -> Running services
     RUNNING_SERVICES = 404;
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 7f10314..5ef1008 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -281,9 +281,9 @@
 
         void onDoubleTapAndHold(int displayId);
 
-        void requestImeLocked(AccessibilityServiceConnection connection);
+        void requestImeLocked(AbstractAccessibilityServiceConnection connection);
 
-        void unbindImeLocked(AccessibilityServiceConnection connection);
+        void unbindImeLocked(AbstractAccessibilityServiceConnection connection);
     }
 
     public AbstractAccessibilityServiceConnection(Context context, ComponentName componentName,
@@ -387,7 +387,6 @@
                 & AccessibilityServiceInfo.FLAG_REQUEST_FINGERPRINT_GESTURES) != 0;
         mRequestAccessibilityButton = (info.flags
                 & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
-        // TODO(b/218193835): request ime when ime flag is set and clean up when ime flag is unset
         mRequestImeApis = (info.flags
                 & AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR) != 0;
     }
@@ -439,6 +438,7 @@
                 // If the XML manifest had data to configure the service its info
                 // should be already set. In such a case update only the dynamically
                 // configurable properties.
+                boolean oldRequestIme = mRequestImeApis;
                 AccessibilityServiceInfo oldInfo = mAccessibilityServiceInfo;
                 if (oldInfo != null) {
                     oldInfo.updateDynamicallyConfigurableProperties(mIPlatformCompat, info);
@@ -447,6 +447,11 @@
                     setDynamicallyConfigurableProperties(info);
                 }
                 mSystemSupport.onClientChangeLocked(true);
+                if (!oldRequestIme && mRequestImeApis) {
+                    mSystemSupport.requestImeLocked(this);
+                } else if (oldRequestIme && !mRequestImeApis) {
+                    mSystemSupport.unbindImeLocked(this);
+                }
             }
         } finally {
             Binder.restoreCallingIdentity(identity);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 0ea087d..22c77e9 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -322,28 +322,28 @@
         @Override
         public void setImeSessionEnabled(SparseArray<IInputMethodSession> sessions,
                 boolean enabled) {
-            mService.setImeSessionEnabled(sessions, enabled);
+            mService.scheduleSetImeSessionEnabled(sessions, enabled);
         }
 
         @Override
         public void unbindInput() {
-            mService.unbindInput();
+            mService.scheduleUnbindInput();
         }
 
         @Override
         public void bindInput(InputBinding binding) {
-            mService.bindInput(binding);
+            mService.scheduleBindInput(binding);
         }
 
         @Override
         public void createImeSession(ArraySet<Integer> ignoreSet) {
-            mService.createImeSession(ignoreSet);
+            mService.scheduleCreateImeSession(ignoreSet);
         }
 
         @Override
         public void startInput(IBinder startInputToken, IInputContext inputContext,
                 EditorInfo editorInfo, boolean restarting) {
-            mService.startInput(startInputToken, inputContext, editorInfo, restarting);
+            mService.scheduleStartInput(startInputToken, inputContext, editorInfo, restarting);
         }
     }
 
@@ -4290,11 +4290,15 @@
     }
 
     private void onDoubleTapInternal(int displayId) {
+        AccessibilityInputFilter inputFilter = null;
         synchronized (mLock) {
             if (mHasInputFilter && mInputFilter != null) {
-                mInputFilter.onDoubleTap(displayId);
+                inputFilter = mInputFilter;
             }
         }
+        if (inputFilter != null) {
+            inputFilter.onDoubleTap(displayId);
+        }
     }
 
     @Override
@@ -4305,7 +4309,7 @@
     }
 
     @Override
-    public void requestImeLocked(AccessibilityServiceConnection connection) {
+    public void requestImeLocked(AbstractAccessibilityServiceConnection connection) {
         mMainHandler.sendMessage(obtainMessage(
                 AccessibilityManagerService::createSessionForConnection, this, connection));
         mMainHandler.sendMessage(obtainMessage(
@@ -4313,12 +4317,12 @@
     }
 
     @Override
-    public void unbindImeLocked(AccessibilityServiceConnection connection) {
+    public void unbindImeLocked(AbstractAccessibilityServiceConnection connection) {
         mMainHandler.sendMessage(obtainMessage(
                 AccessibilityManagerService::unbindInputForConnection, this, connection));
     }
 
-    private void createSessionForConnection(AccessibilityServiceConnection connection) {
+    private void createSessionForConnection(AbstractAccessibilityServiceConnection connection) {
         synchronized (mLock) {
             if (mInputSessionRequested) {
                 connection.createImeSessionLocked();
@@ -4326,7 +4330,7 @@
         }
     }
 
-    private void bindAndStartInputForConnection(AccessibilityServiceConnection connection) {
+    private void bindAndStartInputForConnection(AbstractAccessibilityServiceConnection connection) {
         synchronized (mLock) {
             if (mInputBinding != null) {
                 connection.bindInputLocked(mInputBinding);
@@ -4336,7 +4340,7 @@
         }
     }
 
-    private void unbindInputForConnection(AccessibilityServiceConnection connection) {
+    private void unbindInputForConnection(AbstractAccessibilityServiceConnection connection) {
         InputMethodManagerInternal.get().unbindAccessibilityFromCurrentClient(connection.mId);
         synchronized (mLock) {
             connection.unbindInputLocked();
@@ -4377,12 +4381,16 @@
      *
      * @param binding Information given to an accessibility service about a client connecting to it.
      */
-    public void bindInput(InputBinding binding) {
-        AccessibilityUserState userState;
+    public void scheduleBindInput(InputBinding binding) {
+        mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::bindInput, this,
+                binding));
+    }
+
+    private void bindInput(InputBinding binding) {
         synchronized (mLock) {
             // Keep records of these in case new Accessibility Services are enabled.
             mInputBinding = binding;
-            userState = getCurrentUserStateLocked();
+            AccessibilityUserState userState = getCurrentUserStateLocked();
             for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
                 final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
                 if (service.requestImeApis()) {
@@ -4395,11 +4403,13 @@
     /**
      * Unbind input for accessibility services which request ime capabilities.
      */
-    public void unbindInput() {
-        AccessibilityUserState userState;
-        // TODO(b/218182733): Resolve the Imf lock and mLock possible deadlock
+    public void scheduleUnbindInput() {
+        mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::unbindInput, this));
+    }
+
+    private void unbindInput() {
         synchronized (mLock) {
-            userState = getCurrentUserStateLocked();
+            AccessibilityUserState userState = getCurrentUserStateLocked();
             for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
                 final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
                 if (service.requestImeApis()) {
@@ -4412,16 +4422,21 @@
     /**
      * Start input for accessibility services which request ime capabilities.
      */
-    public void startInput(IBinder startInputToken, IInputContext inputContext,
+    public void scheduleStartInput(IBinder startInputToken, IInputContext inputContext,
             EditorInfo editorInfo, boolean restarting) {
-        AccessibilityUserState userState;
+        mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::startInput, this,
+                startInputToken, inputContext, editorInfo, restarting));
+    }
+
+    private void startInput(IBinder startInputToken, IInputContext inputContext,
+            EditorInfo editorInfo, boolean restarting) {
         synchronized (mLock) {
             // Keep records of these in case new Accessibility Services are enabled.
             mStartInputToken = startInputToken;
             mInputContext = inputContext;
             mEditorInfo = editorInfo;
             mRestarting = restarting;
-            userState = getCurrentUserStateLocked();
+            AccessibilityUserState userState = getCurrentUserStateLocked();
             for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
                 final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
                 if (service.requestImeApis()) {
@@ -4435,11 +4450,15 @@
      * Request input sessions from all accessibility services which request ime capabilities and
      * whose id is not in the ignoreSet
      */
-    public void createImeSession(ArraySet<Integer> ignoreSet) {
-        AccessibilityUserState userState;
+    public void scheduleCreateImeSession(ArraySet<Integer> ignoreSet) {
+        mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::createImeSession,
+                this, ignoreSet));
+    }
+
+    private void createImeSession(ArraySet<Integer> ignoreSet) {
         synchronized (mLock) {
             mInputSessionRequested = true;
-            userState = getCurrentUserStateLocked();
+            AccessibilityUserState userState = getCurrentUserStateLocked();
             for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
                 final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
                 if ((!ignoreSet.contains(service.mId)) && service.requestImeApis()) {
@@ -4455,10 +4474,15 @@
      * @param sessions Sessions to enable or disable.
      * @param enabled True if enable the sessions or false if disable the sessions.
      */
-    public void setImeSessionEnabled(SparseArray<IInputMethodSession> sessions, boolean enabled) {
-        AccessibilityUserState userState;
+    public void scheduleSetImeSessionEnabled(SparseArray<IInputMethodSession> sessions,
+            boolean enabled) {
+        mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::setImeSessionEnabled,
+                this, sessions, enabled));
+    }
+
+    private void setImeSessionEnabled(SparseArray<IInputMethodSession> sessions, boolean enabled) {
         synchronized (mLock) {
-            userState = getCurrentUserStateLocked();
+            AccessibilityUserState userState = getCurrentUserStateLocked();
             for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
                 final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
                 if (sessions.contains(service.mId) && service.requestImeApis()) {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
index e251bcc..c637045 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
@@ -18,7 +18,6 @@
 
 import static android.accessibilityservice.AccessibilityService.SoftKeyboardController.ENABLE_IME_FAIL_BY_ADMIN;
 import static android.accessibilityservice.AccessibilityService.SoftKeyboardController.ENABLE_IME_SUCCESS;
-import static android.content.pm.PackageManagerInternal.PACKAGE_INSTALLER;
 
 import android.Manifest;
 import android.accessibilityservice.AccessibilityService;
@@ -31,9 +30,7 @@
 import android.appwidget.AppWidgetManagerInternal;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.pm.InstallSourceInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
@@ -42,14 +39,12 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Slog;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.inputmethod.InputMethodInfo;
 
 import com.android.internal.util.ArrayUtils;
-import com.android.server.LocalServices;
 import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.settingslib.RestrictedLockUtils;
 
@@ -734,7 +729,7 @@
             final AccessibilityServiceInfo a11yServiceInfo = boundServices.get(
                     i).getServiceInfo();
             final ComponentName service = a11yServiceInfo.getComponentName().clone();
-            if (!isA11yCategoryService(a11yServiceInfo)) {
+            if (!a11yServiceInfo.isAccessibilityTool()) {
                 tempNonA11yCategoryServices.add(service);
                 if (mNonA11yCategoryServices.contains(service)) {
                     mNonA11yCategoryServices.remove(service);
@@ -794,69 +789,4 @@
 
         mPolicyWarningUIController.onEnabledServicesChangedLocked(userId, enabledServices);
     }
-
-    /**
-     * Identifies whether the accessibility service is true and designed for accessibility. An
-     * accessibility service is considered as accessibility category if meets all conditions below:
-     * <ul>
-     *     <li> {@link AccessibilityServiceInfo#isAccessibilityTool} is true</li>
-     *     <li> is installed from the trusted install source</li>
-     * </ul>
-     *
-     * @param serviceInfo The accessibility service's serviceInfo.
-     * @return Returns true if it is a true accessibility service.
-     */
-    public boolean isA11yCategoryService(AccessibilityServiceInfo serviceInfo) {
-        if (!serviceInfo.isAccessibilityTool()) {
-            return false;
-        }
-        if (!serviceInfo.getResolveInfo().serviceInfo.applicationInfo.isSystemApp()) {
-            return hasTrustedSystemInstallSource(
-                    serviceInfo.getResolveInfo().serviceInfo.packageName);
-        }
-        return true;
-    }
-
-    /** Returns true if the {@code installedPackage} is installed from the trusted install source.
-     */
-    private boolean hasTrustedSystemInstallSource(String installedPackage) {
-        try {
-            InstallSourceInfo installSourceInfo = mPackageManager.getInstallSourceInfo(
-                    installedPackage);
-            if (installSourceInfo == null) {
-                return false;
-            }
-            final String installSourcePackageName = installSourceInfo.getInitiatingPackageName();
-            if (installSourcePackageName == null || !mPackageManager.getPackageInfo(
-                    installSourcePackageName,
-                    0).applicationInfo.isSystemApp()) {
-                return false;
-            }
-            return isTrustedInstallSource(installSourcePackageName);
-        } catch (PackageManager.NameNotFoundException e) {
-            Slog.w(LOG_TAG, "can't find the package's install source:" + installedPackage);
-        }
-        return false;
-    }
-
-    /** Returns true if the {@code installerPackage} is a trusted install source. */
-    private boolean isTrustedInstallSource(String installerPackage) {
-        final String[] allowedInstallingSources = mContext.getResources().getStringArray(
-                com.android.internal.R.array
-                        .config_accessibility_allowed_install_source);
-
-        if (allowedInstallingSources.length == 0) {
-            //Filters unwanted default installers if no allowed install sources.
-            String defaultInstaller = ArrayUtils.firstOrNull(LocalServices.getService(
-                    PackageManagerInternal.class).getKnownPackageNames(PACKAGE_INSTALLER,
-                    mCurrentUserId));
-            return !TextUtils.equals(defaultInstaller, installerPackage);
-        }
-        for (int i = 0; i < allowedInstallingSources.length; i++) {
-            if (TextUtils.equals(allowedInstallingSources[i], installerPackage)) {
-                return true;
-            }
-        }
-        return false;
-    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
index 51b49ed..55dc196 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
@@ -37,6 +37,7 @@
 import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.Binder;
 import android.os.RemoteCallbackList;
 import android.provider.Settings;
@@ -123,8 +124,8 @@
     private int mInteractiveUiTimeout = 0;
     private int mLastSentClientState = -1;
 
-    /** {@code true} if the device config supports magnification area. */
-    private final boolean mSupportMagnificationArea;
+    /** {@code true} if the device config supports window magnification. */
+    private final boolean mSupportWindowMagnification;
     // The magnification modes on displays.
     private final SparseIntArray mMagnificationModes = new SparseIntArray();
     // The magnification capabilities used to know magnification mode could be switched.
@@ -148,7 +149,7 @@
 
     boolean isValidMagnificationModeLocked(int displayId) {
         final int mode = getMagnificationModeLocked(displayId);
-        if (!mSupportMagnificationArea
+        if (!mSupportWindowMagnification
                 && mode == Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) {
             return false;
         }
@@ -170,8 +171,9 @@
                 R.color.accessibility_focus_highlight_color);
         mFocusStrokeWidth = mFocusStrokeWidthDefaultValue;
         mFocusColor = mFocusColorDefaultValue;
-        mSupportMagnificationArea = mContext.getResources().getBoolean(
-                R.bool.config_magnification_area);
+        mSupportWindowMagnification = mContext.getResources().getBoolean(
+                R.bool.config_magnification_area) && mContext.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_WINDOW_MAGNIFICATION);
     }
 
     boolean isHandlingAccessibilityEventsLocked() {
diff --git a/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java b/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java
index 5080ca2..7c12ece 100644
--- a/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java
+++ b/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java
@@ -270,7 +270,7 @@
                 final AccessibilityServiceInfo a11yServiceInfo = enabledServiceInfos.get(i);
                 if (componentName.flattenToShortString().equals(
                         a11yServiceInfo.getComponentName().flattenToShortString())) {
-                    if (!mAccessibilitySecurityPolicy.isA11yCategoryService(a11yServiceInfo)
+                    if (!a11yServiceInfo.isAccessibilityTool()
                             && !mNotifiedA11yServices.contains(componentName)) {
                         final CharSequence displayName =
                                 a11yServiceInfo.getResolveInfo().serviceInfo.loadLabel(
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index e20b15a..6846b2e 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -1006,12 +1006,10 @@
                 }
                 break;
             case ACTION_POINTER_UP:
-                if (event.getPointerId(GestureUtils.getActionIndex(event)) == mDraggingPointerId) {
                     mDraggingPointerId = INVALID_POINTER_ID;
                     // Send an event to the end of the drag gesture.
                     mDispatcher.sendMotionEvent(
                             event, ACTION_UP, rawEvent, pointerIdBits, policyFlags);
-                }
                 break;
             case ACTION_UP:
                 if (event.getPointerId(GestureUtils.getActionIndex(event)) == mDraggingPointerId) {
@@ -1146,6 +1144,10 @@
      * closet to an edge of the screen.
      */
     private void computeDraggingPointerIdIfNeeded(MotionEvent event) {
+        if (event.getPointerCount() != 2) {
+            mDraggingPointerId = INVALID_POINTER_ID;
+            return;
+        }
         if (mDraggingPointerId != INVALID_POINTER_ID) {
             // If we have a valid pointer ID, we should be good
             final int pointerIndex = event.findPointerIndex(mDraggingPointerId);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
index fa32452..ecc45eb 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
@@ -18,6 +18,7 @@
 
 import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL;
 import static android.accessibilityservice.MagnificationConfig.MAGNIFICATION_MODE_FULLSCREEN;
+import static android.util.TypedValue.COMPLEX_UNIT_DIP;
 import static android.view.accessibility.MagnificationAnimationCallback.STUB_ANIMATION_CALLBACK;
 
 import static com.android.server.accessibility.AccessibilityManagerService.INVALID_SERVICE_ID;
@@ -31,15 +32,20 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.res.CompatibilityInfo;
 import android.graphics.Rect;
 import android.graphics.Region;
+import android.hardware.display.DisplayManagerInternal;
 import android.os.Handler;
 import android.os.Message;
 import android.text.TextUtils;
+import android.util.DisplayMetrics;
 import android.util.MathUtils;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.TypedValue;
 import android.view.Display;
+import android.view.DisplayInfo;
 import android.view.MagnificationSpec;
 import android.view.View;
 import android.view.accessibility.MagnificationAnimationCallback;
@@ -93,6 +99,8 @@
     // Whether the following typing focus feature for magnification is enabled.
     private boolean mMagnificationFollowTypingEnabled = true;
 
+    private final DisplayManagerInternal mDisplayManagerInternal;
+
     /**
      * This class implements {@link WindowManagerInternal.MagnificationCallbacks} and holds
      * magnification information per display.
@@ -395,6 +403,18 @@
             outRegion.set(mMagnificationRegion);
         }
 
+        private DisplayMetrics getDisplayMetricsForId() {
+            final DisplayMetrics outMetrics = new DisplayMetrics();
+            final DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
+            if (displayInfo != null) {
+                displayInfo.getLogicalMetrics(outMetrics,
+                        CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+            } else {
+                outMetrics.setToDefaults();
+            }
+            return outMetrics;
+        }
+
         void requestRectangleOnScreen(int left, int top, int right, int bottom) {
             synchronized (mLock) {
                 final Rect magnifiedFrame = mTempRect;
@@ -408,6 +428,12 @@
 
                 final float scrollX;
                 final float scrollY;
+                // We offset an additional distance for a user to know the surrounding context.
+                DisplayMetrics metrics = getDisplayMetricsForId();
+                final float offsetViewportX = (float) magnifFrameInScreenCoords.width() / 4;
+                final float offsetViewportY =
+                        TypedValue.applyDimension(COMPLEX_UNIT_DIP, 10, metrics);
+
                 if (right - left > magnifFrameInScreenCoords.width()) {
                     final int direction = TextUtils
                             .getLayoutDirectionFromLocale(Locale.getDefault());
@@ -417,9 +443,9 @@
                         scrollX = right - magnifFrameInScreenCoords.right;
                     }
                 } else if (left < magnifFrameInScreenCoords.left) {
-                    scrollX = left - magnifFrameInScreenCoords.left;
+                    scrollX = left - magnifFrameInScreenCoords.left - offsetViewportX;
                 } else if (right > magnifFrameInScreenCoords.right) {
-                    scrollX = right - magnifFrameInScreenCoords.right;
+                    scrollX = right - magnifFrameInScreenCoords.right + offsetViewportX;
                 } else {
                     scrollX = 0;
                 }
@@ -427,9 +453,9 @@
                 if (bottom - top > magnifFrameInScreenCoords.height()) {
                     scrollY = top - magnifFrameInScreenCoords.top;
                 } else if (top < magnifFrameInScreenCoords.top) {
-                    scrollY = top - magnifFrameInScreenCoords.top;
+                    scrollY = top - magnifFrameInScreenCoords.top - offsetViewportY;
                 } else if (bottom > magnifFrameInScreenCoords.bottom) {
-                    scrollY = bottom - magnifFrameInScreenCoords.bottom;
+                    scrollY = bottom - magnifFrameInScreenCoords.bottom + offsetViewportY;
                 } else {
                     scrollY = 0;
                 }
@@ -687,6 +713,7 @@
         mScreenStateObserver = new ScreenStateObserver(mControllerCtx.getContext(), this);
         mMagnificationInfoChangedCallback = magnificationInfoChangedCallback;
         mScaleProvider = scaleProvider;
+        mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
     }
 
     /**
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/GesturesObserver.java b/services/accessibility/java/com/android/server/accessibility/magnification/GesturesObserver.java
index 3d8f5173..a5c8837 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/GesturesObserver.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/GesturesObserver.java
@@ -114,7 +114,7 @@
      * Clears all states to default.
      */
     @MainThread
-    public void clear() {
+    private void clear() {
         for (GestureMatcher matcher : mGestureMatchers) {
             matcher.clear();
         }
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java
index 085c343..23cded7 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java
@@ -133,7 +133,7 @@
         mDelayedEventQueue = null;
         mCallback.onGestureCompleted(gestureId, mLastDownEventTime, delayEventQueue,
                 event);
-        recycleLastEvent();
+        clear();
     }
 
     @Override
@@ -149,19 +149,18 @@
         mDelayedEventQueue = null;
         mCallback.onGestureCancelled(mLastDownEventTime, delayEventQueue,
                 mLastEvent);
-        recycleLastEvent();
+        clear();
     }
 
     /**
      * Resets all state to default.
      */
-    void clear() {
+    private void clear() {
         if (DBG) {
             Slog.d(LOG_TAG, "clear:" + mDelayedEventQueue);
         }
         recycleLastEvent();
         mLastDownEventTime = 0;
-        mGesturesObserver.clear();
         if (mDelayedEventQueue != null) {
             for (MotionEventInfo eventInfo2: mDelayedEventQueue) {
                 eventInfo2.recycle();
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
index 820be28..9ff51ee 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
@@ -440,21 +440,11 @@
         }
 
         @Override
-        public void onExit() {
-            clear();
-        }
-
-        @Override
         public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
             mGesturesObserver.onMotionEvent(event, rawEvent, policyFlags);
         }
 
         @Override
-        public void clear() {
-            mGesturesObserver.clear();
-        }
-
-        @Override
         public String toString() {
             return "DetectingState{"
                     + ", mGestureTimeoutObserver =" + mGesturesObserver
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
index aeb1112..ca116e3 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -108,6 +108,17 @@
     private @interface ConnectionState {
     }
 
+    private static String connectionStateToString(@ConnectionState int state) {
+        switch (state) {
+            case CONNECTING: return "CONNECTING";
+            case CONNECTED: return "CONNECTED";
+            case DISCONNECTING: return "DISCONNECTING";
+            case DISCONNECTED: return "DISCONNECTED";
+            default:
+                return "UNKNOWN:" + state;
+        }
+    }
+
     @ConnectionState
     private int mConnectionState = DISCONNECTED;
 
@@ -205,7 +216,8 @@
      */
     public void setConnection(@Nullable IWindowMagnificationConnection connection) {
         if (DBG) {
-            Slog.d(TAG, "setConnection :" + connection + " ,mConnectionState=" + mConnectionState);
+            Slog.d(TAG, "setConnection :" + connection + ", mConnectionState="
+                    + connectionStateToString(mConnectionState));
         }
         synchronized (mLock) {
             // Reset connectionWrapper.
@@ -275,9 +287,8 @@
             if ((connect && (mConnectionState == CONNECTED || mConnectionState == CONNECTING))
                     || (!connect && (mConnectionState == DISCONNECTED
                     || mConnectionState == DISCONNECTING))) {
-                Slog.w(TAG,
-                        "requestConnection duplicated request: connect=" + connect
-                                + " ,mConnectionState=" + mConnectionState);
+                Slog.w(TAG, "requestConnection duplicated request: connect=" + connect
+                        + ", mConnectionState=" + connectionStateToString(mConnectionState));
                 return false;
             }
 
@@ -321,14 +332,14 @@
     /**
      * Returns window magnification connection state.
      */
-    public int getConnectionState() {
-        return mConnectionState;
+    public String getConnectionState() {
+        return connectionStateToString(mConnectionState);
     }
 
     private void setConnectionState(@ConnectionState int state) {
         if (DBG) {
-            Slog.d(TAG, "setConnectionState : state=" + state + " ,mConnectionState="
-                    + mConnectionState);
+            Slog.d(TAG, "setConnectionState : state=" + state + ", mConnectionState="
+                    + connectionStateToString(mConnectionState));
         }
         mConnectionState = state;
     }
@@ -1114,7 +1125,7 @@
         if (mConnectionWrapper == null) {
             Slog.w(TAG,
                     "enableWindowMagnificationInternal mConnectionWrapper is null. "
-                            + "mConnectionState=" + mConnectionState);
+                            + "mConnectionState=" + connectionStateToString(mConnectionState));
             return false;
         }
         return mConnectionWrapper.enableWindowMagnification(
diff --git a/services/api/current.txt b/services/api/current.txt
index 45c0059..780fccf 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -38,7 +38,7 @@
 package com.android.server.am {
 
   public interface ActivityManagerLocal {
-    method public boolean bindSdkSandboxService(@NonNull android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull String, int) throws android.os.RemoteException;
+    method public boolean bindSdkSandboxService(@NonNull android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull String, @NonNull String, int) throws android.os.RemoteException;
     method public boolean canStartForegroundService(int, int, @NonNull String);
   }
 
@@ -47,6 +47,9 @@
 package com.android.server.pm {
 
   public interface PackageManagerLocal {
+    method public void reconcileSdkData(@Nullable String, @NonNull String, @NonNull java.util.List<java.lang.String>, int, int, int, @NonNull String, int) throws java.io.IOException;
+    field public static final int FLAG_STORAGE_CE = 2; // 0x2
+    field public static final int FLAG_STORAGE_DE = 1; // 0x1
   }
 
 }
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index a65d5b3..312105a 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -1617,14 +1617,17 @@
             final int providerCount = mProviders.size();
             for (int i = 0; i < providerCount; i++) {
                 Provider provider = mProviders.get(i);
-                AppWidgetProviderInfo info = provider.getInfoLocked(mContext);
                 final String providerPackageName = provider.id.componentName.getPackageName();
 
-                // Ignore an invalid provider, one not matching the filter,
-                // or one that isn't in the given package, if any.
-                boolean inPackage = packageName == null
-                        || providerPackageName.equals(packageName);
-                if (provider.zombie || (info.widgetCategory & categoryFilter) == 0 || !inPackage) {
+                // Ignore an invalid provider or one that isn't in the given package, if any.
+                boolean inPackage = packageName == null || providerPackageName.equals(packageName);
+                if (provider.zombie || !inPackage) {
+                    continue;
+                }
+
+                // Ignore the ones not matching the filter.
+                AppWidgetProviderInfo info = provider.getInfoLocked(mContext);
+                if ((info.widgetCategory & categoryFilter) == 0) {
                     continue;
                 }
 
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 1cff374..8c4db70 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -16,6 +16,8 @@
 
 package com.android.server.autofill;
 
+import static android.service.autofill.FillEventHistory.Event.NO_SAVE_UI_REASON_NONE;
+import static android.service.autofill.FillEventHistory.Event.UI_TYPE_INLINE;
 import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
 import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
 import static android.view.autofill.AutofillManager.FLAG_ADD_CLIENT_ENABLED;
@@ -816,12 +818,13 @@
     /**
      * Updates the last fill response when a dataset is shown.
      */
-    void logDatasetShown(int sessionId, @Nullable Bundle clientState) {
+    void logDatasetShown(int sessionId, @Nullable Bundle clientState, int presentationType) {
         synchronized (mLock) {
             if (isValidEventLocked("logDatasetShown", sessionId)) {
                 mEventHistory.addEvent(
                         new Event(Event.TYPE_DATASETS_SHOWN, null, clientState, null, null, null,
-                                null, null, null, null, null));
+                                null, null, null, null, null, NO_SAVE_UI_REASON_NONE,
+                                presentationType));
             }
         }
     }
@@ -858,9 +861,12 @@
                     || mAugmentedAutofillEventHistory.getSessionId() != sessionId) {
                 return;
             }
+            // Augmented Autofill only logs for inline now, so set UI_TYPE_INLINE here.
+            // Ideally should not hardcode here and should also log for menu presentation.
             mAugmentedAutofillEventHistory.addEvent(
                     new Event(Event.TYPE_DATASETS_SHOWN, null, clientState, null, null, null,
-                            null, null, null, null, null));
+                            null, null, null, null, null, NO_SAVE_UI_REASON_NONE,
+                            UI_TYPE_INLINE));
 
         }
     }
diff --git a/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java b/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java
deleted file mode 100644
index 715697d..0000000
--- a/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.autofill;
-
-import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
-
-import static com.android.server.autofill.Helper.sVerbose;
-
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.app.AppGlobals;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.ICancellationSignal;
-import android.os.RemoteException;
-import android.service.autofill.Dataset;
-import android.service.autofill.FillResponse;
-import android.service.autofill.IFillCallback;
-import android.service.autofill.SaveInfo;
-import android.text.TextUtils;
-import android.text.format.DateUtils;
-import android.util.Slog;
-import android.view.autofill.AutofillId;
-import android.view.autofill.IAutoFillManagerClient;
-import android.view.inputmethod.InlineSuggestionsRequest;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.infra.AndroidFuture;
-
-import java.util.List;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Maintains a client suggestions session with the
- * {@link android.view.autofill.AutofillRequestCallback} through the {@link IAutoFillManagerClient}.
- *
- */
-final class ClientSuggestionsSession {
-
-    private static final String TAG = "ClientSuggestionsSession";
-    private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 15 * DateUtils.SECOND_IN_MILLIS;
-
-    private final int mSessionId;
-    private final IAutoFillManagerClient mClient;
-    private final Handler mHandler;
-    private final ComponentName mComponentName;
-
-    private final RemoteFillService.FillServiceCallbacks mCallbacks;
-
-    private final Object mLock = new Object();
-    @GuardedBy("mLock")
-    private AndroidFuture<FillResponse> mPendingFillRequest;
-    @GuardedBy("mLock")
-    private int mPendingFillRequestId = INVALID_REQUEST_ID;
-
-    ClientSuggestionsSession(int sessionId, IAutoFillManagerClient client, Handler handler,
-            ComponentName componentName, RemoteFillService.FillServiceCallbacks callbacks) {
-        mSessionId = sessionId;
-        mClient = client;
-        mHandler = handler;
-        mComponentName = componentName;
-        mCallbacks = callbacks;
-    }
-
-    void onFillRequest(int requestId, InlineSuggestionsRequest inlineRequest, int flags) {
-        final AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>();
-        final AtomicReference<AndroidFuture<FillResponse>> futureRef = new AtomicReference<>();
-        final AndroidFuture<FillResponse> fillRequest = new AndroidFuture<>();
-
-        mHandler.post(() -> {
-            if (sVerbose) {
-                Slog.v(TAG, "calling onFillRequest() for id=" + requestId);
-            }
-
-            try {
-                mClient.requestFillFromClient(requestId, inlineRequest,
-                        new FillCallbackImpl(fillRequest, futureRef, cancellationSink));
-            } catch (RemoteException e) {
-                fillRequest.completeExceptionally(e);
-            }
-        });
-
-        fillRequest.orTimeout(TIMEOUT_REMOTE_REQUEST_MILLIS, TimeUnit.MILLISECONDS);
-        futureRef.set(fillRequest);
-
-        synchronized (mLock) {
-            mPendingFillRequest = fillRequest;
-            mPendingFillRequestId = requestId;
-        }
-
-        fillRequest.whenComplete((res, err) -> mHandler.post(() -> {
-            synchronized (mLock) {
-                mPendingFillRequest = null;
-                mPendingFillRequestId = INVALID_REQUEST_ID;
-            }
-            if (err == null) {
-                processAutofillId(res);
-                mCallbacks.onFillRequestSuccess(requestId, res,
-                        mComponentName.getPackageName(), flags);
-            } else {
-                Slog.e(TAG, "Error calling on  client fill request", err);
-                if (err instanceof TimeoutException) {
-                    dispatchCancellationSignal(cancellationSink.get());
-                    mCallbacks.onFillRequestTimeout(requestId);
-                } else if (err instanceof CancellationException) {
-                    dispatchCancellationSignal(cancellationSink.get());
-                } else {
-                    mCallbacks.onFillRequestFailure(requestId, err.getMessage());
-                }
-            }
-        }));
-    }
-
-    /**
-     * Gets the application info for the component.
-     */
-    @Nullable
-    static ApplicationInfo getAppInfo(ComponentName comp, @UserIdInt int userId) {
-        try {
-            ApplicationInfo si = AppGlobals.getPackageManager().getApplicationInfo(
-                    comp.getPackageName(),
-                    PackageManager.GET_META_DATA,
-                    userId);
-            if (si != null) {
-                return si;
-            }
-        } catch (RemoteException e) {
-        }
-        return null;
-    }
-
-    /**
-     * Gets the user-visible name of the application.
-     */
-    @Nullable
-    @GuardedBy("mLock")
-    static CharSequence getAppLabelLocked(Context context, ApplicationInfo appInfo) {
-        return appInfo == null ? null : appInfo.loadSafeLabel(
-                context.getPackageManager(), 0 /* do not ellipsize */,
-                TextUtils.SAFE_STRING_FLAG_FIRST_LINE | TextUtils.SAFE_STRING_FLAG_TRIM);
-    }
-
-    /**
-     * Gets the user-visible icon of the application.
-     */
-    @Nullable
-    @GuardedBy("mLock")
-    static Drawable getAppIconLocked(Context context, ApplicationInfo appInfo) {
-        return appInfo == null ? null : appInfo.loadIcon(context.getPackageManager());
-    }
-
-    int cancelCurrentRequest() {
-        synchronized (mLock) {
-            return mPendingFillRequest != null && mPendingFillRequest.cancel(false)
-                    ? mPendingFillRequestId
-                    : INVALID_REQUEST_ID;
-        }
-    }
-
-    /**
-     * The {@link AutofillId} which the client gets from its view is not contain the session id,
-     * but Autofill framework is using the {@link AutofillId} with a session id. So before using
-     * those ids in the Autofill framework, applies the current session id.
-     *
-     * @param res which response need to apply for a session id
-     */
-    private void processAutofillId(FillResponse res) {
-        if (res == null) {
-            return;
-        }
-
-        final List<Dataset> datasets = res.getDatasets();
-        if (datasets != null && !datasets.isEmpty()) {
-            for (int i = 0; i < datasets.size(); i++) {
-                final Dataset dataset = datasets.get(i);
-                if (dataset != null) {
-                    applySessionId(dataset.getFieldIds());
-                }
-            }
-        }
-
-        final SaveInfo saveInfo = res.getSaveInfo();
-        if (saveInfo != null) {
-            applySessionId(saveInfo.getOptionalIds());
-            applySessionId(saveInfo.getRequiredIds());
-            applySessionId(saveInfo.getSanitizerValues());
-            applySessionId(saveInfo.getTriggerId());
-        }
-    }
-
-    private void applySessionId(List<AutofillId> ids) {
-        if (ids == null || ids.isEmpty()) {
-            return;
-        }
-
-        for (int i = 0; i < ids.size(); i++) {
-            applySessionId(ids.get(i));
-        }
-    }
-
-    private void applySessionId(AutofillId[][] ids) {
-        if (ids == null) {
-            return;
-        }
-        for (int i = 0; i < ids.length; i++) {
-            applySessionId(ids[i]);
-        }
-    }
-
-    private void applySessionId(AutofillId[] ids) {
-        if (ids == null) {
-            return;
-        }
-        for (int i = 0; i < ids.length; i++) {
-            applySessionId(ids[i]);
-        }
-    }
-
-    private void applySessionId(AutofillId id) {
-        if (id == null) {
-            return;
-        }
-        id.setSessionId(mSessionId);
-    }
-
-    private void dispatchCancellationSignal(@Nullable ICancellationSignal signal) {
-        if (signal == null) {
-            return;
-        }
-        try {
-            signal.cancel();
-        } catch (RemoteException e) {
-            Slog.e(TAG, "Error requesting a cancellation", e);
-        }
-    }
-
-    private class FillCallbackImpl extends IFillCallback.Stub {
-        final AndroidFuture<FillResponse> mFillRequest;
-        final AtomicReference<AndroidFuture<FillResponse>> mFutureRef;
-        final AtomicReference<ICancellationSignal> mCancellationSink;
-
-        FillCallbackImpl(AndroidFuture<FillResponse> fillRequest,
-                AtomicReference<AndroidFuture<FillResponse>> futureRef,
-                AtomicReference<ICancellationSignal> cancellationSink) {
-            mFillRequest = fillRequest;
-            mFutureRef = futureRef;
-            mCancellationSink = cancellationSink;
-        }
-
-        @Override
-        public void onCancellable(ICancellationSignal cancellation) {
-            AndroidFuture<FillResponse> future = mFutureRef.get();
-            if (future != null && future.isCancelled()) {
-                dispatchCancellationSignal(cancellation);
-            } else {
-                mCancellationSink.set(cancellation);
-            }
-        }
-
-        @Override
-        public void onSuccess(FillResponse response) {
-            mFillRequest.complete(response);
-        }
-
-        @Override
-        public void onFailure(int requestId, CharSequence message) {
-            String errorMessage = message == null ? "" : String.valueOf(message);
-            mFillRequest.completeExceptionally(
-                    new RuntimeException(errorMessage));
-        }
-    }
-}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index e0fa67f..75b6554 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -18,9 +18,12 @@
 
 import static android.service.autofill.AutofillFieldClassificationService.EXTRA_SCORES;
 import static android.service.autofill.AutofillService.EXTRA_FILL_RESPONSE;
-import static android.service.autofill.FillRequest.FLAG_ACTIVITY_START;
+import static android.service.autofill.FillEventHistory.Event.UI_TYPE_DIALOG;
+import static android.service.autofill.FillEventHistory.Event.UI_TYPE_INLINE;
+import static android.service.autofill.FillEventHistory.Event.UI_TYPE_MENU;
 import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
 import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
+import static android.service.autofill.FillRequest.FLAG_SUPPORTS_FILL_DIALOG;
 import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED;
 import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
 import static android.view.autofill.AutofillManager.ACTION_RESPONSE_EXPIRED;
@@ -28,7 +31,6 @@
 import static android.view.autofill.AutofillManager.ACTION_VALUE_CHANGED;
 import static android.view.autofill.AutofillManager.ACTION_VIEW_ENTERED;
 import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED;
-import static android.view.autofill.AutofillManager.FLAG_ENABLED_CLIENT_SUGGESTIONS;
 import static android.view.autofill.AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM;
 import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString;
 
@@ -59,7 +61,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
-import android.content.pm.ApplicationInfo;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -363,9 +364,6 @@
      */
     private final AssistDataReceiverImpl mAssistReceiver = new AssistDataReceiverImpl();
 
-    @Nullable
-    private ClientSuggestionsSession mClientSuggestionsSession;
-
     // TODO(b/216576510): Share one BroadcastReceiver between all Sessions instead of creating a
     // new one per Session.
     private final BroadcastReceiver mDelayedFillBroadcastReceiver =
@@ -458,9 +456,6 @@
         /** Whether the current {@link FillResponse} is expired. */
         private boolean mExpiredResponse;
 
-        /** Whether the client is using {@link android.view.autofill.AutofillRequestCallback}. */
-        private boolean mClientSuggestionsEnabled;
-
         /** Whether the fill dialog UI is disabled. */
         private boolean mFillDialogDisabled;
     }
@@ -491,21 +486,14 @@
                     }
                     mWaitForInlineRequest = inlineSuggestionsRequest != null;
                     mPendingInlineSuggestionsRequest = inlineSuggestionsRequest;
-                    mWaitForInlineRequest = inlineSuggestionsRequest != null;
-                    maybeRequestFillFromServiceLocked();
+                    maybeRequestFillLocked();
                     viewState.resetState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
                 }
             } : null;
         }
 
-        void newAutofillRequestLocked(@Nullable InlineSuggestionsRequest inlineRequest) {
-            mPendingFillRequest = null;
-            mWaitForInlineRequest = inlineRequest != null;
-            mPendingInlineSuggestionsRequest = inlineRequest;
-        }
-
         @GuardedBy("mLock")
-        void maybeRequestFillFromServiceLocked() {
+        void maybeRequestFillLocked() {
             if (mPendingFillRequest == null) {
                 return;
             }
@@ -515,14 +503,10 @@
                     return;
                 }
 
-                if (mPendingInlineSuggestionsRequest.isServiceSupported()) {
-                    mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
-                            mPendingFillRequest.getFillContexts(),
-                            mPendingFillRequest.getClientState(),
-                            mPendingFillRequest.getFlags(),
-                            mPendingInlineSuggestionsRequest,
-                            mPendingFillRequest.getDelayedFillIntentSender());
-                }
+                mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
+                        mPendingFillRequest.getFillContexts(), mPendingFillRequest.getClientState(),
+                        mPendingFillRequest.getFlags(), mPendingInlineSuggestionsRequest,
+                        mPendingFillRequest.getDelayedFillIntentSender());
             }
             mLastFillRequest = mPendingFillRequest;
 
@@ -634,7 +618,7 @@
                             : mDelayedFillPendingIntent.getIntentSender());
 
                 mPendingFillRequest = request;
-                maybeRequestFillFromServiceLocked();
+                maybeRequestFillLocked();
             }
 
             if (mActivityToken != null) {
@@ -859,39 +843,30 @@
     }
 
     /**
-     * Cancels the last request sent to the {@link #mRemoteFillService} or the
-     * {@link #mClientSuggestionsSession}.
+     * Cancels the last request sent to the {@link #mRemoteFillService}.
      */
     @GuardedBy("mLock")
     private void cancelCurrentRequestLocked() {
-        if (mRemoteFillService == null && mClientSuggestionsSession == null) {
-            wtf(null, "cancelCurrentRequestLocked() called without a remote service or a "
-                    + "client suggestions session.  mForAugmentedAutofillOnly: %s",
-                    mSessionFlags.mAugmentedAutofillOnly);
+        if (mRemoteFillService == null) {
+            wtf(null, "cancelCurrentRequestLocked() called without a remote service. "
+                    + "mForAugmentedAutofillOnly: %s", mSessionFlags.mAugmentedAutofillOnly);
             return;
         }
+        final int canceledRequest = mRemoteFillService.cancelCurrentRequest();
 
-        if (mRemoteFillService != null) {
-            final int canceledRequest = mRemoteFillService.cancelCurrentRequest();
+        // Remove the FillContext as there will never be a response for the service
+        if (canceledRequest != INVALID_REQUEST_ID && mContexts != null) {
+            final int numContexts = mContexts.size();
 
-            // Remove the FillContext as there will never be a response for the service
-            if (canceledRequest != INVALID_REQUEST_ID && mContexts != null) {
-                final int numContexts = mContexts.size();
-
-                // It is most likely the last context, hence search backwards
-                for (int i = numContexts - 1; i >= 0; i--) {
-                    if (mContexts.get(i).getRequestId() == canceledRequest) {
-                        if (sDebug) Slog.d(TAG, "cancelCurrentRequest(): id = " + canceledRequest);
-                        mContexts.remove(i);
-                        break;
-                    }
+            // It is most likely the last context, hence search backwards
+            for (int i = numContexts - 1; i >= 0; i--) {
+                if (mContexts.get(i).getRequestId() == canceledRequest) {
+                    if (sDebug) Slog.d(TAG, "cancelCurrentRequest(): id = " + canceledRequest);
+                    mContexts.remove(i);
+                    break;
                 }
             }
         }
-
-        if (mClientSuggestionsSession != null) {
-            mClientSuggestionsSession.cancelCurrentRequest();
-        }
     }
 
     private boolean isViewFocusedLocked(int flags) {
@@ -956,30 +931,17 @@
         // structure is taken. This causes only one fill request per burst of focus changes.
         cancelCurrentRequestLocked();
 
-        // Only ask IME to create inline suggestions request when
-        // 1. Autofill provider supports it or client enabled client suggestions.
-        // 2. The render service is available.
-        // 3. The view is focused. (The view may not be focused if the autofill is triggered
-        //    manually.)
+        // Only ask IME to create inline suggestions request if Autofill provider supports it and
+        // the render service is available except the autofill is triggered manually and the view
+        // is also not focused.
         final RemoteInlineSuggestionRenderService remoteRenderService =
                 mService.getRemoteInlineSuggestionRenderServiceLocked();
-        if ((mSessionFlags.mInlineSupportedByService || mSessionFlags.mClientSuggestionsEnabled)
+        if (mSessionFlags.mInlineSupportedByService
                 && remoteRenderService != null
-                && (isViewFocusedLocked(flags) || (isRequestFromActivityStarted(flags)))) {
-            final Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer;
-            if (mSessionFlags.mClientSuggestionsEnabled) {
-                final int finalRequestId = requestId;
-                inlineSuggestionsRequestConsumer = (inlineSuggestionsRequest) -> {
-                    // Using client suggestions
-                    synchronized (mLock) {
-                        onClientFillRequestLocked(finalRequestId, inlineSuggestionsRequest);
-                    }
-                    viewState.resetState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
-                };
-            } else {
-                inlineSuggestionsRequestConsumer = mAssistReceiver.newAutofillRequestLocked(
-                        viewState, /* isInlineRequest= */ true);
-            }
+                && (isViewFocusedLocked(flags) || isRequestSupportFillDialog(flags))) {
+            Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer =
+                    mAssistReceiver.newAutofillRequestLocked(viewState,
+                            /* isInlineRequest= */ true);
             if (inlineSuggestionsRequestConsumer != null) {
                 final AutofillId focusedId = mCurrentViewId;
                 final int requestIdCopy = requestId;
@@ -995,24 +957,16 @@
                 );
                 viewState.setState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
             }
-        } else if (mSessionFlags.mClientSuggestionsEnabled) {
-            // Request client suggestions for the dropdown mode
-            onClientFillRequestLocked(requestId, null);
         } else {
             mAssistReceiver.newAutofillRequestLocked(viewState, /* isInlineRequest= */ false);
         }
 
-        if (mSessionFlags.mClientSuggestionsEnabled) {
-            // Using client suggestions, unnecessary request AssistStructure
-            return;
-        }
-
         // Now request the assist structure data.
         requestAssistStructureLocked(requestId, flags);
     }
 
-    private boolean isRequestFromActivityStarted(int flags) {
-        return (flags & FLAG_ACTIVITY_START) != 0;
+    private boolean isRequestSupportFillDialog(int flags) {
+        return (flags & FLAG_SUPPORTS_FILL_DIALOG) != 0;
     }
 
     @GuardedBy("mLock")
@@ -1066,13 +1020,10 @@
         mComponentName = componentName;
         mCompatMode = compatMode;
         mSessionState = STATE_ACTIVE;
-
         synchronized (mLock) {
             mSessionFlags = new SessionFlags();
             mSessionFlags.mAugmentedAutofillOnly = forAugmentedAutofillOnly;
             mSessionFlags.mInlineSupportedByService = mService.isInlineSuggestionsEnabledLocked();
-            mSessionFlags.mClientSuggestionsEnabled =
-                    (mFlags & FLAG_ENABLED_CLIENT_SUGGESTIONS) != 0;
             setClientLocked(client);
         }
 
@@ -1184,13 +1135,12 @@
                 if (requestLog != null) {
                     requestLog.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, -1);
                 }
-                processNullResponseOrFallbackLocked(requestId, requestFlags);
+                processNullResponseLocked(requestId, requestFlags);
                 return;
             }
 
             fieldClassificationIds = response.getFieldClassificationIds();
-            if (!mSessionFlags.mClientSuggestionsEnabled && fieldClassificationIds != null
-                    && !mService.isFieldClassificationEnabledLocked()) {
+            if (fieldClassificationIds != null && !mService.isFieldClassificationEnabledLocked()) {
                 Slog.w(TAG, "Ignoring " + response + " because field detection is disabled");
                 processNullResponseLocked(requestId, requestFlags);
                 return;
@@ -1275,26 +1225,6 @@
         }
     }
 
-    @GuardedBy("mLock")
-    private void processNullResponseOrFallbackLocked(int requestId, int flags) {
-        if (!mSessionFlags.mClientSuggestionsEnabled) {
-            processNullResponseLocked(requestId, flags);
-            return;
-        }
-
-        // fallback to the default platform password manager
-        mSessionFlags.mClientSuggestionsEnabled = false;
-
-        final InlineSuggestionsRequest inlineRequest =
-                (mLastInlineSuggestionsRequest != null
-                        && mLastInlineSuggestionsRequest.first == requestId)
-                        ? mLastInlineSuggestionsRequest.second : null;
-        mAssistReceiver.newAutofillRequestLocked(inlineRequest);
-        requestAssistStructureLocked(requestId,
-                flags & ~FLAG_ENABLED_CLIENT_SUGGESTIONS);
-        return;
-    }
-
     // FillServiceCallbacks
     @Override
     public void onFillRequestFailure(int requestId, @Nullable CharSequence message) {
@@ -3002,7 +2932,7 @@
                 // View is triggering autofill.
                 mCurrentViewId = viewState.id;
                 viewState.update(value, virtualBounds, flags);
-                if (!isRequestFromActivityStarted(flags)) {
+                if (!isRequestSupportFillDialog(flags)) {
                     mSessionFlags.mFillDialogDisabled = true;
                 }
                 requestNewFillResponseLocked(viewState, ViewState.STATE_STARTED_SESSION, flags);
@@ -3266,22 +3196,13 @@
             filterText = value.getTextValue().toString();
         }
 
-        final CharSequence targetLabel;
-        final Drawable targetIcon;
+        final CharSequence serviceLabel;
+        final Drawable serviceIcon;
         synchronized (mLock) {
-            if (mSessionFlags.mClientSuggestionsEnabled) {
-                final ApplicationInfo appInfo = ClientSuggestionsSession.getAppInfo(mComponentName,
-                        mService.getUserId());
-                targetLabel = ClientSuggestionsSession.getAppLabelLocked(
-                        mService.getMaster().getContext(), appInfo);
-                targetIcon = ClientSuggestionsSession.getAppIconLocked(
-                        mService.getMaster().getContext(), appInfo);
-            } else {
-                targetLabel = mService.getServiceLabelLocked();
-                targetIcon = mService.getServiceIconLocked();
-            }
+            serviceLabel = mService.getServiceLabelLocked();
+            serviceIcon = mService.getServiceIconLocked();
         }
-        if (targetLabel == null || targetIcon == null) {
+        if (serviceLabel == null || serviceIcon == null) {
             wtf(null, "onFillReady(): no service label or icon");
             return;
         }
@@ -3290,7 +3211,7 @@
             synchronized (mLock) {
                 final ViewState currentView = mViewStates.get(mCurrentViewId);
                 currentView.setState(ViewState.STATE_FILL_DIALOG_SHOWN);
-                mService.logDatasetShown(id, mClientState);
+                mService.logDatasetShown(id, mClientState, UI_TYPE_DIALOG);
             }
             return;
         }
@@ -3304,7 +3225,7 @@
                     currentView.setState(ViewState.STATE_INLINE_SHOWN);
                     //TODO(b/137800469): Fix it to log showed only when IME asks for inflation,
                     // rather than here where framework sends back the response.
-                    mService.logDatasetShown(id, mClientState);
+                    mService.logDatasetShown(id, mClientState, UI_TYPE_INLINE);
                     return;
                 }
             }
@@ -3312,9 +3233,11 @@
 
         getUiForShowing().showFillUi(filledId, response, filterText,
                 mService.getServicePackageName(), mComponentName,
-                targetLabel, targetIcon, this, id, mCompatMode);
+                serviceLabel, serviceIcon, this, id, mCompatMode);
 
-        mService.logDatasetShown(id, mClientState);
+        synchronized (mLock) {
+            mService.logDatasetShown(id, mClientState, UI_TYPE_MENU);
+        }
 
         synchronized (mLock) {
             if (mUiShownTime == 0) {
@@ -3434,17 +3357,6 @@
             return false;
         }
 
-        final InlineSuggestionsRequest request = inlineSuggestionsRequest.get();
-        if (mSessionFlags.mClientSuggestionsEnabled && !request.isClientSupported()
-                || !mSessionFlags.mClientSuggestionsEnabled && !request.isServiceSupported()) {
-            if (sDebug) {
-                Slog.d(TAG, "Inline suggestions not supported for "
-                        + (mSessionFlags.mClientSuggestionsEnabled ? "client" : "service")
-                        + ". Falling back to dropdown.");
-            }
-            return false;
-        }
-
         final RemoteInlineSuggestionRenderService remoteRenderService =
                 mService.getRemoteInlineSuggestionRenderServiceLocked();
         if (remoteRenderService == null) {
@@ -3453,7 +3365,7 @@
         }
 
         final InlineFillUi.InlineFillUiInfo inlineFillUiInfo =
-                new InlineFillUi.InlineFillUiInfo(request, focusedId,
+                new InlineFillUi.InlineFillUiInfo(inlineSuggestionsRequest.get(), focusedId,
                         filterText, remoteRenderService, userId, id);
         InlineFillUi inlineFillUi = InlineFillUi.forAutofill(inlineFillUiInfo, response,
                 new InlineFillUi.InlineSuggestionUiCallback() {
@@ -4063,25 +3975,6 @@
         }
     }
 
-    @GuardedBy("mLock")
-    private void onClientFillRequestLocked(int requestId,
-            InlineSuggestionsRequest inlineSuggestionsRequest) {
-        if (mClientSuggestionsSession == null) {
-            mClientSuggestionsSession = new ClientSuggestionsSession(id, mClient, mHandler,
-                    mComponentName, this);
-        }
-
-        if (mContexts == null) {
-            mContexts = new ArrayList<>(1);
-        }
-
-        if (inlineSuggestionsRequest != null && !inlineSuggestionsRequest.isClientSupported()) {
-            inlineSuggestionsRequest = null;
-        }
-
-        mClientSuggestionsSession.onFillRequest(requestId, inlineSuggestionsRequest, mFlags);
-    }
-
     /**
      * The result of checking whether to show the save dialog, when session can be saved.
      *
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index e10151d..1af35af 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -89,8 +89,6 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.WorkSource;
-import android.os.storage.IStorageManager;
-import android.os.storage.StorageManager;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.ArraySet;
@@ -325,7 +323,6 @@
     private final ActivityManagerInternal mActivityManagerInternal;
     private PowerManager mPowerManager;
     private final AlarmManager mAlarmManager;
-    private final IStorageManager mStorageManager;
     private final BackupManagerConstants mConstants;
     private final BackupWakeLock mWakelock;
     private final BackupHandler mBackupHandler;
@@ -536,7 +533,6 @@
         mBackupPasswordManager = null;
         mPackageManagerBinder = null;
         mActivityManager = null;
-        mStorageManager = null;
         mBackupManagerBinder = null;
         mScheduledBackupEligibility = null;
     }
@@ -560,7 +556,6 @@
 
         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-        mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));
 
         Objects.requireNonNull(parent, "parent cannot be null");
         mBackupManagerBinder = BackupManagerService.asInterface(parent.asBinder());
@@ -2077,26 +2072,6 @@
         }
     }
 
-    /** For adb backup/restore. */
-    public boolean deviceIsEncrypted() {
-        try {
-            return mStorageManager.getEncryptionState()
-                    != StorageManager.ENCRYPTION_STATE_NONE
-                    && mStorageManager.getPasswordType()
-                    != StorageManager.CRYPT_TYPE_DEFAULT;
-        } catch (Exception e) {
-            // If we can't talk to the storagemanager service we have a serious problem; fail
-            // "secure" i.e. assuming that the device is encrypted.
-            Slog.e(
-                    TAG,
-                    addUserIdToLogMessage(
-                            mUserId,
-                            "Unable to communicate with storagemanager service: "
-                                    + e.getMessage()));
-            return true;
-        }
-    }
-
     // ----- Full-data backup scheduling -----
 
     /**
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
index 7ee307e..ec58e17 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
@@ -320,12 +320,6 @@
         try {
             boolean encrypting = (mEncryptPassword != null && mEncryptPassword.length() > 0);
 
-            // Only allow encrypted backups of encrypted devices
-            if (mUserBackupManagerService.deviceIsEncrypted() && !encrypting) {
-                Slog.e(TAG, "Unencrypted backup of encrypted device; aborting");
-                return;
-            }
-
             OutputStream finalOutput = ofstream;
 
             // Verify that the given password matches the currently-active
diff --git a/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchPerUserService.java b/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchPerUserService.java
index 116c739..8e0e395 100644
--- a/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchPerUserService.java
+++ b/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchPerUserService.java
@@ -107,6 +107,10 @@
     @GuardedBy("mLock")
     public void onSearchLocked(@NonNull SearchRequest searchRequest,
             @NonNull ICloudSearchManagerCallback callback) {
+        if (mRemoteComponentName == null) {
+            return;
+        }
+
         String filterList = searchRequest.getSearchConstraints().containsKey(
                 SearchRequest.CONSTRAINT_SEARCH_PROVIDER_FILTER)
                 ? searchRequest.getSearchConstraints().getString(
diff --git a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
index bf8b18c..7a5fa62 100644
--- a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
+++ b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
@@ -51,6 +51,7 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.UserHandle;
+import android.util.Log;
 import android.util.PackageUtils;
 import android.util.Slog;
 
@@ -332,13 +333,28 @@
             }
         }
 
-        String[] sameOemPackages = mContext.getResources()
+        // Below we check if the requesting package is allowlisted (usually by the OEM) for creating
+        // CDM associations without user confirmation (prompt).
+        // For this we'll check to config arrays:
+        // - com.android.internal.R.array.config_companionDevicePackages
+        // and
+        // - com.android.internal.R.array.config_companionDeviceCerts.
+        // Both arrays are expected to contain similar number of entries.
+        // config_companionDevicePackages contains package names of the allowlisted packages.
+        // config_companionDeviceCerts contains SHA256 digests of the signatures of the
+        // corresponding packages.
+        // If a package may be signed with one of several certificates, its package name would
+        // appear multiple times in the config_companionDevicePackages, with different entries
+        // (one for each of the valid signing certificates) at the corresponding positions in
+        // config_companionDeviceCerts.
+        final String[] allowlistedPackages = mContext.getResources()
                 .getStringArray(com.android.internal.R.array.config_companionDevicePackages);
-        if (!ArrayUtils.contains(sameOemPackages, packageName)) {
-            Slog.w(TAG, packageName
-                    + " can not silently create associations due to no package found."
-                    + " Packages from OEM: " + Arrays.toString(sameOemPackages)
-            );
+        if (!ArrayUtils.contains(allowlistedPackages, packageName)) {
+            if (DEBUG) {
+                Log.d(TAG, packageName + " is not allowlisted for creating associations "
+                        + "without user confirmation (prompt)");
+                Log.v(TAG, "Allowlisted packages=" + Arrays.toString(allowlistedPackages));
+            }
             return false;
         }
 
@@ -361,44 +377,41 @@
             }
         }
 
-        String[] sameOemCerts = mContext.getResources()
+        final String[] allowlistedPackagesSignatureDigests = mContext.getResources()
                 .getStringArray(com.android.internal.R.array.config_companionDeviceCerts);
-
-        Signature[] signatures = mPackageManager.getPackage(packageName).getSigningDetails()
-                .getSignatures();
-        String[] apkCerts = PackageUtils.computeSignaturesSha256Digests(signatures);
-
-        Set<String> sameOemPackageCerts =
-                getSameOemPackageCerts(packageName, sameOemPackages, sameOemCerts);
-
-        for (String cert : apkCerts) {
-            if (sameOemPackageCerts.contains(cert)) {
-                return true;
+        final Set<String> allowlistedSignatureDigestsForRequestingPackage = new HashSet<>();
+        for (int i = 0; i < allowlistedPackages.length; i++) {
+            if (allowlistedPackages[i].equals(packageName)) {
+                final String digest = allowlistedPackagesSignatureDigests[i].replaceAll(":", "");
+                allowlistedSignatureDigestsForRequestingPackage.add(digest);
             }
         }
 
-        Slog.w(TAG, packageName
-                + " can not silently create associations. " + packageName
-                + " has SHA256 certs from APK: " + Arrays.toString(apkCerts)
-                + " and from OEM: " + Arrays.toString(sameOemCerts)
-        );
+        final Signature[] requestingPackageSignatures = mPackageManager.getPackage(packageName)
+                .getSigningDetails().getSignatures();
+        final String[] requestingPackageSignatureDigests =
+                PackageUtils.computeSignaturesSha256Digests(requestingPackageSignatures);
 
-        return false;
-    }
-
-    private static Set<String> getSameOemPackageCerts(
-            String packageName, String[] oemPackages, String[] sameOemCerts) {
-        Set<String> sameOemPackageCerts = new HashSet<>();
-
-        // Assume OEM may enter same package name in the parallel string array with
-        // multiple APK certs corresponding to it
-        for (int i = 0; i < oemPackages.length; i++) {
-            if (oemPackages[i].equals(packageName)) {
-                sameOemPackageCerts.add(sameOemCerts[i].replaceAll(":", ""));
+        boolean requestingPackageSignatureAllowlisted = false;
+        for (String signatureDigest : requestingPackageSignatureDigests) {
+            if (allowlistedSignatureDigestsForRequestingPackage.contains(signatureDigest)) {
+                requestingPackageSignatureAllowlisted = true;
+                break;
             }
         }
 
-        return sameOemPackageCerts;
+        if (!requestingPackageSignatureAllowlisted) {
+            Slog.w(TAG, "Certificate mismatch for allowlisted package " + packageName);
+            if (DEBUG) {
+                Log.d(TAG, "  > allowlisted signatures for " + packageName + ": ["
+                        + String.join(", ", allowlistedSignatureDigestsForRequestingPackage)
+                        + "]");
+                Log.d(TAG, "  > actual signatures for " + packageName + ": "
+                        + Arrays.toString(requestingPackageSignatureDigests));
+            }
+        }
+
+        return requestingPackageSignatureAllowlisted;
     }
 
     /**
diff --git a/services/companion/java/com/android/server/companion/CompanionApplicationController.java b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
index f32eebc..2a83a3c 100644
--- a/services/companion/java/com/android/server/companion/CompanionApplicationController.java
+++ b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
@@ -49,7 +49,7 @@
  * The following is the list of the APIs provided by {@link CompanionApplicationController} (to be
  * utilized by {@link CompanionDeviceManagerService}):
  * <ul>
- * <li> {@link #bindCompanionApplication(int, String)}
+ * <li> {@link #bindCompanionApplication(int, String, boolean)}
  * <li> {@link #unbindCompanionApplication(int, String)}
  * <li> {@link #notifyCompanionApplicationDeviceAppeared(AssociationInfo)}
  * <li> {@link #notifyCompanionApplicationDeviceDisappeared(AssociationInfo)}
@@ -103,8 +103,12 @@
         mCompanionServicesRegister.invalidate(userId);
     }
 
-    void bindCompanionApplication(@UserIdInt int userId, @NonNull String packageName) {
-        if (DEBUG) Log.i(TAG, "bind() u" + userId + "/" + packageName);
+    void bindCompanionApplication(@UserIdInt int userId, @NonNull String packageName,
+            boolean bindImportant) {
+        if (DEBUG) {
+            Log.i(TAG, "bind() u" + userId + "/" + packageName
+                    + " important=" + bindImportant);
+        }
 
         final List<ComponentName> companionServices =
                 mCompanionServicesRegister.forPackage(userId, packageName);
@@ -125,7 +129,8 @@
             }
 
             serviceConnectors = CollectionUtils.map(companionServices, componentName ->
-                            new CompanionDeviceServiceConnector(mContext, userId, componentName));
+                            CompanionDeviceServiceConnector.newInstance(mContext, userId,
+                                    componentName, bindImportant));
             mBoundCompanionApplications.setValueForPackage(userId, packageName, serviceConnectors);
         }
 
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index eaa99f7..13a5a28 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -254,9 +254,12 @@
 
         final int userId = association.getUserId();
         final String packageName = association.getPackageName();
+        // Set bindImportant to true when the association is self-managed to avoid the target
+        // service being killed.
+        final boolean bindImportant = association.isSelfManaged();
 
         if (!mCompanionAppController.isCompanionApplicationBound(userId, packageName)) {
-            mCompanionAppController.bindCompanionApplication(userId, packageName);
+            mCompanionAppController.bindCompanionApplication(userId, packageName, bindImportant);
         } else if (DEBUG) {
             Log.i(TAG, "u" + userId + "\\" + packageName + " is already bound");
         }
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
index f2a58b7..a6bd480 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
@@ -16,6 +16,7 @@
 
 package com.android.server.companion;
 
+import static android.content.Context.BIND_ALMOST_PERCEPTIBLE;
 import static android.content.Context.BIND_IMPORTANT;
 import static android.os.Process.THREAD_PRIORITY_DEFAULT;
 
@@ -44,7 +45,6 @@
 class CompanionDeviceServiceConnector extends ServiceConnector.Impl<ICompanionDeviceService> {
     private static final String TAG = "CompanionDevice_ServiceConnector";
     private static final boolean DEBUG = false;
-    private static final int BINDING_FLAGS = BIND_IMPORTANT;
 
     /** Listener for changes to the state of the {@link CompanionDeviceServiceConnector}  */
     interface Listener {
@@ -53,11 +53,35 @@
 
     private final @UserIdInt int mUserId;
     private final @NonNull ComponentName mComponentName;
+    // IMPORTANT: this can (and will!) be null (at the moment, CompanionApplicationController only
+    // installs a listener to the primary ServiceConnector), hence we should always null-check the
+    // reference before calling on it.
     private @Nullable Listener mListener;
 
-    CompanionDeviceServiceConnector(@NonNull Context context, @UserIdInt int userId,
-            @NonNull ComponentName componentName) {
-        super(context, buildIntent(componentName), BINDING_FLAGS, userId, null);
+    /**
+     * Create a CompanionDeviceServiceConnector instance.
+     *
+     * When bindImportant is false, the binding flag will be BIND_ALMOST_PERCEPTIBLE
+     * (oom_score_adj = PERCEPTIBLE_MEDIUM_APP = 225). The target service will be treated
+     * as important as a perceptible app (IMPORTANCE_VISIBLE = 200), and will be unbound when
+     * the app is removed from task manager.
+     * When bindImportant is true, the binding flag will be BIND_IMPORTANT
+     * (oom_score_adj = PERCEPTIBLE_MEDIUM_APP = -700). The target service will
+     * have the highest priority to avoid being killed (IMPORTANCE_FOREGROUND = 100).
+     *
+     * One time permission's importance level to keep session alive is
+     * IMPORTANCE_FOREGROUND_SERVICE = 125. In order to kill the one time permission session, the
+     * service importance level should be higher than 125.
+     */
+    static CompanionDeviceServiceConnector newInstance(@NonNull Context context,
+            @UserIdInt int userId, @NonNull ComponentName componentName, boolean bindImportant) {
+        final int bindingFlags = bindImportant ? BIND_IMPORTANT : BIND_ALMOST_PERCEPTIBLE;
+        return new CompanionDeviceServiceConnector(context, userId, componentName, bindingFlags);
+    }
+
+    private CompanionDeviceServiceConnector(@NonNull Context context, @UserIdInt int userId,
+            @NonNull ComponentName componentName, int bindingFlags) {
+        super(context, buildIntent(componentName), bindingFlags, userId, null);
         mUserId = userId;
         mComponentName = componentName;
     }
@@ -101,7 +125,9 @@
 
         if (DEBUG) Log.d(TAG, "onBindingDied() " + mComponentName.toShortString());
 
-        mListener.onBindingDied(mUserId, mComponentName.getPackageName());
+        if (mListener != null) {
+            mListener.onBindingDied(mUserId, mComponentName.getPackageName());
+        }
     }
 
     @Override
diff --git a/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java b/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
index 1ba198a..823743d 100644
--- a/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
+++ b/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
@@ -94,7 +94,7 @@
             int reason) {
         if (DEBUG) {
             Log.i(TAG, "onDevice_Disconnected() " + btDeviceToString(device));
-            Log.d(TAG, "  reason=" + disconnectReasonText(reason));
+            Log.d(TAG, "  reason=" + disconnectReasonToString(reason));
         }
 
         final MacAddress macAddress = MacAddress.fromString(device.getAddress());
diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
index b991ba8..f4c24a8 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -22,6 +22,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.WindowConfiguration;
 import android.app.compat.CompatChanges;
 import android.companion.virtual.VirtualDeviceManager.ActivityListener;
 import android.companion.virtual.VirtualDeviceParams;
@@ -119,6 +120,7 @@
             @ActivityPolicy int defaultActivityPolicy,
             @NonNull ActivityListener activityListener,
             @NonNull Consumer<ActivityInfo> activityBlockedCallback) {
+        super();
         mAllowedUsers = allowedUsers;
         mAllowedActivities = new ArraySet<>(allowedActivities);
         mBlockedActivities = new ArraySet<>(blockedActivities);
@@ -134,7 +136,11 @@
     }
 
     @Override
-    public boolean canContainActivities(@NonNull List<ActivityInfo> activities) {
+    public boolean canContainActivities(@NonNull List<ActivityInfo> activities,
+            @WindowConfiguration.WindowingMode int windowingMode) {
+        if (!isWindowingModeSupported(windowingMode)) {
+            return false;
+        }
         // Can't display all the activities if any of them don't want to be displayed.
         final int activityCount = activities.size();
         for (int i = 0; i < activityCount; i++) {
@@ -159,7 +165,10 @@
 
     @Override
     public void onTopActivityChanged(ComponentName topActivity, int uid) {
-        if (mActivityListener != null) {
+        // Don't send onTopActivityChanged() callback when topActivity is null because it's defined
+        // as @NonNull in ActivityListener interface. Sends onDisplayEmpty() callback instead when
+        // there is no activity running on virtual display.
+        if (mActivityListener != null && topActivity != null) {
             // Post callback on the main thread so it doesn't block activity launching
             mHandler.post(() ->
                     mActivityListener.onTopActivityChanged(Display.INVALID_DISPLAY, topActivity));
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index b05a7db..06fd5c0 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -173,6 +173,11 @@
         return flags;
     }
 
+    /** Returns the device display name. */
+    CharSequence getDisplayName() {
+        return mAssociationInfo.getDisplayName();
+    }
+
     @Override // Binder call
     public int getAssociationId() {
         return mAssociationInfo.getId();
@@ -523,8 +528,7 @@
             }
             PowerManager powerManager = mContext.getSystemService(PowerManager.class);
             PowerManager.WakeLock wakeLock = powerManager.newWakeLock(
-                    PowerManager.SCREEN_BRIGHT_WAKE_LOCK
-                            | PowerManager.ACQUIRE_CAUSES_WAKEUP,
+                    PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
                     TAG + ":" + displayId, displayId);
             wakeLock.acquire();
             mPerDisplayWakelocks.put(displayId, wakeLock);
@@ -596,6 +600,13 @@
      * Shows a toast on virtual displays owned by this device which have a given uid running.
      */
     void showToastWhereUidIsRunning(int uid, @StringRes int resId, @Toast.Duration int duration) {
+        showToastWhereUidIsRunning(uid, mContext.getString(resId), duration);
+    }
+
+    /**
+     * Shows a toast on virtual displays owned by this device which have a given uid running.
+     */
+    void showToastWhereUidIsRunning(int uid, String text, @Toast.Duration int duration) {
         synchronized (mVirtualDeviceLock) {
             DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
             final int size = mWindowPolicyControllers.size();
@@ -604,7 +615,7 @@
                     int displayId = mWindowPolicyControllers.keyAt(i);
                     Display display = displayManager.getDisplay(displayId);
                     if (display != null && display.isValid()) {
-                        Toast.makeText(mContext.createDisplayContext(display), resId,
+                        Toast.makeText(mContext.createDisplayContext(display), text,
                                 duration).show();
                     }
                 }
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index 9f252d7..96400c1 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -193,8 +193,12 @@
         synchronized (mVirtualDeviceManagerLock) {
             int size = mVirtualDevices.size();
             for (int i = 0; i < size; i++) {
+                CharSequence deviceName = mVirtualDevices.valueAt(i).getDisplayName();
                 mVirtualDevices.valueAt(i).showToastWhereUidIsRunning(appUid,
-                        com.android.internal.R.string.vdm_camera_access_denied, Toast.LENGTH_LONG);
+                        getContext().getString(
+                            com.android.internal.R.string.vdm_camera_access_denied,
+                            deviceName),
+                        Toast.LENGTH_LONG);
             }
         }
     }
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 2068e6d..68cd288 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -48,7 +48,6 @@
 import com.android.server.pm.dex.DynamicCodeLogger;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.pkg.AndroidPackageApi;
-import com.android.server.pm.pkg.PackageState;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.SharedUserApi;
 import com.android.server.pm.pkg.component.ParsedMainComponent;
@@ -690,8 +689,6 @@
     @Nullable
     public abstract PackageStateInternal getPackageStateInternal(@NonNull String packageName);
 
-    public abstract @Nullable PackageState getPackageState(@NonNull String packageName);
-
     @NonNull
     public abstract ArrayMap<String, ? extends PackageStateInternal> getPackageStates();
 
diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java
index a2a232d..1d457aa 100644
--- a/services/core/java/com/android/server/DropBoxManagerService.java
+++ b/services/core/java/com/android/server/DropBoxManagerService.java
@@ -60,6 +60,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.IDropBoxManagerService;
 import com.android.internal.util.DumpUtils;
+import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.ObjectUtils;
 import com.android.server.DropBoxManagerInternal.EntrySource;
 
@@ -501,12 +502,20 @@
             }
         } catch (IOException e) {
             Slog.e(TAG, "Can't write: " + tag, e);
+            logDropboxDropped(
+                    FrameworkStatsLog.DROPBOX_ENTRY_DROPPED__DROP_REASON__WRITE_FAILURE,
+                    tag,
+                    0);
         } finally {
             IoUtils.closeQuietly(entry);
             if (temp != null) temp.delete();
         }
     }
 
+    private void logDropboxDropped(int reason, String tag, long entryAge) {
+        FrameworkStatsLog.write(FrameworkStatsLog.DROPBOX_ENTRY_DROPPED, reason, tag, entryAge);
+    }
+
     public boolean isTagEnabled(String tag) {
         final long token = Binder.clearCallingIdentity();
         try {
@@ -1119,13 +1128,19 @@
                 Settings.Global.DROPBOX_MAX_FILES,
                 (ActivityManager.isLowRamDeviceStatic()
                         ?  DEFAULT_MAX_FILES_LOWRAM : DEFAULT_MAX_FILES));
-        long cutoffMillis = System.currentTimeMillis() - ageSeconds * 1000;
+        long curTimeMillis = System.currentTimeMillis();
+        long cutoffMillis = curTimeMillis - ageSeconds * 1000;
         while (!mAllFiles.contents.isEmpty()) {
             EntryFile entry = mAllFiles.contents.first();
             if (entry.timestampMillis > cutoffMillis && mAllFiles.contents.size() < mMaxFiles) {
                 break;
             }
 
+            logDropboxDropped(
+                    FrameworkStatsLog.DROPBOX_ENTRY_DROPPED__DROP_REASON__AGED,
+                    entry.tag,
+                    curTimeMillis - entry.timestampMillis);
+
             FileList tag = mFilesByTag.get(entry.tag);
             if (tag != null && tag.contents.remove(entry)) tag.blocks -= entry.blocks;
             if (mAllFiles.contents.remove(entry)) mAllFiles.blocks -= entry.blocks;
@@ -1194,6 +1209,11 @@
                 if (mAllFiles.blocks < mCachedQuotaBlocks) break;
                 while (tag.blocks > tagQuota && !tag.contents.isEmpty()) {
                     EntryFile entry = tag.contents.first();
+                    logDropboxDropped(
+                            FrameworkStatsLog.DROPBOX_ENTRY_DROPPED__DROP_REASON__CLEARING_DATA,
+                            entry.tag,
+                            curTimeMillis - entry.timestampMillis);
+
                     if (tag.contents.remove(entry)) tag.blocks -= entry.blocks;
                     if (mAllFiles.contents.remove(entry)) mAllFiles.blocks -= entry.blocks;
 
diff --git a/services/core/java/com/android/server/FactoryResetter.java b/services/core/java/com/android/server/FactoryResetter.java
new file mode 100644
index 0000000..30314a3
--- /dev/null
+++ b/services/core/java/com/android/server/FactoryResetter.java
@@ -0,0 +1,54 @@
+/*
+ * 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.server;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * TODO(b/225012970): add javadoc from {@code com.android.server.devicepolicy.FactoryResetter}
+ */
+public final class FactoryResetter {
+
+    private static final AtomicBoolean sFactoryResetting = new AtomicBoolean(false);
+
+    /**
+     * Checks whether a factory reset is in progress.
+     */
+    public static boolean isFactoryResetting() {
+        return sFactoryResetting.get();
+    }
+
+    /**
+     * @deprecated called by {@code com.android.server.devicepolicy.FactoryResetter}, won't be
+     * needed once that class logic is moved into this.
+     */
+    @Deprecated
+    public static void setFactoryResetting(Context context) {
+        Preconditions.checkCallAuthorization(context.checkCallingOrSelfPermission(
+                android.Manifest.permission.MASTER_CLEAR) == PackageManager.PERMISSION_GRANTED);
+        sFactoryResetting.set(true);
+    }
+
+    private FactoryResetter() {
+        throw new UnsupportedOperationException("Provides only static methods");
+    }
+}
diff --git a/services/core/java/com/android/server/MasterClearReceiver.java b/services/core/java/com/android/server/MasterClearReceiver.java
index be2b7f7..7c3a75f 100644
--- a/services/core/java/com/android/server/MasterClearReceiver.java
+++ b/services/core/java/com/android/server/MasterClearReceiver.java
@@ -131,7 +131,7 @@
         final UserManager userManager = context.getSystemService(UserManager.class);
         final int result = userManager.removeUserWhenPossible(
                 UserHandle.of(userId), /* overrideDevicePolicy= */ false);
-        if (result == UserManager.REMOVE_RESULT_ERROR) {
+        if (!UserManager.isRemoveResultSuccessful(result)) {
             Slogf.e(TAG, "Can't remove user %d", userId);
             return false;
         }
@@ -169,7 +169,7 @@
 
     private String getWorkProfileDeletedTitle(Context context) {
         final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
-        return dpm.getString(WORK_PROFILE_DELETED_TITLE,
+        return dpm.getResources().getString(WORK_PROFILE_DELETED_TITLE,
                 () -> context.getString(R.string.work_profile_deleted));
     }
 
diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java
index 593c406..59db686 100644
--- a/services/core/java/com/android/server/MmsServiceBroker.java
+++ b/services/core/java/com/android/server/MmsServiceBroker.java
@@ -129,15 +129,15 @@
 
         @Override
         public void sendMessage(int subId, String callingPkg, Uri contentUri, String locationUrl,
-                Bundle configOverrides, PendingIntent sentIntent, long messageId)
-                throws RemoteException {
+                Bundle configOverrides, PendingIntent sentIntent, long messageId,
+                String attributionTag) throws RemoteException {
             returnPendingIntentWithError(sentIntent);
         }
 
         @Override
         public void downloadMessage(int subId, String callingPkg, String locationUrl,
                 Uri contentUri, Bundle configOverrides, PendingIntent downloadedIntent,
-                long messageId)
+                long messageId, String attributionTag)
                 throws RemoteException {
             returnPendingIntentWithError(downloadedIntent);
         }
@@ -333,12 +333,12 @@
         @Override
         public void sendMessage(int subId, String callingPkg, Uri contentUri,
                 String locationUrl, Bundle configOverrides, PendingIntent sentIntent,
-                long messageId)
+                long messageId, String attributionTag)
                 throws RemoteException {
             Slog.d(TAG, "sendMessage() by " + callingPkg);
             mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, "Send MMS message");
             if (getAppOpsManager().noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
-                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                    callingPkg, attributionTag, null) != AppOpsManager.MODE_ALLOWED) {
                 Slog.e(TAG, callingPkg + " is not allowed to call sendMessage()");
                 return;
             }
@@ -347,18 +347,18 @@
                     Intent.FLAG_GRANT_READ_URI_PERMISSION,
                     subId);
             getServiceGuarded().sendMessage(subId, callingPkg, contentUri, locationUrl,
-                    configOverrides, sentIntent, messageId);
+                    configOverrides, sentIntent, messageId, attributionTag);
         }
 
         @Override
         public void downloadMessage(int subId, String callingPkg, String locationUrl,
-                Uri contentUri, Bundle configOverrides,
-                PendingIntent downloadedIntent, long messageId) throws RemoteException {
+                Uri contentUri, Bundle configOverrides, PendingIntent downloadedIntent,
+                long messageId, String attributionTag) throws RemoteException {
             Slog.d(TAG, "downloadMessage() by " + callingPkg);
             mContext.enforceCallingPermission(Manifest.permission.RECEIVE_MMS,
                     "Download MMS message");
             if (getAppOpsManager().noteOp(AppOpsManager.OP_RECEIVE_MMS, Binder.getCallingUid(),
-                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                    callingPkg, attributionTag, null) != AppOpsManager.MODE_ALLOWED) {
                 Slog.e(TAG, callingPkg + " is not allowed to call downloadMessage()");
                 return;
             }
@@ -368,14 +368,14 @@
                     subId);
 
             getServiceGuarded().downloadMessage(subId, callingPkg, locationUrl, contentUri,
-                    configOverrides, downloadedIntent, messageId);
+                    configOverrides, downloadedIntent, messageId, attributionTag);
         }
 
         @Override
         public Uri importTextMessage(String callingPkg, String address, int type, String text,
                 long timestampMillis, boolean seen, boolean read) throws RemoteException {
             if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
-                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                    callingPkg, null, null) != AppOpsManager.MODE_ALLOWED) {
                 // Silently fail AppOps failure due to not being the default SMS app
                 // while writing the TelephonyProvider
                 return FAKE_SMS_SENT_URI;
@@ -389,7 +389,7 @@
                 String messageId, long timestampSecs, boolean seen, boolean read)
                 throws RemoteException {
             if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
-                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                    callingPkg, null, null) != AppOpsManager.MODE_ALLOWED) {
                 // Silently fail AppOps failure due to not being the default SMS app
                 // while writing the TelephonyProvider
                 return FAKE_MMS_SENT_URI;
@@ -402,7 +402,7 @@
         public boolean deleteStoredMessage(String callingPkg, Uri messageUri)
                 throws RemoteException {
             if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
-                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                    callingPkg, null, null) != AppOpsManager.MODE_ALLOWED) {
                 return false;
             }
             return getServiceGuarded().deleteStoredMessage(callingPkg, messageUri);
@@ -412,7 +412,7 @@
         public boolean deleteStoredConversation(String callingPkg, long conversationId)
                 throws RemoteException {
             if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
-                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                    callingPkg, null, null) != AppOpsManager.MODE_ALLOWED) {
                 return false;
             }
             return getServiceGuarded().deleteStoredConversation(callingPkg, conversationId);
@@ -422,7 +422,7 @@
         public boolean updateStoredMessageStatus(String callingPkg, Uri messageUri,
                 ContentValues statusValues) throws RemoteException {
             if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
-                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                    callingPkg, null, null) != AppOpsManager.MODE_ALLOWED) {
                 return false;
             }
             return getServiceGuarded()
@@ -433,7 +433,7 @@
         public boolean archiveStoredConversation(String callingPkg, long conversationId,
                 boolean archived) throws RemoteException {
             if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
-                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                    callingPkg, null, null) != AppOpsManager.MODE_ALLOWED) {
                 return false;
             }
             return getServiceGuarded()
@@ -444,7 +444,7 @@
         public Uri addTextMessageDraft(String callingPkg, String address, String text)
                 throws RemoteException {
             if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
-                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                    callingPkg, null, null) != AppOpsManager.MODE_ALLOWED) {
                 // Silently fail AppOps failure due to not being the default SMS app
                 // while writing the TelephonyProvider
                 return FAKE_SMS_DRAFT_URI;
@@ -456,7 +456,7 @@
         public Uri addMultimediaMessageDraft(String callingPkg, Uri contentUri)
                 throws RemoteException {
             if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
-                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                    callingPkg, null, null) != AppOpsManager.MODE_ALLOWED) {
                 // Silently fail AppOps failure due to not being the default SMS app
                 // while writing the TelephonyProvider
                 return FAKE_MMS_DRAFT_URI;
@@ -468,7 +468,7 @@
         public void sendStoredMessage(int subId, String callingPkg, Uri messageUri,
                 Bundle configOverrides, PendingIntent sentIntent) throws RemoteException {
             if (getAppOpsManager().noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
-                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                    callingPkg, null, null) != AppOpsManager.MODE_ALLOWED) {
                 return;
             }
             getServiceGuarded().sendStoredMessage(subId, callingPkg, messageUri, configOverrides,
@@ -478,7 +478,7 @@
         @Override
         public void setAutoPersisting(String callingPkg, boolean enabled) throws RemoteException {
             if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
-                    callingPkg) != AppOpsManager.MODE_ALLOWED) {
+                    callingPkg, null, null) != AppOpsManager.MODE_ALLOWED) {
                 return;
             }
             getServiceGuarded().setAutoPersisting(callingPkg, enabled);
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 1a39ffa..73d9cc7 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1528,7 +1528,7 @@
         if (updateFirewallUidRuleLocked(chain, uid, rule)) {
             final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
             try {
-                cm.updateFirewallRule(chain, uid, isFirewallRuleAllow(chain, rule));
+                cm.setUidFirewallRule(chain, uid, rule);
             } catch (RuntimeException e) {
                 throw new IllegalStateException(e);
             }
@@ -1601,14 +1601,6 @@
         }
     }
 
-    // There are only two type of firewall rule: FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY.
-    private boolean isFirewallRuleAllow(int chain, int rule) {
-        if (rule == NetworkPolicyManager.FIREWALL_RULE_DEFAULT) {
-            return getFirewallType(chain) == FIREWALL_DENYLIST;
-        }
-        return rule == INetd.FIREWALL_RULE_ALLOW;
-    }
-
     private void enforceSystemUid() {
         final int uid = mDeps.getCallingUid();
         if (uid != Process.SYSTEM_UID) {
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java
index 186ff62..2015dc9 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java
@@ -196,13 +196,15 @@
      * Overrides the NTP server config for tests. Passing {@code null} to a parameter clears the
      * test value, i.e. so the normal value will be used next time.
      */
-    void setServerConfigForTests(@Nullable String hostname, @Nullable Duration timeout) {
+    void setServerConfigForTests(
+            @Nullable String hostname, @Nullable Integer port, @Nullable Duration timeout) {
         mContext.enforceCallingPermission(
                 android.Manifest.permission.SET_TIME, "set NTP server config for tests");
 
         mLocalLog.log("Setting server config for tests: hostname=" + hostname
+                + ", port=" + port
                 + ", timeout=" + timeout);
-        mTime.setServerConfigForTests(hostname, timeout);
+        mTime.setServerConfigForTests(hostname, port, timeout);
     }
 
     private void onPollNetworkTime(int event) {
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java b/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java
index 464af01..d7504ce 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java
@@ -46,6 +46,7 @@
      */
     private static final String SHELL_COMMAND_SET_SERVER_CONFIG = "set_server_config";
     private static final String SET_SERVER_CONFIG_HOSTNAME_ARG = "--hostname";
+    private static final String SET_SERVER_CONFIG_PORT_ARG = "--port";
     private static final String SET_SERVER_CONFIG_TIMEOUT_ARG = "--timeout_millis";
 
     @NonNull
@@ -87,6 +88,7 @@
 
     private int runSetServerConfig() {
         String hostname = null;
+        Integer port = null;
         Duration timeout = null;
         String opt;
         while ((opt = getNextArg()) != null) {
@@ -95,6 +97,10 @@
                     hostname = getNextArgRequired();
                     break;
                 }
+                case SET_SERVER_CONFIG_PORT_ARG: {
+                    port = Integer.parseInt(getNextArgRequired());
+                    break;
+                }
                 case SET_SERVER_CONFIG_TIMEOUT_ARG: {
                     timeout = Duration.ofMillis(Integer.parseInt(getNextArgRequired()));
                     break;
@@ -104,7 +110,7 @@
                 }
             }
         }
-        mNetworkTimeUpdateService.setServerConfigForTests(hostname, timeout);
+        mNetworkTimeUpdateService.setServerConfigForTests(hostname, port, timeout);
         return 0;
     }
 
@@ -120,8 +126,9 @@
         pw.printf("    Refreshes the latest time. Prints whether it was successful.\n");
         pw.printf("  %s\n", SHELL_COMMAND_SET_SERVER_CONFIG);
         pw.printf("    Sets the NTP server config for tests. The config is not persisted.\n");
-        pw.printf("      Options: [%s <hostname>] [%s <millis>]\n",
-                SET_SERVER_CONFIG_HOSTNAME_ARG, SET_SERVER_CONFIG_TIMEOUT_ARG);
+        pw.printf("      Options: [%s <hostname>] [%s <port>] [%s <millis>]\n",
+                SET_SERVER_CONFIG_HOSTNAME_ARG, SET_SERVER_CONFIG_PORT_ARG,
+                SET_SERVER_CONFIG_TIMEOUT_ARG);
         pw.printf("      Each key/value is optional and must be specified to override the\n");
         pw.printf("      normal value, not specifying a key causes it to reset to the original.\n");
         pw.println();
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 7075ed3..af7dcd1 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -38,7 +38,6 @@
 import static android.os.storage.OnObbStateChangeListener.ERROR_ALREADY_MOUNTED;
 import static android.os.storage.OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT;
 import static android.os.storage.OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT;
-import static android.os.storage.OnObbStateChangeListener.ERROR_INTERNAL;
 import static android.os.storage.OnObbStateChangeListener.ERROR_NOT_MOUNTED;
 import static android.os.storage.OnObbStateChangeListener.ERROR_PERMISSION_DENIED;
 import static android.os.storage.OnObbStateChangeListener.MOUNTED;
@@ -598,12 +597,6 @@
         }
     }
 
-    /** List of crypto types.
-      * These must match CRYPT_TYPE_XXX in cryptfs.h AND their
-      * corresponding commands in CommandListener.cpp */
-    public static final String[] CRYPTO_TYPES
-        = { "password", "default", "pattern", "pin" };
-
     private final Context mContext;
     private final ContentResolver mResolver;
 
@@ -622,18 +615,6 @@
     private final Callbacks mCallbacks;
     private final LockPatternUtils mLockPatternUtils;
 
-    /**
-     * The size of the crypto algorithm key in bits for OBB files. Currently
-     * Twofish is used which takes 128-bit keys.
-     */
-    private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128;
-
-    /**
-     * The number of times to run SHA1 in the PBKDF2 function for OBB files.
-     * 1024 is reasonably secure and not too slow.
-     */
-    private static final int PBKDF2_HASH_ROUNDS = 1024;
-
     private static final String ANR_DELAY_MILLIS_DEVICE_CONFIG_KEY =
             "anr_delay_millis";
 
@@ -3129,220 +3110,6 @@
         }
     }
 
-    @Override
-    public int getEncryptionState() {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
-                "no permission to access the crypt keeper");
-
-        try {
-            return mVold.fdeComplete();
-        } catch (Exception e) {
-            Slog.wtf(TAG, e);
-            return StorageManager.ENCRYPTION_STATE_ERROR_UNKNOWN;
-        }
-    }
-
-    @Override
-    public int decryptStorage(String password) {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
-                "no permission to access the crypt keeper");
-
-        if (TextUtils.isEmpty(password)) {
-            throw new IllegalArgumentException("password cannot be empty");
-        }
-
-        if (DEBUG_EVENTS) {
-            Slog.i(TAG, "decrypting storage...");
-        }
-
-        try {
-            mVold.fdeCheckPassword(password);
-            mHandler.postDelayed(() -> {
-                try {
-                    mVold.fdeRestart();
-                } catch (Exception e) {
-                    Slog.wtf(TAG, e);
-                }
-            }, DateUtils.SECOND_IN_MILLIS);
-            return 0;
-        } catch (ServiceSpecificException e) {
-            Slog.e(TAG, "fdeCheckPassword failed", e);
-            return e.errorCode;
-        } catch (Exception e) {
-            Slog.wtf(TAG, e);
-            return StorageManager.ENCRYPTION_STATE_ERROR_UNKNOWN;
-        }
-    }
-
-    @Override
-    public int encryptStorage(int type, String password) {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
-            "no permission to access the crypt keeper");
-
-        if (type == StorageManager.CRYPT_TYPE_DEFAULT) {
-            password = "";
-        } else if (TextUtils.isEmpty(password)) {
-            throw new IllegalArgumentException("password cannot be empty");
-        }
-
-        if (DEBUG_EVENTS) {
-            Slog.i(TAG, "encrypting storage...");
-        }
-
-        try {
-            mVold.fdeEnable(type, password, 0);
-        } catch (Exception e) {
-            Slog.wtf(TAG, e);
-            return -1;
-        }
-
-        return 0;
-    }
-
-    /** Set the password for encrypting the main key.
-     *  @param type One of the CRYPTO_TYPE_XXX consts defined in StorageManager.
-     *  @param password The password to set.
-     */
-    @Override
-    public int changeEncryptionPassword(int type, String password) {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
-            "no permission to access the crypt keeper");
-
-        if (StorageManager.isFileEncryptedNativeOnly()) {
-            // Not supported on FBE devices
-            return -1;
-        }
-
-        if (type == StorageManager.CRYPT_TYPE_DEFAULT) {
-            password = "";
-        } else if (TextUtils.isEmpty(password)) {
-            throw new IllegalArgumentException("password cannot be empty");
-        }
-
-        if (DEBUG_EVENTS) {
-            Slog.i(TAG, "changing encryption password...");
-        }
-
-        try {
-            mVold.fdeChangePassword(type, password);
-            return 0;
-        } catch (Exception e) {
-            Slog.wtf(TAG, e);
-            return -1;
-        }
-    }
-
-    /**
-     * Validate a user-supplied password string with cryptfs
-     */
-    @Override
-    public int verifyEncryptionPassword(String password) throws RemoteException {
-        // Only the system process is permitted to validate passwords
-        if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
-            throw new SecurityException("no permission to access the crypt keeper");
-        }
-
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
-            "no permission to access the crypt keeper");
-
-        if (TextUtils.isEmpty(password)) {
-            throw new IllegalArgumentException("password cannot be empty");
-        }
-
-        if (DEBUG_EVENTS) {
-            Slog.i(TAG, "validating encryption password...");
-        }
-
-        try {
-            mVold.fdeVerifyPassword(password);
-            return 0;
-        } catch (Exception e) {
-            Slog.wtf(TAG, e);
-            return -1;
-        }
-    }
-
-    /**
-     * Get the type of encryption used to encrypt the main key.
-     * @return The type, one of the CRYPT_TYPE_XXX consts from StorageManager.
-     */
-    @Override
-    public int getPasswordType() {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
-            "no permission to access the crypt keeper");
-
-        try {
-            return mVold.fdeGetPasswordType();
-        } catch (Exception e) {
-            Slog.wtf(TAG, e);
-            return -1;
-        }
-    }
-
-    /**
-     * Set a field in the crypto header.
-     * @param field field to set
-     * @param contents contents to set in field
-     */
-    @Override
-    public void setField(String field, String contents) throws RemoteException {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
-            "no permission to access the crypt keeper");
-
-        if (!StorageManager.isBlockEncrypted()) {
-            // Only supported on FDE devices
-            return;
-        }
-
-        try {
-            mVold.fdeSetField(field, contents);
-            return;
-        } catch (Exception e) {
-            Slog.wtf(TAG, e);
-            return;
-        }
-    }
-
-    /**
-     * Gets a field from the crypto header.
-     * @param field field to get
-     * @return contents of field
-     */
-    @Override
-    public String getField(String field) throws RemoteException {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
-            "no permission to access the crypt keeper");
-
-        if (!StorageManager.isBlockEncrypted()) {
-            // Only supported on FDE devices
-            return null;
-        }
-
-        try {
-            return mVold.fdeGetField(field);
-        } catch (Exception e) {
-            Slog.wtf(TAG, e);
-            return null;
-        }
-    }
-
-    /**
-     * Is userdata convertible to file based encryption?
-     * @return non zero for convertible
-     */
-    @Override
-    public boolean isConvertibleToFBE() throws RemoteException {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
-            "no permission to access the crypt keeper");
-
-        try {
-            return mVold.isConvertibleToFbe();
-        } catch (Exception e) {
-            Slog.wtf(TAG, e);
-            return false;
-        }
-    }
-
     /**
      * Check whether the device supports filesystem checkpointing.
      *
@@ -3408,33 +3175,6 @@
     }
 
     @Override
-    public String getPassword() throws RemoteException {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
-                "only keyguard can retrieve password");
-
-        try {
-            return mVold.fdeGetPassword();
-        } catch (Exception e) {
-            Slog.wtf(TAG, e);
-            return null;
-        }
-    }
-
-    @Override
-    public void clearPassword() throws RemoteException {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
-                "only keyguard can clear password");
-
-        try {
-            mVold.fdeClearPassword();
-            return;
-        } catch (Exception e) {
-            Slog.wtf(TAG, e);
-            return;
-        }
-    }
-
-    @Override
     public void createUserKey(int userId, int serialNumber, boolean ephemeral) {
         enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
 
diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java
index ed545a6..206a310 100644
--- a/services/core/java/com/android/server/SystemService.java
+++ b/services/core/java/com/android/server/SystemService.java
@@ -32,6 +32,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.pm.UserManagerService;
 
 import java.io.PrintWriter;
@@ -261,13 +262,23 @@
         public @interface EventTypesFlag {
         }
 
-        private @EventTypesFlag int mEventType;
+        private final @EventTypesFlag int mEventType;
 
         /** @hide */
         UserCompletedEventType(@EventTypesFlag int eventType) {
             mEventType = eventType;
         }
 
+        /**
+         * Creates a new instance of {@link UserCompletedEventType}.
+         * @hide
+         */
+        @VisibleForTesting
+        public static UserCompletedEventType newUserCompletedEventTypeForTest(
+                @EventTypesFlag int eventType) {
+            return new UserCompletedEventType(eventType);
+        }
+
         /** Returns whether one of the events is {@link #onUserStarting}. */
         public boolean includesOnUserStarting() {
             return (mEventType & EVENT_TYPE_USER_STARTING) != 0;
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index b6b3618..24e5de9 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -1,9 +1,6 @@
 {
     "presubmit": [
         {
-            "name": "CtsLocationFineTestCases"
-        },
-        {
             "name": "CtsLocationCoarseTestCases"
         },
         {
@@ -64,5 +61,10 @@
             ],
             "file_patterns": ["ClipboardService\\.java"]
         }
+    ],
+    "postsubmit": [
+        {
+            "name": "CtsLocationFineTestCases"
+        }
     ]
 }
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 40ab0c0..839cdc6 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -91,7 +91,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IBatteryStats;
-import com.android.internal.telephony.ICarrierPrivilegesListener;
+import com.android.internal.telephony.ICarrierPrivilegesCallback;
 import com.android.internal.telephony.IOnSubscriptionsChangedListener;
 import com.android.internal.telephony.IPhoneStateListener;
 import com.android.internal.telephony.ITelephonyRegistry;
@@ -153,7 +153,7 @@
         IPhoneStateListener callback;
         IOnSubscriptionsChangedListener onSubscriptionsChangedListenerCallback;
         IOnSubscriptionsChangedListener onOpportunisticSubscriptionsChangedListenerCallback;
-        ICarrierPrivilegesListener carrierPrivilegesListener;
+        ICarrierPrivilegesCallback carrierPrivilegesCallback;
 
         int callerUid;
         int callerPid;
@@ -178,8 +178,8 @@
             return (onOpportunisticSubscriptionsChangedListenerCallback != null);
         }
 
-        boolean matchCarrierPrivilegesListener() {
-            return carrierPrivilegesListener != null;
+        boolean matchCarrierPrivilegesCallback() {
+            return carrierPrivilegesCallback != null;
         }
 
         boolean canReadCallLog() {
@@ -199,7 +199,7 @@
                     + onSubscriptionsChangedListenerCallback
                     + " onOpportunisticSubscriptionsChangedListenererCallback="
                     + onOpportunisticSubscriptionsChangedListenerCallback
-                    + " carrierPrivilegesListener=" + carrierPrivilegesListener
+                    + " carrierPrivilegesCallback=" + carrierPrivilegesCallback
                     + " subId=" + subId + " phoneId=" + phoneId + " events=" + eventList + "}";
         }
     }
@@ -414,7 +414,9 @@
             mPreciseDataConnectionStates;
 
     /** Per-phoneId snapshot of privileged packages (names + UIDs). */
-    private List<Pair<List<String>, int[]>> mCarrierPrivilegeStates;
+    @NonNull private List<Pair<List<String>, int[]>> mCarrierPrivilegeStates;
+    /** Per-phoneId of CarrierService (PackageName, UID) pair. */
+    @NonNull private List<Pair<String, Integer>> mCarrierServiceStates;
 
     /**
      * Support backward compatibility for {@link android.telephony.TelephonyDisplayInfo}.
@@ -705,6 +707,7 @@
                 cutListToSize(mPhysicalChannelConfigs, mNumPhones);
                 cutListToSize(mLinkCapacityEstimateLists, mNumPhones);
                 cutListToSize(mCarrierPrivilegeStates, mNumPhones);
+                cutListToSize(mCarrierServiceStates, mNumPhones);
                 return;
             }
 
@@ -746,6 +749,7 @@
                 mAllowedNetworkTypeValue[i] = -1;
                 mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST);
                 mCarrierPrivilegeStates.add(i, new Pair<>(Collections.emptyList(), new int[0]));
+                mCarrierServiceStates.add(i, new Pair<>(null, Process.INVALID_UID));
             }
         }
     }
@@ -813,6 +817,7 @@
         mDataEnabledReason = new int[numPhones];
         mLinkCapacityEstimateLists = new ArrayList<>();
         mCarrierPrivilegeStates = new ArrayList<>();
+        mCarrierServiceStates = new ArrayList<>();
 
         for (int i = 0; i < numPhones; i++) {
             mCallState[i] =  TelephonyManager.CALL_STATE_IDLE;
@@ -851,6 +856,7 @@
             mAllowedNetworkTypeValue[i] = -1;
             mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST);
             mCarrierPrivilegeStates.add(i, new Pair<>(Collections.emptyList(), new int[0]));
+            mCarrierServiceStates.add(i, new Pair<>(null, Process.INVALID_UID));
         }
 
         mAppOps = mContext.getSystemService(AppOpsManager.class);
@@ -2013,10 +2019,8 @@
             return;
         }
 
-        ApnSetting apnSetting = preciseState.getApnSetting();
-
         synchronized (mRecords) {
-            if (validatePhoneId(phoneId)) {
+            if (validatePhoneId(phoneId) && preciseState.getApnSetting() != null) {
                 Pair<Integer, ApnSetting> key = Pair.create(preciseState.getTransportType(),
                         preciseState.getApnSetting());
                 PreciseDataConnectionState oldState = mPreciseDataConnectionStates.get(phoneId)
@@ -2786,16 +2790,16 @@
     }
 
     @Override
-    public void addCarrierPrivilegesListener(
+    public void addCarrierPrivilegesCallback(
             int phoneId,
-            ICarrierPrivilegesListener callback,
-            String callingPackage,
-            String callingFeatureId) {
+            @NonNull ICarrierPrivilegesCallback callback,
+            @NonNull String callingPackage,
+            @NonNull String callingFeatureId) {
         int callerUserId = UserHandle.getCallingUserId();
         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
-                "addCarrierPrivilegesListener");
+                "addCarrierPrivilegesCallback");
         if (VDBG) {
             log(
                     "listen carrier privs: E pkg=" + pii(callingPackage) + " phoneId=" + phoneId
@@ -2815,7 +2819,7 @@
             if (r == null) return;
 
             r.context = mContext;
-            r.carrierPrivilegesListener = callback;
+            r.carrierPrivilegesCallback = callback;
             r.callingPackage = callingPackage;
             r.callingFeatureId = callingFeatureId;
             r.callerUid = Binder.getCallingUid();
@@ -2827,10 +2831,18 @@
             }
 
             Pair<List<String>, int[]> state = mCarrierPrivilegeStates.get(phoneId);
+            Pair<String, Integer> carrierServiceState = mCarrierServiceStates.get(phoneId);
             try {
-                r.carrierPrivilegesListener.onCarrierPrivilegesChanged(
-                        Collections.unmodifiableList(state.first),
-                        Arrays.copyOf(state.second, state.second.length));
+                if (r.matchCarrierPrivilegesCallback()) {
+                    // Here, two callbacks are triggered in quick succession on the same binder.
+                    // In typical case, we expect the callers to care about only one or the other.
+                    r.carrierPrivilegesCallback.onCarrierPrivilegesChanged(
+                            Collections.unmodifiableList(state.first),
+                            Arrays.copyOf(state.second, state.second.length));
+
+                    r.carrierPrivilegesCallback.onCarrierServiceChanged(carrierServiceState.first,
+                            carrierServiceState.second);
+                }
             } catch (RemoteException ex) {
                 remove(r.binder);
             }
@@ -2838,12 +2850,12 @@
     }
 
     @Override
-    public void removeCarrierPrivilegesListener(
-            ICarrierPrivilegesListener callback, String callingPackage) {
+    public void removeCarrierPrivilegesCallback(
+            @NonNull ICarrierPrivilegesCallback callback, @NonNull String callingPackage) {
         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
-                "removeCarrierPrivilegesListener");
+                "removeCarrierPrivilegesCallback");
         remove(callback.asBinder());
     }
 
@@ -2868,13 +2880,13 @@
             for (Record r : mRecords) {
                 // Listeners are per-slot, not per-subscription. This is to provide a stable
                 // view across SIM profile switches.
-                if (!r.matchCarrierPrivilegesListener()
+                if (!r.matchCarrierPrivilegesCallback()
                         || !idMatch(r, SubscriptionManager.INVALID_SUBSCRIPTION_ID, phoneId)) {
                     continue;
                 }
                 try {
                     // Make sure even in-process listeners can't modify the values.
-                    r.carrierPrivilegesListener.onCarrierPrivilegesChanged(
+                    r.carrierPrivilegesCallback.onCarrierPrivilegesChanged(
                             Collections.unmodifiableList(privilegedPackageNames),
                             Arrays.copyOf(privilegedUids, privilegedUids.length));
                 } catch (RemoteException ex) {
@@ -2885,6 +2897,34 @@
         }
     }
 
+    @Override
+    public void notifyCarrierServiceChanged(int phoneId, @Nullable String packageName, int uid) {
+        if (!checkNotifyPermission("notifyCarrierServiceChanged")) return;
+        if (!validatePhoneId(phoneId)) return;
+        if (VDBG) {
+            log("notifyCarrierServiceChanged: phoneId=" + phoneId
+                    + ", package=" + pii(packageName) + ", uid=" + uid);
+        }
+
+        synchronized (mRecords) {
+            mCarrierServiceStates.set(
+                    phoneId, new Pair<>(packageName, uid));
+            for (Record r : mRecords) {
+                // Listeners are per-slot, not per-subscription.
+                if (!r.matchCarrierPrivilegesCallback()
+                        || !idMatch(r, SubscriptionManager.INVALID_SUBSCRIPTION_ID, phoneId)) {
+                    continue;
+                }
+                try {
+                    r.carrierPrivilegesCallback.onCarrierServiceChanged(packageName, uid);
+                } catch (RemoteException ex) {
+                    mRemoveList.add(r.binder);
+                }
+            }
+            handleRemoveListLocked();
+        }
+    }
+
     @NeverCompile // Avoid size overhead of debugging code.
     @Override
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
@@ -2940,6 +2980,9 @@
                 pw.println(
                         "mCarrierPrivilegeState=<packages=" + pii(carrierPrivilegeState.first)
                                 + ", uids=" + Arrays.toString(carrierPrivilegeState.second) + ">");
+                Pair<String, Integer> carrierServiceState = mCarrierServiceStates.get(i);
+                pw.println("mCarrierServiceState=<package=" + pii(carrierServiceState.first)
+                        + ", uid=" + carrierServiceState.second + ">");
                 pw.decreaseIndent();
             }
 
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 569d480..2f84ec5 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -362,11 +362,9 @@
         getContext().getContentResolver().unregisterContentObserver(mSetupWizardObserver);
         verifySetupWizardCompleted();
         synchronized (mLock) {
-            // only update if the value is actually changed
-            if (updateNightModeFromSettingsLocked(getContext(), getContext().getResources(),
-                    to.getUserIdentifier())) {
-                updateLocked(0, 0);
-            }
+            updateNightModeFromSettingsLocked(getContext(), getContext().getResources(),
+                    to.getUserIdentifier());
+            updateLocked(0, 0);
         }
     }
 
@@ -534,19 +532,16 @@
     }
 
     /**
-     * Updates the night mode setting in Settings.Secure and returns if the value was successfully
-     * changed.
+     * Updates the night mode setting in Settings.Secure
      *
      * @param context A valid context
      * @param res     A valid resource object
      * @param userId  The user to update the setting for
-     * @return True if the new value is different from the old value. False otherwise.
      */
-    private boolean updateNightModeFromSettingsLocked(Context context, Resources res, int userId) {
+    private void updateNightModeFromSettingsLocked(Context context, Resources res, int userId) {
         if (mCarModeEnabled || mCar) {
-            return false;
+            return;
         }
-        int oldNightMode = mNightMode;
         if (mSetupWizardComplete) {
             mNightMode = Secure.getIntForUser(context.getContentResolver(),
                     Secure.UI_NIGHT_MODE, res.getInteger(
@@ -570,8 +565,6 @@
                         Secure.UI_NIGHT_MODE_LAST_COMPUTED, 0, userId) != 0;
             }
         }
-
-        return oldNightMode != mNightMode;
     }
 
     private static long toMilliSeconds(LocalTime t) {
@@ -1302,7 +1295,7 @@
             pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState);
 
             pw.print("  mNightMode="); pw.print(mNightMode); pw.print(" (");
-            pw.print(Shell.nightModeToStr(mNightMode)); pw.print(") ");
+            pw.print(Shell.nightModeToStr(mNightMode, mNightModeCustomType)); pw.print(") ");
             pw.print(" mOverrideOn/Off="); pw.print(mOverrideNightModeOn);
             pw.print("/"); pw.print(mOverrideNightModeOff);
 
@@ -1917,7 +1910,8 @@
         public static final String NIGHT_MODE_STR_YES = "yes";
         public static final String NIGHT_MODE_STR_NO = "no";
         public static final String NIGHT_MODE_STR_AUTO = "auto";
-        public static final String NIGHT_MODE_STR_CUSTOM = "custom";
+        public static final String NIGHT_MODE_STR_CUSTOM_SCHEDULE = "custom_schedule";
+        public static final String NIGHT_MODE_STR_CUSTOM_BEDTIME = "custom_bedtime";
         public static final String NIGHT_MODE_STR_UNKNOWN = "unknown";
         private final IUiModeManager mInterface;
 
@@ -1931,7 +1925,7 @@
             pw.println("UiModeManager service (uimode) commands:");
             pw.println("  help");
             pw.println("    Print this help text.");
-            pw.println("  night [yes|no|auto|custom]");
+            pw.println("  night [yes|no|auto|custom_schedule|custom_bedtime]");
             pw.println("    Set or read night mode.");
             pw.println("  car [yes|no]");
             pw.println("    Set or read car mode.");
@@ -2001,14 +1995,19 @@
             }
 
             final int mode = strToNightMode(modeStr);
+            final int customType = strToNightModeCustomType(modeStr);
             if (mode >= 0) {
                 mInterface.setNightMode(mode);
+                if (mode == UiModeManager.MODE_NIGHT_CUSTOM) {
+                    mInterface.setNightModeCustomType(customType);
+                }
                 printCurrentNightMode();
                 return 0;
             } else {
                 err.println("Error: mode must be '" + NIGHT_MODE_STR_YES + "', '"
                         + NIGHT_MODE_STR_NO + "', or '" + NIGHT_MODE_STR_AUTO
-                        +  "', or '" + NIGHT_MODE_STR_CUSTOM + "'");
+                        +  "', or '" + NIGHT_MODE_STR_CUSTOM_SCHEDULE + "', or '"
+                        + NIGHT_MODE_STR_CUSTOM_BEDTIME + "'");
                 return -1;
             }
         }
@@ -2016,11 +2015,12 @@
         private void printCurrentNightMode() throws RemoteException {
             final PrintWriter pw = getOutPrintWriter();
             final int currMode = mInterface.getNightMode();
-            final String currModeStr = nightModeToStr(currMode);
+            final int customType = mInterface.getNightModeCustomType();
+            final String currModeStr = nightModeToStr(currMode, customType);
             pw.println("Night mode: " + currModeStr);
         }
 
-        private static String nightModeToStr(int mode) {
+        private static String nightModeToStr(int mode, int customType) {
             switch (mode) {
                 case UiModeManager.MODE_NIGHT_YES:
                     return NIGHT_MODE_STR_YES;
@@ -2029,7 +2029,12 @@
                 case UiModeManager.MODE_NIGHT_AUTO:
                     return NIGHT_MODE_STR_AUTO;
                 case MODE_NIGHT_CUSTOM:
-                    return NIGHT_MODE_STR_CUSTOM;
+                    if (customType == UiModeManager.MODE_NIGHT_CUSTOM_TYPE_SCHEDULE) {
+                        return NIGHT_MODE_STR_CUSTOM_SCHEDULE;
+                    }
+                    if (customType == UiModeManager.MODE_NIGHT_CUSTOM_TYPE_BEDTIME) {
+                        return NIGHT_MODE_STR_CUSTOM_BEDTIME;
+                    }
                 default:
                     return NIGHT_MODE_STR_UNKNOWN;
             }
@@ -2043,13 +2048,25 @@
                     return UiModeManager.MODE_NIGHT_NO;
                 case NIGHT_MODE_STR_AUTO:
                     return UiModeManager.MODE_NIGHT_AUTO;
-                case NIGHT_MODE_STR_CUSTOM:
+                case NIGHT_MODE_STR_CUSTOM_SCHEDULE:
+                case NIGHT_MODE_STR_CUSTOM_BEDTIME:
                     return UiModeManager.MODE_NIGHT_CUSTOM;
                 default:
                     return -1;
             }
         }
 
+        private static int strToNightModeCustomType(String customTypeStr) {
+            switch (customTypeStr) {
+                case NIGHT_MODE_STR_CUSTOM_BEDTIME:
+                    return UiModeManager.MODE_NIGHT_CUSTOM_TYPE_BEDTIME;
+                case NIGHT_MODE_STR_CUSTOM_SCHEDULE:
+                    return UiModeManager.MODE_NIGHT_CUSTOM_TYPE_SCHEDULE;
+                default:
+                    return -1;
+            }
+        }
+
         private int handleCarMode() throws RemoteException {
             final PrintWriter err = getErrPrintWriter();
             final String modeStr = getNextArg();
diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java
index 7b8cce5..c1d8e7b 100644
--- a/services/core/java/com/android/server/VpnManagerService.java
+++ b/services/core/java/com/android/server/VpnManagerService.java
@@ -37,6 +37,7 @@
 import android.net.UnderlyingNetworkInfo;
 import android.net.Uri;
 import android.net.VpnManager;
+import android.net.VpnProfileState;
 import android.net.VpnService;
 import android.net.util.NetdService;
 import android.os.Binder;
@@ -374,6 +375,24 @@
     }
 
     /**
+     * Retrieve the VpnProfileState for the profile provisioned by the given package.
+     *
+     * @return the VpnProfileState with current information, or null if there was no profile
+     *         provisioned by the given package.
+     * @hide
+     */
+    @Override
+    @Nullable
+    public VpnProfileState getProvisionedVpnProfileState(@NonNull String packageName) {
+        final int callingUid = Binder.getCallingUid();
+        verifyCallingUidAndPackage(packageName, callingUid);
+        final int user = UserHandle.getUserId(callingUid);
+        synchronized (mVpns) {
+            return mVpns.get(user).getProvisionedVpnProfileState(packageName);
+        }
+    }
+
+    /**
      * Start legacy VPN, controlling native daemons as needed. Creates a
      * secondary thread to perform connection work, returning quickly.
      *
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index d4ad718..2c0514d 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -203,10 +203,6 @@
     // How long we wait for a service to finish executing.
     static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;
 
-    // How long the startForegroundService() grace period is to get around to
-    // calling startForeground() before we ANR + stop it.
-    static final int SERVICE_START_FOREGROUND_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
-
     // Foreground service types that always get immediate notification display,
     // expressed in the same bitmask format that ServiceRecord.foregroundServiceType
     // uses.
@@ -2722,7 +2718,7 @@
     int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
             String resolvedType, final IServiceConnection connection, int flags,
             String instanceName, boolean isSdkSandboxService, int sdkSandboxClientAppUid,
-            String callingPackage, final int userId)
+            String sdkSandboxClientAppPackage, String callingPackage, final int userId)
             throws TransactionTooLargeException {
         if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "bindService: " + service
                 + " type=" + resolvedType + " conn=" + connection.asBinder()
@@ -2789,6 +2785,11 @@
                             + ") set BIND_ALLOW_INSTANT when binding service " + service);
         }
 
+        if ((flags & Context.BIND_ALMOST_PERCEPTIBLE) != 0 && !isCallerSystem) {
+            throw new SecurityException("Non-system caller (pid=" + callingPid
+                    + ") set BIND_ALMOST_PERCEPTIBLE when binding service " + service);
+        }
+
         if ((flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) {
             mAm.enforceCallingPermission(
                     android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
@@ -2807,8 +2808,9 @@
         final boolean allowInstant = (flags & Context.BIND_ALLOW_INSTANT) != 0;
 
         ServiceLookupResult res = retrieveServiceLocked(service, instanceName,
-                isSdkSandboxService, sdkSandboxClientAppUid, resolvedType, callingPackage,
-                callingPid, callingUid, userId, true, callerFg, isBindExternal, allowInstant);
+                isSdkSandboxService, sdkSandboxClientAppUid, sdkSandboxClientAppPackage,
+                resolvedType, callingPackage, callingPid, callingUid, userId, true, callerFg,
+                isBindExternal, allowInstant);
         if (res == null) {
             return 0;
         }
@@ -2892,6 +2894,12 @@
                 s.isNotAppComponentUsage = true;
             }
 
+            if (s.app != null && s.app.mState != null
+                    && s.app.mState.getCurProcState() <= PROCESS_STATE_TOP
+                    && (flags & Context.BIND_ALMOST_PERCEPTIBLE) != 0) {
+                s.lastTopAlmostPerceptibleBindRequestUptimeMs = SystemClock.uptimeMillis();
+            }
+
             if (s.app != null) {
                 updateServiceClientActivitiesLocked(s.app.mServices, c, true);
             }
@@ -3228,14 +3236,14 @@
             int callingPid, int callingUid, int userId,
             boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal,
             boolean allowInstant) {
-        return retrieveServiceLocked(service, instanceName, false, 0, resolvedType, callingPackage,
-                callingPid, callingUid, userId, createIfNeeded, callingFromFg, isBindExternal,
-                allowInstant);
+        return retrieveServiceLocked(service, instanceName, false, 0, null, resolvedType,
+                callingPackage, callingPid, callingUid, userId, createIfNeeded, callingFromFg,
+                isBindExternal, allowInstant);
     }
 
     private ServiceLookupResult retrieveServiceLocked(Intent service,
             String instanceName, boolean isSdkSandboxService, int sdkSandboxClientAppUid,
-            String resolvedType,
+            String sdkSandboxClientAppPackage, String resolvedType,
             String callingPackage, int callingPid, int callingUid, int userId,
             boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal,
             boolean allowInstant) {
@@ -3416,7 +3424,8 @@
                                                                                   : null;
                     r = new ServiceRecord(mAm, className, name, definingPackageName,
                             definingUid, filter, sInfo, callingFromFg, res,
-                            sdkSandboxProcessName, sdkSandboxClientAppUid);
+                            sdkSandboxProcessName, sdkSandboxClientAppUid,
+                            sdkSandboxClientAppPackage);
                     res.setService(r);
                     smap.mServicesByInstanceName.put(name, r);
                     smap.mServicesByIntent.put(filter, r);
@@ -3799,6 +3808,18 @@
     @GuardedBy("mAm")
     void performScheduleRestartLocked(ServiceRecord r, @NonNull String scheduling,
             @NonNull String reason, @UptimeMillisLong long now) {
+
+        // If the service is waiting to become a foreground service, remove the pending
+        // SERVICE_FOREGROUND_TIMEOUT_MSG msg, and set fgWaiting to false, so next time the service
+        // is brought up, scheduleServiceForegroundTransitionTimeoutLocked() can be called again and
+        // a new SERVICE_FOREGROUND_TIMEOUT_MSG is scheduled in SERVICE_START_FOREGROUND_TIMEOUT
+        // again.
+        if (r.fgRequired && r.fgWaiting) {
+            mAm.mHandler.removeMessages(
+                    ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
+            r.fgWaiting = false;
+        }
+
         mAm.mHandler.removeCallbacks(r.restarter);
         mAm.mHandler.postAtTime(r.restarter, r.nextRestartTime);
         r.nextRestartTime = now + r.restartDelay;
@@ -4195,7 +4216,7 @@
             if (r.isSdkSandbox) {
                 final int uid = Process.toSdkSandboxUid(r.sdkSandboxClientAppUid);
                 app = mAm.startSdkSandboxProcessLocked(procName, r.appInfo, true, intentFlags,
-                        hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, uid);
+                        hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, uid, r.sdkSandboxClientAppPackage);
                 r.isolationHostProc = app;
             } else {
                 app = mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
@@ -4221,7 +4242,7 @@
                         + " for fg-service launch");
             }
             mAm.tempAllowlistUidLocked(r.appInfo.uid,
-                    SERVICE_START_FOREGROUND_TIMEOUT, REASON_SERVICE_LAUNCH,
+                    mAm.mConstants.mServiceStartForegroundTimeoutMs, REASON_SERVICE_LAUNCH,
                     "fg-service-launch",
                     TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
                     r.mRecentCallingUid);
@@ -4783,6 +4804,10 @@
             if ((c.flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) {
                 s.updateIsAllowedBgActivityStartsByBinding();
             }
+            // And for almost perceptible exceptions.
+            if ((c.flags & Context.BIND_ALMOST_PERCEPTIBLE) != 0) {
+                psr.updateHasTopStartedAlmostPerceptibleServices();
+            }
             if (s.app != null) {
                 updateServiceClientActivitiesLocked(s.app.mServices, c, true);
             }
@@ -5676,7 +5701,7 @@
     void serviceForegroundTimeout(ServiceRecord r) {
         ProcessRecord app;
         synchronized (mAm) {
-            if (!r.fgRequired || r.destroying) {
+            if (!r.fgRequired || !r.fgWaiting || r.destroying) {
                 return;
             }
 
@@ -5694,12 +5719,23 @@
         }
 
         if (app != null) {
-            mAm.mAnrHelper.appNotResponding(app,
-                    "Context.startForegroundService() did not then call Service.startForeground(): "
-                        + r);
+            final String annotation = "Context.startForegroundService() did not then call "
+                    + "Service.startForeground(): " + r;
+            Message msg = mAm.mHandler.obtainMessage(
+                    ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_ANR_MSG);
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = app;
+            args.arg2 = annotation;
+            msg.obj = args;
+            mAm.mHandler.sendMessageDelayed(msg,
+                    mAm.mConstants.mServiceStartForegroundAnrDelayMs);
         }
     }
 
+    void serviceForegroundTimeoutANR(ProcessRecord app, String annotation) {
+        mAm.mAnrHelper.appNotResponding(app, annotation);
+    }
+
     public void updateServiceApplicationInfoLocked(ApplicationInfo applicationInfo) {
         final int userId = UserHandle.getUserId(applicationInfo.uid);
         ServiceMap serviceMap = mServiceMap.get(userId);
@@ -5720,7 +5756,7 @@
             ComponentName service) {
         mAm.crashApplicationWithTypeWithExtras(
                 app.uid, app.getPid(), app.info.packageName, app.userId,
-                "Context.startForegroundService() did not then call Service.startForeground(): "
+                "Context.startForegroundService() did not then call " + "Service.startForeground(): "
                     + serviceRecord, false /*force*/,
                 ForegroundServiceDidNotStartInTimeException.TYPE_ID,
                 ForegroundServiceDidNotStartInTimeException.createExtrasForService(service));
@@ -5745,7 +5781,7 @@
                 ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG);
         msg.obj = r;
         r.fgWaiting = true;
-        mAm.mHandler.sendMessageDelayed(msg, SERVICE_START_FOREGROUND_TIMEOUT);
+        mAm.mHandler.sendMessageDelayed(msg, mAm.mConstants.mServiceStartForegroundTimeoutMs);
     }
 
     final class ServiceDumper {
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 18e0155..af9e410 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -108,6 +108,8 @@
     static final String KEY_PROCESS_START_ASYNC = "process_start_async";
     static final String KEY_MEMORY_INFO_THROTTLE_TIME = "memory_info_throttle_time";
     static final String KEY_TOP_TO_FGS_GRACE_DURATION = "top_to_fgs_grace_duration";
+    static final String KEY_TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION =
+            "top_to_almost_perceptible_grace_duration";
     static final String KEY_PENDINGINTENT_WARNING_THRESHOLD = "pendingintent_warning_threshold";
     static final String KEY_MIN_CRASH_INTERVAL = "min_crash_interval";
     static final String KEY_PROCESS_CRASH_COUNT_RESET_INTERVAL =
@@ -127,7 +129,15 @@
     static final String KEY_KILL_BG_RESTRICTED_CACHED_IDLE = "kill_bg_restricted_cached_idle";
     static final String KEY_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME =
             "kill_bg_restricted_cached_idle_settle_time";
+    /**
+     * Note this key is on {@link DeviceConfig#NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS}.
+     * @see #mEnableComponentAlias
+     */
     static final String KEY_ENABLE_COMPONENT_ALIAS = "enable_experimental_component_alias";
+    /**
+     * Note this key is on {@link DeviceConfig#NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS}.
+     * @see #mComponentAliasOverrides
+     */
     static final String KEY_COMPONENT_ALIAS_OVERRIDES = "component_alias_overrides";
 
     private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
@@ -162,6 +172,7 @@
     private static final boolean DEFAULT_PROCESS_START_ASYNC = true;
     private static final long DEFAULT_MEMORY_INFO_THROTTLE_TIME = 5*60*1000;
     private static final long DEFAULT_TOP_TO_FGS_GRACE_DURATION = 15 * 1000;
+    private static final long DEFAULT_TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION = 15 * 1000;
     private static final int DEFAULT_PENDINGINTENT_WARNING_THRESHOLD = 2000;
     private static final int DEFAULT_MIN_CRASH_INTERVAL = 2 * 60 * 1000;
     private static final int DEFAULT_MAX_PHANTOM_PROCESSES = 32;
@@ -208,8 +219,14 @@
     private static final String DEFAULT_COMPONENT_ALIAS_OVERRIDES = "";
 
     private static final int DEFAULT_DEFER_BOOT_COMPLETED_BROADCAST =
-            DEFER_BOOT_COMPLETED_BROADCAST_BACKGROUND_RESTRICTED_ONLY
-            | DEFER_BOOT_COMPLETED_BROADCAST_TARGET_T_ONLY;
+             DEFER_BOOT_COMPLETED_BROADCAST_BACKGROUND_RESTRICTED_ONLY
+             | DEFER_BOOT_COMPLETED_BROADCAST_TARGET_T_ONLY;
+
+    private static final int DEFAULT_SERVICE_START_FOREGROUND_TIMEOUT_MS = 30 * 1000;
+
+    private static final int DEFAULT_SERVICE_START_FOREGROUND_ANR_DELAY_MS = 10 * 1000;
+
+    private static final long DEFAULT_SERVICE_BIND_ALMOST_PERCEPTIBLE_TIMEOUT_MS = 15 * 1000;
 
     // Flag stored in the DeviceConfig API.
     /**
@@ -303,6 +320,15 @@
     private static final String KEY_DEFER_BOOT_COMPLETED_BROADCAST =
             "defer_boot_completed_broadcast";
 
+    private static final String KEY_SERVICE_START_FOREGROUND_TIMEOUT_MS =
+            "service_start_foreground_timeout_ms";
+
+    private static final String KEY_SERVICE_START_FOREGROUND_ANR_DELAY_MS =
+            "service_start_foreground_anr_delay_ms";
+
+    private static final String KEY_SERVICE_BIND_ALMOST_PERCEPTIBLE_TIMEOUT_MS =
+            "service_bind_almost_perceptible_timeout_ms";
+
     // Maximum number of cached processes we will allow.
     public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
 
@@ -446,6 +472,13 @@
     public long TOP_TO_FGS_GRACE_DURATION = DEFAULT_TOP_TO_FGS_GRACE_DURATION;
 
     /**
+     * Allow app just leaving TOP with an already running ALMOST_PERCEPTIBLE service to stay in
+     * a higher adj value for this long.
+     */
+    public long TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION =
+            DEFAULT_TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION;
+
+    /**
      * The minimum time we allow between crashes, for us to consider this
      * application to be bad and stop its services and reject broadcasts.
      * A reasonable interval here would be anything between 1-3 minutes.
@@ -623,6 +656,26 @@
             DEFAULT_DEFER_BOOT_COMPLETED_BROADCAST;
 
     /**
+     * How long the Context.startForegroundService() grace period is to get around to
+     * calling Service.startForeground() before we generate ANR.
+     */
+    volatile int mServiceStartForegroundTimeoutMs = DEFAULT_SERVICE_START_FOREGROUND_TIMEOUT_MS;
+
+    /**
+     *  How long from Service.startForeground() timed-out to when we generate ANR of the user app.
+     *  This delay is after the timeout {@link #mServiceStartForegroundTimeoutMs}.
+     */
+    volatile int mServiceStartForegroundAnrDelayMs =
+            DEFAULT_SERVICE_START_FOREGROUND_ANR_DELAY_MS;
+
+    /**
+     * How long the grace period is from starting an almost perceptible service to a successful
+     * binding before we stop considering it an almost perceptible service.
+     */
+    volatile long mServiceBindAlmostPerceptibleTimeoutMs =
+            DEFAULT_SERVICE_BIND_ALMOST_PERCEPTIBLE_TIMEOUT_MS;
+
+    /**
      * Defines component aliases. Format
      * ComponentName ":" ComponentName ( "," ComponentName ":" ComponentName )*
      */
@@ -660,11 +713,11 @@
             "no_kill_cached_processes_post_boot_completed_duration_millis";
 
     /** @see #mNoKillCachedProcessesUntilBootCompleted */
-    private static final boolean DEFAULT_NO_KILL_CACHED_PROCESSES_UNTIL_BOOT_COMPLETED = false;
+    private static final boolean DEFAULT_NO_KILL_CACHED_PROCESSES_UNTIL_BOOT_COMPLETED = true;
 
     /** @see #mNoKillCachedProcessesPostBootCompletedDurationMillis */
     private static final long
-            DEFAULT_NO_KILL_CACHED_PROCESSES_POST_BOOT_COMPLETED_DURATION_MILLIS = 0;
+            DEFAULT_NO_KILL_CACHED_PROCESSES_POST_BOOT_COMPLETED_DURATION_MILLIS = 600_000;
 
     /**
      * If true, do not kill excessive cached processes proactively, until user-0 is unlocked.
@@ -899,16 +952,21 @@
                             case KEY_ENABLE_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE:
                                 updateEnableExtraServiceRestartDelayOnMemPressure();
                                 break;
-                            case KEY_ENABLE_COMPONENT_ALIAS:
-                            case KEY_COMPONENT_ALIAS_OVERRIDES:
-                                updateComponentAliases();
-                                break;
                             case KEY_PROCESS_KILL_TIMEOUT:
                                 updateProcessKillTimeout();
                                 break;
                             case KEY_DEFER_BOOT_COMPLETED_BROADCAST:
                                 updateDeferBootCompletedBroadcast();
                                 break;
+                            case KEY_SERVICE_START_FOREGROUND_TIMEOUT_MS:
+                                updateServiceStartForegroundTimeoutMs();
+                                break;
+                            case KEY_SERVICE_START_FOREGROUND_ANR_DELAY_MS:
+                                updateServiceStartForegroundAnrDealyMs();
+                                break;
+                            case KEY_SERVICE_BIND_ALMOST_PERCEPTIBLE_TIMEOUT_MS:
+                                updateServiceBindAlmostPerceptibleTimeoutMs();
+                                break;
                             case KEY_NO_KILL_CACHED_PROCESSES_UNTIL_BOOT_COMPLETED:
                                 updateNoKillCachedProcessesUntilBootCompleted();
                                 break;
@@ -925,6 +983,26 @@
                 }
             };
 
+    private final OnPropertiesChangedListener mOnDeviceConfigChangedForComponentAliasListener =
+            new OnPropertiesChangedListener() {
+                @Override
+                public void onPropertiesChanged(Properties properties) {
+                    for (String name : properties.getKeyset()) {
+                        if (name == null) {
+                            return;
+                        }
+                        switch (name) {
+                            case KEY_ENABLE_COMPONENT_ALIAS:
+                            case KEY_COMPONENT_ALIAS_OVERRIDES:
+                                updateComponentAliases();
+                                break;
+                            default:
+                                break;
+                        }
+                    }
+                }
+            };
+
     ActivityManagerConstants(Context context, ActivityManagerService service, Handler handler) {
         super(handler);
         mService = service;
@@ -991,6 +1069,10 @@
         DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                 ActivityThread.currentApplication().getMainExecutor(),
                 mOnDeviceConfigChangedListener);
+        DeviceConfig.addOnPropertiesChangedListener(
+                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS,
+                ActivityThread.currentApplication().getMainExecutor(),
+                mOnDeviceConfigChangedForComponentAliasListener);
         loadDeviceConfigConstants();
         // The following read from Settings.
         updateActivityStartsLoggingEnabled();
@@ -1000,6 +1082,9 @@
     private void loadDeviceConfigConstants() {
         mOnDeviceConfigChangedListener.onPropertiesChanged(
                 DeviceConfig.getProperties(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER));
+        mOnDeviceConfigChangedForComponentAliasListener.onPropertiesChanged(
+                DeviceConfig.getProperties(
+                        DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS));
     }
 
     public void setOverrideMaxCachedProcesses(int value) {
@@ -1110,6 +1195,9 @@
                     DEFAULT_MEMORY_INFO_THROTTLE_TIME);
             TOP_TO_FGS_GRACE_DURATION = mParser.getDurationMillis(KEY_TOP_TO_FGS_GRACE_DURATION,
                     DEFAULT_TOP_TO_FGS_GRACE_DURATION);
+            TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION = mParser.getDurationMillis(
+                    KEY_TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION,
+                    DEFAULT_TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION);
             MIN_CRASH_INTERVAL = mParser.getInt(KEY_MIN_CRASH_INTERVAL,
                     DEFAULT_MIN_CRASH_INTERVAL);
             PENDINGINTENT_WARNING_THRESHOLD = mParser.getInt(KEY_PENDINGINTENT_WARNING_THRESHOLD,
@@ -1358,6 +1446,28 @@
                 DEFAULT_MAX_EMPTY_TIME_MILLIS);
     }
 
+    private void updateServiceStartForegroundTimeoutMs() {
+        mServiceStartForegroundTimeoutMs = DeviceConfig.getInt(
+                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_SERVICE_START_FOREGROUND_TIMEOUT_MS,
+                DEFAULT_SERVICE_START_FOREGROUND_TIMEOUT_MS);
+    }
+
+    private void updateServiceStartForegroundAnrDealyMs() {
+        mServiceStartForegroundAnrDelayMs = DeviceConfig.getInt(
+                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_SERVICE_START_FOREGROUND_ANR_DELAY_MS,
+                DEFAULT_SERVICE_START_FOREGROUND_ANR_DELAY_MS);
+    }
+
+    private void updateServiceBindAlmostPerceptibleTimeoutMs() {
+        mServiceBindAlmostPerceptibleTimeoutMs = DeviceConfig.getLong(
+                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_SERVICE_BIND_ALMOST_PERCEPTIBLE_TIMEOUT_MS,
+                DEFAULT_SERVICE_BIND_ALMOST_PERCEPTIBLE_TIMEOUT_MS);
+    }
+
+
     private long[] parseLongArray(@NonNull String key, @NonNull long[] def) {
         final String val = DeviceConfig.getString(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                 key, null);
@@ -1379,11 +1489,11 @@
 
     private void updateComponentAliases() {
         mEnableComponentAlias = DeviceConfig.getBoolean(
-                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS,
                 KEY_ENABLE_COMPONENT_ALIAS,
                 DEFAULT_ENABLE_COMPONENT_ALIAS);
         mComponentAliasOverrides = DeviceConfig.getString(
-                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS,
                 KEY_COMPONENT_ALIAS_OVERRIDES,
                 DEFAULT_COMPONENT_ALIAS_OVERRIDES);
         mService.mComponentAliasResolver.update(mEnableComponentAlias, mComponentAliasOverrides);
@@ -1573,6 +1683,8 @@
         pw.println(MEMORY_INFO_THROTTLE_TIME);
         pw.print("  "); pw.print(KEY_TOP_TO_FGS_GRACE_DURATION); pw.print("=");
         pw.println(TOP_TO_FGS_GRACE_DURATION);
+        pw.print("  "); pw.print(KEY_TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION); pw.print("=");
+        pw.println(TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION);
         pw.print("  "); pw.print(KEY_MIN_CRASH_INTERVAL); pw.print("=");
         pw.println(MIN_CRASH_INTERVAL);
         pw.print("  "); pw.print(KEY_PROCESS_CRASH_COUNT_RESET_INTERVAL); pw.print("=");
@@ -1638,6 +1750,12 @@
         pw.print("="); pw.println(mNoKillCachedProcessesPostBootCompletedDurationMillis);
         pw.print("  "); pw.print(KEY_MAX_EMPTY_TIME_MILLIS);
         pw.print("="); pw.println(mMaxEmptyTimeMillis);
+        pw.print("  "); pw.print(KEY_SERVICE_START_FOREGROUND_TIMEOUT_MS);
+        pw.print("="); pw.println(mServiceStartForegroundTimeoutMs);
+        pw.print("  "); pw.print(KEY_SERVICE_START_FOREGROUND_ANR_DELAY_MS);
+        pw.print("="); pw.println(mServiceStartForegroundAnrDelayMs);
+        pw.print("  "); pw.print(KEY_SERVICE_BIND_ALMOST_PERCEPTIBLE_TIMEOUT_MS);
+        pw.print("="); pw.println(mServiceBindAlmostPerceptibleTimeoutMs);
 
         pw.println();
         if (mOverrideMaxCachedProcesses >= 0) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerLocal.java b/services/core/java/com/android/server/am/ActivityManagerLocal.java
index 3226a2b..1d2c36b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerLocal.java
+++ b/services/core/java/com/android/server/am/ActivityManagerLocal.java
@@ -74,6 +74,8 @@
      * @param conn Receives information as the service is started and stopped.
      *        This must be a valid ServiceConnection object; it must not be null.
      * @param clientAppUid Uid of the app for which the sdk sandbox process needs to be spawned.
+     * @param clientAppPackage Package of the app for which the sdk sandbox process needs to
+     *        be spawned. This package must belong to the clientAppUid.
      * @param processName Unique identifier for the service instance. Each unique name here will
      *        result in a different service instance being created. Identifiers must only contain
      *        ASCII letters, digits, underscores, and periods.
@@ -87,6 +89,7 @@
      */
     @SuppressLint("RethrowRemoteException")
     boolean bindSdkSandboxService(@NonNull Intent service, @NonNull ServiceConnection conn,
-            int clientAppUid, @NonNull String processName, @Context.BindServiceFlags int flags)
+            int clientAppUid, @NonNull String clientAppPackage, @NonNull String processName,
+            @Context.BindServiceFlags int flags)
             throws RemoteException;
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 95e35ef..c45b9f2 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -36,6 +36,7 @@
 import static android.app.ActivityManager.StopUserOnSwitch;
 import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
 import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
+import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.OP_NONE;
 import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT;
 import static android.content.pm.PackageManager.GET_SHARED_LIBRARY_FILES;
@@ -405,6 +406,7 @@
 import com.android.server.pm.pkg.SELinuxUtil;
 import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
 import com.android.server.pm.snapshot.PackageDataSnapshot;
+import com.android.server.sdksandbox.SdkSandboxManagerLocal;
 import com.android.server.uri.GrantUri;
 import com.android.server.uri.NeededUriGrants;
 import com.android.server.uri.UriGrantsManagerInternal;
@@ -573,6 +575,7 @@
     static final String EXTRA_TITLE = "android.intent.extra.TITLE";
     static final String EXTRA_DESCRIPTION = "android.intent.extra.DESCRIPTION";
     static final String EXTRA_BUGREPORT_TYPE = "android.intent.extra.BUGREPORT_TYPE";
+    static final String EXTRA_BUGREPORT_NONCE = "android.intent.extra.BUGREPORT_NONCE";
 
     /**
      * It is now required for apps to explicitly set either
@@ -1533,6 +1536,7 @@
     static final int IDLE_UIDS_MSG = 58;
     static final int HANDLE_TRUST_STORAGE_UPDATE_MSG = 63;
     static final int SERVICE_FOREGROUND_TIMEOUT_MSG = 66;
+    static final int SERVICE_FOREGROUND_TIMEOUT_ANR_MSG = 67;
     static final int PUSH_TEMP_ALLOWLIST_UI_MSG = 68;
     static final int SERVICE_FOREGROUND_CRASH_MSG = 69;
     static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70;
@@ -1721,6 +1725,12 @@
             case SERVICE_FOREGROUND_TIMEOUT_MSG: {
                 mServices.serviceForegroundTimeout((ServiceRecord) msg.obj);
             } break;
+            case SERVICE_FOREGROUND_TIMEOUT_ANR_MSG: {
+                SomeArgs args = (SomeArgs) msg.obj;
+                mServices.serviceForegroundTimeoutANR((ProcessRecord) args.arg1,
+                        (String) args.arg2);
+                args.recycle();
+            } break;
             case SERVICE_FOREGROUND_CRASH_MSG: {
                 SomeArgs args = (SomeArgs) msg.obj;
                 mServices.serviceForegroundCrash(
@@ -1895,6 +1905,7 @@
                         0,
                         false,
                         0,
+                        null,
                         new HostingRecord("system"));
                 app.setPersistent(true);
                 app.setPid(MY_PID);
@@ -2783,7 +2794,8 @@
                     false /* knownToBeDead */, 0 /* intentFlags */,
                     sNullHostingRecord  /* hostingRecord */, ZYGOTE_POLICY_FLAG_EMPTY,
                     true /* allowWhileBooting */, true /* isolated */,
-                    uid, false /* supplemental */, 0 /* supplementalUid */,
+                    uid, false /* isSdkSandbox */, 0 /* sdkSandboxUid */,
+                    null /* sdkSandboxClientAppPackage */,
                     abiOverride, entryPoint, entryPointArgs, crashHandler);
             return proc != null;
         }
@@ -2792,11 +2804,12 @@
     @GuardedBy("this")
     final ProcessRecord startSdkSandboxProcessLocked(String processName,
             ApplicationInfo info, boolean knownToBeDead, int intentFlags,
-            HostingRecord hostingRecord, int zygotePolicyFlags, int sdkSandboxUid) {
+            HostingRecord hostingRecord, int zygotePolicyFlags, int sdkSandboxUid,
+            String sdkSandboxClientAppPackage) {
         return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
                 hostingRecord, zygotePolicyFlags, false /* allowWhileBooting */,
                 false /* isolated */, 0 /* isolatedUid */,
-                true /* isSdkSandbox */, sdkSandboxUid,
+                true /* isSdkSandbox */, sdkSandboxUid, sdkSandboxClientAppPackage,
                 null /* ABI override */, null /* entryPoint */,
                 null /* entryPointArgs */, null /* crashHandler */);
     }
@@ -2808,7 +2821,8 @@
             boolean isolated) {
         return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
                 hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */,
-                false /* isSdkSandbox */, 0 /* sdkSandboxClientdAppUid */,
+                false /* isSdkSandbox */, 0 /* sdkSandboxClientAppUid */,
+                null /* sdkSandboxClientAppPackage */,
                 null /* ABI override */, null /* entryPoint */,
                 null /* entryPointArgs */, null /* crashHandler */);
     }
@@ -2906,12 +2920,35 @@
         return mAtmInternal.compatibilityInfoForPackage(ai);
     }
 
+    /**
+     * Enforces that the uid that calls a method is not an
+     * {@link UserHandle#isIsolated(int) isolated} uid.
+     *
+     * @param caller the name of the method being called.
+     * @throws SecurityException if the calling uid is an isolated uid.
+     */
     /* package */ void enforceNotIsolatedCaller(String caller) {
         if (UserHandle.isIsolated(Binder.getCallingUid())) {
             throw new SecurityException("Isolated process not allowed to call " + caller);
         }
     }
 
+    /**
+     * Enforces that the uid that calls a method is not an
+     * {@link UserHandle#isIsolated(int) isolated} uid or an
+     * {@link Process#isSdkSandboxUid(int) SDK sandbox} uid.
+     *
+     * @param caller the name of the method being called.
+     * @throws SecurityException if the calling uid is an isolated uid or SDK sandbox uid.
+     */
+    void enforceNotIsolatedOrSdkSandboxCaller(String caller) {
+        enforceNotIsolatedCaller(caller);
+
+        if (Process.isSdkSandboxUid(Binder.getCallingUid())) {
+            throw new SecurityException("SDK sandbox process not allowed to call " + caller);
+        }
+    }
+
     @Override
     public void setPackageScreenCompatMode(String packageName, int mode) {
         mActivityTaskManager.setPackageScreenCompatMode(packageName, mode);
@@ -4773,7 +4810,8 @@
                 thread.runIsolatedEntryPoint(
                         app.getIsolatedEntryPoint(), app.getIsolatedEntryPointArgs());
             } else if (instr2 != null) {
-                thread.bindApplication(processName, appInfo, providerList,
+                thread.bindApplication(processName, appInfo, app.sdkSandboxClientAppPackage,
+                        providerList,
                         instr2.mClass,
                         profilerInfo, instr2.mArguments,
                         instr2.mWatcher,
@@ -4787,8 +4825,8 @@
                         app.getDisabledCompatChanges(), serializedSystemFontMap,
                         app.getStartElapsedTime(), app.getStartUptime());
             } else {
-                thread.bindApplication(processName, appInfo, providerList, null, profilerInfo,
-                        null, null, null, testMode,
+                thread.bindApplication(processName, appInfo, app.sdkSandboxClientAppPackage,
+                        providerList, null, profilerInfo, null, null, null, testMode,
                         mBinderTransactionTrackingEnabled, enableTrackAllocation,
                         isRestrictedBackupMode || !normalMode, app.isPersistent(),
                         new Configuration(app.getWindowProcessController().getConfiguration()),
@@ -5749,6 +5787,18 @@
                 owningUid, exported);
     }
 
+    private void enforceDebuggable(ProcessRecord proc) {
+        if (!Build.IS_DEBUGGABLE && !proc.isDebuggable()) {
+            throw new SecurityException("Process not debuggable: " + proc.info.packageName);
+        }
+    }
+
+    private void enforceDebuggable(ApplicationInfo info) {
+        if (!Build.IS_DEBUGGABLE && (info.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
+            throw new SecurityException("Process not debuggable: " + info.packageName);
+        }
+    }
+
     /**
      * As the only public entry point for permissions checking, this method
      * can enforce the semantic that requesting a check on a null global
@@ -6543,6 +6593,30 @@
     final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
             boolean disableHiddenApiChecks, boolean disableTestApiChecks,
             String abiOverride, int zygotePolicyFlags) {
+        return addAppLocked(
+                info,
+                customProcess,
+                isolated,
+                /* isSdkSandbox= */ false,
+                /* sdkSandboxUid= */ 0,
+                /* sdkSandboxClientAppPackage= */ null,
+                disableHiddenApiChecks,
+                disableTestApiChecks,
+                abiOverride,
+                zygotePolicyFlags);
+    }
+
+    final ProcessRecord addAppLocked(
+            ApplicationInfo info,
+            String customProcess,
+            boolean isolated,
+            boolean isSdkSandbox,
+            int sdkSandboxUid,
+            @Nullable String sdkSandboxClientAppPackage,
+            boolean disableHiddenApiChecks,
+            boolean disableTestApiChecks,
+            String abiOverride,
+            int zygotePolicyFlags) {
         ProcessRecord app;
         if (!isolated) {
             app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName,
@@ -6552,10 +6626,16 @@
         }
 
         if (app == null) {
-            app = mProcessList.newProcessRecordLocked(info, customProcess, isolated, 0,
-                    false, 0,
+            app = mProcessList.newProcessRecordLocked(
+                    info,
+                    customProcess,
+                    isolated,
+                    /* isolatedUid= */0,
+                    isSdkSandbox,
+                    sdkSandboxUid,
+                    sdkSandboxClientAppPackage,
                     new HostingRecord("added application",
-                        customProcess != null ? customProcess : info.processName));
+                            customProcess != null ? customProcess : info.processName));
             updateLruProcessLocked(app, false, null);
             updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN);
         }
@@ -6565,13 +6645,16 @@
                 Event.APP_COMPONENT_USED);
 
         // This package really, really can not be stopped.
-        try {
-            AppGlobals.getPackageManager().setPackageStoppedState(
-                    info.packageName, false, UserHandle.getUserId(app.uid));
-        } catch (RemoteException e) {
-        } catch (IllegalArgumentException e) {
-            Slog.w(TAG, "Failed trying to unstop package "
-                    + info.packageName + ": " + e);
+        // TODO: how set package stopped state should work for sdk sandboxes?
+        if (!isSdkSandbox) {
+            try {
+                AppGlobals.getPackageManager().setPackageStoppedState(
+                        info.packageName, false, UserHandle.getUserId(app.uid));
+            } catch (RemoteException e) {
+            } catch (IllegalArgumentException e) {
+                Slog.w(TAG, "Failed trying to unstop package "
+                        + info.packageName + ": " + e);
+            }
         }
 
         if ((info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
@@ -6786,22 +6869,25 @@
     }
 
     void setTrackAllocationApp(ApplicationInfo app, String processName) {
-        if (!Build.IS_DEBUGGABLE) {
-            if ((app.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
-                throw new SecurityException("Process not debuggable: " + app.packageName);
-            }
-        }
+        enforceDebuggable(app);
 
         synchronized (mProcLock) {
             mTrackAllocationApp = processName;
         }
     }
 
-    void setProfileApp(ApplicationInfo app, String processName, ProfilerInfo profilerInfo) {
+    void setProfileApp(ApplicationInfo app, String processName, ProfilerInfo profilerInfo,
+            ApplicationInfo sdkSandboxClientApp) {
         synchronized (mAppProfiler.mProfilerLock) {
             if (!Build.IS_DEBUGGABLE) {
                 boolean isAppDebuggable = (app.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
                 boolean isAppProfileable = app.isProfileableByShell();
+
+                if (sdkSandboxClientApp != null) {
+                    isAppDebuggable |=
+                            (sdkSandboxClientApp.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+                    isAppProfileable |= sdkSandboxClientApp.isProfileableByShell();
+                }
                 if (!isAppDebuggable && !isAppProfileable) {
                     throw new SecurityException("Process not debuggable, "
                             + "and not profileable by shell: " + app.packageName);
@@ -6812,11 +6898,7 @@
     }
 
     void setNativeDebuggingAppLocked(ApplicationInfo app, String processName) {
-        if (!Build.IS_DEBUGGABLE) {
-            if ((app.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
-                throw new SecurityException("Process not debuggable: " + app.packageName);
-            }
-        }
+        enforceDebuggable(app);
         mNativeDebuggingApp = processName;
     }
 
@@ -6904,7 +6986,7 @@
      */
     @Override
     public void requestBugReport(@BugreportParams.BugreportMode int bugreportType) {
-        requestBugReportWithDescription(null, null, bugreportType);
+        requestBugReportWithDescription(null, null, bugreportType, 0L);
     }
 
     /**
@@ -6914,6 +6996,15 @@
     @Override
     public void requestBugReportWithDescription(@Nullable String shareTitle,
             @Nullable String shareDescription, int bugreportType) {
+        requestBugReportWithDescription(shareTitle, shareDescription, bugreportType, /*nonce*/ 0L);
+    }
+
+    /**
+     * Takes a bugreport using bug report API ({@code BugreportManager}) which gets
+     * triggered by sending a broadcast to Shell.
+     */
+    public void requestBugReportWithDescription(@Nullable String shareTitle,
+            @Nullable String shareDescription, int bugreportType, long nonce) {
         String type = null;
         switch (bugreportType) {
             case BugreportParams.BUGREPORT_MODE_FULL:
@@ -6964,6 +7055,7 @@
         triggerShellBugreport.setAction(INTENT_BUGREPORT_REQUESTED);
         triggerShellBugreport.setPackage(SHELL_APP_PACKAGE);
         triggerShellBugreport.putExtra(EXTRA_BUGREPORT_TYPE, bugreportType);
+        triggerShellBugreport.putExtra(EXTRA_BUGREPORT_NONCE, nonce);
         triggerShellBugreport.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
         triggerShellBugreport.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
         if (shareTitle != null) {
@@ -7030,8 +7122,8 @@
      * Takes a bugreport remotely
      */
     @Override
-    public void requestRemoteBugReport() {
-        requestBugReportWithDescription(null, null, BugreportParams.BUGREPORT_MODE_REMOTE);
+    public void requestRemoteBugReport(long nonce) {
+        requestBugReportWithDescription(null, null, BugreportParams.BUGREPORT_MODE_REMOTE, nonce);
     }
 
     /**
@@ -9169,6 +9261,10 @@
         mAppRestrictionController.dump(pw, "");
     }
 
+    void dumpAppRestrictionController(ProtoOutputStream proto, int uid) {
+        mAppRestrictionController.dumpAsProto(proto, uid);
+    }
+
     /**
      * Wrapper function to print out debug data filtered by specified arguments.
     */
@@ -9281,6 +9377,29 @@
                         mProcessList.writeProcessesToProtoLSP(proto, dumpPackage);
                     }
                 }
+            } else if ("app-restrictions".equals(cmd)) {
+                int uid = Process.INVALID_UID;
+                boolean error = false;
+                for (int i = 0; i < args.length; i++) {
+                    if ("--uid".equals(args[i])) {
+                        if (i + 1 < args.length) {
+                            try {
+                                uid = Integer.parseInt(args[i + 1]);
+                            } catch (NumberFormatException e) {
+                                error = true;
+                            }
+                        } else {
+                            error = true;
+                        }
+                        break;
+                    }
+                }
+                if (error) {
+                    pw.println("Invalid --uid argument");
+                    pw.println("Use -h for help.");
+                } else {
+                    dumpAppRestrictionController(proto, uid);
+                }
             } else {
                 // default option, dump everything, output is ActivityManagerServiceProto
                 synchronized (this) {
@@ -12395,13 +12514,13 @@
             String resolvedType, IServiceConnection connection, int flags, String instanceName,
             String callingPackage, int userId) throws TransactionTooLargeException {
         return bindServiceInstance(caller, token, service, resolvedType, connection, flags,
-                instanceName, false, 0, callingPackage, userId);
+                instanceName, false, 0, null, callingPackage, userId);
     }
 
     private int bindServiceInstance(IApplicationThread caller, IBinder token, Intent service,
             String resolvedType, IServiceConnection connection, int flags, String instanceName,
-            boolean isSdkSandboxService, int sdkSandboxClientdAppUid, String callingPackage,
-            int userId)
+            boolean isSdkSandboxService, int sdkSandboxClientAppUid,
+            String sdkSandboxClientAppPackage, String callingPackage, int userId)
             throws TransactionTooLargeException {
         enforceNotIsolatedCaller("bindService");
 
@@ -12438,8 +12557,8 @@
             }
             synchronized (this) {
                 return mServices.bindServiceLocked(caller, token, service, resolvedType, connection,
-                        flags, instanceName, isSdkSandboxService, sdkSandboxClientdAppUid,
-                        callingPackage, userId);
+                        flags, instanceName, isSdkSandboxService, sdkSandboxClientAppUid,
+                        sdkSandboxClientAppPackage, callingPackage, userId);
             }
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
@@ -12826,7 +12945,12 @@
     public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,
             String callerFeatureId, String receiverId, IIntentReceiver receiver,
             IntentFilter filter, String permission, int userId, int flags) {
-        enforceNotIsolatedCaller("registerReceiver");
+        // Allow Sandbox process to register only unexported receivers.
+        if ((flags & Context.RECEIVER_NOT_EXPORTED) != 0) {
+            enforceNotIsolatedCaller("registerReceiver");
+        } else {
+            enforceNotIsolatedOrSdkSandboxCaller("registerReceiver");
+        }
         ArrayList<Intent> stickyIntents = null;
         ProcessRecord callerApp = null;
         final boolean visibleToInstantApps
@@ -13438,8 +13562,13 @@
             }
 
             if (brOptions.getIdForResponseEvent() > 0) {
-                enforceUsageStatsPermission(callerPackage, callingUid, callingPid,
-                        "recordResponseEventWhileInBackground()");
+                // STOPSHIP (206518114): Temporarily check for PACKAGE_USAGE_STATS permission as
+                // well until the clients switch to using the new permission.
+                if (checkPermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS,
+                        callingPid, callingUid) != PERMISSION_GRANTED) {
+                    enforceUsageStatsPermission(callerPackage, callingUid, callingPid,
+                            "recordResponseEventWhileInBackground()");
+                }
             }
         }
 
@@ -14370,6 +14499,32 @@
                 }
             }
 
+            boolean disableHiddenApiChecks = ai.usesNonSdkApi()
+                    || (flags & INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS) != 0;
+            boolean disableTestApiChecks = disableHiddenApiChecks
+                    || (flags & INSTR_FLAG_DISABLE_TEST_API_CHECKS) != 0;
+
+            if (disableHiddenApiChecks || disableTestApiChecks) {
+                enforceCallingPermission(android.Manifest.permission.DISABLE_HIDDEN_API_CHECKS,
+                        "disable hidden API checks");
+            }
+
+            if ((flags & ActivityManager.INSTR_FLAG_INSTRUMENT_SDK_SANDBOX) != 0) {
+                return startInstrumentationOfSdkSandbox(
+                        className,
+                        profileFile,
+                        arguments,
+                        watcher,
+                        uiAutomationConnection,
+                        userId,
+                        abiOverride,
+                        ii,
+                        ai,
+                        noRestart,
+                        disableHiddenApiChecks,
+                        disableTestApiChecks);
+            }
+
             ActiveInstrumentation activeInstr = new ActiveInstrumentation(this);
             activeInstr.mClass = className;
             String defProcess = ai.processName;;
@@ -14394,15 +14549,6 @@
                     START_FOREGROUND_SERVICES_FROM_BACKGROUND, callingPid, callingUid)
                             == PackageManager.PERMISSION_GRANTED;
             activeInstr.mNoRestart = noRestart;
-            boolean disableHiddenApiChecks = ai.usesNonSdkApi()
-                    || (flags & INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS) != 0;
-            boolean disableTestApiChecks = disableHiddenApiChecks
-                    || (flags & INSTR_FLAG_DISABLE_TEST_API_CHECKS) != 0;
-
-            if (disableHiddenApiChecks || disableTestApiChecks) {
-                enforceCallingPermission(android.Manifest.permission.DISABLE_HIDDEN_API_CHECKS,
-                        "disable hidden API checks");
-            }
 
             final long origId = Binder.clearCallingIdentity();
 
@@ -14448,6 +14594,111 @@
         return true;
     }
 
+    @GuardedBy("this")
+    private boolean startInstrumentationOfSdkSandbox(
+            ComponentName className,
+            String profileFile,
+            Bundle arguments,
+            IInstrumentationWatcher watcher,
+            IUiAutomationConnection uiAutomationConnection,
+            int userId,
+            String abiOverride,
+            InstrumentationInfo instrumentationInfo,
+            ApplicationInfo sdkSandboxClientAppInfo,
+            boolean noRestart,
+            boolean disableHiddenApiChecks,
+            boolean disableTestApiChecks) {
+
+        if (noRestart) {
+            reportStartInstrumentationFailureLocked(
+                    watcher,
+                    className,
+                    "Instrumenting sdk sandbox with --no-restart flag is not supported");
+            return false;
+        }
+
+        final ApplicationInfo sdkSandboxInfo;
+        try {
+            final PackageManager pm = mContext.getPackageManager();
+            sdkSandboxInfo = pm.getApplicationInfoAsUser(pm.getSdkSandboxPackageName(), 0, userId);
+        } catch (NameNotFoundException e) {
+            reportStartInstrumentationFailureLocked(
+                    watcher, className, "Can't find SdkSandbox package");
+            return false;
+        }
+
+        final SdkSandboxManagerLocal sandboxManagerLocal =
+                LocalManagerRegistry.getManager(SdkSandboxManagerLocal.class);
+        if (sandboxManagerLocal == null) {
+            reportStartInstrumentationFailureLocked(
+                    watcher, className, "Can't locate SdkSandboxManagerLocal");
+            return false;
+        }
+
+        final String processName = sandboxManagerLocal.getSdkSandboxProcessNameForInstrumentation(
+                sdkSandboxClientAppInfo);
+
+        ActiveInstrumentation activeInstr = new ActiveInstrumentation(this);
+        activeInstr.mClass = className;
+        activeInstr.mTargetProcesses = new String[]{processName};
+        activeInstr.mTargetInfo = sdkSandboxInfo;
+        activeInstr.mProfileFile = profileFile;
+        activeInstr.mArguments = arguments;
+        activeInstr.mWatcher = watcher;
+        activeInstr.mUiAutomationConnection = uiAutomationConnection;
+        activeInstr.mResultClass = className;
+        activeInstr.mHasBackgroundActivityStartsPermission = false;
+        activeInstr.mHasBackgroundForegroundServiceStartsPermission = false;
+        // Instrumenting sdk sandbox without a restart is not supported
+        activeInstr.mNoRestart = false;
+
+        final int callingUid = Binder.getCallingUid();
+        final long token = Binder.clearCallingIdentity();
+        try {
+            sandboxManagerLocal.notifyInstrumentationStarted(
+                    sdkSandboxClientAppInfo.packageName, sdkSandboxClientAppInfo.uid);
+            synchronized (mProcLock) {
+                int sdkSandboxUid = Process.toSdkSandboxUid(sdkSandboxClientAppInfo.uid);
+                // Kill the package sdk sandbox process belong to. At this point sdk sandbox is
+                // already killed.
+                forceStopPackageLocked(
+                        instrumentationInfo.targetPackage,
+                        /* appId= */ -1,
+                        /* callerWillRestart= */ true,
+                        /* purgeCache= */ false,
+                        /* doIt= */ true,
+                        /* evenPersistent= */ true,
+                        /* uninstalling= */ false,
+                        userId,
+                        "start instr");
+
+                ProcessRecord app = addAppLocked(
+                        sdkSandboxInfo,
+                        processName,
+                        /* isolated= */ false,
+                        /* isSdkSandbox= */ true,
+                        sdkSandboxUid,
+                        sdkSandboxClientAppInfo.packageName,
+                        disableHiddenApiChecks,
+                        disableTestApiChecks,
+                        abiOverride,
+                        ZYGOTE_POLICY_FLAG_EMPTY);
+
+                app.setActiveInstrumentation(activeInstr);
+                activeInstr.mFinished = false;
+                activeInstr.mSourceUid = callingUid;
+                activeInstr.mRunningProcesses.add(app);
+                if (!mActiveInstrumentation.contains(activeInstr)) {
+                    mActiveInstrumentation.add(activeInstr);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+
+        return true;
+    }
+
     private void instrumentWithoutRestart(ActiveInstrumentation activeInstr,
             ApplicationInfo targetInfo) {
         ProcessRecord pr;
@@ -14570,7 +14821,17 @@
             app.setActiveInstrumentation(null);
         }
 
-        if (!instr.mNoRestart) {
+        if (app.isSdkSandbox) {
+            // For sharedUid apps this will kill all sdk sandbox processes, which is not ideal.
+            // TODO(b/209061624): should we call ProcessList.removeProcessLocked instead?
+            killUid(UserHandle.getAppId(app.uid), UserHandle.getUserId(app.uid), "finished instr");
+            final SdkSandboxManagerLocal sandboxManagerLocal =
+                    LocalManagerRegistry.getManager(SdkSandboxManagerLocal.class);
+            if (sandboxManagerLocal != null) {
+                sandboxManagerLocal.notifyInstrumentationFinished(
+                        app.sdkSandboxClientAppPackage, Process.getAppUidForSdkSandboxUid(app.uid));
+            }
+        } else if (!instr.mNoRestart) {
             forceStopPackageLocked(app.info.packageName, -1, false, false, true, true, false,
                     app.userId,
                     "finished inst");
@@ -15562,12 +15823,7 @@
                     throw new IllegalArgumentException("Unknown process: " + process);
                 }
 
-                boolean isDebuggable = Build.IS_DEBUGGABLE;
-                if (!isDebuggable) {
-                    if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
-                        throw new SecurityException("Process not debuggable: " + proc);
-                    }
-                }
+                enforceDebuggable(proc);
 
                 mOomAdjuster.mCachedAppOptimizer.enableFreezer(false);
 
@@ -15670,10 +15926,7 @@
                     throw new SecurityException("No process found for calling pid "
                             + Binder.getCallingPid());
                 }
-                if (!Build.IS_DEBUGGABLE
-                        && (proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
-                    throw new SecurityException("Not running a debuggable build");
-                }
+                enforceDebuggable(proc);
                 processName = proc.processName;
                 uid = proc.uid;
                 if (reportPackage != null && !proc.getPkgList().containsKey(reportPackage)) {
@@ -15884,13 +16137,7 @@
             return false;
         }
 
-        if (!Build.IS_DEBUGGABLE) {
-            if ((process.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
-                return false;
-            }
-        }
-
-        return true;
+        return Build.IS_DEBUGGABLE || process.isDebuggable();
     }
 
     public boolean startBinderTracking() throws RemoteException {
@@ -16022,22 +16269,29 @@
 
         @Override
         public boolean bindSdkSandboxService(Intent service, ServiceConnection conn,
-                int userAppUid, String processName, int flags) throws RemoteException {
+                int clientAppUid, String clientAppPackage, String processName, int flags)
+                throws RemoteException {
             if (service == null) {
                 throw new IllegalArgumentException("intent is null");
             }
             if (conn == null) {
                 throw new IllegalArgumentException("connection is null");
             }
+            if (clientAppPackage == null) {
+                throw new IllegalArgumentException("clientAppPackage is null");
+            }
             if (processName == null) {
                 throw new IllegalArgumentException("processName is null");
             }
             if (service.getComponent() == null) {
                 throw new IllegalArgumentException("service must specify explicit component");
             }
-            if (!UserHandle.isApp(userAppUid)) {
+            if (!UserHandle.isApp(clientAppUid)) {
                 throw new IllegalArgumentException("uid is not within application range");
             }
+            if (mAppOpsService.checkPackage(clientAppUid, clientAppPackage) != MODE_ALLOWED) {
+                throw new IllegalArgumentException("uid does not belong to provided package");
+            }
 
             Handler handler = mContext.getMainThreadHandler();
 
@@ -16046,8 +16300,8 @@
             return ActivityManagerService.this.bindServiceInstance(
                     mContext.getIApplicationThread(), mContext.getActivityToken(), service,
                     service.resolveTypeIfNeeded(mContext.getContentResolver()), sd, flags,
-                    processName, /*isSupplementalProcessService*/ true, userAppUid,
-                    mContext.getOpPackageName(), UserHandle.getUserId(userAppUid)) != 0;
+                    processName, /*isSdkSandboxService*/ true, clientAppUid, clientAppPackage,
+                    mContext.getOpPackageName(), UserHandle.getUserId(clientAppUid)) != 0;
         }
 
         @Override
@@ -16837,7 +17091,7 @@
                     }
 
                     if (profilerInfo != null) {
-                        setProfileApp(aInfo.applicationInfo, aInfo.processName, profilerInfo);
+                        setProfileApp(aInfo.applicationInfo, aInfo.processName, profilerInfo, null);
                     }
                     wmLock.notify();
                 }
@@ -17016,8 +17270,8 @@
         }
 
         @Override
-        public void deletePendingTopUid(int uid) {
-            mPendingStartActivityUids.delete(uid);
+        public void deletePendingTopUid(int uid, long nowElapsed) {
+            mPendingStartActivityUids.delete(uid, nowElapsed);
         }
 
         @Override
@@ -17120,6 +17374,11 @@
         }
 
         @Override
+        public int getServiceStartForegroundTimeout() {
+            return mConstants.mServiceStartForegroundTimeoutMs;
+        }
+
+        @Override
         public int getUidCapability(int uid) {
             synchronized (ActivityManagerService.this) {
                 UidRecord uidRecord = mProcessList.getUidRecordLOSP(uid);
@@ -17625,11 +17884,7 @@
                     throw new IllegalArgumentException("Unknown process: " + process);
                 }
 
-                if (!Build.IS_DEBUGGABLE) {
-                    if ((proc.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
-                        throw new SecurityException("Process not debuggable: " + proc);
-                    }
-                }
+                enforceDebuggable(proc);
 
                 thread.attachAgent(path);
             }
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 28b807c..5024a4a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -183,6 +183,7 @@
     private boolean mAsync;
     private BroadcastOptions mBroadcastOptions;
     private boolean mShowSplashScreen;
+    private boolean mDismissKeyguardIfInsecure;
 
     final boolean mDumping;
 
@@ -343,6 +344,8 @@
                     return runSetStopUserOnSwitch(pw);
                 case "set-bg-abusive-uids":
                     return runSetBgAbusiveUids(pw);
+                case "list-bg-exemptions-config":
+                    return runListBgExemptionsConfig(pw);
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -437,6 +440,8 @@
                     mAsync = true;
                 } else if (opt.equals("--splashscreen-show-icon")) {
                     mShowSplashScreen = true;
+                } else if (opt.equals("--dismiss-keyguard-if-insecure")) {
+                    mDismissKeyguardIfInsecure = true;
                 } else {
                     return false;
                 }
@@ -581,6 +586,12 @@
                 }
                 options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON);
             }
+            if (mDismissKeyguardIfInsecure) {
+                if (options == null) {
+                    options = ActivityOptions.makeBasic();
+                }
+                options.setDismissKeyguardIfInsecure();
+            }
             if (mWaitOption) {
                 result = mInternal.startActivityAndWait(null, SHELL_PACKAGE_NAME, null, intent,
                         mimeType, null, null, 0, mStartFlags, profilerInfo,
@@ -3292,6 +3303,19 @@
         return 0;
     }
 
+    private int runListBgExemptionsConfig(PrintWriter pw) throws RemoteException {
+        final ArraySet<String> sysConfigs = mInternal.mAppRestrictionController
+                .mBgRestrictionExemptioFromSysConfig;
+        if (sysConfigs != null) {
+            for (int i = 0, size = sysConfigs.size(); i < size; i++) {
+                pw.print(sysConfigs.valueAt(i));
+                pw.print(' ');
+            }
+            pw.println();
+        }
+        return 0;
+    }
+
     private Resources getResources(PrintWriter pw) throws RemoteException {
         // system resources does not contain all the device configuration, construct it manually.
         Configuration config = mInterface.getConfiguration();
diff --git a/services/core/java/com/android/server/am/AppBatteryExemptionTracker.java b/services/core/java/com/android/server/am/AppBatteryExemptionTracker.java
index d1cf004..6f11b00 100644
--- a/services/core/java/com/android/server/am/AppBatteryExemptionTracker.java
+++ b/services/core/java/com/android/server/am/AppBatteryExemptionTracker.java
@@ -26,10 +26,13 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.os.SystemClock;
+import android.util.ArrayMap;
 import android.util.Pair;
 import android.util.Slog;
+import android.util.SparseArray;
 
 import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.am.AppBatteryExemptionTracker.AppBatteryExemptionPolicy;
 import com.android.server.am.AppBatteryExemptionTracker.UidBatteryStates;
@@ -65,6 +68,11 @@
     // As it's a UID-based tracker, anywhere which requires a package name, use this default name.
     static final String DEFAULT_NAME = "";
 
+    // As it's a UID-based tracker, while the state change event it receives could be
+    // in the combination of UID + package name, we'd have to leverage each package's state.
+    @GuardedBy("mLock")
+    private UidProcessMap<Integer> mUidPackageStates = new UidProcessMap<>();
+
     AppBatteryExemptionTracker(Context context, AppRestrictionController controller) {
         this(context, controller, null, null);
     }
@@ -103,12 +111,75 @@
                 .getUidBatteryUsage(uid);
         final int stateTypeIndex = stateTypeToIndex(stateType);
         synchronized (mLock) {
-            UidBatteryStates pkg = mPkgEvents.get(uid, DEFAULT_NAME);
-            if (pkg == null) {
-                pkg = createAppStateEvents(uid, DEFAULT_NAME);
-                mPkgEvents.put(uid, DEFAULT_NAME, pkg);
+            final SparseArray<ArrayMap<String, Integer>> map = mUidPackageStates.getMap();
+            ArrayMap<String, Integer> pkgsStates = map.get(uid);
+            if (pkgsStates == null) {
+                pkgsStates = new ArrayMap<>();
+                map.put(uid, pkgsStates);
             }
-            pkg.addEvent(start, now, batteryUsage, stateTypeIndex);
+            int states = 0;
+            int indexOfPkg = pkgsStates.indexOfKey(packageName);
+            if (indexOfPkg >= 0) {
+                states = pkgsStates.valueAt(indexOfPkg);
+            } else {
+                pkgsStates.put(packageName, 0);
+                indexOfPkg = pkgsStates.indexOfKey(packageName);
+            }
+            boolean addEvent = false;
+            if (start) {
+                // Check if there is another package within this UID with this type of event start.
+                boolean alreadyStarted = false;
+                for (int i = pkgsStates.size() - 1; i >= 0; i--) {
+                    final int s = pkgsStates.valueAt(i);
+                    if ((s & stateType) != 0) {
+                        alreadyStarted = true;
+                        break;
+                    }
+                }
+                pkgsStates.setValueAt(indexOfPkg, states | stateType);
+                if (!alreadyStarted) {
+                    // This is the first package within this UID with this type of event start.
+                    addEvent = true;
+                }
+            } else {
+                states &= ~stateType;
+                pkgsStates.setValueAt(indexOfPkg, states);
+                boolean allStopped = true;
+                for (int i = pkgsStates.size() - 1; i >= 0; i--) {
+                    final int s = pkgsStates.valueAt(i);
+                    if ((s & stateType) != 0) {
+                        allStopped = false;
+                        break;
+                    }
+                }
+                if (allStopped) {
+                    // None of the packages in this UID has an active event of this type.
+                    addEvent = true;
+                }
+                if (states == 0) { // None of the states of this package are active, prune it.
+                    pkgsStates.removeAt(indexOfPkg);
+                    if (pkgsStates.size() == 0) {
+                        map.remove(uid);
+                    }
+                }
+            }
+            if (addEvent) {
+                UidBatteryStates pkg = mPkgEvents.get(uid, DEFAULT_NAME);
+                if (pkg == null) {
+                    pkg = createAppStateEvents(uid, DEFAULT_NAME);
+                    mPkgEvents.put(uid, DEFAULT_NAME, pkg);
+                }
+                pkg.addEvent(start, now, batteryUsage, stateTypeIndex);
+            }
+        }
+    }
+
+    @VisibleForTesting
+    @Override
+    void reset() {
+        super.reset();
+        synchronized (mLock) {
+            mUidPackageStates.clear();
         }
     }
 
@@ -116,6 +187,7 @@
         if (!enabled) {
             synchronized (mLock) {
                 mPkgEvents.clear();
+                mUidPackageStates.clear();
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/AppBatteryTracker.java b/services/core/java/com/android/server/am/AppBatteryTracker.java
index 7cd45fe..690051f 100644
--- a/services/core/java/com/android/server/am/AppBatteryTracker.java
+++ b/services/core/java/com/android/server/am/AppBatteryTracker.java
@@ -28,6 +28,7 @@
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.os.BatteryConsumer.POWER_COMPONENT_ANY;
 import static android.os.BatteryConsumer.PROCESS_STATE_BACKGROUND;
+import static android.os.BatteryConsumer.PROCESS_STATE_CACHED;
 import static android.os.BatteryConsumer.PROCESS_STATE_COUNT;
 import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND;
 import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE;
@@ -38,7 +39,6 @@
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.AppRestrictionController.DEVICE_CONFIG_SUBNAMESPACE_PREFIX;
-import static com.android.server.am.BaseAppStateTracker.ONE_MINUTE;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -48,6 +48,7 @@
 import android.content.pm.ServiceInfo;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.os.AppBatteryStatsProto;
 import android.os.BatteryConsumer;
 import android.os.BatteryConsumer.Dimensions;
 import android.os.BatteryStatsInternal;
@@ -64,6 +65,7 @@
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
@@ -71,7 +73,6 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.server.am.AppBatteryTracker.AppBatteryPolicy;
 import com.android.server.am.AppRestrictionController.UidBatteryUsageProvider;
-import com.android.server.am.BaseAppStateTracker.Injector;
 import com.android.server.pm.UserManagerInternal;
 
 import java.io.PrintWriter;
@@ -679,11 +680,69 @@
         super.dump(pw, prefix);
     }
 
+    @Override
+    void dumpAsProto(ProtoOutputStream proto, int uid) {
+        synchronized (mLock) {
+            final SparseArray<ImmutableBatteryUsage> uidConsumers = mUidBatteryUsageInWindow;
+            if (uid != android.os.Process.INVALID_UID) {
+                final BatteryUsage usage = uidConsumers.get(uid);
+                if (usage != null) {
+                    dumpUidStats(proto, uid, usage);
+                }
+            } else {
+                for (int i = 0, size = uidConsumers.size(); i < size; i++) {
+                    final int aUid = uidConsumers.keyAt(i);
+                    final BatteryUsage usage = uidConsumers.valueAt(i);
+                    dumpUidStats(proto, aUid, usage);
+                }
+            }
+        }
+    }
+
+    private void dumpUidStats(ProtoOutputStream proto, int uid, BatteryUsage usage) {
+        if (usage.mUsage == null) {
+            return;
+        }
+
+        final double foregroundUsage = usage.getUsagePowerMah(PROCESS_STATE_FOREGROUND);
+        final double backgroundUsage = usage.getUsagePowerMah(PROCESS_STATE_BACKGROUND);
+        final double fgsUsage = usage.getUsagePowerMah(PROCESS_STATE_FOREGROUND_SERVICE);
+
+        if (foregroundUsage == 0 && backgroundUsage == 0 && fgsUsage == 0) {
+            return;
+        }
+
+        final long token = proto.start(AppBatteryStatsProto.UID_STATS);
+        proto.write(AppBatteryStatsProto.UidStats.UID, uid);
+        dumpProcessStateStats(proto,
+                AppBatteryStatsProto.UidStats.ProcessStateStats.FOREGROUND,
+                foregroundUsage);
+        dumpProcessStateStats(proto,
+                AppBatteryStatsProto.UidStats.ProcessStateStats.BACKGROUND,
+                backgroundUsage);
+        dumpProcessStateStats(proto,
+                AppBatteryStatsProto.UidStats.ProcessStateStats.FOREGROUND_SERVICE,
+                fgsUsage);
+        proto.end(token);
+    }
+
+    private void dumpProcessStateStats(ProtoOutputStream proto, int processState, double powerMah) {
+        if (powerMah == 0) {
+            return;
+        }
+
+        final long token = proto.start(AppBatteryStatsProto.UidStats.PROCESS_STATE_STATS);
+        proto.write(AppBatteryStatsProto.UidStats.ProcessStateStats.PROCESS_STATE, processState);
+        proto.write(AppBatteryStatsProto.UidStats.ProcessStateStats.POWER_MAH, powerMah);
+        proto.end(token);
+    }
+
     static class BatteryUsage {
         static final int BATTERY_USAGE_INDEX_UNSPECIFIED = PROCESS_STATE_UNSPECIFIED;
         static final int BATTERY_USAGE_INDEX_FOREGROUND = PROCESS_STATE_FOREGROUND;
         static final int BATTERY_USAGE_INDEX_BACKGROUND = PROCESS_STATE_BACKGROUND;
         static final int BATTERY_USAGE_INDEX_FOREGROUND_SERVICE = PROCESS_STATE_FOREGROUND_SERVICE;
+        static final int BATTERY_USAGE_INDEX_CACHED = PROCESS_STATE_CACHED;
         static final int BATTERY_USAGE_COUNT = PROCESS_STATE_COUNT;
 
         static final Dimensions[] BATT_DIMENS = new Dimensions[] {
@@ -695,17 +754,20 @@
                         PROCESS_STATE_BACKGROUND),
                 new Dimensions(AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS,
                         PROCESS_STATE_FOREGROUND_SERVICE),
+                new Dimensions(AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS,
+                        PROCESS_STATE_CACHED),
         };
 
         @NonNull double[] mUsage;
         @Nullable double[] mPercentage;
 
         BatteryUsage() {
-            this(0.0d, 0.0d, 0.0d, 0.0d);
+            this(0.0d, 0.0d, 0.0d, 0.0d, 0.0d);
         }
 
-        BatteryUsage(double unspecifiedUsage, double fgUsage, double bgUsage, double fgsUsage) {
-            mUsage = new double[] {unspecifiedUsage, fgUsage, bgUsage, fgsUsage};
+        BatteryUsage(double unspecifiedUsage, double fgUsage, double bgUsage, double fgsUsage,
+                double cachedUsage) {
+            mUsage = new double[] {unspecifiedUsage, fgUsage, bgUsage, fgsUsage, cachedUsage};
         }
 
         BatteryUsage(@NonNull double[] usage) {
@@ -728,7 +790,8 @@
                     getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_UNSPECIFIED]),
                     getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_FOREGROUND]),
                     getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_BACKGROUND]),
-                    getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE])
+                    getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]),
+                    getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_CACHED]),
             };
         }
 
@@ -798,6 +861,15 @@
             return formatBatteryUsage(mUsage);
         }
 
+        double getUsagePowerMah(@BatteryConsumer.ProcessState int processState) {
+            switch (processState) {
+                case PROCESS_STATE_FOREGROUND: return mUsage[1];
+                case PROCESS_STATE_BACKGROUND: return mUsage[2];
+                case PROCESS_STATE_FOREGROUND_SERVICE: return mUsage[3];
+            }
+            return 0;
+        }
+
         boolean isValid() {
             for (int i = 0; i < mUsage.length; i++) {
                 if (mUsage[i] < 0.0d) {
@@ -840,19 +912,21 @@
         }
 
         private static String formatBatteryUsage(double[] usage) {
-            return String.format("%.3f %.3f %.3f %.3f mAh",
+            return String.format("%.3f %.3f %.3f %.3f %.3f mAh",
                     usage[BATTERY_USAGE_INDEX_UNSPECIFIED],
                     usage[BATTERY_USAGE_INDEX_FOREGROUND],
                     usage[BATTERY_USAGE_INDEX_BACKGROUND],
-                    usage[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]);
+                    usage[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE],
+                    usage[BATTERY_USAGE_INDEX_CACHED]);
         }
 
         static String formatBatteryUsagePercentage(double[] percentage) {
-            return String.format("%4.2f%% %4.2f%% %4.2f%% %4.2f%%",
+            return String.format("%4.2f%% %4.2f%% %4.2f%% %4.2f%% %4.2f%%",
                     percentage[BATTERY_USAGE_INDEX_UNSPECIFIED],
                     percentage[BATTERY_USAGE_INDEX_FOREGROUND],
                     percentage[BATTERY_USAGE_INDEX_BACKGROUND],
-                    percentage[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]);
+                    percentage[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE],
+                    percentage[BATTERY_USAGE_INDEX_CACHED]);
         }
 
         private static double getConsumedPowerNoThrow(final UidBatteryConsumer uidConsumer,
@@ -871,8 +945,8 @@
         }
 
         ImmutableBatteryUsage(double unspecifiedUsage, double fgUsage, double bgUsage,
-                double fgsUsage) {
-            super(unspecifiedUsage, fgUsage, bgUsage, fgsUsage);
+                double fgsUsage, double cachedUsage) {
+            super(unspecifiedUsage, fgUsage, bgUsage, fgsUsage, cachedUsage);
         }
 
         ImmutableBatteryUsage(@NonNull double[] usage) {
@@ -932,6 +1006,7 @@
         static final int BATTERY_USAGE_TYPE_FOREGROUND = 1 << 1;
         static final int BATTERY_USAGE_TYPE_BACKGROUND = 1 << 2;
         static final int BATTERY_USAGE_TYPE_FOREGROUND_SERVICE = 1 << 3;
+        static final int BATTERY_USAGE_TYPE_CACHED = 1 << 4;
 
         /**
          * Whether or not we should enable the monitoring on background current drains.
@@ -1007,8 +1082,8 @@
         /**
          * The types of battery drain we're checking on each app; if the sum of the battery drain
          * exceeds the threshold, it'll be moved to restricted standby bucket; the type here
-         * must be one of, or combination of {@link #BATTERY_USAGE_TYPE_BACKGROUND} and
-         * {@link #BATTERY_USAGE_TYPE_FOREGROUND_SERVICE}.
+         * must be one of, or combination of {@link #BATTERY_USAGE_TYPE_BACKGROUND},
+         * {@link #BATTERY_USAGE_TYPE_FOREGROUND_SERVICE} and {@link #BATTERY_USAGE_TYPE_CACHED}.
          */
         static final String KEY_BG_CURRENT_DRAIN_TYPES_TO_RESTRICTED_BUCKET =
                 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_types_to_restricted_bucket";
@@ -1016,8 +1091,8 @@
         /**
          * The types of battery drain we're checking on each app; if the sum of the battery drain
          * exceeds the threshold, it'll be moved to background restricted level; the type here
-         * must be one of, or combination of {@link #BATTERY_USAGE_TYPE_BACKGROUND} and
-         * {@link #BATTERY_USAGE_TYPE_FOREGROUND_SERVICE}.
+         * must be one of, or combination of {@link #BATTERY_USAGE_TYPE_BACKGROUND},
+         * {@link #BATTERY_USAGE_TYPE_FOREGROUND_SERVICE} and {@link #BATTERY_USAGE_TYPE_CACHED}.
          */
         static final String KEY_BG_CURRENT_DRAIN_TYPES_TO_BG_RESTRICTED =
                 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_types_to_bg_restricted";
@@ -1461,6 +1536,9 @@
                     case BATTERY_USAGE_TYPE_FOREGROUND_SERVICE:
                         sb.append("FOREGROUND_SERVICE");
                         break;
+                    case BATTERY_USAGE_TYPE_CACHED:
+                        sb.append("CACHED");
+                        break;
                     default:
                         return "[UNKNOWN(" + Integer.toHexString(types) + ")]";
                 }
diff --git a/services/core/java/com/android/server/am/AppFGSTracker.java b/services/core/java/com/android/server/am/AppFGSTracker.java
index 075402f..246725e 100644
--- a/services/core/java/com/android/server/am/AppFGSTracker.java
+++ b/services/core/java/com/android/server/am/AppFGSTracker.java
@@ -32,18 +32,22 @@
 import android.annotation.NonNull;
 import android.app.ActivityManagerInternal.ForegroundServiceStateListener;
 import android.app.IProcessObserver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ServiceInfo.ForegroundServiceType;
 import android.os.Handler;
 import android.os.Message;
 import android.os.PowerExemptionManager.ReasonCode;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
-import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.util.TimeUtils;
 
 import com.android.internal.annotations.GuardedBy;
@@ -53,7 +57,6 @@
 import com.android.server.am.BaseAppStateEventsTracker.BaseAppStateEventsPolicy;
 import com.android.server.am.BaseAppStateTimeEvents.BaseTimeEvent;
 import com.android.server.am.BaseAppStateTracker.Injector;
-import com.android.server.notification.NotificationManagerInternal;
 
 import java.io.PrintWriter;
 import java.lang.reflect.Constructor;
@@ -72,11 +75,14 @@
     private final MyHandler mHandler;
 
     @GuardedBy("mLock")
-    private final UidProcessMap<ArraySet<Integer>> mFGSNotificationIDs = new UidProcessMap<>();
+    private final UidProcessMap<SparseBooleanArray> mFGSNotificationIDs = new UidProcessMap<>();
 
     // Unlocked since it's only accessed in single thread.
     private final ArrayMap<PackageDurations, Long> mTmpPkgDurations = new ArrayMap<>();
 
+    @VisibleForTesting
+    final NotificationListener mNotificationListener = new NotificationListener();
+
     final IProcessObserver.Stub mProcessObserver = new IProcessObserver.Stub() {
         @Override
         public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
@@ -116,6 +122,8 @@
         static final int MSG_FOREGROUND_SERVICES_CHANGED = 2;
         static final int MSG_FOREGROUND_SERVICES_NOTIFICATION_UPDATED = 3;
         static final int MSG_CHECK_LONG_RUNNING_FGS = 4;
+        static final int MSG_NOTIFICATION_POSTED = 5;
+        static final int MSG_NOTIFICATION_REMOVED = 6;
 
         private final AppFGSTracker mTracker;
 
@@ -146,6 +154,12 @@
                 case MSG_CHECK_LONG_RUNNING_FGS:
                     mTracker.checkLongRunningFgs();
                     break;
+                case MSG_NOTIFICATION_POSTED:
+                    mTracker.handleNotificationPosted((String) msg.obj, msg.arg1, msg.arg2);
+                    break;
+                case MSG_NOTIFICATION_REMOVED:
+                    mTracker.handleNotificationRemoved((String) msg.obj, msg.arg1, msg.arg2);
+                    break;
             }
         }
     }
@@ -223,19 +237,36 @@
     private void handleForegroundServiceNotificationUpdated(String packageName, int uid,
             int notificationId) {
         synchronized (mLock) {
+            SparseBooleanArray notificationIDs = mFGSNotificationIDs.get(uid, packageName);
             if (notificationId > 0) {
-                ArraySet<Integer> notificationIDs = mFGSNotificationIDs.get(uid, packageName);
                 if (notificationIDs == null) {
-                    notificationIDs = new ArraySet<>();
+                    notificationIDs = new SparseBooleanArray();
                     mFGSNotificationIDs.put(uid, packageName, notificationIDs);
                 }
-                notificationIDs.add(notificationId);
+                notificationIDs.put(notificationId, false);
             } else if (notificationId < 0) {
-                final ArraySet<Integer> notificationIDs = mFGSNotificationIDs.get(uid, packageName);
                 if (notificationIDs != null) {
-                    notificationIDs.remove(-notificationId);
-                    if (notificationIDs.isEmpty()) {
-                        mFGSNotificationIDs.remove(uid, packageName);
+                    final int indexOfKey = notificationIDs.indexOfKey(-notificationId);
+                    if (indexOfKey >= 0) {
+                        final boolean wasVisible = notificationIDs.valueAt(indexOfKey);
+                        notificationIDs.removeAt(indexOfKey);
+                        if (notificationIDs.size() == 0) {
+                            mFGSNotificationIDs.remove(uid, packageName);
+                        }
+                        // Walk through the list of FGS notification IDs and see if there are any
+                        // visible ones.
+                        for (int i = notificationIDs.size() - 1; i >= 0; i--) {
+                            if (notificationIDs.valueAt(i)) {
+                                // Still visible, nothing to do.
+                                return;
+                            }
+                        }
+                        if (wasVisible) {
+                            // That was the last visible notification, notify the listeners.
+                            notifyListenersOnStateChange(uid, packageName, false,
+                                    SystemClock.elapsedRealtime(),
+                                    STATE_TYPE_FGS_WITH_NOTIFICATION);
+                        }
                     }
                 }
             }
@@ -244,20 +275,74 @@
 
     @GuardedBy("mLock")
     private boolean hasForegroundServiceNotificationsLocked(String packageName, int uid) {
-        final ArraySet<Integer> notificationIDs = mFGSNotificationIDs.get(uid, packageName);
-        if (notificationIDs == null || notificationIDs.isEmpty()) {
+        final SparseBooleanArray notificationIDs = mFGSNotificationIDs.get(uid, packageName);
+        if (notificationIDs == null || notificationIDs.size() == 0) {
             return false;
         }
-        final NotificationManagerInternal nm = mInjector.getNotificationManagerInternal();
-        final int userId = UserHandle.getUserId(uid);
         for (int i = notificationIDs.size() - 1; i >= 0; i--) {
-            if (nm.isNotificationShown(packageName, null, notificationIDs.valueAt(i), userId)) {
+            if (notificationIDs.valueAt(i)) {
                 return true;
             }
         }
         return false;
     }
 
+    private void handleNotificationPosted(String pkgName, int uid, int notificationId) {
+        synchronized (mLock) {
+            final SparseBooleanArray notificationIDs = mFGSNotificationIDs.get(uid, pkgName);
+            final int indexOfKey;
+            if (notificationIDs == null
+                    || (indexOfKey = notificationIDs.indexOfKey(notificationId)) < 0) {
+                return;
+            }
+            if (notificationIDs.valueAt(indexOfKey)) {
+                // It's already visible.
+                return;
+            }
+            boolean anyVisible = false;
+            // Walk through the list of FGS notification IDs and see if there are any visible ones.
+            for (int i = notificationIDs.size() - 1; i >= 0; i--) {
+                if (notificationIDs.valueAt(i)) {
+                    anyVisible = true;
+                    break;
+                }
+            }
+            notificationIDs.setValueAt(indexOfKey, true);
+            if (!anyVisible) {
+                // We didn't have any visible FGS notifications but now we have one,
+                // let the listeners know.
+                notifyListenersOnStateChange(uid, pkgName, true, SystemClock.elapsedRealtime(),
+                        STATE_TYPE_FGS_WITH_NOTIFICATION);
+            }
+        }
+    }
+
+    private void handleNotificationRemoved(String pkgName, int uid, int notificationId) {
+        synchronized (mLock) {
+            final SparseBooleanArray notificationIDs = mFGSNotificationIDs.get(uid, pkgName);
+            final int indexOfKey;
+            if (notificationIDs == null
+                    || (indexOfKey = notificationIDs.indexOfKey(notificationId)) < 0) {
+                return;
+            }
+            if (!notificationIDs.valueAt(indexOfKey)) {
+                // It's already invisible.
+                return;
+            }
+            notificationIDs.setValueAt(indexOfKey, false);
+            // Walk through the list of FGS notification IDs and see if there are any visible ones.
+            for (int i = notificationIDs.size() - 1; i >= 0; i--) {
+                if (notificationIDs.valueAt(i)) {
+                    // Still visible, nothing to do.
+                    return;
+                }
+            }
+            // Nothing is visible now, let the listeners know.
+            notifyListenersOnStateChange(uid, pkgName, false, SystemClock.elapsedRealtime(),
+                    STATE_TYPE_FGS_WITH_NOTIFICATION);
+        }
+    }
+
     @GuardedBy("mLock")
     private void scheduleDurationCheckLocked(long now) {
         // Look for the active FGS with longest running time till now.
@@ -374,7 +459,19 @@
             synchronized (mLock) {
                 scheduleDurationCheckLocked(SystemClock.elapsedRealtime());
             }
+            try {
+                mNotificationListener.registerAsSystemService(mContext,
+                        new ComponentName(mContext, NotificationListener.class),
+                        UserHandle.USER_ALL);
+            } catch (RemoteException e) {
+                // Intra-process call, should never happen.
+            }
         } else {
+            try {
+                mNotificationListener.unregisterAsSystemService();
+            } catch (RemoteException e) {
+                // Intra-process call, should never happen.
+            }
             mHandler.removeMessages(MyHandler.MSG_CHECK_LONG_RUNNING_FGS);
             synchronized (mLock) {
                 mPkgEvents.clear();
@@ -436,9 +533,9 @@
 
     boolean hasForegroundServiceNotifications(int uid) {
         synchronized (mLock) {
-            final SparseArray<ArrayMap<String, ArraySet<Integer>>> map =
+            final SparseArray<ArrayMap<String, SparseBooleanArray>> map =
                     mFGSNotificationIDs.getMap();
-            final ArrayMap<String, ArraySet<Integer>> pkgs = map.get(uid);
+            final ArrayMap<String, SparseBooleanArray> pkgs = map.get(uid);
             if (pkgs != null) {
                 for (int i = pkgs.size() - 1; i >= 0; i--) {
                     if (hasForegroundServiceNotificationsLocked(pkgs.keyAt(i), uid)) {
@@ -463,7 +560,7 @@
         pw.println("APPS WITH ACTIVE FOREGROUND SERVICES:");
         prefix = "  " + prefix;
         synchronized (mLock) {
-            final SparseArray<ArrayMap<String, ArraySet<Integer>>> map =
+            final SparseArray<ArrayMap<String, SparseBooleanArray>> map =
                     mFGSNotificationIDs.getMap();
             if (map.size() == 0) {
                 pw.print(prefix);
@@ -472,7 +569,7 @@
             for (int i = 0, size = map.size(); i < size; i++) {
                 final int uid = map.keyAt(i);
                 final String uidString = UserHandle.formatUid(uid);
-                final ArrayMap<String, ArraySet<Integer>> pkgs = map.valueAt(i);
+                final ArrayMap<String, SparseBooleanArray> pkgs = map.valueAt(i);
                 for (int j = 0, numOfPkgs = pkgs.size(); j < numOfPkgs; j++) {
                     final String pkgName = pkgs.keyAt(j);
                     pw.print(prefix);
@@ -622,6 +719,28 @@
         }
     }
 
+    @VisibleForTesting
+    class NotificationListener extends NotificationListenerService {
+        @Override
+        public void onNotificationPosted(StatusBarNotification sbn, RankingMap map) {
+            if (DEBUG_BACKGROUND_FGS_TRACKER) {
+                Slog.i(TAG, "Notification posted: " + sbn);
+            }
+            mHandler.obtainMessage(MyHandler.MSG_NOTIFICATION_POSTED,
+                    sbn.getUid(), sbn.getId(), sbn.getPackageName()).sendToTarget();
+        }
+
+        @Override
+        public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap,
+                int reason) {
+            if (DEBUG_BACKGROUND_FGS_TRACKER) {
+                Slog.i(TAG, "Notification removed: " + sbn);
+            }
+            mHandler.obtainMessage(MyHandler.MSG_NOTIFICATION_REMOVED,
+                    sbn.getUid(), sbn.getId(), sbn.getPackageName()).sendToTarget();
+        }
+    }
+
     static final class AppFGSPolicy extends BaseAppStateEventsPolicy<AppFGSTracker> {
         /**
          * Whether or not we should enable the monitoring on abusive FGS.
diff --git a/services/core/java/com/android/server/am/AppPermissionTracker.java b/services/core/java/com/android/server/am/AppPermissionTracker.java
index 69f70ca..622d746 100644
--- a/services/core/java/com/android/server/am/AppPermissionTracker.java
+++ b/services/core/java/com/android/server/am/AppPermissionTracker.java
@@ -17,6 +17,14 @@
 package com.android.server.am;
 
 import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.Manifest.permission.CAMERA;
+import static android.Manifest.permission.RECORD_AUDIO;
+import static android.app.AppOpsManager.OPSTR_CAMERA;
+import static android.app.AppOpsManager.OPSTR_FINE_LOCATION;
+import static android.app.AppOpsManager.OPSTR_RECORD_AUDIO;
+import static android.app.AppOpsManager.OP_NONE;
+import static android.app.AppOpsManager.opToPublicName;
+import static android.app.AppOpsManager.strOpToOp;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.os.Process.SYSTEM_UID;
 
@@ -27,28 +35,37 @@
 import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_PERMISSION;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager.OnPermissionsChangedListener;
 import android.content.pm.PackageManagerInternal;
 import android.os.Handler;
 import android.os.Message;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.permission.PermissionManager;
 import android.provider.DeviceConfig;
+import android.text.TextUtils;
 import android.util.ArraySet;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.IAppOpsCallback;
+import com.android.internal.app.IAppOpsService;
 import com.android.server.am.AppPermissionTracker.AppPermissionPolicy;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
 
 import java.io.PrintWriter;
 import java.lang.reflect.Constructor;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * The tracker for monitoring selected permission state of apps.
@@ -61,8 +78,17 @@
 
     private final MyHandler mHandler;
 
+    /**
+     * Keep a new instance of callback for each appop we're monitoring,
+     * as the AppOpsService doesn't support monitoring multiple appops with single callback
+     * instance (except the ALL_OPS case).
+     */
+    @GuardedBy("mAppOpsCallbacks")
+    private final SparseArray<MyAppOpsCallback> mAppOpsCallbacks = new SparseArray<>();
+
     @GuardedBy("mLock")
-    private SparseArray<ArraySet<String>> mUidGrantedPermissionsInMonitor = new SparseArray<>();
+    private SparseArray<ArraySet<UidGrantedPermissionState>> mUidGrantedPermissionsInMonitor =
+            new SparseArray<>();
 
     private volatile boolean mLockedBootCompleted = false;
 
@@ -82,12 +108,25 @@
         mHandler.obtainMessage(MyHandler.MSG_PERMISSIONS_CHANGED, uid, 0).sendToTarget();
     }
 
+    private void handleAppOpsInit() {
+        final ArrayList<Integer> ops = new ArrayList<>();
+        final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+        for (int i = 0; i < permissions.length; i++) {
+            final Pair<String, Integer> pair = permissions[i];
+            if (pair.second != OP_NONE) {
+                ops.add(pair.second);
+            }
+        }
+        startWatchingMode(ops.toArray(new Integer[ops.size()]));
+    }
+
     private void handlePermissionsInit() {
         final int[] allUsers = mInjector.getUserManagerInternal().getUserIds();
         final PackageManagerInternal pmi = mInjector.getPackageManagerInternal();
         final PermissionManagerServiceInternal pm = mInjector.getPermissionManagerServiceInternal();
-        final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
-        final SparseArray<ArraySet<String>> uidPerms = mUidGrantedPermissionsInMonitor;
+        final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+        final SparseArray<ArraySet<UidGrantedPermissionState>> uidPerms =
+                mUidGrantedPermissionsInMonitor;
         for (int userId : allUsers) {
             final List<ApplicationInfo> apps = pmi.getInstalledApplications(0, userId, SYSTEM_UID);
             if (apps == null) {
@@ -96,33 +135,44 @@
             final long now = SystemClock.elapsedRealtime();
             for (int i = 0, size = apps.size(); i < size; i++) {
                 final ApplicationInfo ai = apps.get(i);
-                for (String permission : permissions) {
-                    if (pm.checkUidPermission(ai.uid, permission) != PERMISSION_GRANTED) {
+                for (Pair<String, Integer> permission : permissions) {
+                    final UidGrantedPermissionState state = new UidGrantedPermissionState(
+                            ai.uid, permission.first, permission.second);
+                    if (!state.isGranted()) {
+                        // No need to track it.
                         continue;
                     }
                     synchronized (mLock) {
-                        ArraySet<String> grantedPermissions = uidPerms.get(ai.uid);
+                        ArraySet<UidGrantedPermissionState> grantedPermissions =
+                                uidPerms.get(ai.uid);
                         if (grantedPermissions == null) {
-                            grantedPermissions = new ArraySet<String>();
+                            grantedPermissions = new ArraySet<UidGrantedPermissionState>();
                             uidPerms.put(ai.uid, grantedPermissions);
+                            // This UID has at least one active permission-in-interest now,
+                            // let the listeners know.
+                            notifyListenersOnStateChange(ai.uid, DEFAULT_NAME, true, now,
+                                    STATE_TYPE_PERMISSION);
                         }
-                        grantedPermissions.add(permission);
-                        notifyListenersOnStateChange(ai.uid, DEFAULT_NAME, true, now,
-                                STATE_TYPE_PERMISSION);
+                        grantedPermissions.add(state);
                     }
                 }
             }
         }
     }
 
+    private void handleAppOpsDestroy() {
+        stopWatchingMode();
+    }
+
     private void handlePermissionsDestroy() {
         synchronized (mLock) {
-            final SparseArray<ArraySet<String>> uidPerms = mUidGrantedPermissionsInMonitor;
+            final SparseArray<ArraySet<UidGrantedPermissionState>> uidPerms =
+                    mUidGrantedPermissionsInMonitor;
             final long now = SystemClock.elapsedRealtime();
             for (int i = 0, size = uidPerms.size(); i < size; i++) {
                 final int uid = uidPerms.keyAt(i);
-                final ArraySet<String> grantedPermissions = uidPerms.valueAt(i);
-                for (int j = 0, numOfPerms = grantedPermissions.size(); j < numOfPerms; j++) {
+                final ArraySet<UidGrantedPermissionState> grantedPermissions = uidPerms.valueAt(i);
+                if (grantedPermissions.size() > 0) {
                     notifyListenersOnStateChange(uid, DEFAULT_NAME, false, now,
                             STATE_TYPE_PERMISSION);
                 }
@@ -131,44 +181,78 @@
         }
     }
 
+    private void handleOpChanged(int op, int uid, String packageName) {
+        if (DEBUG_PERMISSION_TRACKER) {
+            final IAppOpsService appOpsService = mInjector.getIAppOpsService();
+            try {
+                final int mode = appOpsService.checkOperation(op, uid, packageName);
+                Slog.i(TAG, "onOpChanged: " + opToPublicName(op)
+                        + " " + UserHandle.formatUid(uid)
+                        + " " + packageName + " " + mode);
+            } catch (RemoteException e) {
+                // Intra-process call, should never happen.
+            }
+        }
+        final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+        if (permissions != null && permissions.length > 0) {
+            for (int i = 0; i < permissions.length; i++) {
+                final Pair<String, Integer> pair = permissions[i];
+                if (pair.second != op) {
+                    continue;
+                }
+                final UidGrantedPermissionState state =
+                        new UidGrantedPermissionState(uid, pair.first, op);
+                synchronized (mLock) {
+                    handlePermissionsChangedLocked(uid, new UidGrantedPermissionState[] {state});
+                }
+                break;
+            }
+        }
+    }
+
     private void handlePermissionsChanged(int uid) {
-        final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+        if (DEBUG_PERMISSION_TRACKER) {
+            Slog.i(TAG, "handlePermissionsChanged " + UserHandle.formatUid(uid));
+        }
+        final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
         if (permissions != null && permissions.length > 0) {
             final PermissionManagerServiceInternal pm =
                     mInjector.getPermissionManagerServiceInternal();
-            final boolean[] states = new boolean[permissions.length];
+            final UidGrantedPermissionState[] states =
+                    new UidGrantedPermissionState[permissions.length];
             for (int i = 0; i < permissions.length; i++) {
-                states[i] = pm.checkUidPermission(uid, permissions[i]) == PERMISSION_GRANTED;
+                final Pair<String, Integer> pair = permissions[i];
+                states[i] = new UidGrantedPermissionState(uid, pair.first, pair.second);
                 if (DEBUG_PERMISSION_TRACKER) {
-                    Slog.i(TAG, UserHandle.formatUid(uid) + " " + permissions[i] + "=" + states[i]);
+                    Slog.i(TAG, states[i].toString());
                 }
             }
             synchronized (mLock) {
-                handlePermissionsChangedLocked(uid, permissions, states);
+                handlePermissionsChangedLocked(uid, states);
             }
         }
     }
 
     @GuardedBy("mLock")
-    private void handlePermissionsChangedLocked(int uid, String[] permissions, boolean[] states) {
+    private void handlePermissionsChangedLocked(int uid, UidGrantedPermissionState[] states) {
         final int index = mUidGrantedPermissionsInMonitor.indexOfKey(uid);
-        ArraySet<String> grantedPermissions = index >= 0
+        ArraySet<UidGrantedPermissionState> grantedPermissions = index >= 0
                 ? mUidGrantedPermissionsInMonitor.valueAt(index) : null;
         final long now = SystemClock.elapsedRealtime();
-        for (int i = 0; i < permissions.length; i++) {
-            final String permission = permissions[i];
-            final boolean granted = states[i];
+        for (int i = 0; i < states.length; i++) {
+            final boolean granted = states[i].isGranted();
             boolean changed = false;
             if (granted) {
                 if (grantedPermissions == null) {
                     grantedPermissions = new ArraySet<>();
                     mUidGrantedPermissionsInMonitor.put(uid, grantedPermissions);
+                    changed = true;
                 }
-                changed = grantedPermissions.add(permission);
-            } else if (grantedPermissions != null) {
-                changed = grantedPermissions.remove(permission);
-                if (grantedPermissions.isEmpty()) {
+                grantedPermissions.add(states[i]);
+            } else if (grantedPermissions != null && !grantedPermissions.isEmpty()) {
+                if (grantedPermissions.remove(states[i]) && grantedPermissions.isEmpty()) {
                     mUidGrantedPermissionsInMonitor.removeAt(index);
+                    changed = true;
                 }
             }
             if (changed) {
@@ -178,10 +262,141 @@
         }
     }
 
+    /**
+     * Represents the grant state of a permission + appop of the given UID.
+     */
+    private class UidGrantedPermissionState {
+        final int mUid;
+        final @Nullable String mPermission;
+        final int mAppOp;
+
+        private boolean mPermissionGranted;
+        private boolean mAppOpAllowed;
+
+        UidGrantedPermissionState(int uid, @Nullable String permission, int appOp) {
+            mUid = uid;
+            mPermission = permission;
+            mAppOp = appOp;
+            updatePermissionState();
+            updateAppOps();
+        }
+
+        void updatePermissionState() {
+            if (TextUtils.isEmpty(mPermission)) {
+                mPermissionGranted = true;
+                return;
+            }
+            mPermissionGranted = mInjector.getPermissionManagerServiceInternal()
+                    .checkUidPermission(mUid, mPermission) == PERMISSION_GRANTED;
+        }
+
+        void updateAppOps() {
+            if (mAppOp == OP_NONE) {
+                mAppOpAllowed = true;
+                return;
+            }
+            final String[] packages = mInjector.getPackageManager().getPackagesForUid(mUid);
+            if (packages != null) {
+                final IAppOpsService appOpsService = mInjector.getIAppOpsService();
+                for (String pkg : packages) {
+                    try {
+                        final int mode = appOpsService.checkOperation(mAppOp, mUid, pkg);
+                        if (mode == AppOpsManager.MODE_ALLOWED) {
+                            mAppOpAllowed = true;
+                            return;
+                        }
+                    } catch (RemoteException e) {
+                        // Intra-process call, should never happen.
+                    }
+                }
+            }
+            mAppOpAllowed = false;
+        }
+
+        boolean isGranted() {
+            return mPermissionGranted && mAppOpAllowed;
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (other == null || !(other instanceof UidGrantedPermissionState)) {
+                return false;
+            }
+            final UidGrantedPermissionState otherState = (UidGrantedPermissionState) other;
+            return mUid == otherState.mUid && mAppOp == otherState.mAppOp
+                    && Objects.equals(mPermission, otherState.mPermission);
+        }
+
+        @Override
+        public int hashCode() {
+            return (Integer.hashCode(mUid) * 31 + Integer.hashCode(mAppOp)) * 31
+                    + (mPermission == null ? 0 : mPermission.hashCode());
+        }
+
+        @Override
+        public String toString() {
+            String s = "UidGrantedPermissionState{"
+                    + System.identityHashCode(this) + " "
+                    + UserHandle.formatUid(mUid) + ": ";
+            final boolean emptyPermissionName = TextUtils.isEmpty(mPermission);
+            if (!emptyPermissionName) {
+                s += mPermission + "=" + mPermissionGranted;
+            }
+            if (mAppOp != OP_NONE) {
+                if (!emptyPermissionName) {
+                    s += ",";
+                }
+                s += opToPublicName(mAppOp) + "=" + mAppOpAllowed;
+            }
+            s += "}";
+            return s;
+        }
+    }
+
+    private void startWatchingMode(@NonNull Integer[] ops) {
+        synchronized (mAppOpsCallbacks) {
+            stopWatchingMode();
+            final IAppOpsService appOpsService = mInjector.getIAppOpsService();
+            try {
+                for (int op: ops) {
+                    final MyAppOpsCallback cb = new MyAppOpsCallback();
+                    mAppOpsCallbacks.put(op, cb);
+                    appOpsService.startWatchingModeWithFlags(op, null,
+                            AppOpsManager.WATCH_FOREGROUND_CHANGES, cb);
+                }
+            } catch (RemoteException e) {
+                // Intra-process call, should never happen.
+            }
+        }
+    }
+
+    private void stopWatchingMode() {
+        synchronized (mAppOpsCallbacks) {
+            final IAppOpsService appOpsService = mInjector.getIAppOpsService();
+            for (int i = mAppOpsCallbacks.size() - 1; i >= 0; i--) {
+                try {
+                    appOpsService.stopWatchingMode(mAppOpsCallbacks.valueAt(i));
+                } catch (RemoteException e) {
+                    // Intra-process call, should never happen.
+                }
+            }
+            mAppOpsCallbacks.clear();
+        }
+    }
+
+    private class MyAppOpsCallback extends IAppOpsCallback.Stub {
+        @Override
+        public void opChanged(int op, int uid, String packageName) {
+            mHandler.obtainMessage(MyHandler.MSG_APPOPS_CHANGED, op, uid, packageName)
+                    .sendToTarget();
+        }
+    }
+
     private static class MyHandler extends Handler {
         static final int MSG_PERMISSIONS_INIT = 0;
         static final int MSG_PERMISSIONS_DESTROY = 1;
         static final int MSG_PERMISSIONS_CHANGED = 2;
+        static final int MSG_APPOPS_CHANGED = 3;
 
         private @NonNull AppPermissionTracker mTracker;
 
@@ -194,14 +409,19 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_PERMISSIONS_INIT:
+                    mTracker.handleAppOpsInit();
                     mTracker.handlePermissionsInit();
                     break;
                 case MSG_PERMISSIONS_DESTROY:
                     mTracker.handlePermissionsDestroy();
+                    mTracker.handleAppOpsDestroy();
                     break;
                 case MSG_PERMISSIONS_CHANGED:
                     mTracker.handlePermissionsChanged(msg.arg1);
                     break;
+                case MSG_APPOPS_CHANGED:
+                    mTracker.handleOpChanged(msg.arg1, msg.arg2, (String) msg.obj);
+                    break;
             }
         }
     }
@@ -231,25 +451,41 @@
     void dump(PrintWriter pw, String prefix) {
         pw.print(prefix);
         pw.println("APP PERMISSIONS TRACKER:");
-        final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+        final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
         final String prefixMore = "  " + prefix;
         final String prefixMoreMore = "  " + prefixMore;
-        for (String permission : permissions) {
+        for (Pair<String, Integer> permission : permissions) {
             pw.print(prefixMore);
-            pw.print(permission);
+            final boolean emptyPermissionName = TextUtils.isEmpty(permission.first);
+            if (!emptyPermissionName) {
+                pw.print(permission.first);
+            }
+            if (permission.second != OP_NONE) {
+                if (!emptyPermissionName) {
+                    pw.print('+');
+                }
+                pw.print(opToPublicName(permission.second));
+            }
             pw.println(':');
             synchronized (mLock) {
-                final SparseArray<ArraySet<String>> uidPerms = mUidGrantedPermissionsInMonitor;
+                final SparseArray<ArraySet<UidGrantedPermissionState>> uidPerms =
+                        mUidGrantedPermissionsInMonitor;
                 pw.print(prefixMoreMore);
                 pw.print('[');
                 boolean needDelimiter = false;
                 for (int i = 0, size = uidPerms.size(); i < size; i++) {
-                    if (uidPerms.valueAt(i).contains(permission)) {
-                        if (needDelimiter) {
-                            pw.print(',');
+                    final ArraySet<UidGrantedPermissionState> uidPerm = uidPerms.valueAt(i);
+                    for (int j = uidPerm.size() - 1; j >= 0; j--) {
+                        final UidGrantedPermissionState state = uidPerm.valueAt(j);
+                        if (state.mAppOp == permission.second
+                                && TextUtils.equals(state.mPermission, permission.first)) {
+                            if (needDelimiter) {
+                                pw.print(',');
+                            }
+                            needDelimiter = true;
+                            pw.print(UserHandle.formatUid(state.mUid));
+                            break;
                         }
-                        needDelimiter = true;
-                        pw.print(UserHandle.formatUid(uidPerms.keyAt(i)));
                     }
                 }
                 pw.println(']');
@@ -277,20 +513,25 @@
         static final boolean DEFAULT_BG_PERMISSION_MONITOR_ENABLED = true;
 
         /**
-         * Default value to {@link #mBgPermissionsInMonitor}.
+         * Default value to {@link #mBgPermissionsInMonitor}, it comes in pair;
+         * the first string strings in the pair is the permission name, and the second string
+         * is the appops name, if they are associated.
          */
         static final String[] DEFAULT_BG_PERMISSIONS_IN_MONITOR = new String[] {
-            ACCESS_FINE_LOCATION,
+            ACCESS_FINE_LOCATION, OPSTR_FINE_LOCATION,
+            CAMERA, OPSTR_CAMERA,
+            RECORD_AUDIO, OPSTR_RECORD_AUDIO,
         };
 
         /**
          * @see #KEY_BG_PERMISSIONS_IN_MONITOR.
          */
-        volatile String[] mBgPermissionsInMonitor = DEFAULT_BG_PERMISSIONS_IN_MONITOR;
+        volatile @NonNull Pair[] mBgPermissionsInMonitor;
 
         AppPermissionPolicy(@NonNull Injector injector, @NonNull AppPermissionTracker tracker) {
             super(injector, tracker, KEY_BG_PERMISSION_MONITOR_ENABLED,
                     DEFAULT_BG_PERMISSION_MONITOR_ENABLED);
+            mBgPermissionsInMonitor = parsePermissionConfig(DEFAULT_BG_PERMISSIONS_IN_MONITOR);
         }
 
         @Override
@@ -311,17 +552,38 @@
             }
         }
 
-        String[] getBgPermissionsInMonitor() {
+        Pair[] getBgPermissionsInMonitor() {
             return mBgPermissionsInMonitor;
         }
 
+        private @NonNull Pair[] parsePermissionConfig(@NonNull String[] perms) {
+            final Pair[] result = new Pair[perms.length / 2];
+            for (int i = 0, j = 0; i < perms.length; i += 2, j++) {
+                try {
+                    result[j] = Pair.create(TextUtils.isEmpty(perms[i]) ? null : perms[i],
+                            TextUtils.isEmpty(perms[i + 1]) ? OP_NONE : strOpToOp(perms[i + 1]));
+                } catch (Exception e) {
+                    // Ignore.
+                }
+            }
+            return result;
+        }
+
         private void updateBgPermissionsInMonitor() {
             final String config = DeviceConfig.getString(
                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                     KEY_BG_PERMISSIONS_IN_MONITOR,
                     null);
-            mBgPermissionsInMonitor = config != null
-                    ? config.split(",") : DEFAULT_BG_PERMISSIONS_IN_MONITOR;
+            final Pair[] newPermsInMonitor = parsePermissionConfig(
+                    config != null ? config.split(",") : DEFAULT_BG_PERMISSIONS_IN_MONITOR);
+            if (!Arrays.equals(mBgPermissionsInMonitor, newPermsInMonitor)) {
+                mBgPermissionsInMonitor = newPermsInMonitor;
+                if (isEnabled()) {
+                    // Trigger a reload.
+                    onTrackerEnabled(false);
+                    onTrackerEnabled(true);
+                }
+            }
         }
 
         @Override
@@ -338,7 +600,21 @@
             pw.print(prefix);
             pw.print(KEY_BG_PERMISSIONS_IN_MONITOR);
             pw.print('=');
-            pw.println(Arrays.toString(mBgPermissionsInMonitor));
+            pw.print('[');
+            for (int i = 0; i < mBgPermissionsInMonitor.length; i++) {
+                if (i > 0) {
+                    pw.print(',');
+                }
+                final Pair<String, Integer> pair = mBgPermissionsInMonitor[i];
+                if (pair.first != null) {
+                    pw.print(pair.first);
+                }
+                pw.print(',');
+                if (pair.second != OP_NONE) {
+                    pw.print(opToPublicName(pair.second));
+                }
+            }
+            pw.println(']');
         }
     }
 }
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index d6a4cf6..16a7283 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -58,7 +58,6 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.net.Uri;
 import android.os.Binder;
@@ -608,13 +607,7 @@
         if (check != null) {
             if ((pss * 1024) >= check && profile.getThread() != null
                     && mMemWatchDumpProcName == null) {
-                boolean isDebuggable = Build.IS_DEBUGGABLE;
-                if (!isDebuggable) {
-                    if ((proc.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
-                        isDebuggable = true;
-                    }
-                }
-                if (isDebuggable) {
+                if (Build.IS_DEBUGGABLE || proc.isDebuggable()) {
                     Slog.w(TAG, "Process " + proc + " exceeded pss limit " + check + "; reporting");
                     startHeapDumpLPf(profile, false);
                 } else {
@@ -1702,7 +1695,8 @@
         try {
             if (start) {
                 stopProfilerLPf(null, 0);
-                mService.setProfileApp(proc.info, proc.processName, profilerInfo);
+                mService.setProfileApp(proc.info, proc.processName, profilerInfo,
+                        proc.isSdkSandbox ? proc.getClientInfoForSdkSandbox() : null);
                 mProfileData.setProfileProc(proc);
                 mProfileType = profileType;
                 ParcelFileDescriptor fd = profilerInfo.profileFd;
@@ -1886,8 +1880,7 @@
                                     BatteryStatsImpl.Uid.Proc ps = st.batteryStats;
                                     if (ps == null || !ps.isActive()) {
                                         st.batteryStats = ps = bstats.getProcessStatsLocked(
-                                                bstats.mapUid(st.uid), st.name,
-                                                elapsedRealtime, uptime);
+                                                st.uid, st.name, elapsedRealtime, uptime);
                                     }
                                     ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
                                 }
@@ -2076,7 +2069,7 @@
             if (mAppAgentMap != null && mAppAgentMap.containsKey(processName)) {
                 // We need to do a debuggable check here. See setAgentApp for why the check is
                 // postponed to here.
-                if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+                if (app.isDebuggable()) {
                     String agent = mAppAgentMap.get(processName);
                     // Do not overwrite already requested agent.
                     if (profilerInfo == null) {
@@ -2133,7 +2126,7 @@
         if (preBindAgent != null) {
             thread.attachAgent(preBindAgent);
         }
-        if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+        if (app.isDebuggable()) {
             thread.attachStartupAgents(app.info.dataDir);
         }
         return profilerInfo;
diff --git a/services/core/java/com/android/server/am/AppRestrictionController.java b/services/core/java/com/android/server/am/AppRestrictionController.java
index 6e6cb87..41ff083 100644
--- a/services/core/java/com/android/server/am/AppRestrictionController.java
+++ b/services/core/java/com/android/server/am/AppRestrictionController.java
@@ -135,6 +135,7 @@
 import android.util.SparseArray;
 import android.util.SparseArrayMap;
 import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -182,7 +183,7 @@
     /**
      * Whether or not to show the foreground service manager on tapping notifications.
      */
-    private static final boolean ENABLE_SHOW_FOREGROUND_SERVICE_MANAGER = false;
+    private static final boolean ENABLE_SHOW_FOREGROUND_SERVICE_MANAGER = true;
 
     private final Context mContext;
     private final HandlerThread mBgHandlerThread;
@@ -241,7 +242,7 @@
     /**
      * The pre-config packages that are exempted from the background restrictions.
      */
-    private ArraySet<String> mBgRestrictionExemptioFromSysConfig;
+    ArraySet<String> mBgRestrictionExemptioFromSysConfig;
 
     /**
      * Lock specifically for bookkeeping around the carrier-privileged app set.
@@ -1369,6 +1370,12 @@
         }
     }
 
+    void dumpAsProto(ProtoOutputStream proto, int uid) {
+        for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
+            mAppStateTrackers.get(i).dumpAsProto(proto, uid);
+        }
+    }
+
     private void applyRestrictionLevel(String pkgName, int uid, @RestrictionLevel int level,
             int curBucket, boolean allowUpdateBucket, int reason, int subReason) {
         int curLevel;
@@ -1595,8 +1602,8 @@
                         cancelRequestBgRestrictedIfNecessary(packageName, uid);
                         final Intent newIntent = new Intent(ACTION_SHOW_FOREGROUND_SERVICE_MANAGER);
                         newIntent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
-                        mContext.sendBroadcastAsUser(newIntent,
-                                UserHandle.of(UserHandle.getUserId(uid)));
+                        // Task manager runs in SystemUI, which is SYSTEM user only.
+                        mContext.sendBroadcastAsUser(newIntent, UserHandle.SYSTEM);
                         break;
                 }
             }
@@ -1670,9 +1677,10 @@
             if (ENABLE_SHOW_FOREGROUND_SERVICE_MANAGER) {
                 final Intent intent = new Intent(ACTION_SHOW_FOREGROUND_SERVICE_MANAGER);
                 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+                // Task manager runs in SystemUI, which is SYSTEM user only.
                 pendingIntent = PendingIntent.getBroadcastAsUser(mContext, 0,
                         intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
-                        UserHandle.of(UserHandle.getUserId(uid)));
+                        UserHandle.SYSTEM);
             } else {
                 final Intent intent = new Intent(Settings.ACTION_VIEW_ADVANCED_POWER_USAGE_DETAIL);
                 intent.setData(Uri.fromParts(PACKAGE_SCHEME, packageName, null));
@@ -1750,7 +1758,7 @@
                     SYSTEM_UID, UserHandle.getUserId(uid));
             final String title = mContext.getString(titleRes);
             final String message = mContext.getString(messageRes,
-                    ai != null ? pm.getText(packageName, ai.labelRes, ai) : packageName);
+                    ai != null ? ai.loadLabel(pm) : packageName);
             final Icon icon = ai != null ? Icon.createWithResource(packageName, ai.icon) : null;
 
             postNotification(notificationId, packageName, uid, title, message, icon, pendingIntent,
@@ -1833,6 +1841,9 @@
     }
 
     void handleUidInactive(int uid, boolean disabled) {
+        if (!mConstantsObserver.mBgAutoRestrictedBucket) {
+            return;
+        }
         final ArrayList<Runnable> pendingTasks = mTmpRunnables;
         synchronized (mSettingsLock) {
             final int index = mActiveUids.indexOfKey(uid);
@@ -1855,6 +1866,9 @@
     }
 
     void handleUidActive(int uid) {
+        if (!mConstantsObserver.mBgAutoRestrictedBucket) {
+            return;
+        }
         synchronized (mSettingsLock) {
             final AppStandbyInternal appStandbyInternal = mInjector.getAppStandbyInternal();
             final int userId = UserHandle.getUserId(uid);
diff --git a/services/core/java/com/android/server/am/BaseAppStateTracker.java b/services/core/java/com/android/server/am/BaseAppStateTracker.java
index 0fada53..cb21a4b 100644
--- a/services/core/java/com/android/server/am/BaseAppStateTracker.java
+++ b/services/core/java/com/android/server/am/BaseAppStateTracker.java
@@ -16,7 +16,6 @@
 
 package com.android.server.am;
 
-import static com.android.server.am.ActiveServices.SERVICE_START_FOREGROUND_TIMEOUT;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 
@@ -33,9 +32,12 @@
 import android.os.BatteryManagerInternal;
 import android.os.BatteryStatsInternal;
 import android.os.Handler;
+import android.os.ServiceManager;
 import android.permission.PermissionManager;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
 
+import com.android.internal.app.IAppOpsService;
 import com.android.server.DeviceIdleInternal;
 import com.android.server.LocalServices;
 import com.android.server.notification.NotificationManagerInternal;
@@ -61,13 +63,15 @@
     static final int STATE_TYPE_MEDIA_SESSION = 1;
     static final int STATE_TYPE_FGS_MEDIA_PLAYBACK = 1 << 1;
     static final int STATE_TYPE_FGS_LOCATION = 1 << 2;
-    static final int STATE_TYPE_PERMISSION = 1 << 3;
-    static final int STATE_TYPE_NUM = 4;
+    static final int STATE_TYPE_FGS_WITH_NOTIFICATION = 1 << 3;
+    static final int STATE_TYPE_PERMISSION = 1 << 4;
+    static final int STATE_TYPE_NUM = 5;
 
     static final int STATE_TYPE_INDEX_MEDIA_SESSION = 0;
     static final int STATE_TYPE_INDEX_FGS_MEDIA_PLAYBACK = 1;
     static final int STATE_TYPE_INDEX_FGS_LOCATION = 2;
-    static final int STATE_TYPE_INDEX_PERMISSION = 3;
+    static final int STATE_TYPE_INDEX_FGS_WITH_NOTIFICATION = 3;
+    static final int STATE_TYPE_INDEX_PERMISSION = 4;
 
     protected final AppRestrictionController mAppRestrictionController;
     protected final Injector<T> mInjector;
@@ -126,6 +130,9 @@
                 case STATE_TYPE_FGS_LOCATION:
                     sb.append("FGS_LOCATION");
                     break;
+                case STATE_TYPE_FGS_WITH_NOTIFICATION:
+                    sb.append("FGS_NOTIFICATION");
+                    break;
                 case STATE_TYPE_PERMISSION:
                     sb.append("PERMISSION");
                     break;
@@ -250,6 +257,9 @@
         mInjector.getPolicy().dump(pw, "  " + prefix);
     }
 
+    void dumpAsProto(ProtoOutputStream proto, int uid) {
+    }
+
     static class Injector<T extends BaseAppStatePolicy> {
         T mAppStatePolicy;
 
@@ -266,6 +276,7 @@
         MediaSessionManager mMediaSessionManager;
         RoleManager mRoleManager;
         NotificationManagerInternal mNotificationManagerInternal;
+        IAppOpsService mIAppOpsService;
 
         void setPolicy(T policy) {
             mAppStatePolicy = policy;
@@ -288,6 +299,8 @@
             mRoleManager = context.getSystemService(RoleManager.class);
             mNotificationManagerInternal = LocalServices.getService(
                     NotificationManagerInternal.class);
+            mIAppOpsService = IAppOpsService.Stub.asInterface(
+                    ServiceManager.getService(Context.APP_OPS_SERVICE));
 
             getPolicy().onSystemReady();
         }
@@ -348,7 +361,7 @@
         }
 
         long getServiceStartForegroundTimeout() {
-            return SERVICE_START_FOREGROUND_TIMEOUT;
+            return mActivityManagerInternal.getServiceStartForegroundTimeout();
         }
 
         RoleManager getRoleManager() {
@@ -358,5 +371,9 @@
         NotificationManagerInternal getNotificationManagerInternal() {
             return mNotificationManagerInternal;
         }
+
+        IAppOpsService getIAppOpsService() {
+            return mIAppOpsService;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 1131fa8..4fdc88d 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -561,8 +561,18 @@
             // We were asked to fetch Bluetooth data.
             final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
             if (adapter != null) {
-                bluetoothReceiver = new SynchronousResultReceiver("bluetooth");
-                adapter.requestControllerActivityEnergyInfo(bluetoothReceiver);
+                SynchronousResultReceiver resultReceiver =
+                        new SynchronousResultReceiver("bluetooth");
+                adapter.requestControllerActivityEnergyInfo(
+                        Runnable::run,
+                        info -> {
+                            Bundle bundle = new Bundle();
+                            bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY,
+                                    info);
+                            resultReceiver.send(0, bundle);
+                        }
+                );
+                bluetoothReceiver = resultReceiver;
             }
         }
 
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 91822ac..eb7897b 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -799,6 +799,7 @@
                     final BatteryUsageStatsQuery querySinceReset =
                             new BatteryUsageStatsQuery.Builder()
                                     .includeProcessStateData()
+                                    .includeVirtualUids()
                                     .build();
                     bus = getBatteryUsageStats(List.of(querySinceReset)).get(0);
                     break;
@@ -806,6 +807,7 @@
                     final BatteryUsageStatsQuery queryPowerProfile =
                             new BatteryUsageStatsQuery.Builder()
                                     .includeProcessStateData()
+                                    .includeVirtualUids()
                                     .powerProfileModeledOnly()
                                     .build();
                     bus = getBatteryUsageStats(List.of(queryPowerProfile)).get(0);
@@ -821,6 +823,7 @@
                     final BatteryUsageStatsQuery queryBeforeReset =
                             new BatteryUsageStatsQuery.Builder()
                                     .includeProcessStateData()
+                                    .includeVirtualUids()
                                     .aggregateSnapshots(sessionStart, sessionEnd)
                                     .build();
                     bus = getBatteryUsageStats(List.of(queryBeforeReset)).get(0);
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index ea63c08..ade44ea 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -21,6 +21,9 @@
 import static android.os.Process.ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE;
 import static android.text.TextUtils.formatSimple;
 
+import static com.android.internal.util.FrameworkStatsLog.BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED;
+import static com.android.internal.util.FrameworkStatsLog.BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED__EVENT__BOOT_COMPLETED;
+import static com.android.internal.util.FrameworkStatsLog.BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED__EVENT__LOCKED_BOOT_COMPLETED;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_DEFERRAL;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_LIGHT;
@@ -29,6 +32,7 @@
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU;
 
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -51,6 +55,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PermissionInfo;
 import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -64,6 +69,7 @@
 import android.os.SystemClock;
 import android.os.Trace;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.permission.IPermissionManager;
 import android.text.TextUtils;
 import android.util.EventLog;
@@ -75,6 +81,7 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.server.LocalServices;
+import com.android.server.pm.UserManagerInternal;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -250,12 +257,16 @@
 
     public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
         r.enqueueClockTime = System.currentTimeMillis();
+        r.enqueueTime = SystemClock.uptimeMillis();
+        r.enqueueRealTime = SystemClock.elapsedRealtime();
         mParallelBroadcasts.add(r);
         enqueueBroadcastHelper(r);
     }
 
     public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
         r.enqueueClockTime = System.currentTimeMillis();
+        r.enqueueTime = SystemClock.uptimeMillis();
+        r.enqueueRealTime = SystemClock.elapsedRealtime();
         mDispatcher.enqueueOrderedBroadcastLocked(r);
         enqueueBroadcastHelper(r);
     }
@@ -1121,6 +1132,7 @@
         while (mParallelBroadcasts.size() > 0) {
             r = mParallelBroadcasts.remove(0);
             r.dispatchTime = SystemClock.uptimeMillis();
+            r.dispatchRealTime = SystemClock.elapsedRealtime();
             r.dispatchClockTime = System.currentTimeMillis();
 
             if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
@@ -1292,6 +1304,7 @@
                             performReceiveLocked(r.callerApp, r.resultTo,
                                     new Intent(r.intent), r.resultCode,
                                     r.resultData, r.resultExtras, false, false, r.userId);
+                            logBootCompletedBroadcastCompletionLatencyIfPossible(r);
                             // Set this to null so that the reference
                             // (local and remote) isn't kept in the mBroadcastHistory.
                             r.resultTo = null;
@@ -1408,6 +1421,7 @@
         r.receiverTime = SystemClock.uptimeMillis();
         if (recIdx == 0) {
             r.dispatchTime = r.receiverTime;
+            r.dispatchRealTime = SystemClock.elapsedRealtime();
             r.dispatchClockTime = System.currentTimeMillis();
 
             if (mLogLatencyMetrics) {
@@ -1866,6 +1880,59 @@
         return null;
     }
 
+    private void logBootCompletedBroadcastCompletionLatencyIfPossible(BroadcastRecord r) {
+        // Only log after last receiver.
+        // In case of split BOOT_COMPLETED broadcast, make sure only call this method on the
+        // last BroadcastRecord of the split broadcast which has non-null resultTo.
+        final int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
+        if (r.nextReceiver < numReceivers) {
+            return;
+        }
+        final String action = r.intent.getAction();
+        int event = 0;
+        if (Intent.ACTION_LOCKED_BOOT_COMPLETED.equals(action)) {
+            event = BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED__EVENT__LOCKED_BOOT_COMPLETED;
+        } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
+            event = BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED__EVENT__BOOT_COMPLETED;
+        }
+        if (event != 0) {
+            final int dispatchLatency = (int)(r.dispatchTime - r.enqueueTime);
+            final int completeLatency = (int)
+                    (SystemClock.uptimeMillis() - r.enqueueTime);
+            final int dispatchRealLatency = (int)(r.dispatchRealTime - r.enqueueRealTime);
+            final int completeRealLatency = (int)
+                    (SystemClock.elapsedRealtime() - r.enqueueRealTime);
+            int userType = FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__TYPE_UNKNOWN;
+            // This method is called very infrequently, no performance issue we call
+            // LocalServices.getService() here.
+            final UserManagerInternal umInternal = LocalServices.getService(
+                    UserManagerInternal.class);
+            final UserInfo userInfo = umInternal.getUserInfo(r.userId);
+            if (userInfo != null) {
+                userType = UserManager.getUserTypeForStatsd(userInfo.userType);
+            }
+            Slog.i(TAG_BROADCAST,
+                    "BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED action:"
+                            + action
+                            + " dispatchLatency:" + dispatchLatency
+                            + " completeLatency:" + completeLatency
+                            + " dispatchRealLatency:" + dispatchRealLatency
+                            + " completeRealLatency:" + completeRealLatency
+                            + " receiversSize:" + r.receivers.size()
+                            + " userId:" + r.userId
+                            + " userType:" + (userInfo != null? userInfo.userType : null));
+            FrameworkStatsLog.write(
+                    BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED,
+                    event,
+                    dispatchLatency,
+                    completeLatency,
+                    dispatchRealLatency,
+                    completeRealLatency,
+                    r.userId,
+                    userType);
+        }
+    }
+
     private void maybeReportBroadcastDispatchedEventLocked(BroadcastRecord r, int targetUid) {
         // STOPSHIP (217251579): Temporarily use temp-allowlist reason to identify
         // push messages and record response events.
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 8b1e829..2ee32b6 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -84,11 +84,14 @@
     boolean deferred;
     int splitCount;         // refcount for result callback, when split
     int splitToken;         // identifier for cross-BroadcastRecord refcount
+    long enqueueTime;       // uptimeMillis when the broadcast was enqueued
+    long enqueueRealTime;   // elapsedRealtime when the broadcast was enqueued
     long enqueueClockTime;  // the clock time the broadcast was enqueued
     long dispatchTime;      // when dispatch started on this set of receivers
+    long dispatchRealTime;  // elapsedRealtime when the broadcast was dispatched
     long dispatchClockTime; // the clock time the dispatch started
     long receiverTime;      // when current receiver started for timeouts.
-    long finishTime;        // when we finished the broadcast.
+    long finishTime;        // when we finished the current receiver.
     boolean timeoutExempt;  // true if this broadcast is not subject to receiver timeouts
     int resultCode;         // current result code value.
     String resultData;      // current result data value.
@@ -169,7 +172,7 @@
         pw.print(prefix); pw.print("dispatchTime=");
                 TimeUtils.formatDuration(dispatchTime, now, pw);
                 pw.print(" (");
-                TimeUtils.formatDuration(dispatchClockTime-enqueueClockTime, pw);
+                TimeUtils.formatDuration(dispatchTime - enqueueTime, pw);
                 pw.print(" since enq)");
         if (finishTime != 0) {
             pw.print(" finishTime="); TimeUtils.formatDuration(finishTime, now, pw);
@@ -324,8 +327,11 @@
         delivery = from.delivery;
         duration = from.duration;
         resultTo = from.resultTo;
+        enqueueTime = from.enqueueTime;
+        enqueueRealTime = from.enqueueRealTime;
         enqueueClockTime = from.enqueueClockTime;
         dispatchTime = from.dispatchTime;
+        dispatchRealTime = from.dispatchRealTime;
         dispatchClockTime = from.dispatchClockTime;
         receiverTime = from.receiverTime;
         finishTime = from.finishTime;
@@ -378,7 +384,9 @@
                 requiredPermissions, excludedPermissions, appOp, options, splitReceivers, resultTo,
                 resultCode, resultData, resultExtras, ordered, sticky, initialSticky, userId,
                 allowBackgroundActivityStarts, mBackgroundActivityStartsToken, timeoutExempt);
-
+        split.enqueueTime = this.enqueueTime;
+        split.enqueueRealTime = this.enqueueRealTime;
+        split.enqueueClockTime = this.enqueueClockTime;
         split.splitToken = this.splitToken;
         return split;
     }
@@ -448,9 +456,11 @@
             final BroadcastRecord br = new BroadcastRecord(queue, intent, callerApp, callerPackage,
                     callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
                     requiredPermissions, excludedPermissions, appOp, options,
-                    uid2receiverList.valueAt(i), resultTo,
+                    uid2receiverList.valueAt(i), null /* _resultTo */,
                     resultCode, resultData, resultExtras, ordered, sticky, initialSticky, userId,
                     allowBackgroundActivityStarts, mBackgroundActivityStartsToken, timeoutExempt);
+            br.enqueueTime = this.enqueueTime;
+            br.enqueueRealTime = this.enqueueRealTime;
             br.enqueueClockTime = this.enqueueClockTime;
             ret.put(uid2receiverList.keyAt(i), br);
         }
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 7ed3dcf..02206ff 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -407,7 +407,6 @@
                 uids.clear();
                 uids.put(uidRec.getUid(), uidRec);
                 updateUidsLSP(uids, SystemClock.elapsedRealtime());
-                mProcessList.incrementProcStateSeqAndNotifyAppsLOSP(uids);
             }
         }
 
@@ -1144,8 +1143,6 @@
             }
         }
 
-        mProcessList.incrementProcStateSeqAndNotifyAppsLOSP(activeUids);
-
         return mService.mAppProfiler.updateLowMemStateLSP(numCached, numEmpty, numTrimming);
     }
 
@@ -1180,6 +1177,11 @@
 
     @GuardedBy({"mService", "mProcLock"})
     private void updateUidsLSP(ActiveUids activeUids, final long nowElapsed) {
+        // This compares previously set procstate to the current procstate in regards to whether
+        // or not the app's network access will be blocked. So, this needs to be called before
+        // we update the UidRecord's procstate by calling {@link UidRecord#setSetProcState}.
+        mProcessList.incrementProcStateSeqAndNotifyAppsLOSP(activeUids);
+
         ArrayList<UidRecord> becameIdle = mTmpBecameIdle;
         becameIdle.clear();
 
@@ -1252,7 +1254,7 @@
                     mService.mServices.foregroundServiceProcStateChangedLocked(uidRec);
                 }
             }
-            mService.mInternal.deletePendingTopUid(uidRec.getUid());
+            mService.mInternal.deletePendingTopUid(uidRec.getUid(), nowElapsed);
         }
         if (mLocalPowerManager != null) {
             mLocalPowerManager.finishUidChanges();
@@ -1672,6 +1674,24 @@
             }
         }
 
+        // If the app was recently in the foreground and has expedited jobs running,
+        // allow it to get a higher rank in memory for some time, compared to other EJS and even
+        // foreground services so that it can finish performing any persistence/processing of
+        // in-memory state.
+        if (psr.hasTopStartedAlmostPerceptibleServices()
+                && adj > ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ
+                && (state.getLastTopTime()
+                        + mConstants.TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION > now
+                || state.getSetProcState() <= PROCESS_STATE_TOP)) {
+            adj = ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ;
+            // This shall henceforth be called the "EJ" exemption, despite utilizing the
+            // ALMOST_PERCEPTIBLE flag to work.
+            state.setAdjType("top-ej-act");
+            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to recent fg for EJ: " + app);
+            }
+        }
+
         if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
                 || procState > PROCESS_STATE_TRANSIENT_BACKGROUND) {
             if (state.getForcingToImportant() != null) {
@@ -2852,8 +2872,7 @@
         // To avoid some abuse patterns, we are going to be careful about what we consider
         // to be an app interaction.  Being the top activity doesn't count while the display
         // is sleeping, nor do short foreground services.
-        if (state.getCurProcState() <= PROCESS_STATE_TOP
-                || state.getCurProcState() == PROCESS_STATE_BOUND_TOP) {
+        if (ActivityManager.isProcStateConsideredInteraction(state.getCurProcState())) {
             isInteraction = true;
             state.setFgInteractionTime(0);
         } else if (state.getCurProcState() <= PROCESS_STATE_FOREGROUND_SERVICE) {
diff --git a/services/core/java/com/android/server/am/PendingStartActivityUids.java b/services/core/java/com/android/server/am/PendingStartActivityUids.java
index 455c75b..bd60057 100644
--- a/services/core/java/com/android/server/am/PendingStartActivityUids.java
+++ b/services/core/java/com/android/server/am/PendingStartActivityUids.java
@@ -55,9 +55,15 @@
         return false;
     }
 
-    synchronized void delete(int uid) {
+    synchronized void delete(int uid, long nowElapsed) {
         final Pair<Integer, Long> pendingPid = mPendingUids.get(uid);
         if (pendingPid != null) {
+            if (nowElapsed < pendingPid.second) {
+                Slog.i(TAG,
+                        "updateOomAdj start time is before than pendingPid added,"
+                        + " don't delete it");
+                return;
+            }
             final long delay = SystemClock.elapsedRealtime() - pendingPid.second;
             if (delay >= 1000 /*ms*/) {
                 Slog.i(TAG,
@@ -87,4 +93,4 @@
     synchronized boolean isPendingTopUid(int uid) {
         return mPendingUids.get(uid) != null;
     }
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 48ca59d..253686c 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1718,8 +1718,16 @@
             int runtimeFlags = 0;
 
             boolean debuggableFlag = (app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
-            if (!debuggableFlag && app.isSdkSandbox) {
-                debuggableFlag = isAppForSdkSandboxDebuggable(app);
+            boolean isProfileableByShell = app.info.isProfileableByShell();
+            boolean isProfileable = app.info.isProfileable();
+
+            if (app.isSdkSandbox) {
+                ApplicationInfo clientInfo = app.getClientInfoForSdkSandbox();
+                if (clientInfo != null) {
+                    debuggableFlag |= (clientInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+                    isProfileableByShell |= clientInfo.isProfileableByShell();
+                    isProfileable |= clientInfo.isProfileable();
+                }
             }
 
             if (debuggableFlag) {
@@ -1741,10 +1749,10 @@
             if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 || mService.mSafeMode) {
                 runtimeFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
             }
-            if ((app.info.privateFlags & ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL) != 0) {
+            if (isProfileableByShell) {
                 runtimeFlags |= Zygote.PROFILE_FROM_SHELL;
             }
-            if (app.info.isProfileable()) {
+            if (isProfileable) {
                 runtimeFlags |= Zygote.PROFILEABLE;
             }
             if ("1".equals(SystemProperties.get("debug.checkjni"))) {
@@ -1812,7 +1820,7 @@
             }
 
             String invokeWith = null;
-            if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+            if (debuggableFlag) {
                 // Debuggable apps may include a wrapper script with their library directory.
                 String wrapperFileName = app.info.nativeLibraryDir + "/wrap.sh";
                 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
@@ -1887,24 +1895,6 @@
         }
     }
 
-    /** Return true if the client app for the SDK sandbox process is debuggable. */
-    private boolean isAppForSdkSandboxDebuggable(ProcessRecord sandboxProcess) {
-        // TODO (b/221004701) use client app process name
-        final int appUid = Process.getAppUidForSdkSandboxUid(sandboxProcess.uid);
-        IPackageManager pm = mService.getPackageManager();
-        try {
-            String[] packages = pm.getPackagesForUid(appUid);
-            for (String aPackage : packages) {
-                ApplicationInfo i = pm.getApplicationInfo(aPackage, 0, sandboxProcess.userId);
-                if ((i.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
-                    return true;
-                }
-            }
-        } catch (RemoteException e) {
-            // shouldn't happen
-        }
-        return false;
-    }
 
     @GuardedBy("mService")
     boolean startProcessLocked(HostingRecord hostingRecord, String entryPoint, ProcessRecord app,
@@ -2365,7 +2355,7 @@
     ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
             boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord,
             int zygotePolicyFlags, boolean allowWhileBooting, boolean isolated, int isolatedUid,
-            boolean isSdkSandbox, int sdkSandboxUid,
+            boolean isSdkSandbox, int sdkSandboxUid, String sdkSandboxClientAppPackage,
             String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
         long startTime = SystemClock.uptimeMillis();
         ProcessRecord app;
@@ -2460,7 +2450,7 @@
         if (app == null) {
             checkSlow(startTime, "startProcess: creating new process record");
             app = newProcessRecordLocked(info, processName, isolated, isolatedUid, isSdkSandbox,
-                    sdkSandboxUid, hostingRecord);
+                    sdkSandboxUid, sdkSandboxClientAppPackage, hostingRecord);
             if (app == null) {
                 Slog.w(TAG, "Failed making new process record for "
                         + processName + "/" + info.uid + " isolated=" + isolated);
@@ -2956,7 +2946,7 @@
     @GuardedBy("mService")
     ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
             boolean isolated, int isolatedUid, boolean isSdkSandbox, int sdkSandboxUid,
-            HostingRecord hostingRecord) {
+            String sdkSandboxClientAppPackage, HostingRecord hostingRecord) {
         String proc = customProcess != null ? customProcess : info.processName;
         final int userId = UserHandle.getUserId(info.uid);
         int uid = info.uid;
@@ -2992,6 +2982,7 @@
                     FrameworkStatsLog.ISOLATED_UID_CHANGED__EVENT__CREATED);
         }
         final ProcessRecord r = new ProcessRecord(mService, info, proc, uid,
+                sdkSandboxClientAppPackage,
                 hostingRecord.getDefiningUid(), hostingRecord.getDefiningProcessName());
         final ProcessStateRecord state = r.mState;
 
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index f7cc3d7..b4ff870 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -27,6 +27,7 @@
 import android.app.ApplicationExitInfo.SubReason;
 import android.app.IApplicationThread;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.ProcessInfo;
 import android.content.pm.VersionedPackage;
 import android.content.res.CompatibilityInfo;
@@ -84,6 +85,8 @@
     final int uid;              // uid of process; may be different from 'info' if isolated
     final int userId;           // user of process.
     final String processName;   // name of the process
+    final String sdkSandboxClientAppPackage; // if this is an sdk sandbox process, name of the
+                                             // app package for which it is running
 
     /**
      * Overall state of process's uid.
@@ -493,11 +496,12 @@
 
     ProcessRecord(ActivityManagerService _service, ApplicationInfo _info, String _processName,
             int _uid) {
-        this(_service, _info, _processName, _uid, -1, null);
+        this(_service, _info, _processName, _uid, null, -1, null);
     }
 
     ProcessRecord(ActivityManagerService _service, ApplicationInfo _info, String _processName,
-            int _uid, int _definingUid, String _definingProcessName) {
+            int _uid, String _sdkSandboxClientAppPackage, int _definingUid,
+            String _definingProcessName) {
         mService = _service;
         mProcLock = _service.mProcLock;
         info = _info;
@@ -530,6 +534,7 @@
         uid = _uid;
         userId = UserHandle.getUserId(_uid);
         processName = _processName;
+        sdkSandboxClientAppPackage = _sdkSandboxClientAppPackage;
         mPersistent = false;
         mRemoved = false;
         mProfile = new ProcessProfileRecord(this);
@@ -861,6 +866,29 @@
         return mDebugging;
     }
 
+    @Nullable
+    public ApplicationInfo getClientInfoForSdkSandbox() {
+        if (!isSdkSandbox || sdkSandboxClientAppPackage == null) {
+            throw new IllegalStateException(
+                    "getClientInfoForSdkSandbox called for non-sandbox process"
+            );
+        }
+        PackageManagerInternal pm = mService.getPackageManagerInternal();
+        return pm.getApplicationInfo(
+                sdkSandboxClientAppPackage, /* flags */0, Process.SYSTEM_UID, userId);
+    }
+
+    public boolean isDebuggable() {
+        if ((info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+            return true;
+        }
+        if (isSdkSandbox) {
+            ApplicationInfo clientInfo = getClientInfoForSdkSandbox();
+            return clientInfo != null && (clientInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+        }
+        return false;
+    }
+
     @GuardedBy("mService")
     void setDebugging(boolean debugging) {
         mDebugging = debugging;
diff --git a/services/core/java/com/android/server/am/ProcessServiceRecord.java b/services/core/java/com/android/server/am/ProcessServiceRecord.java
index 8f77b87..6b748193 100644
--- a/services/core/java/com/android/server/am/ProcessServiceRecord.java
+++ b/services/core/java/com/android/server/am/ProcessServiceRecord.java
@@ -19,6 +19,7 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.os.IBinder;
+import android.os.SystemClock;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 
@@ -42,6 +43,18 @@
     private boolean mHasForegroundServices;
 
     /**
+     * Running any services that are almost perceptible (started with
+     * {@link Context#BIND_ALMOST_PERCEPTIBLE} while the app was on TOP)?
+     */
+    private boolean mHasTopStartedAlmostPerceptibleServices;
+
+    /**
+     * The latest value of {@link ServiceRecord#lastTopAlmostPerceptibleBindRequestUptimeMs} among
+     * the currently running services.
+     */
+    private long mLastTopStartedAlmostPerceptibleBindRequestUptimeMs;
+
+    /**
      * Service that applied current connectionGroup/Importance.
      */
     private ServiceRecord mConnectionService;
@@ -146,6 +159,46 @@
         mRepFgServiceTypes = foregroundServiceTypes;
     }
 
+    void updateHasTopStartedAlmostPerceptibleServices() {
+        mHasTopStartedAlmostPerceptibleServices = false;
+        mLastTopStartedAlmostPerceptibleBindRequestUptimeMs = 0;
+        for (int s = mServices.size() - 1; s >= 0; --s) {
+            final ServiceRecord sr = mServices.valueAt(s);
+            mLastTopStartedAlmostPerceptibleBindRequestUptimeMs = Math.max(
+                    mLastTopStartedAlmostPerceptibleBindRequestUptimeMs,
+                    sr.lastTopAlmostPerceptibleBindRequestUptimeMs);
+            if (!mHasTopStartedAlmostPerceptibleServices && isAlmostPerceptible(sr)) {
+                mHasTopStartedAlmostPerceptibleServices = true;
+            }
+        }
+    }
+
+    private boolean isAlmostPerceptible(ServiceRecord record) {
+        if (record.lastTopAlmostPerceptibleBindRequestUptimeMs <= 0) {
+            return false;
+        }
+        final ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections =
+                record.getConnections();
+        for (int m = serviceConnections.size() - 1; m >= 0; --m) {
+            final ArrayList<ConnectionRecord> clist = serviceConnections.valueAt(m);
+
+            for (int c = clist.size() - 1; c >= 0; --c) {
+                final ConnectionRecord cr = clist.get(c);
+                if ((cr.flags & Context.BIND_ALMOST_PERCEPTIBLE) != 0) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    boolean hasTopStartedAlmostPerceptibleServices() {
+        return mHasTopStartedAlmostPerceptibleServices
+                || (mLastTopStartedAlmostPerceptibleBindRequestUptimeMs > 0
+                && SystemClock.uptimeMillis() - mLastTopStartedAlmostPerceptibleBindRequestUptimeMs
+                < mService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs);
+    }
+
     ServiceRecord getConnectionService() {
         return mConnectionService;
     }
@@ -243,6 +296,14 @@
         if (added && record.serviceInfo != null) {
             mApp.getWindowProcessController().onServiceStarted(record.serviceInfo);
         }
+        if (record.lastTopAlmostPerceptibleBindRequestUptimeMs > 0) {
+            mLastTopStartedAlmostPerceptibleBindRequestUptimeMs = Math.max(
+                    mLastTopStartedAlmostPerceptibleBindRequestUptimeMs,
+                    record.lastTopAlmostPerceptibleBindRequestUptimeMs);
+            if (!mHasTopStartedAlmostPerceptibleServices) {
+                mHasTopStartedAlmostPerceptibleServices = isAlmostPerceptible(record);
+            }
+        }
         return added;
     }
 
@@ -253,7 +314,11 @@
      * @return true if the service was removed, false otherwise.
      */
     boolean stopService(ServiceRecord record) {
-        return mServices.remove(record);
+        final boolean removed = mServices.remove(record);
+        if (record.lastTopAlmostPerceptibleBindRequestUptimeMs > 0) {
+            updateHasTopStartedAlmostPerceptibleServices();
+        }
+        return removed;
     }
 
     /**
@@ -261,6 +326,7 @@
      */
     void stopAllServices() {
         mServices.clear();
+        updateHasTopStartedAlmostPerceptibleServices();
     }
 
     /**
@@ -408,6 +474,13 @@
             pw.print(prefix); pw.print("mHasForegroundServices="); pw.print(mHasForegroundServices);
             pw.print(" forcingToImportant="); pw.println(mApp.mState.getForcingToImportant());
         }
+        if (mHasTopStartedAlmostPerceptibleServices
+                || mLastTopStartedAlmostPerceptibleBindRequestUptimeMs > 0) {
+            pw.print(prefix); pw.print("mHasTopStartedAlmostPerceptibleServices=");
+            pw.print(mHasTopStartedAlmostPerceptibleServices);
+            pw.print(" mLastTopStartedAlmostPerceptibleBindRequestUptimeMs=");
+            pw.println(mLastTopStartedAlmostPerceptibleBindRequestUptimeMs);
+        }
         if (mHasClientActivities || mHasAboveClient || mTreatLikeActivity) {
             pw.print(prefix); pw.print("hasClientActivities="); pw.print(mHasClientActivities);
             pw.print(" hasAboveClient="); pw.print(mHasAboveClient);
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index c53d4d6..639f56c 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -24,6 +24,7 @@
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.IApplicationThread;
 import android.app.Notification;
@@ -96,6 +97,8 @@
     final long createRealTime;  // when this service was created
     final boolean isSdkSandbox; // whether this is a sdk sandbox service
     final int sdkSandboxClientAppUid; // the app uid for which this sdk sandbox service is running
+    final String sdkSandboxClientAppPackage; // the app package for which this sdk sandbox service
+                                             // is running
     final ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings
             = new ArrayMap<Intent.FilterComparison, IntentBindRecord>();
                             // All active bindings to the service.
@@ -139,6 +142,12 @@
     int pendingConnectionGroup;        // To be filled in to ProcessRecord once it connects
     int pendingConnectionImportance;   // To be filled in to ProcessRecord once it connects
 
+    /**
+     * The last time (in uptime timebase) a bind request was made with BIND_ALMOST_PERCEPTIBLE for
+     * this service while on TOP.
+     */
+    long lastTopAlmostPerceptibleBindRequestUptimeMs;
+
     // any current binding to this service has BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS flag?
     private boolean mIsAllowedBgActivityStartsByBinding;
     // is this service currently allowed to start activities from background by providing
@@ -573,13 +582,14 @@
             Intent.FilterComparison intent, ServiceInfo sInfo, boolean callerIsFg,
             Runnable restarter) {
         this(ams, name, instanceName, definingPackageName, definingUid, intent, sInfo, callerIsFg,
-                restarter, null, 0);
+                restarter, null, 0, null);
     }
 
     ServiceRecord(ActivityManagerService ams, ComponentName name,
             ComponentName instanceName, String definingPackageName, int definingUid,
             Intent.FilterComparison intent, ServiceInfo sInfo, boolean callerIsFg,
-            Runnable restarter, String sdkSandboxProcessName, int sdkSandboxClientAppUid) {
+            Runnable restarter, String sdkSandboxProcessName, int sdkSandboxClientAppUid,
+            String sdkSandboxClientAppPackage) {
         this.ams = ams;
         this.name = name;
         this.instanceName = instanceName;
@@ -590,8 +600,9 @@
         serviceInfo = sInfo;
         appInfo = sInfo.applicationInfo;
         packageName = sInfo.applicationInfo.packageName;
-        isSdkSandbox = sdkSandboxProcessName != null;
+        this.isSdkSandbox = sdkSandboxProcessName != null;
         this.sdkSandboxClientAppUid = sdkSandboxClientAppUid;
+        this.sdkSandboxClientAppPackage = sdkSandboxClientAppPackage;
         if ((sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0) {
             processName = sInfo.processName + ":" + instanceName.getClassName();
         } else if (sdkSandboxProcessName != null) {
@@ -709,6 +720,7 @@
         }
     }
 
+    @NonNull
     ArrayMap<IBinder, ArrayList<ConnectionRecord>> getConnections() {
         return connections;
     }
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index ad17655..b886196 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -107,6 +107,7 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.server.FactoryResetter;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService.UserCompletedEventType;
@@ -1797,6 +1798,10 @@
             Slogf.w(TAG, "Cannot switch to User #" + targetUserId + ": not a full user");
             return false;
         }
+        if (FactoryResetter.isFactoryResetting()) {
+            Slogf.w(TAG, "Cannot switch to User #" + targetUserId + ": factory reset in progress");
+            return false;
+        }
         boolean userSwitchUiEnabled;
         synchronized (mLock) {
             if (!mInitialized) {
@@ -2618,7 +2623,7 @@
         if (getStartedUserState(userId) == null) {
             return false;
         }
-        if (!mInjector.getUserManager().isCredentialSharedWithParent(userId)) {
+        if (!mInjector.getUserManager().isCredentialSharableWithParent(userId)) {
             return false;
         }
         if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java
index b73cf5b..42a7423 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java
@@ -171,16 +171,15 @@
                 return;
             }
 
-            // Remove any existing intent and unregister for this package before adding a new one.
+            // Remove any existing PendingIntent for this package.
             String callingPackage = pendingIntent.getCreatorPackage();
             PendingIntent duplicatePendingIntent = findExistingRequestByPackage(callingPackage);
             if (duplicatePendingIntent != null) {
-                Slog.d(TAG, "Unregister duplicate request from " + callingPackage);
-                onUnregisterObserver(callingPackage);
+                Slog.d(TAG, "Replace duplicate request from " + callingPackage);
                 mExistingPendingIntents.remove(duplicatePendingIntent);
             }
 
-            // Register new package and add request to mExistingRequests
+            // Register package and add pendingIntent to mExistingPendingIntents
             startDetection(request, callingPackage, createDetectionResultRemoteCallback(),
                     getServerStatusCallback(clientStatusCallback));
             mExistingPendingIntents.add(pendingIntent);
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java b/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java
index 010bf1b..e2b22dc 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java
@@ -110,6 +110,8 @@
                 return runStopDetection();
             case "get-last-status-code":
                 return getLastStatusCode();
+            case "get-last-package-name":
+                return getLastPackageName();
             case "query-service-status":
                 return runQueryServiceStatus();
             case "get-bound-package":
@@ -157,6 +159,13 @@
         return lastResponse.getStatusCode();
     }
 
+    private int getLastPackageName() {
+        AmbientContextDetectionServiceStatus lastResponse =
+                sTestableCallbackInternal.getLastStatus();
+        out.println(lastResponse == null ? "" : lastResponse.getPackageName());
+        return 0;
+    }
+
     @Override
     public void onHelp() {
         PrintWriter pw = getOutPrintWriter();
@@ -167,6 +176,7 @@
         pw.println("  start-detection USER_ID PACKAGE_NAME: Starts AmbientContextEvent detection.");
         pw.println("  stop-detection USER_ID: Stops AmbientContextEvent detection.");
         pw.println("  get-last-status-code: Prints the latest request status code.");
+        pw.println("  get-last-package-name: Prints the latest request package name.");
         pw.println("  query-event-status USER_ID PACKAGE_NAME: Prints the event status code.");
         pw.println("  get-bound-package USER_ID:"
                 + "     Print the bound package that implements the service.");
diff --git a/services/core/java/com/android/server/ambientcontext/RemoteAmbientContextDetectionService.java b/services/core/java/com/android/server/ambientcontext/RemoteAmbientContextDetectionService.java
index f42080d..8aec752 100644
--- a/services/core/java/com/android/server/ambientcontext/RemoteAmbientContextDetectionService.java
+++ b/services/core/java/com/android/server/ambientcontext/RemoteAmbientContextDetectionService.java
@@ -49,6 +49,12 @@
         connect();
     }
 
+    @Override
+    protected long getAutoDisconnectTimeoutMs() {
+        // Disable automatic unbinding.
+        return -1;
+    }
+
     /**
      * Asks the implementation to start detection.
      *
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java
index b0a389d..a76eb8f 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
 import android.app.ActivityTaskManager;
 import android.content.Context;
 import android.content.Intent;
@@ -52,6 +53,7 @@
                 mContext,
                 new GameClassifierImpl(mContext.getPackageManager()),
                 ActivityManager.getService(),
+                LocalServices.getService(ActivityManagerInternal.class),
                 ActivityTaskManager.getService(),
                 (WindowManagerService) ServiceManager.getService(Context.WINDOW_SERVICE),
                 LocalServices.getService(WindowManagerInternal.class),
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
index faf5c38..b38195a 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
@@ -21,9 +21,11 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityManagerInternal;
 import android.app.ActivityTaskManager;
 import android.app.IActivityManager;
 import android.app.IActivityTaskManager;
+import android.app.IProcessObserver;
 import android.app.TaskStackListener;
 import android.content.ComponentName;
 import android.content.Context;
@@ -45,6 +47,7 @@
 import android.service.games.IGameSession;
 import android.service.games.IGameSessionController;
 import android.service.games.IGameSessionService;
+import android.text.TextUtils;
 import android.util.Slog;
 import android.view.SurfaceControl;
 import android.view.SurfaceControlViewHost.SurfacePackage;
@@ -82,15 +85,6 @@
                         Slog.w(TAG, "Failed to send connected event", ex);
                     }
                 }
-
-                @Override
-                public void onDisconnected(@NonNull IGameService service) {
-                    try {
-                        service.disconnected();
-                    } catch (RemoteException ex) {
-                        Slog.w(TAG, "Failed to send disconnected event", ex);
-                    }
-                }
             };
 
     private final ServiceLifecycleCallbacks<IGameSessionService>
@@ -143,12 +137,43 @@
                 GameServiceProviderInstanceImpl.this.onTaskFocusChanged(taskId, focused);
             });
         }
+    };
 
-        // TODO(b/204503192): Limit the lifespan of the game session in the Game Service provider
-        // to only when the associated task is running. Right now it is possible for a task to
-        // move into the background and for all associated processes to die and for the Game Session
-        // provider's GameSessionService to continue to be running. Ideally we could unbind the
-        // service when this happens.
+    /**
+     * The TaskStackListener declared above gives us good visibility into game task lifecycle.
+     * However, it is possible for the Android system to kill all the processes associated with a
+     * game task (e.g., when the system is under memory pressure or reaches a background process
+     * limit). When this happens, the game task remains (and no TaskStackListener callbacks are
+     * invoked), but we would nonetheless want to destroy a game session associated with the task
+     * if this were to happen.
+     *
+     * This process observer gives us visibility into process lifecycles and lets us track all the
+     * processes associated with each package so that any game sessions associated with the package
+     * are destroyed if the process count for a given package reaches zero (most packages will
+     * have at most one task). If processes for a given package are started up again, the destroyed
+     * game sessions will be re-created.
+     */
+    private final IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
+        @Override
+        public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
+            // This callback is used to track how many processes are running for a given package.
+            // Then, when a process dies, we will know if it was the only process running for that
+            // package and the associated game sessions should be destroyed.
+            mBackgroundExecutor.execute(() -> {
+                GameServiceProviderInstanceImpl.this.onForegroundActivitiesChanged(pid);
+            });
+        }
+
+        @Override
+        public void onProcessDied(int pid, int uid) {
+            mBackgroundExecutor.execute(() -> {
+                GameServiceProviderInstanceImpl.this.onProcessDied(pid);
+            });
+        }
+
+        @Override
+        public void onForegroundServicesChanged(int pid, int uid, int serviceTypes) {
+        }
     };
 
     private final IGameServiceController mGameServiceController =
@@ -167,8 +192,11 @@
     private final IGameSessionController mGameSessionController =
             new IGameSessionController.Stub() {
                 @Override
+                @RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY)
                 public void takeScreenshot(int taskId,
                         @NonNull AndroidFuture gameScreenshotResultFuture) {
+                    mContext.enforceCallingPermission(Manifest.permission.MANAGE_GAME_ACTIVITY,
+                            "takeScreenshot()");
                     mBackgroundExecutor.execute(() -> {
                         GameServiceProviderInstanceImpl.this.takeScreenshot(taskId,
                                 gameScreenshotResultFuture);
@@ -192,6 +220,7 @@
     private final Context mContext;
     private final GameClassifier mGameClassifier;
     private final IActivityManager mActivityManager;
+    private final ActivityManagerInternal mActivityManagerInternal;
     private final IActivityTaskManager mActivityTaskManager;
     private final WindowManagerService mWindowManagerService;
     private final WindowManagerInternal mWindowManagerInternal;
@@ -203,6 +232,12 @@
     private final ConcurrentHashMap<Integer, GameSessionRecord> mGameSessions =
             new ConcurrentHashMap<>();
     @GuardedBy("mLock")
+    private final ConcurrentHashMap<Integer, String> mPidToPackageMap = new ConcurrentHashMap<>();
+    @GuardedBy("mLock")
+    private final ConcurrentHashMap<String, Integer> mPackageNameToProcessCountMap =
+            new ConcurrentHashMap<>();
+
+    @GuardedBy("mLock")
     private volatile boolean mIsRunning;
 
     GameServiceProviderInstanceImpl(
@@ -211,6 +246,7 @@
             @NonNull Context context,
             @NonNull GameClassifier gameClassifier,
             @NonNull IActivityManager activityManager,
+            @NonNull ActivityManagerInternal activityManagerInternal,
             @NonNull IActivityTaskManager activityTaskManager,
             @NonNull WindowManagerService windowManagerService,
             @NonNull WindowManagerInternal windowManagerInternal,
@@ -222,6 +258,7 @@
         mContext = context;
         mGameClassifier = gameClassifier;
         mActivityManager = activityManager;
+        mActivityManagerInternal = activityManagerInternal;
         mActivityTaskManager = activityTaskManager;
         mWindowManagerService = windowManagerService;
         mWindowManagerInternal = windowManagerInternal;
@@ -263,6 +300,12 @@
             Slog.w(TAG, "Failed to register task stack listener", e);
         }
 
+        try {
+            mActivityManager.registerProcessObserver(mProcessObserver);
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Failed to register process observer", e);
+        }
+
         mWindowManagerInternal.registerTaskSystemBarsListener(mTaskSystemBarsVisibilityListener);
     }
 
@@ -274,6 +317,12 @@
         mIsRunning = false;
 
         try {
+            mActivityManager.unregisterProcessObserver(mProcessObserver);
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Failed to unregister process observer", e);
+        }
+
+        try {
             mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
         } catch (RemoteException e) {
             Slog.w(TAG, "Failed to unregister task stack listener", e);
@@ -284,7 +333,9 @@
 
         destroyAndClearAllGameSessionsLocked();
 
-        mGameServiceConnector.unbind();
+        mGameServiceConnector.post(IGameService::disconnected).whenComplete((result, t) -> {
+            mGameServiceConnector.unbind();
+        });
         mGameSessionServiceConnector.unbind();
 
         mGameServiceConnector.setServiceLifecycleCallbacks(null);
@@ -596,6 +647,126 @@
         }
     }
 
+    private void onForegroundActivitiesChanged(int pid) {
+        synchronized (mLock) {
+            onForegroundActivitiesChangedLocked(pid);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void onForegroundActivitiesChangedLocked(int pid) {
+        if (mPidToPackageMap.containsKey(pid)) {
+            // We are already tracking this pid, nothing to do.
+            return;
+        }
+
+        final String packageName = mActivityManagerInternal.getPackageNameByPid(pid);
+        if (TextUtils.isEmpty(packageName)) {
+            // Game processes should always have a package name.
+            return;
+        }
+
+        if (!gameSessionExistsForPackageNameLocked(packageName)) {
+            // We only need to track processes for tasks with game session records.
+            return;
+        }
+
+        mPidToPackageMap.put(pid, packageName);
+        final int processCountForPackage = mPackageNameToProcessCountMap.getOrDefault(packageName,
+                0) + 1;
+        mPackageNameToProcessCountMap.put(packageName, processCountForPackage);
+
+        if (DEBUG) {
+            Slog.d(TAG, "onForegroundActivitiesChangedLocked: tracking pid " + pid + ", for "
+                    + packageName + ". Process count for package: " + processCountForPackage);
+        }
+
+        // If there are processes for the package, we may need to re-create game sessions
+        // that are associated with the package
+        if (processCountForPackage > 0) {
+            recreateEndedGameSessionsLocked(packageName);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void recreateEndedGameSessionsLocked(String packageName) {
+        for (GameSessionRecord gameSessionRecord : mGameSessions.values()) {
+            if (gameSessionRecord.isGameSessionEndedForProcessDeath() && packageName.equals(
+                    gameSessionRecord.getComponentName().getPackageName())) {
+                if (DEBUG) {
+                    Slog.d(TAG,
+                            "recreateGameSessionsLocked(): re-creating game session for: "
+                                    + packageName + " with taskId: "
+                                    + gameSessionRecord.getTaskId());
+                }
+
+                final int taskId = gameSessionRecord.getTaskId();
+                mGameSessions.put(taskId, GameSessionRecord.awaitingGameSessionRequest(taskId,
+                        gameSessionRecord.getComponentName()));
+                createGameSessionLocked(gameSessionRecord.getTaskId());
+            }
+        }
+    }
+
+    private void onProcessDied(int pid) {
+        synchronized (mLock) {
+            onProcessDiedLocked(pid);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void onProcessDiedLocked(int pid) {
+        final String packageName = mPidToPackageMap.remove(pid);
+        if (packageName == null) {
+            // We weren't tracking this process.
+            return;
+        }
+
+        final Integer oldProcessCountForPackage = mPackageNameToProcessCountMap.get(packageName);
+        if (oldProcessCountForPackage == null) {
+            // This should never happen; we should have a process count for all tracked packages.
+            Slog.w(TAG, "onProcessDiedLocked(): Missing process count for package");
+            return;
+        }
+
+        final int processCountForPackage = oldProcessCountForPackage - 1;
+        mPackageNameToProcessCountMap.put(packageName, processCountForPackage);
+
+        // If there are no more processes for the game, then we will terminate any game sessions
+        // running for the package.
+        if (processCountForPackage <= 0) {
+            endGameSessionsForPackageLocked(packageName);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void endGameSessionsForPackageLocked(String packageName) {
+        for (GameSessionRecord gameSessionRecord : mGameSessions.values()) {
+            if (gameSessionRecord.getGameSession() != null && packageName.equals(
+                    gameSessionRecord.getComponentName().getPackageName())) {
+                if (DEBUG) {
+                    Slog.d(TAG, "endGameSessionsForPackageLocked(): No more processes for "
+                            + packageName + ", ending game session with taskId: "
+                            + gameSessionRecord.getTaskId());
+                }
+                mGameSessions.put(gameSessionRecord.getTaskId(),
+                        gameSessionRecord.withGameSessionEndedOnProcessDeath());
+                destroyGameSessionFromRecordLocked(gameSessionRecord);
+            }
+        }
+    }
+
+    @GuardedBy("mLock")
+    private boolean gameSessionExistsForPackageNameLocked(String packageName) {
+        for (GameSessionRecord gameSessionRecord : mGameSessions.values()) {
+            if (packageName.equals(gameSessionRecord.getComponentName().getPackageName())) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
     @Nullable
     private GameSessionViewHostConfiguration createViewHostConfigurationForTask(int taskId) {
         RunningTaskInfo runningTaskInfo = getRunningTaskInfoForTask(taskId);
diff --git a/services/core/java/com/android/server/app/GameSessionRecord.java b/services/core/java/com/android/server/app/GameSessionRecord.java
index a241812..74e538e 100644
--- a/services/core/java/com/android/server/app/GameSessionRecord.java
+++ b/services/core/java/com/android/server/app/GameSessionRecord.java
@@ -35,6 +35,10 @@
         // A Game Session is created and attached.
         // GameSessionRecord.getGameSession() != null.
         GAME_SESSION_ATTACHED,
+        // A Game Session did exist for a given game task but was destroyed because the last process
+        // for the game died.
+        // GameSessionRecord.getGameSession() == null.
+        GAME_SESSION_ENDED_PROCESS_DEATH,
     }
 
     private final int mTaskId;
@@ -99,6 +103,20 @@
     }
 
     @NonNull
+    public GameSessionRecord withGameSessionEndedOnProcessDeath() {
+        return new GameSessionRecord(
+                mTaskId,
+                State.GAME_SESSION_ENDED_PROCESS_DEATH,
+                mRootComponentName,
+                /* gameSession=*/ null,
+                /* surfacePackage=*/ null);
+    }
+
+    public boolean isGameSessionEndedForProcessDeath() {
+        return mState == State.GAME_SESSION_ENDED_PROCESS_DEATH;
+    }
+
+    @NonNull
     public int getTaskId() {
         return mTaskId;
     }
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index 567d1ae..d16fe12 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -74,6 +74,8 @@
 import java.io.PrintWriter;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 /**
  * An attention service implementation that runs in System Server process.
@@ -87,6 +89,9 @@
     /** Service will unbind if connection is not used for that amount of time. */
     private static final long CONNECTION_TTL_MILLIS = 60_000;
 
+    /** How long AttentionManagerService will wait for service binding after lazy binding. */
+    private static final long SERVICE_BINDING_WAIT_MILLIS = 1000;
+
     /** DeviceConfig flag name, if {@code true}, enables AttentionManagerService features. */
     @VisibleForTesting
     static final String KEY_SERVICE_ENABLED = "service_enabled";
@@ -129,6 +134,7 @@
     @GuardedBy("mLock")
     private boolean mBinding;
     private AttentionHandler mAttentionHandler;
+    private CountDownLatch mServiceBindingLatch;
 
     @VisibleForTesting
     ComponentName mComponentName;
@@ -161,6 +167,7 @@
         mLock = lock;
         mAttentionHandler = handler;
         mPrivacyManager = SensorPrivacyManager.getInstance(context);
+        mServiceBindingLatch = new CountDownLatch(1);
     }
 
     @Override
@@ -275,13 +282,16 @@
         }
 
         synchronized (mLock) {
-            final long now = SystemClock.uptimeMillis();
             // schedule shutting down the connection if no one resets this timer
             freeIfInactiveLocked();
 
             // lazily start the service, which should be very lightweight to start
             bindLocked();
-
+        }
+        final long now = SystemClock.uptimeMillis();
+        // Proceed when the service binding is complete.
+        awaitServiceBinding(Math.min(SERVICE_BINDING_WAIT_MILLIS, timeout));
+        synchronized (mLock) {
             // throttle frequent requests
             final AttentionCheckCache cache = mAttentionCheckCacheBuffer == null ? null
                     : mAttentionCheckCacheBuffer.getLast();
@@ -361,7 +371,10 @@
 
             // lazily start the service, which should be very lightweight to start
             bindLocked();
-
+        }
+        // Proceed when the service binding is complete.
+        awaitServiceBinding(SERVICE_BINDING_WAIT_MILLIS);
+        synchronized (mLock) {
             /*
             Prevent spamming with multiple requests, only one at a time is allowed.
             If there are use-cases for keeping track of multiple requests, we
@@ -419,6 +432,14 @@
         return context.getPackageManager().getAttentionServicePackageName();
     }
 
+    private void awaitServiceBinding(long millis) {
+        try {
+            mServiceBindingLatch.await(millis, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            Slog.e(LOG_TAG, "Interrupted while waiting to bind Attention Service.", e);
+        }
+    }
+
     /**
      * Provides attention service component name at runtime, making sure it's provided by the
      * system.
@@ -711,6 +732,7 @@
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
             init(IAttentionService.Stub.asInterface(service));
+            mServiceBindingLatch.countDown();
         }
 
         @Override
@@ -730,6 +752,7 @@
 
         void cleanupService() {
             init(null);
+            mServiceBindingLatch = new CountDownLatch(1);
         }
 
         private void init(@Nullable IAttentionService service) {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 270a61b..1a482e4 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -252,8 +252,8 @@
                         return;
                     }
                 }
-                setCommunicationRouteForClient(
-                        cb, pid, device, BtHelper.SCO_MODE_UNDEFINED, eventSource);
+                postSetCommunicationRouteForClient(new CommunicationClientInfo(
+                        cb, pid, device, BtHelper.SCO_MODE_UNDEFINED, eventSource));
             }
         }
     }
@@ -283,8 +283,8 @@
                         return false;
                     }
                 }
-                setCommunicationRouteForClient(
-                        cb, pid, deviceAttr, BtHelper.SCO_MODE_UNDEFINED, eventSource);
+                postSetCommunicationRouteForClient(new CommunicationClientInfo(
+                        cb, pid, deviceAttr, BtHelper.SCO_MODE_UNDEFINED, eventSource));
             }
         }
         return true;
@@ -348,26 +348,35 @@
     }
 
     /**
-     * Returns the device currently requested for communication use case.
-     * If the current audio mode owner is in the communication route client list,
-     * use this preference.
-     * Otherwise use first client's preference (first client corresponds to latest request).
-     * null is returned if no client is in the list.
-     * @return AudioDeviceAttributes the requested device for communication.
+     * Returns the communication client with the highest priority:
+     * - 1) the client which is currently also controlling the audio mode
+     * - 2) the first client in the stack if there is no audio mode owner
+     * - 3) no client otherwise
+     * @return CommunicationRouteClient the client driving the communication use case routing.
      */
-
     @GuardedBy("mDeviceStateLock")
-    private AudioDeviceAttributes requestedCommunicationDevice() {
-        AudioDeviceAttributes device = null;
-        for (CommunicationRouteClient cl : mCommunicationRouteClients) {
-            if (cl.getPid() == mModeOwnerPid) {
-                device = cl.getDevice();
+    private CommunicationRouteClient topCommunicationRouteClient() {
+        for (CommunicationRouteClient crc : mCommunicationRouteClients) {
+            if (crc.getPid() == mModeOwnerPid) {
+                return crc;
             }
         }
         if (!mCommunicationRouteClients.isEmpty() && mModeOwnerPid == 0) {
-            device = mCommunicationRouteClients.get(0).getDevice();
+            return mCommunicationRouteClients.get(0);
         }
+        return null;
+    }
 
+    /**
+     * Returns the device currently requested for communication use case.
+     * Use the device requested by the communication route client selected by
+     * {@link #topCommunicationRouteClient()} if any or none otherwise.
+     * @return AudioDeviceAttributes the requested device for communication.
+     */
+    @GuardedBy("mDeviceStateLock")
+    private AudioDeviceAttributes requestedCommunicationDevice() {
+        CommunicationRouteClient crc = topCommunicationRouteClient();
+        AudioDeviceAttributes device = crc != null ? crc.getDevice() : null;
         if (AudioService.DEBUG_COMM_RTE) {
             Log.v(TAG, "requestedCommunicationDevice, device: "
                     + device + " mode owner pid: " + mModeOwnerPid);
@@ -710,7 +719,7 @@
         }
         synchronized (mDeviceStateLock) {
             mBluetoothScoOn = on;
-            sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE, SENDMSG_QUEUE, eventSource);
+            postUpdateCommunicationRouteClient(eventSource);
         }
     }
 
@@ -770,7 +779,9 @@
             synchronized (mDeviceStateLock) {
                 AudioDeviceAttributes device =
                         new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, "");
-                setCommunicationRouteForClient(cb, pid, device, scoAudioMode, eventSource);
+
+                postSetCommunicationRouteForClient(new CommunicationClientInfo(
+                        cb, pid, device, scoAudioMode, eventSource));
             }
         }
     }
@@ -788,8 +799,8 @@
                 if (client == null || !client.requestsBluetoothSco()) {
                     return;
                 }
-                setCommunicationRouteForClient(
-                        cb, pid, null, BtHelper.SCO_MODE_UNDEFINED, eventSource);
+                postSetCommunicationRouteForClient(new CommunicationClientInfo(
+                        cb, pid, null, BtHelper.SCO_MODE_UNDEFINED, eventSource));
             }
         }
     }
@@ -990,6 +1001,61 @@
                 MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET, SENDMSG_QUEUE, capturePreset);
     }
 
+    /*package*/ void postUpdateCommunicationRouteClient(String eventSource) {
+        sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT, SENDMSG_QUEUE, eventSource);
+    }
+
+    /*package*/ void postSetCommunicationRouteForClient(CommunicationClientInfo info) {
+        sendLMsgNoDelay(MSG_L_SET_COMMUNICATION_ROUTE_FOR_CLIENT, SENDMSG_QUEUE, info);
+    }
+
+    /*package*/ void postScoAudioStateChanged(int state) {
+        sendIMsgNoDelay(MSG_I_SCO_AUDIO_STATE_CHANGED, SENDMSG_QUEUE, state);
+    }
+
+    /*package*/ static final class CommunicationClientInfo {
+        final @NonNull IBinder mCb;
+        final int mPid;
+        final @NonNull AudioDeviceAttributes mDevice;
+        final int mScoAudioMode;
+        final @NonNull String mEventSource;
+
+        CommunicationClientInfo(@NonNull IBinder cb, int pid, @NonNull AudioDeviceAttributes device,
+                int scoAudioMode, @NonNull String eventSource) {
+            mCb = cb;
+            mPid = pid;
+            mDevice = device;
+            mScoAudioMode = scoAudioMode;
+            mEventSource = eventSource;
+        }
+
+        // redefine equality op so we can match messages intended for this client
+        @Override
+        public boolean equals(Object o) {
+            if (o == null) {
+                return false;
+            }
+            if (this == o) {
+                return true;
+            }
+            if (!(o instanceof CommunicationClientInfo)) {
+                return false;
+            }
+
+            return mCb.equals(((CommunicationClientInfo) o).mCb)
+                    && mPid == ((CommunicationClientInfo) o).mPid;
+        }
+
+        @Override
+        public String toString() {
+            return "CommunicationClientInfo mCb=" + mCb.toString()
+                    +"mPid=" + mPid
+                    +"mDevice=" + mDevice.toString()
+                    +"mScoAudioMode=" + mScoAudioMode
+                    +"mEventSource=" + mEventSource;
+        }
+    }
+
     //---------------------------------------------------------------------
     // Method forwarding between the helper classes (BtHelper, AudioDeviceInventory)
     // only call from a "handle"* method or "on"* method
@@ -1265,18 +1331,30 @@
                         synchronized (mDeviceStateLock) {
                             mModeOwnerPid = msg.arg1;
                             if (msg.arg2 != AudioSystem.MODE_RINGTONE) {
-                                onUpdateCommunicationRoute("setNewModeOwner");
+                                onUpdateCommunicationRouteClient("setNewModeOwner");
                             }
                         }
                     }
                     break;
-                case MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED:
+
+                case MSG_L_SET_COMMUNICATION_ROUTE_FOR_CLIENT:
                     synchronized (mSetModeLock) {
                         synchronized (mDeviceStateLock) {
-                            onCommunicationRouteClientDied((CommunicationRouteClient) msg.obj);
+                            CommunicationClientInfo info = (CommunicationClientInfo) msg.obj;
+                            setCommunicationRouteForClient(info.mCb, info.mPid, info.mDevice,
+                                    info.mScoAudioMode, info.mEventSource);
                         }
                     }
                     break;
+
+                case MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT:
+                    synchronized (mSetModeLock) {
+                        synchronized (mDeviceStateLock) {
+                            onUpdateCommunicationRouteClient((String) msg.obj);
+                        }
+                    }
+                    break;
+
                 case MSG_L_UPDATE_COMMUNICATION_ROUTE:
                     synchronized (mSetModeLock) {
                         synchronized (mDeviceStateLock) {
@@ -1284,6 +1362,23 @@
                         }
                     }
                     break;
+
+                case MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED:
+                    synchronized (mSetModeLock) {
+                        synchronized (mDeviceStateLock) {
+                            onCommunicationRouteClientDied((CommunicationRouteClient) msg.obj);
+                        }
+                    }
+                    break;
+
+                case MSG_I_SCO_AUDIO_STATE_CHANGED:
+                    synchronized (mSetModeLock) {
+                        synchronized (mDeviceStateLock) {
+                            mBtHelper.onScoAudioStateChanged(msg.arg1);
+                        }
+                    }
+                    break;
+
                 case MSG_TOGGLE_HDMI:
                     synchronized (mDeviceStateLock) {
                         mDeviceInventory.onToggleHdmi();
@@ -1437,6 +1532,9 @@
     private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE = 39;
     private static final int MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY = 40;
     private static final int MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY = 41;
+    private static final int MSG_L_SET_COMMUNICATION_ROUTE_FOR_CLIENT = 42;
+    private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT = 43;
+    private static final int MSG_I_SCO_AUDIO_STATE_CHANGED = 44;
 
     private static final int MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT = 45;
     //
@@ -1679,9 +1777,8 @@
             return;
         }
         Log.w(TAG, "Communication client died");
-        setCommunicationRouteForClient(
-                client.getBinder(), client.getPid(), null, BtHelper.SCO_MODE_UNDEFINED,
-                "onCommunicationRouteClientDied");
+        removeCommunicationRouteClient(client.getBinder(), true);
+        onUpdateCommunicationRouteClient("onCommunicationRouteClientDied");
     }
 
     /**
@@ -1735,11 +1832,31 @@
             AudioSystem.setParameters("BT_SCO=on");
         }
         if (preferredCommunicationDevice == null) {
-            postRemovePreferredDevicesForStrategy(mCommunicationStrategyId);
+            removePreferredDevicesForStrategySync(mCommunicationStrategyId);
         } else {
-            postSetPreferredDevicesForStrategy(
+            setPreferredDevicesForStrategySync(
                     mCommunicationStrategyId, Arrays.asList(preferredCommunicationDevice));
         }
+        onUpdatePhoneStrategyDevice(preferredCommunicationDevice);
+    }
+
+    /**
+     * Select new communication device from communication route client at the top of the stack
+     * and restore communication route including restarting SCO audio if needed.
+     */
+    // @GuardedBy("mSetModeLock")
+    @GuardedBy("mDeviceStateLock")
+    private void onUpdateCommunicationRouteClient(String eventSource) {
+        onUpdateCommunicationRoute(eventSource);
+        CommunicationRouteClient crc = topCommunicationRouteClient();
+        if (AudioService.DEBUG_COMM_RTE) {
+            Log.v(TAG, "onUpdateCommunicationRouteClient, crc: "
+                    + crc + " eventSource: " + eventSource);
+        }
+        if (crc != null) {
+            setCommunicationRouteForClient(crc.getBinder(), crc.getPid(), crc.getDevice(),
+                    BtHelper.SCO_MODE_UNDEFINED, eventSource);
+        }
     }
 
     private void onUpdatePhoneStrategyDevice(AudioDeviceAttributes device) {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 0e29041..69b75e6 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -1154,6 +1154,7 @@
             mConnectedDevices.put(DeviceInfo.makeDeviceListKey(device, address),
                     new DeviceInfo(device, name, address, AudioSystem.AUDIO_FORMAT_DEFAULT));
             mDeviceBroker.postAccessoryPlugMediaUnmute(device);
+            setCurrentAudioRouteNameIfPossible(name, /*fromA2dp=*/false);
         }
 
         if (streamType == AudioSystem.STREAM_DEFAULT) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index d01be58..d775581 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -78,6 +78,7 @@
 import android.media.AudioAttributes.AttributeSystemUsage;
 import android.media.AudioDeviceAttributes;
 import android.media.AudioDeviceInfo;
+import android.media.AudioDeviceVolumeManager;
 import android.media.AudioFocusInfo;
 import android.media.AudioFocusRequest;
 import android.media.AudioFormat;
@@ -96,12 +97,14 @@
 import android.media.IAudioService;
 import android.media.ICapturePresetDevicesRoleDispatcher;
 import android.media.ICommunicationDeviceDispatcher;
+import android.media.IDeviceVolumeBehaviorDispatcher;
 import android.media.IMuteAwaitConnectionCallback;
 import android.media.IPlaybackConfigDispatcher;
 import android.media.IRecordingConfigDispatcher;
 import android.media.IRingtonePlayer;
 import android.media.ISpatializerCallback;
 import android.media.ISpatializerHeadToSoundStagePoseCallback;
+import android.media.ISpatializerHeadTrackerAvailableCallback;
 import android.media.ISpatializerHeadTrackingModeCallback;
 import android.media.ISpatializerOutputCallback;
 import android.media.IStrategyPreferredDevicesDispatcher;
@@ -152,6 +155,7 @@
 import android.telecom.TelecomManager;
 import android.text.TextUtils;
 import android.util.AndroidRuntimeException;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.IntArray;
 import android.util.Log;
@@ -225,6 +229,7 @@
 
     private final AudioSystemAdapter mAudioSystem;
     private final SystemServerAdapter mSystemServer;
+    private final SettingsAdapter mSettings;
 
     /** Debug audio mode */
     protected static final boolean DEBUG_MODE = false;
@@ -339,6 +344,7 @@
     private static final int MSG_ADD_ASSISTANT_SERVICE_UID = 44;
     private static final int MSG_REMOVE_ASSISTANT_SERVICE_UID = 45;
     private static final int MSG_UPDATE_ACTIVE_ASSISTANT_SERVICE_UID = 46;
+    private static final int MSG_DISPATCH_DEVICE_VOLUME_BEHAVIOR = 47;
 
     // start of messages handled under wakelock
     //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
@@ -623,6 +629,47 @@
             AudioSystem.DEVICE_OUT_HDMI_ARC,
             AudioSystem.DEVICE_OUT_HDMI_EARC
     ));
+
+    // Devices where the framework sends a full scale audio signal, and controls the volume of
+    // the external audio system separately.
+    Map<Integer, AbsoluteVolumeDeviceInfo> mAbsoluteVolumeDeviceInfoMap = new ArrayMap<>();
+
+    /**
+     * Stores information about a device using absolute volume behavior.
+     */
+    private static final class AbsoluteVolumeDeviceInfo {
+        private final AudioDeviceAttributes mDevice;
+        private final List<VolumeInfo> mVolumeInfos;
+        private final IAudioDeviceVolumeDispatcher mCallback;
+        private final boolean mHandlesVolumeAdjustment;
+
+        private AbsoluteVolumeDeviceInfo(AudioDeviceAttributes device, List<VolumeInfo> volumeInfos,
+                IAudioDeviceVolumeDispatcher callback, boolean handlesVolumeAdjustment) {
+            this.mDevice = device;
+            this.mVolumeInfos = volumeInfos;
+            this.mCallback = callback;
+            this.mHandlesVolumeAdjustment = handlesVolumeAdjustment;
+        }
+
+        /**
+         * Given a stream type, returns a matching VolumeInfo.
+         */
+        @Nullable
+        private VolumeInfo getMatchingVolumeInfoForStream(int streamType) {
+            for (VolumeInfo volumeInfo : mVolumeInfos) {
+                boolean streamTypeMatches = volumeInfo.hasStreamType()
+                        && volumeInfo.getStreamType() == streamType;
+                boolean volumeGroupMatches = volumeInfo.hasVolumeGroup()
+                        && Arrays.stream(volumeInfo.getVolumeGroup().getLegacyStreamTypes())
+                        .anyMatch(s -> s == streamType);
+                if (streamTypeMatches || volumeGroupMatches) {
+                    return volumeInfo;
+                }
+            }
+            return null;
+        }
+    }
+
     // Devices for the which use the "absolute volume" concept (framework sends audio signal
     // full scale, and volume control separately) and can be used for multiple use cases reflected
     // by the audio mode (e.g. media playback in MODE_NORMAL, and phone calls in MODE_IN_CALL).
@@ -874,12 +921,23 @@
 
     /** @hide */
     public AudioService(Context context) {
-        this(context, AudioSystemAdapter.getDefaultAdapter(),
-                SystemServerAdapter.getDefaultAdapter(context));
+        this(context,
+                AudioSystemAdapter.getDefaultAdapter(),
+                SystemServerAdapter.getDefaultAdapter(context),
+                SettingsAdapter.getDefaultAdapter(),
+                null);
     }
 
+    /**
+     * @param context
+     * @param audioSystem Adapter for {@link AudioSystem}
+     * @param systemServer Adapter for privilieged functionality for system server components
+     * @param settings Adapter for {@link Settings}
+     * @param looper Looper to use for the service's message handler. If this is null, an
+     *               {@link AudioSystemThread} is created as the messaging thread instead.
+     */
     public AudioService(Context context, AudioSystemAdapter audioSystem,
-            SystemServerAdapter systemServer) {
+            SystemServerAdapter systemServer, SettingsAdapter settings, @Nullable Looper looper) {
         sLifecycleLogger.log(new AudioEventLogger.StringEvent("AudioService()"));
         mContext = context;
         mContentResolver = context.getContentResolver();
@@ -887,6 +945,7 @@
 
         mAudioSystem = audioSystem;
         mSystemServer = systemServer;
+        mSettings = settings;
 
         mPlatformType = AudioSystem.getPlatformType(context);
 
@@ -1006,7 +1065,11 @@
                         MAX_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM];
         }
 
-        createAudioSystemThread();
+        if (looper == null) {
+            createAudioSystemThread();
+        } else {
+            mAudioHandler = new AudioHandler(looper);
+        }
 
         AudioSystem.setErrorCallback(mAudioSystemCallback);
 
@@ -1023,7 +1086,7 @@
                 new String("AudioService ctor"),
                 0);
 
-        mSafeMediaVolumeState = Settings.Global.getInt(mContentResolver,
+        mSafeMediaVolumeState = mSettings.getGlobalInt(mContentResolver,
                                             Settings.Global.AUDIO_SAFE_VOLUME_STATE,
                                             SAFE_MEDIA_VOLUME_NOT_CONFIGURED);
         // The default safe volume index read here will be replaced by the actual value when
@@ -1305,14 +1368,18 @@
             mRm = (RoleManager) mContext.getSystemService(Context.ROLE_SERVICE);
             if (mRm != null) {
                 mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.ALL);
-                updateAssistantUId(true);
+                synchronized (mSettingsLock) {
+                    updateAssistantUIdLocked(/* forceUpdate= */ true);
+                }
             }
         }
 
         @Override
         public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
             if (RoleManager.ROLE_ASSISTANT.equals(roleName)) {
-                updateAssistantUId(false);
+                synchronized (mSettingsLock) {
+                    updateAssistantUIdLocked(/* forceUpdate= */ false);
+                }
             }
         }
 
@@ -1411,7 +1478,7 @@
             sendEncodedSurroundMode(mContentResolver, "onAudioServerDied");
             sendEnabledSurroundFormats(mContentResolver, true);
             AudioSystem.setRttEnabled(mRttEnabled);
-            updateAssistantServicesUidsLocked();
+            resetAssistantServicesUidsLocked();
         }
 
         synchronized (mAccessibilityServiceUidsLock) {
@@ -1540,6 +1607,12 @@
     }
 
     @GuardedBy("mSettingsLock")
+    private void resetAssistantServicesUidsLocked() {
+        mAssistantUids.clear();
+        updateAssistantUIdLocked(/* forceUpdate= */ true);
+    }
+
+    @GuardedBy("mSettingsLock")
     private void updateAssistantServicesUidsLocked() {
         int[] assistantUids = mAssistantUids.stream().mapToInt(Integer::intValue).toArray();
         AudioSystem.setAssistantServicesUids(assistantUids);
@@ -2008,7 +2081,7 @@
 
     private void readDockAudioSettings(ContentResolver cr)
     {
-        mDockAudioMediaEnabled = Settings.Global.getInt(
+        mDockAudioMediaEnabled = mSettings.getGlobalInt(
                                         cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
 
         sendMsg(mAudioHandler,
@@ -2024,7 +2097,7 @@
 
     private void updateMasterMono(ContentResolver cr)
     {
-        final boolean masterMono = System.getIntForUser(
+        final boolean masterMono = mSettings.getSystemIntForUser(
                 cr, System.MASTER_MONO, 0 /* default */, UserHandle.USER_CURRENT) == 1;
         if (DEBUG_VOL) {
             Log.d(TAG, String.format("Master mono %b", masterMono));
@@ -2045,7 +2118,7 @@
 
     private void sendEncodedSurroundMode(ContentResolver cr, String eventSource)
     {
-        final int encodedSurroundMode = Settings.Global.getInt(
+        final int encodedSurroundMode = mSettings.getGlobalInt(
                 cr, Settings.Global.ENCODED_SURROUND_OUTPUT,
                 Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
         sendEncodedSurroundMode(encodedSurroundMode, eventSource);
@@ -2161,7 +2234,7 @@
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mSettingsLock) {
-                Settings.Global.putString(mContentResolver,
+                mSettings.putGlobalString(mContentResolver,
                         Settings.Global.ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS,
                         TextUtils.join(",", enabledFormats));
             }
@@ -2182,7 +2255,7 @@
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mSettingsLock) {
-                Settings.Global.putInt(mContentResolver,
+                mSettings.putGlobalInt(mContentResolver,
                         Settings.Global.ENCODED_SURROUND_OUTPUT,
                         toEncodedSurroundSetting(mode));
             }
@@ -2203,7 +2276,7 @@
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mSettingsLock) {
-                int encodedSurroundSetting = Settings.Global.getInt(mContentResolver,
+                int encodedSurroundSetting = mSettings.getGlobalInt(mContentResolver,
                         Settings.Global.ENCODED_SURROUND_OUTPUT,
                         AudioManager.ENCODED_SURROUND_OUTPUT_AUTO);
                 return toEncodedSurroundOutputMode(encodedSurroundSetting, targetSdkVersion);
@@ -2216,7 +2289,7 @@
     /** @return the formats that are enabled in global settings */
     private HashSet<Integer> getEnabledFormats() {
         HashSet<Integer> formats = new HashSet<>();
-        String enabledFormats = Settings.Global.getString(mContentResolver,
+        String enabledFormats = mSettings.getGlobalString(mContentResolver,
                 Settings.Global.ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS);
         if (enabledFormats != null) {
             try {
@@ -2279,7 +2352,7 @@
             // Manually enable surround formats only when the setting is in manual mode.
             return;
         }
-        String enabledSurroundFormats = Settings.Global.getString(
+        String enabledSurroundFormats = mSettings.getGlobalString(
                 cr, Settings.Global.ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS);
         if (enabledSurroundFormats == null) {
             // Never allow enabledSurroundFormats as a null, which could happen when
@@ -2307,7 +2380,7 @@
         }
         // Set filtered surround formats to settings DB in case
         // there are invalid surround formats in original settings.
-        Settings.Global.putString(mContext.getContentResolver(),
+        mSettings.putGlobalString(mContext.getContentResolver(),
                 Settings.Global.ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS,
                 TextUtils.join(",", formats));
         sendMsg(mAudioHandler, MSG_ENABLE_SURROUND_FORMATS, SENDMSG_QUEUE, 0, 0, formats, 0);
@@ -2323,7 +2396,7 @@
     }
 
     @GuardedBy("mSettingsLock")
-    private void updateAssistantUId(boolean forceUpdate) {
+    private void updateAssistantUIdLocked(boolean forceUpdate) {
         int assistantUid = INVALID_UID;
         // Consider assistants in the following order of priority:
         // 1) apk in assistant role
@@ -2335,11 +2408,11 @@
             packageName = mRoleObserver.getAssistantRoleHolder();
         }
         if (TextUtils.isEmpty(packageName)) {
-            String assistantName = Settings.Secure.getStringForUser(
+            String assistantName = mSettings.getSecureStringForUser(
                             mContentResolver,
                             Settings.Secure.VOICE_INTERACTION_SERVICE, UserHandle.USER_CURRENT);
             if (TextUtils.isEmpty(assistantName)) {
-                assistantName = Settings.Secure.getStringForUser(
+                assistantName = mSettings.getSecureStringForUser(
                         mContentResolver,
                         Settings.Secure.ASSISTANT, UserHandle.USER_CURRENT);
             }
@@ -2382,7 +2455,7 @@
         final ContentResolver cr = mContentResolver;
 
         int ringerModeFromSettings =
-                Settings.Global.getInt(
+                mSettings.getGlobalInt(
                         cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
         int ringerMode = ringerModeFromSettings;
         // validity check in case the settings are restored from a device with incompatible
@@ -2394,7 +2467,7 @@
             ringerMode = AudioManager.RINGER_MODE_SILENT;
         }
         if (ringerMode != ringerModeFromSettings) {
-            Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
+            mSettings.putGlobalInt(cr, Settings.Global.MODE_RINGER, ringerMode);
         }
         if (mUseFixedVolume || mIsSingleVolume) {
             ringerMode = AudioManager.RINGER_MODE_NORMAL;
@@ -2421,12 +2494,12 @@
             readDockAudioSettings(cr);
             sendEncodedSurroundMode(cr, "readPersistedSettings");
             sendEnabledSurroundFormats(cr, true);
-            updateAssistantUId(true);
+            updateAssistantUIdLocked(/* forceUpdate= */ true);
             resetActiveAssistantUidsLocked();
             AudioSystem.setRttEnabled(mRttEnabled);
         }
 
-        mMuteAffectedStreams = System.getIntForUser(cr,
+        mMuteAffectedStreams = mSettings.getSystemIntForUser(cr,
                 System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
                 UserHandle.USER_CURRENT);
 
@@ -2489,17 +2562,44 @@
         return (mStreamStates[streamType].getMaxIndex() - mStreamStates[streamType].getMinIndex());
     }
 
-    private int rescaleIndex(int index, int srcStream, int dstStream) {
-        int srcRange = getIndexRange(srcStream);
-        int dstRange = getIndexRange(dstStream);
-        if (srcRange == 0) {
-            Log.e(TAG, "rescaleIndex : index range should not be zero");
+    private int rescaleIndex(VolumeInfo volumeInfo, int dstStream) {
+        if (volumeInfo.getVolumeIndex() == VolumeInfo.INDEX_NOT_SET
+                || volumeInfo.getMinVolumeIndex() == VolumeInfo.INDEX_NOT_SET
+                || volumeInfo.getMaxVolumeIndex() == VolumeInfo.INDEX_NOT_SET) {
+            Log.e(TAG, "rescaleIndex: volumeInfo has invalid index or range");
             return mStreamStates[dstStream].getMinIndex();
         }
+        return rescaleIndex(volumeInfo.getVolumeIndex(),
+                volumeInfo.getMinVolumeIndex(), volumeInfo.getMaxVolumeIndex(),
+                mStreamStates[dstStream].getMinIndex(), mStreamStates[dstStream].getMaxIndex());
+    }
 
-        return mStreamStates[dstStream].getMinIndex()
-                + ((index - mStreamStates[srcStream].getMinIndex()) * dstRange + srcRange / 2)
-                / srcRange;
+    private int rescaleIndex(int index, int srcStream, VolumeInfo dstVolumeInfo) {
+        int dstMin = dstVolumeInfo.getMinVolumeIndex();
+        int dstMax = dstVolumeInfo.getMaxVolumeIndex();
+        // Don't rescale index if the VolumeInfo is missing a min or max index
+        if (dstMin == VolumeInfo.INDEX_NOT_SET || dstMax == VolumeInfo.INDEX_NOT_SET) {
+            return index;
+        }
+        return rescaleIndex(index,
+                mStreamStates[srcStream].getMinIndex(), mStreamStates[srcStream].getMaxIndex(),
+                dstMin, dstMax);
+    }
+
+    private int rescaleIndex(int index, int srcStream, int dstStream) {
+        return rescaleIndex(index,
+                mStreamStates[srcStream].getMinIndex(), mStreamStates[srcStream].getMaxIndex(),
+                mStreamStates[dstStream].getMinIndex(), mStreamStates[dstStream].getMaxIndex());
+    }
+
+    private int rescaleIndex(int index, int srcMin, int srcMax, int dstMin, int dstMax) {
+        int srcRange = srcMax - srcMin;
+        int dstRange = dstMax - dstMin;
+        if (srcRange == 0) {
+            Log.e(TAG, "rescaleIndex : index range should not be zero");
+            return dstMin;
+        }
+        return dstMin + ((index - srcMin) * dstRange + srcRange / 2) / srcRange;
     }
 
     private int rescaleStep(int step, int srcStream, int dstStream) {
@@ -2732,26 +2832,19 @@
         return mAudioSystem.getDevicesForAttributes(attributes, forVolume);
     }
 
-    /** Indicates no special treatment in the handling of the volume adjustement */
-    private static final int VOL_ADJUST_NORMAL = 0;
-    /** Indicates the start of a volume adjustement */
-    private static final int VOL_ADJUST_START = 1;
-    /** Indicates the end of a volume adjustment */
-    private static final int VOL_ADJUST_END = 2;
-
     // pre-condition: event.getKeyCode() is one of KeyEvent.KEYCODE_VOLUME_UP,
     //                                   KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_VOLUME_MUTE
     public void handleVolumeKey(@NonNull KeyEvent event, boolean isOnTv,
             @NonNull String callingPackage, @NonNull String caller) {
-        int keyEventMode = VOL_ADJUST_NORMAL;
+        int keyEventMode = AudioDeviceVolumeManager.ADJUST_MODE_NORMAL;
         if (isOnTv) {
             if (event.getAction() == KeyEvent.ACTION_DOWN) {
-                keyEventMode = VOL_ADJUST_START;
+                keyEventMode = AudioDeviceVolumeManager.ADJUST_MODE_START;
             } else { // may catch more than ACTION_UP, but will end vol adjustement
                 // the vol key is either released (ACTION_UP), or multiple keys are pressed
                 // (ACTION_MULTIPLE) and we don't know what to do for volume control on CEC, end
                 // the repeated volume adjustement
-                keyEventMode = VOL_ADJUST_END;
+                keyEventMode = AudioDeviceVolumeManager.ADJUST_MODE_END;
             }
         } else if (event.getAction() != KeyEvent.ACTION_DOWN) {
             return;
@@ -2776,7 +2869,7 @@
                     adjustSuggestedStreamVolume(AudioManager.ADJUST_TOGGLE_MUTE,
                             AudioManager.USE_DEFAULT_STREAM_TYPE, flags, callingPackage, caller,
                             Binder.getCallingUid(), Binder.getCallingPid(),
-                            true, VOL_ADJUST_NORMAL);
+                            true, AudioDeviceVolumeManager.ADJUST_MODE_NORMAL);
                 }
                 break;
             default:
@@ -2921,7 +3014,7 @@
                 direction/*val1*/, flags/*val2*/, callingPackage));
         adjustStreamVolume(streamType, direction, flags, callingPackage, callingPackage,
                 Binder.getCallingUid(), Binder.getCallingPid(), attributionTag,
-                callingHasAudioSettingsPermission(), VOL_ADJUST_NORMAL);
+                callingHasAudioSettingsPermission(), AudioDeviceVolumeManager.ADJUST_MODE_NORMAL);
     }
 
     protected void adjustStreamVolume(int streamType, int direction, int flags,
@@ -3054,8 +3147,19 @@
         }
         int oldIndex = mStreamStates[streamType].getIndex(device);
 
-        if (adjustVolume
-                && (direction != AudioManager.ADJUST_SAME) && (keyEventMode != VOL_ADJUST_END)) {
+        // Check if the volume adjustment should be handled by an absolute volume controller instead
+        if (isAbsoluteVolumeDevice(device)
+                && (flags & AudioManager.FLAG_ABSOLUTE_VOLUME) == 0) {
+            AbsoluteVolumeDeviceInfo info = mAbsoluteVolumeDeviceInfoMap.get(device);
+            if (info.mHandlesVolumeAdjustment) {
+                dispatchAbsoluteVolumeAdjusted(streamType, info, oldIndex, direction,
+                        keyEventMode);
+                return;
+            }
+        }
+
+        if (adjustVolume && (direction != AudioManager.ADJUST_SAME)
+                && (keyEventMode != AudioDeviceVolumeManager.ADJUST_MODE_END)) {
             mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
 
             if (isMuteAdjust && !mFullVolumeDevices.contains(device)) {
@@ -3116,6 +3220,10 @@
                             + newIndex + "stream=" + streamType);
                 }
                 mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(newIndex / 10);
+            } else if (isAbsoluteVolumeDevice(device)
+                    && (flags & AudioManager.FLAG_ABSOLUTE_VOLUME) == 0) {
+                AbsoluteVolumeDeviceInfo info = mAbsoluteVolumeDeviceInfoMap.get(device);
+                dispatchAbsoluteVolumeChanged(streamType, info, newIndex);
             }
 
             if (device == AudioSystem.DEVICE_OUT_BLE_HEADSET
@@ -3181,14 +3289,14 @@
                             final long ident = Binder.clearCallingIdentity();
                             try {
                                 switch (keyEventMode) {
-                                    case VOL_ADJUST_NORMAL:
+                                    case AudioDeviceVolumeManager.ADJUST_MODE_NORMAL:
                                         fullVolumeHdmiClient.sendVolumeKeyEvent(keyCode, true);
                                         fullVolumeHdmiClient.sendVolumeKeyEvent(keyCode, false);
                                         break;
-                                    case VOL_ADJUST_START:
+                                    case AudioDeviceVolumeManager.ADJUST_MODE_START:
                                         fullVolumeHdmiClient.sendVolumeKeyEvent(keyCode, true);
                                         break;
-                                    case VOL_ADJUST_END:
+                                    case AudioDeviceVolumeManager.ADJUST_MODE_END:
                                         fullVolumeHdmiClient.sendVolumeKeyEvent(keyCode, false);
                                         break;
                                     default:
@@ -3774,6 +3882,11 @@
                             + "stream=" + streamType);
                 }
                 mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(index / 10);
+            } else if (isAbsoluteVolumeDevice(device)
+                    && ((flags & AudioManager.FLAG_ABSOLUTE_VOLUME) == 0)) {
+                AbsoluteVolumeDeviceInfo info = mAbsoluteVolumeDeviceInfoMap.get(device);
+
+                dispatchAbsoluteVolumeChanged(streamType, info, index);
             }
 
             if (device == AudioSystem.DEVICE_OUT_BLE_HEADSET
@@ -3852,6 +3965,38 @@
         return AudioVolumeGroup.DEFAULT_VOLUME_GROUP;
     }
 
+    private void dispatchAbsoluteVolumeChanged(int streamType, AbsoluteVolumeDeviceInfo deviceInfo,
+            int index) {
+        VolumeInfo volumeInfo = deviceInfo.getMatchingVolumeInfoForStream(streamType);
+        if (volumeInfo != null) {
+            try {
+                deviceInfo.mCallback.dispatchDeviceVolumeChanged(deviceInfo.mDevice,
+                        new VolumeInfo.Builder(volumeInfo)
+                                .setVolumeIndex(rescaleIndex(index, streamType, volumeInfo))
+                                .build());
+            } catch (RemoteException e) {
+                Log.w(TAG, "Couldn't dispatch absolute volume behavior volume change");
+            }
+        }
+    }
+
+    private void dispatchAbsoluteVolumeAdjusted(int streamType,
+            AbsoluteVolumeDeviceInfo deviceInfo, int index, int direction, int mode) {
+        VolumeInfo volumeInfo = deviceInfo.getMatchingVolumeInfoForStream(streamType);
+        if (volumeInfo != null) {
+            try {
+                deviceInfo.mCallback.dispatchDeviceVolumeAdjusted(deviceInfo.mDevice,
+                        new VolumeInfo.Builder(volumeInfo)
+                                .setVolumeIndex(rescaleIndex(index, streamType, volumeInfo))
+                                .build(),
+                        direction,
+                        mode);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Couldn't dispatch absolute volume behavior volume adjustment");
+            }
+        }
+    }
+
 
     // No ringer or zen muted stream volumes can be changed unless it'll exit dnd
     private boolean volumeAdjustmentAllowedByDnd(int streamTypeAlias, int flags) {
@@ -3987,6 +4132,14 @@
 
         if (streamType == AudioSystem.STREAM_MUSIC) {
             flags = updateFlagsForTvPlatform(flags);
+            synchronized (mHdmiClientLock) {
+                // Don't display volume UI on a TV Playback device when using absolute volume
+                if (mHdmiCecVolumeControlEnabled && mHdmiPlaybackClient != null
+                        && (isAbsoluteVolumeDevice(device)
+                        || isA2dpAbsoluteVolumeDevice(device))) {
+                    flags &= ~AudioManager.FLAG_SHOW_UI;
+                }
+            }
             if (isFullVolumeDevice(device)) {
                 flags &= ~AudioManager.FLAG_SHOW_UI;
             }
@@ -4479,7 +4632,7 @@
         int silenceRingerSetting = Settings.Secure.VOLUME_HUSH_OFF;
         if (mContext.getResources()
                 .getBoolean(com.android.internal.R.bool.config_volumeHushGestureEnabled)) {
-            silenceRingerSetting = Settings.Secure.getIntForUser(mContentResolver,
+            silenceRingerSetting = mSettings.getSecureIntForUser(mContentResolver,
                     Settings.Secure.VOLUME_HUSH_GESTURE, VOLUME_HUSH_OFF,
                     UserHandle.USER_CURRENT);
         }
@@ -5163,7 +5316,8 @@
         // direction and stream type swap here because the public
         // adjustSuggested has a different order than the other methods.
         adjustSuggestedStreamVolume(direction, streamType, flags, packageName, packageName,
-                uid, pid, hasAudioSettingsPermission(uid, pid), VOL_ADJUST_NORMAL);
+                uid, pid, hasAudioSettingsPermission(uid, pid),
+                AudioDeviceVolumeManager.ADJUST_MODE_NORMAL);
     }
 
     /** @see AudioManager#adjustStreamVolumeForUid(int, int, int, String, int, int, int) */
@@ -5183,7 +5337,8 @@
         }
 
         adjustStreamVolume(streamType, direction, flags, packageName, packageName, uid, pid,
-                null, hasAudioSettingsPermission(uid, pid), VOL_ADJUST_NORMAL);
+                null, hasAudioSettingsPermission(uid, pid),
+                AudioDeviceVolumeManager.ADJUST_MODE_NORMAL);
     }
 
     /** @see AudioManager#setStreamVolumeForUid(int, int, int, String, int, int, int) */
@@ -5240,7 +5395,7 @@
      * Settings has an in memory cache, so this is fast.
      */
     private boolean querySoundEffectsEnabled(int user) {
-        return Settings.System.getIntForUser(getContentResolver(),
+        return mSettings.getSystemIntForUser(getContentResolver(),
                 Settings.System.SOUND_EFFECTS_ENABLED, 0, user) != 0;
     }
 
@@ -5325,7 +5480,7 @@
         checkMuteAffectedStreams();
 
         synchronized (mSafeMediaVolumeStateLock) {
-            mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
+            mMusicActiveMs = MathUtils.constrain(mSettings.getSecureIntForUser(mContentResolver,
                     Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
                     0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
             if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
@@ -5967,7 +6122,7 @@
     @GuardedBy("mSettingsLock")
     private boolean updateRingerAndZenModeAffectedStreams() {
         boolean updatedZenModeAffectedStreams = updateZenModeAffectedStreams();
-        int ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
+        int ringerModeAffectedStreams = mSettings.getSystemIntForUser(mContentResolver,
                 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
                 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
                  (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
@@ -5991,7 +6146,7 @@
         }
 
         if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
-            Settings.System.putIntForUser(mContentResolver,
+            mSettings.putSystemIntForUser(mContentResolver,
                     Settings.System.MODE_RINGER_STREAMS_AFFECTED,
                     ringerModeAffectedStreams,
                     UserHandle.USER_CURRENT);
@@ -6403,15 +6558,16 @@
 
     /**
      * @see AudioDeviceVolumeManager#setDeviceAbsoluteMultiVolumeBehavior
-     * @param cb
-     * @param attr
-     * @param volumes
+     *
+     * @param register Whether the listener is to be registered or unregistered. If false, the
+     *                 device adopts variable volume behavior.
      */
     @RequiresPermission(anyOf = { android.Manifest.permission.MODIFY_AUDIO_ROUTING,
             android.Manifest.permission.BLUETOOTH_PRIVILEGED })
     public void registerDeviceVolumeDispatcherForAbsoluteVolume(boolean register,
             IAudioDeviceVolumeDispatcher cb, String packageName,
-            AudioDeviceAttributes device, List<VolumeInfo> volumes) {
+            AudioDeviceAttributes device, List<VolumeInfo> volumes,
+            boolean handlesVolumeAdjustment) {
         // verify permissions
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
                 != PackageManager.PERMISSION_GRANTED
@@ -6424,12 +6580,44 @@
         Objects.requireNonNull(device);
         Objects.requireNonNull(volumes);
 
-        // current implementation maps this call to existing abs volume API of AudioManager
-        // TODO implement the volume/device listener through IAudioDeviceVolumeDispatcher
-        final int volumeBehavior = volumes.size() == 1
-                ? AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE
-                : AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE;
-        setDeviceVolumeBehavior(device, volumeBehavior, packageName);
+        int deviceOut = device.getInternalType();
+        if (register) {
+            AbsoluteVolumeDeviceInfo info = new AbsoluteVolumeDeviceInfo(
+                    device, volumes, cb, handlesVolumeAdjustment);
+            boolean volumeBehaviorChanged =
+                    removeAudioSystemDeviceOutFromFullVolumeDevices(deviceOut)
+                    | removeAudioSystemDeviceOutFromFixedVolumeDevices(deviceOut)
+                    | (addAudioSystemDeviceOutToAbsVolumeDevices(deviceOut, info) == null);
+            if (volumeBehaviorChanged) {
+                dispatchDeviceVolumeBehavior(device, AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
+            }
+            // Update stream volumes to the given device, if specified in a VolumeInfo.
+            // Mute state is not updated because it is stream-wide - the only way to mute a
+            // stream's output to a particular device is to set the volume index to zero.
+            for (VolumeInfo volumeInfo : volumes) {
+                if (volumeInfo.getVolumeIndex() != VolumeInfo.INDEX_NOT_SET
+                        && volumeInfo.getMinVolumeIndex() != VolumeInfo.INDEX_NOT_SET
+                        && volumeInfo.getMaxVolumeIndex() != VolumeInfo.INDEX_NOT_SET) {
+                    if (volumeInfo.hasStreamType()) {
+                        setStreamVolumeInt(volumeInfo.getStreamType(),
+                                rescaleIndex(volumeInfo, volumeInfo.getStreamType()),
+                                deviceOut, false /*force*/, packageName,
+                                true /*hasModifyAudioSettings*/);
+                    } else {
+                        for (int streamType : volumeInfo.getVolumeGroup().getLegacyStreamTypes()) {
+                            setStreamVolumeInt(streamType, rescaleIndex(volumeInfo, streamType),
+                                    deviceOut, false /*force*/, packageName,
+                                    true /*hasModifyAudioSettings*/);
+                        }
+                    }
+                }
+            }
+        } else {
+            boolean wasAbsVol = removeAudioSystemDeviceOutFromAbsVolumeDevices(deviceOut) != null;
+            if (wasAbsVol) {
+                dispatchDeviceVolumeBehavior(device, AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE);
+            }
+        }
     }
 
     /**
@@ -6453,34 +6641,47 @@
             return;
         }
 
-        int audioSystemDeviceOut = AudioDeviceInfo.convertDeviceTypeToInternalDevice(
-                device.getType());
-        setDeviceVolumeBehaviorInternal(audioSystemDeviceOut, deviceVolumeBehavior, pkgName);
-
-        persistDeviceVolumeBehavior(audioSystemDeviceOut, deviceVolumeBehavior);
+        setDeviceVolumeBehaviorInternal(device, deviceVolumeBehavior, pkgName);
+        persistDeviceVolumeBehavior(device.getInternalType(), deviceVolumeBehavior);
     }
 
-    private void setDeviceVolumeBehaviorInternal(int audioSystemDeviceOut,
+    private void setDeviceVolumeBehaviorInternal(@NonNull AudioDeviceAttributes device,
             @AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior, @NonNull String caller) {
+        int audioSystemDeviceOut = device.getInternalType();
+        boolean volumeBehaviorChanged = false;
         // update device masks based on volume behavior
         switch (deviceVolumeBehavior) {
             case AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE:
-                removeAudioSystemDeviceOutFromFullVolumeDevices(audioSystemDeviceOut);
-                removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut);
+                volumeBehaviorChanged |=
+                        removeAudioSystemDeviceOutFromFullVolumeDevices(audioSystemDeviceOut)
+                        | removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut)
+                        | (removeAudioSystemDeviceOutFromAbsVolumeDevices(audioSystemDeviceOut)
+                                != null);
                 break;
             case AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED:
-                removeAudioSystemDeviceOutFromFullVolumeDevices(audioSystemDeviceOut);
-                addAudioSystemDeviceOutToFixedVolumeDevices(audioSystemDeviceOut);
+                volumeBehaviorChanged |=
+                        removeAudioSystemDeviceOutFromFullVolumeDevices(audioSystemDeviceOut)
+                        | addAudioSystemDeviceOutToFixedVolumeDevices(audioSystemDeviceOut)
+                        | (removeAudioSystemDeviceOutFromAbsVolumeDevices(audioSystemDeviceOut)
+                                != null);
                 break;
             case AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL:
-                addAudioSystemDeviceOutToFullVolumeDevices(audioSystemDeviceOut);
-                removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut);
+                volumeBehaviorChanged |=
+                        addAudioSystemDeviceOutToFullVolumeDevices(audioSystemDeviceOut)
+                        | removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut)
+                        | (removeAudioSystemDeviceOutFromAbsVolumeDevices(audioSystemDeviceOut)
+                                != null);
                 break;
             case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE:
             case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
                 throw new IllegalArgumentException("Absolute volume unsupported for now");
         }
 
+        if (volumeBehaviorChanged) {
+            sendMsg(mAudioHandler, MSG_DISPATCH_DEVICE_VOLUME_BEHAVIOR, SENDMSG_QUEUE,
+                    deviceVolumeBehavior, 0, device, /*delay*/ 0);
+        }
+
         // log event and caller
         sDeviceLogger.log(new AudioEventLogger.StringEvent(
                 "Volume behavior " + deviceVolumeBehavior + " for dev=0x"
@@ -6518,17 +6719,17 @@
 
         // setDeviceVolumeBehavior has not been explicitly called for the device type. Deduce the
         // current volume behavior.
-        if ((mFullVolumeDevices.contains(audioSystemDeviceOut))) {
+        if (mFullVolumeDevices.contains(audioSystemDeviceOut)) {
             return AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL;
         }
-        if ((mFixedVolumeDevices.contains(audioSystemDeviceOut))) {
+        if (mFixedVolumeDevices.contains(audioSystemDeviceOut)) {
             return AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED;
         }
-        if ((mAbsVolumeMultiModeCaseDevices.contains(audioSystemDeviceOut))) {
+        if (mAbsVolumeMultiModeCaseDevices.contains(audioSystemDeviceOut)) {
             return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE;
         }
-        if (audioSystemDeviceOut == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP
-                && mAvrcpAbsVolSupported) {
+        if (isAbsoluteVolumeDevice(audioSystemDeviceOut)
+                || isA2dpAbsoluteVolumeDevice(audioSystemDeviceOut)) {
             return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE;
         }
         return AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE;
@@ -6968,7 +7169,7 @@
                         + ", device " + AudioSystem.getOutputDeviceName(device)
                         + " and User=" + ActivityManager.getCurrentUser());
             }
-            boolean success = Settings.System.putIntForUser(mContentResolver,
+            boolean success = mSettings.putSystemIntForUser(mContentResolver,
                     getSettingNameForDevice(device),
                     getIndex(device),
                     UserHandle.USER_CURRENT);
@@ -6994,7 +7195,7 @@
                             ? AudioSystem.DEFAULT_STREAM_VOLUME[mPublicStreamType] : -1;
                     int index;
                     String name = getSettingNameForDevice(device);
-                    index = Settings.System.getIntForUser(
+                    index = mSettings.getSystemIntForUser(
                             mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
                     if (index == -1) {
                         continue;
@@ -7243,7 +7444,7 @@
                         index = defaultIndex;
                     } else {
                         String name = getSettingNameForDevice(device);
-                        index = Settings.System.getIntForUser(
+                        index = mSettings.getSystemIntForUser(
                                 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
                     }
                     if (index == -1) {
@@ -7293,8 +7494,7 @@
             int index;
             if (isFullyMuted()) {
                 index = 0;
-            } else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
-                    && mAvrcpAbsVolSupported) {
+            } else if (isAbsoluteVolumeDevice(device) || isA2dpAbsoluteVolumeDevice(device)) {
                 index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
             } else if (isFullVolumeDevice(device)) {
                 index = (mIndexMax + 5)/10;
@@ -7315,8 +7515,8 @@
                     if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
                         if (isFullyMuted()) {
                             index = 0;
-                        } else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
-                                && mAvrcpAbsVolSupported) {
+                        } else if (isAbsoluteVolumeDevice(device)
+                                || isA2dpAbsoluteVolumeDevice(device)) {
                             index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
                         } else if (isFullVolumeDevice(device)) {
                             index = (mIndexMax + 5)/10;
@@ -7735,8 +7935,9 @@
                     // Make sure volume is also maxed out on A2DP device for aliased stream
                     // that may have a different device selected
                     int streamDevice = getDeviceForStream(streamType);
-                    if ((device != streamDevice) && mAvrcpAbsVolSupported
-                            && AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)) {
+                    if ((device != streamDevice)
+                            && (isAbsoluteVolumeDevice(device)
+                            || isA2dpAbsoluteVolumeDevice(device))) {
                         mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
                     }
                     mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
@@ -7757,6 +7958,14 @@
     /** Handles internal volume messages in separate volume thread. */
     private class AudioHandler extends Handler {
 
+        AudioHandler() {
+            super();
+        }
+
+        AudioHandler(Looper looper) {
+            super(looper);
+        }
+
         private void setAllVolumes(VolumeStreamState streamState) {
 
             // Apply volume
@@ -7780,7 +7989,7 @@
                 return;
             }
             if (streamState.hasValidSettingsName()) {
-                System.putIntForUser(mContentResolver,
+                mSettings.putSystemIntForUser(mContentResolver,
                         streamState.getSettingNameForDevice(device),
                         (streamState.getIndex(device) + 5)/ 10,
                         UserHandle.USER_CURRENT);
@@ -7791,11 +8000,11 @@
             if (mUseFixedVolume) {
                 return;
             }
-            Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
+            mSettings.putGlobalInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
         }
 
         private void onPersistSafeVolumeState(int state) {
-            Settings.Global.putInt(mContentResolver,
+            mSettings.putGlobalInt(mContentResolver,
                     Settings.Global.AUDIO_SAFE_VOLUME_STATE,
                     state);
         }
@@ -7939,7 +8148,7 @@
 
                 case MSG_PERSIST_MUSIC_ACTIVE_MS:
                     final int musicActiveMs = msg.arg1;
-                    Settings.Secure.putIntForUser(mContentResolver,
+                    mSettings.putSecureIntForUser(mContentResolver,
                             Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
                             UserHandle.USER_CURRENT);
                     break;
@@ -8059,6 +8268,10 @@
                 case MSG_UPDATE_ACTIVE_ASSISTANT_SERVICE_UID:
                     updateActiveAssistantServiceUids();
                     break;
+
+                case MSG_DISPATCH_DEVICE_VOLUME_BEHAVIOR:
+                    dispatchDeviceVolumeBehavior((AudioDeviceAttributes) msg.obj, msg.arg1);
+                    break;
             }
         }
     }
@@ -8080,12 +8293,12 @@
             mContentResolver.registerContentObserver(Settings.System.getUriFor(
                     Settings.System.MASTER_BALANCE), false, this);
 
-            mEncodedSurroundMode = Settings.Global.getInt(
+            mEncodedSurroundMode = mSettings.getGlobalInt(
                     mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT,
                     Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
             mContentResolver.registerContentObserver(Settings.Global.getUriFor(
                     Settings.Global.ENCODED_SURROUND_OUTPUT), false, this);
-            mEnabledSurroundFormats = Settings.Global.getString(
+            mEnabledSurroundFormats = mSettings.getGlobalString(
                     mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS);
             mContentResolver.registerContentObserver(Settings.Global.getUriFor(
                     Settings.Global.ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS), false, this);
@@ -8114,12 +8327,12 @@
                 updateMasterBalance(mContentResolver);
                 updateEncodedSurroundOutput();
                 sendEnabledSurroundFormats(mContentResolver, mSurroundModeChanged);
-                updateAssistantUId(false);
+                updateAssistantUIdLocked(/* forceUpdate= */ false);
             }
         }
 
         private void updateEncodedSurroundOutput() {
-            int newSurroundMode = Settings.Global.getInt(
+            int newSurroundMode = mSettings.getGlobalInt(
                 mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT,
                 Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
             // Did it change?
@@ -8662,13 +8875,13 @@
     }
 
     void onPersistSpatialAudioEnabled(boolean enabled) {
-        Settings.Secure.putIntForUser(mContentResolver,
+        mSettings.putSecureIntForUser(mContentResolver,
                 Settings.Secure.SPATIAL_AUDIO_ENABLED, enabled ? 1 : 0,
                 UserHandle.USER_CURRENT);
     }
 
     boolean isSpatialAudioEnabled() {
-        return Settings.Secure.getIntForUser(mContentResolver,
+        return mSettings.getSecureIntForUser(mContentResolver,
                 Settings.Secure.SPATIAL_AUDIO_ENABLED, SPATIAL_AUDIO_ENABLED_DEFAULT ? 1 : 0,
                 UserHandle.USER_CURRENT) == 1;
     }
@@ -8723,6 +8936,11 @@
         return mSpatializerHelper.isHeadTrackerEnabled(Objects.requireNonNull(device));
     }
 
+    /** @see Spatializer#isHeadTrackerAvailable() */
+    public boolean isHeadTrackerAvailable() {
+        return mSpatializerHelper.isHeadTrackerAvailable();
+    }
+
     /** @see Spatializer#setSpatializerEnabled(boolean) */
     public void setSpatializerEnabled(boolean enabled) {
         enforceModifyDefaultAudioEffectsPermission();
@@ -8767,6 +8985,13 @@
         mSpatializerHelper.unregisterHeadTrackingModeCallback(cb);
     }
 
+    /** @see Spatializer.SpatializerHeadTrackerAvailableDispatcherStub */
+    public void registerSpatializerHeadTrackerAvailableCallback(
+            @NonNull ISpatializerHeadTrackerAvailableCallback cb, boolean register) {
+        Objects.requireNonNull(cb);
+        mSpatializerHelper.registerHeadTrackerAvailableCallback(cb, register);
+    }
+
     /** @see Spatializer#setOnHeadToSoundstagePoseUpdatedListener */
     public void registerHeadToSoundstagePoseCallback(
             @NonNull ISpatializerHeadToSoundStagePoseCallback cb) {
@@ -9064,6 +9289,35 @@
         mMuteAwaitConnectionDispatchers.finishBroadcast();
     }
 
+    final RemoteCallbackList<IDeviceVolumeBehaviorDispatcher> mDeviceVolumeBehaviorDispatchers =
+            new RemoteCallbackList<IDeviceVolumeBehaviorDispatcher>();
+
+    /**
+     *  @see AudioDeviceVolumeManager#addOnDeviceVolumeBehaviorChangedListener and
+     *  AudioDeviceVolumeManager#removeOnDeviceVolumeBehaviorChangedListener
+     */
+    public void registerDeviceVolumeBehaviorDispatcher(boolean register,
+            @NonNull IDeviceVolumeBehaviorDispatcher dispatcher) {
+        enforceQueryStateOrModifyRoutingPermission();
+        Objects.requireNonNull(dispatcher);
+        if (register) {
+            mDeviceVolumeBehaviorDispatchers.register(dispatcher);
+        } else {
+            mDeviceVolumeBehaviorDispatchers.unregister(dispatcher);
+        }
+    }
+
+    private void dispatchDeviceVolumeBehavior(AudioDeviceAttributes device, int volumeBehavior) {
+        final int dispatchers = mDeviceVolumeBehaviorDispatchers.beginBroadcast();
+        for (int i = 0; i < dispatchers; i++) {
+            try {
+                mDeviceVolumeBehaviorDispatchers.getBroadcastItem(i)
+                        .dispatchDeviceVolumeBehaviorChanged(device, volumeBehavior);
+            } catch (RemoteException e) {
+            }
+        }
+        mDeviceVolumeBehaviorDispatchers.finishBroadcast();
+    }
 
     //==========================================================================================
     // Device orientation
@@ -9294,14 +9548,20 @@
                 if (DEBUG_VOL) {
                     Log.d(TAG, "CEC sink: setting HDMI as full vol device");
                 }
-                addAudioSystemDeviceOutToFullVolumeDevices(AudioSystem.DEVICE_OUT_HDMI);
+                setDeviceVolumeBehaviorInternal(
+                        new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_HDMI, ""),
+                        AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL,
+                        "AudioService.updateHdmiCecSinkLocked()");
             } else {
                 if (DEBUG_VOL) {
                     Log.d(TAG, "TV, no CEC: setting HDMI as regular vol device");
                 }
                 // Android TV devices without CEC service apply software volume on
                 // HDMI output
-                removeAudioSystemDeviceOutFromFullVolumeDevices(AudioSystem.DEVICE_OUT_HDMI);
+                setDeviceVolumeBehaviorInternal(
+                        new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_HDMI, ""),
+                        AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE,
+                        "AudioService.updateHdmiCecSinkLocked()");
             }
             postUpdateVolumeStatesForAudioDevice(AudioSystem.DEVICE_OUT_HDMI,
                     "HdmiPlaybackClient.DisplayStatusCallback");
@@ -9602,6 +9862,8 @@
         pw.print("  mUseFixedVolume="); pw.println(mUseFixedVolume);
         pw.print("  mFixedVolumeDevices="); pw.println(dumpDeviceTypes(mFixedVolumeDevices));
         pw.print("  mFullVolumeDevices="); pw.println(dumpDeviceTypes(mFullVolumeDevices));
+        pw.print("  mAbsoluteVolumeDevices.keySet()="); pw.println(dumpDeviceTypes(
+                mAbsoluteVolumeDeviceInfoMap.keySet()));
         pw.print("  mExtVolumeController="); pw.println(mExtVolumeController);
         pw.print("  mHdmiAudioSystemClient="); pw.println(mHdmiAudioSystemClient);
         pw.print("  mHdmiPlaybackClient="); pw.println(mHdmiPlaybackClient);
@@ -9793,7 +10055,7 @@
         }
 
         public void loadSettings(ContentResolver cr) {
-            mLongPressTimeout = Settings.Secure.getIntForUser(cr,
+            mLongPressTimeout = mSettings.getSecureIntForUser(cr,
                     Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
         }
 
@@ -11403,6 +11665,23 @@
         return mFullVolumeDevices.contains(deviceType);
     }
 
+    /**
+     * Returns whether the input device uses absolute volume behavior. This is distinct
+     * from Bluetooth A2DP absolute volume behavior ({@link #isA2dpAbsoluteVolumeDevice}).
+     */
+    private boolean isAbsoluteVolumeDevice(int deviceType) {
+        return  mAbsoluteVolumeDeviceInfoMap.containsKey(deviceType);
+    }
+
+    /**
+     * Returns whether the input device is a Bluetooth A2dp device that uses absolute volume
+     * behavior. This is distinct from the general implementation of absolute volume behavior
+     * ({@link #isAbsoluteVolumeDevice}).
+     */
+    private boolean isA2dpAbsoluteVolumeDevice(int deviceType) {
+        return mAvrcpAbsVolSupported && AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(deviceType);
+    }
+
     //====================
     // Helper functions for {set,get}DeviceVolumeBehavior
     //====================
@@ -11417,7 +11696,7 @@
         }
         final long callingIdentity = Binder.clearCallingIdentity();
         try {
-            System.putIntForUser(mContentResolver,
+            mSettings.putSystemIntForUser(mContentResolver,
                     getSettingsNameForDeviceVolumeBehavior(deviceType),
                     deviceVolumeBehavior,
                     UserHandle.USER_CURRENT);
@@ -11428,7 +11707,7 @@
 
     @AudioManager.DeviceVolumeBehaviorState
     private int retrieveStoredDeviceVolumeBehavior(int deviceType) {
-        return System.getIntForUser(mContentResolver,
+        return mSettings.getSystemIntForUser(mContentResolver,
                 getSettingsNameForDeviceVolumeBehavior(deviceType),
                 AudioManager.DEVICE_VOLUME_BEHAVIOR_UNSET,
                 UserHandle.USER_CURRENT);
@@ -11447,8 +11726,8 @@
                 continue;
             }
 
-            setDeviceVolumeBehaviorInternal(deviceType, deviceVolumeBehavior,
-                    "AudioService.restoreDeviceVolumeBehavior()");
+            setDeviceVolumeBehaviorInternal(new AudioDeviceAttributes(deviceType, ""),
+                    deviceVolumeBehavior, "AudioService.restoreDeviceVolumeBehavior()");
         }
     }
 
@@ -11463,36 +11742,54 @@
                 != AudioManager.DEVICE_VOLUME_BEHAVIOR_UNSET;
     }
 
-    private void addAudioSystemDeviceOutToFixedVolumeDevices(int audioSystemDeviceOut) {
+    private boolean addAudioSystemDeviceOutToFixedVolumeDevices(int audioSystemDeviceOut) {
         if (DEBUG_VOL) {
             Log.d(TAG, "Adding DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut)
                     + " to mFixedVolumeDevices");
         }
-        mFixedVolumeDevices.add(audioSystemDeviceOut);
+        return mFixedVolumeDevices.add(audioSystemDeviceOut);
     }
 
-    private void removeAudioSystemDeviceOutFromFixedVolumeDevices(int audioSystemDeviceOut) {
+    private boolean removeAudioSystemDeviceOutFromFixedVolumeDevices(int audioSystemDeviceOut) {
         if (DEBUG_VOL) {
             Log.d(TAG, "Removing DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut)
                     + " from mFixedVolumeDevices");
         }
-        mFixedVolumeDevices.remove(audioSystemDeviceOut);
+        return mFixedVolumeDevices.remove(audioSystemDeviceOut);
     }
 
-    private void addAudioSystemDeviceOutToFullVolumeDevices(int audioSystemDeviceOut) {
+    private boolean addAudioSystemDeviceOutToFullVolumeDevices(int audioSystemDeviceOut) {
         if (DEBUG_VOL) {
             Log.d(TAG, "Adding DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut)
                     + " to mFullVolumeDevices");
         }
-        mFullVolumeDevices.add(audioSystemDeviceOut);
+        return mFullVolumeDevices.add(audioSystemDeviceOut);
     }
 
-    private void removeAudioSystemDeviceOutFromFullVolumeDevices(int audioSystemDeviceOut) {
+    private boolean removeAudioSystemDeviceOutFromFullVolumeDevices(int audioSystemDeviceOut) {
         if (DEBUG_VOL) {
             Log.d(TAG, "Removing DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut)
                     + " from mFullVolumeDevices");
         }
-        mFullVolumeDevices.remove(audioSystemDeviceOut);
+        return mFullVolumeDevices.remove(audioSystemDeviceOut);
+    }
+
+    private AbsoluteVolumeDeviceInfo addAudioSystemDeviceOutToAbsVolumeDevices(
+            int audioSystemDeviceOut, AbsoluteVolumeDeviceInfo info) {
+        if (DEBUG_VOL) {
+            Log.d(TAG, "Adding DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut)
+                    + " from mAbsoluteVolumeDeviceInfoMap");
+        }
+        return mAbsoluteVolumeDeviceInfoMap.put(audioSystemDeviceOut, info);
+    }
+
+    private AbsoluteVolumeDeviceInfo removeAudioSystemDeviceOutFromAbsVolumeDevices(
+            int audioSystemDeviceOut) {
+        if (DEBUG_VOL) {
+            Log.d(TAG, "Removing DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut)
+                    + " from mAbsoluteVolumeDeviceInfoMap");
+        }
+        return mAbsoluteVolumeDeviceInfoMap.remove(audioSystemDeviceOut);
     }
 
     //====================
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 49a935e..d10ed55 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -104,7 +104,7 @@
     // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
     /*package*/  static final int SCO_MODE_VIRTUAL_CALL = 0;
     // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
-    private  static final int SCO_MODE_VR = 2;
+    private static final int SCO_MODE_VR = 2;
     // max valid SCO audio mode values
     private static final int SCO_MODE_MAX = 2;
 
@@ -305,69 +305,77 @@
             BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
             setBtScoActiveDevice(btDevice);
         } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
-            boolean broadcast = false;
-            int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
             int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
-            Log.i(TAG, "receiveBtEvent ACTION_AUDIO_STATE_CHANGED: " + btState);
-            switch (btState) {
-                case BluetoothHeadset.STATE_AUDIO_CONNECTED:
-                    scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
-                    if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL
-                            && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
-                        mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
-                    } else if (mDeviceBroker.isBluetoothScoRequested()) {
-                        // broadcast intent if the connection was initated by AudioService
-                        broadcast = true;
-                    }
-                    mDeviceBroker.setBluetoothScoOn(true, "BtHelper.receiveBtEvent");
-                    break;
-                case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
-                    mDeviceBroker.setBluetoothScoOn(false, "BtHelper.receiveBtEvent");
-                    scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
-                    // There are two cases where we want to immediately reconnect audio:
-                    // 1) If a new start request was received while disconnecting: this was
-                    // notified by requestScoState() setting state to SCO_STATE_ACTIVATE_REQ.
-                    // 2) If audio was connected then disconnected via Bluetooth APIs and
-                    // we still have pending activation requests by apps: this is indicated by
-                    // state SCO_STATE_ACTIVE_EXTERNAL and BT SCO is requested.
-                    if (mScoAudioState == SCO_STATE_ACTIVATE_REQ
-                            || (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL
-                                    && mDeviceBroker.isBluetoothScoRequested())) {
-                        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null
-                                && connectBluetoothScoAudioHelper(mBluetoothHeadset,
-                                mBluetoothHeadsetDevice, mScoAudioMode)) {
-                            mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
-                            scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTING;
-                            broadcast = true;
-                            break;
-                        }
-                    }
-                    if (mScoAudioState != SCO_STATE_ACTIVE_EXTERNAL) {
-                        broadcast = true;
-                    }
-                    mScoAudioState = SCO_STATE_INACTIVE;
-                    break;
-                case BluetoothHeadset.STATE_AUDIO_CONNECTING:
-                    if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL
-                            && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
-                        mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
-                    }
-                    break;
-                default:
-                    break;
-            }
-            if (broadcast) {
-                broadcastScoConnectionState(scoAudioState);
-                //FIXME: this is to maintain compatibility with deprecated intent
-                // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
-                Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
-                newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
-                sendStickyBroadcastToAll(newIntent);
-            }
+            Log.i(TAG,"receiveBtEvent ACTION_AUDIO_STATE_CHANGED: "+btState);
+            mDeviceBroker.postScoAudioStateChanged(btState);
         }
     }
 
     /**
+     * Exclusively called from AudioDeviceBroker when handling MSG_I_SCO_AUDIO_STATE_CHANGED
+     * as part of the serialization of the communication route selection
+     */
+    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
+    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+    void onScoAudioStateChanged(int state) {
+        boolean broadcast = false;
+        int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
+        switch (state) {
+            case BluetoothHeadset.STATE_AUDIO_CONNECTED:
+                scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
+                if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL
+                        && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
+                    mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
+                } else if (mDeviceBroker.isBluetoothScoRequested()) {
+                    // broadcast intent if the connection was initated by AudioService
+                    broadcast = true;
+                }
+                mDeviceBroker.setBluetoothScoOn(true, "BtHelper.receiveBtEvent");
+                break;
+            case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
+                mDeviceBroker.setBluetoothScoOn(false, "BtHelper.receiveBtEvent");
+                scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
+                // There are two cases where we want to immediately reconnect audio:
+                // 1) If a new start request was received while disconnecting: this was
+                // notified by requestScoState() setting state to SCO_STATE_ACTIVATE_REQ.
+                // 2) If audio was connected then disconnected via Bluetooth APIs and
+                // we still have pending activation requests by apps: this is indicated by
+                // state SCO_STATE_ACTIVE_EXTERNAL and BT SCO is requested.
+                if (mScoAudioState == SCO_STATE_ACTIVATE_REQ) {
+                    if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null
+                            && connectBluetoothScoAudioHelper(mBluetoothHeadset,
+                            mBluetoothHeadsetDevice, mScoAudioMode)) {
+                        mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+                        scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTING;
+                        broadcast = true;
+                        break;
+                    }
+                }
+                if (mScoAudioState != SCO_STATE_ACTIVE_EXTERNAL) {
+                    broadcast = true;
+                }
+                mScoAudioState = SCO_STATE_INACTIVE;
+                break;
+            case BluetoothHeadset.STATE_AUDIO_CONNECTING:
+                if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL
+                        && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
+                    mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
+                }
+                break;
+            default:
+                break;
+        }
+        if(broadcast) {
+            broadcastScoConnectionState(scoAudioState);
+            //FIXME: this is to maintain compatibility with deprecated intent
+            // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
+            Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
+            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
+            sendStickyBroadcastToAll(newIntent);
+        }
+
+    }
+    /**
      *
      * @return false if SCO isn't connected
      */
@@ -756,6 +764,15 @@
                 case SCO_STATE_ACTIVE_INTERNAL:
                     Log.w(TAG, "requestScoState: already in ACTIVE mode, simply return");
                     break;
+                case SCO_STATE_ACTIVE_EXTERNAL:
+                    /* Confirm SCO Audio connection to requesting app as it is already connected
+                     * externally (i.e. through SCO APIs by Telecom service).
+                     * Once SCO Audio is disconnected by the external owner, we will reconnect it
+                     * automatically on behalf of the requesting app and the state will move to
+                     * SCO_STATE_ACTIVE_INTERNAL.
+                     */
+                    broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
+                    break;
                 default:
                     Log.w(TAG, "requestScoState: failed to connect in state "
                             + mScoAudioState + ", scoAudioMode=" + scoAudioMode);
diff --git a/services/core/java/com/android/server/audio/SettingsAdapter.java b/services/core/java/com/android/server/audio/SettingsAdapter.java
new file mode 100644
index 0000000..dbc4d6d
--- /dev/null
+++ b/services/core/java/com/android/server/audio/SettingsAdapter.java
@@ -0,0 +1,92 @@
+/*
+ * 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.server.audio;
+
+import android.content.ContentResolver;
+import android.provider.Settings;
+
+/**
+ * Adapter for methods that read and write settings in android.provider.Settings.
+ */
+public class SettingsAdapter {
+    public static SettingsAdapter getDefaultAdapter() {
+        return new SettingsAdapter();
+    }
+
+    /**
+     * Wrapper methods for Settings.Global
+     */
+
+    /** Wraps {@link Settings.Global#getInt(ContentResolver, String, int)} */
+    public int getGlobalInt(ContentResolver cr, String name, int def) {
+        return Settings.Global.getInt(cr, name, def);
+    }
+
+    /** Wraps {@link Settings.Global#getString(ContentResolver, String)} */
+    public String getGlobalString(ContentResolver resolver, String name) {
+        return Settings.Global.getString(resolver, name);
+    }
+
+    /** Wraps {@link Settings.Global#putInt(ContentResolver, String, int)} */
+    public boolean putGlobalInt(ContentResolver cr, String name, int value) {
+        return Settings.Global.putInt(cr, name, value);
+    }
+
+    /** Wraps {@link Settings.Global#putString(ContentResolver, String, String)} */
+    public boolean putGlobalString(ContentResolver resolver, String name, String value) {
+        return Settings.Global.putString(resolver, name, value);
+    }
+
+    /**
+     * Wrapper methods for Settings.System
+     */
+
+    /** Wraps {@link Settings.System#getIntForUser(ContentResolver, String, int, int)} */
+    public int getSystemIntForUser(ContentResolver cr, String name, int def, int userHandle) {
+        return Settings.System.getIntForUser(cr, name, def, userHandle);
+    }
+
+    /** Wraps {@link Settings.System#putIntForUser(ContentResolver, String, int, int)} */
+    public boolean putSystemIntForUser(ContentResolver cr, String name, int value, int userHandle) {
+        return Settings.System.putIntForUser(cr, name, value, userHandle);
+    }
+
+    /**
+     * Wrapper methods for Settings.Secure
+     */
+
+    /** Wraps {@link Settings.Secure#getIntForUser(ContentResolver, String, int, int)} */
+    public int getSecureIntForUser(ContentResolver cr, String name, int def, int userHandle) {
+        return Settings.Secure.getIntForUser(cr, name, def, userHandle);
+    }
+
+    /** Wraps {@link Settings.Secure#getStringForUser(ContentResolver, String, int)} */
+    public String getSecureStringForUser(ContentResolver resolver, String name, int userHandle) {
+        return Settings.Secure.getStringForUser(resolver, name, userHandle);
+    }
+
+    /** Wraps {@link Settings.Secure#putIntForUser(ContentResolver, String, int, int)} */
+    public boolean putSecureIntForUser(ContentResolver cr, String name, int value, int userHandle) {
+        return Settings.Secure.putIntForUser(cr, name, value, userHandle);
+    }
+
+    /** Wraps {@link Settings.Secure#putStringForUser(ContentResolver, String, String, int)} */
+    public boolean putSecureStringForUser(ContentResolver cr, String name, String value,
+            int userHandle) {
+        return Settings.Secure.putStringForUser(cr, name, value, userHandle);
+    }
+}
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index 193cc5f..f0f04e2 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -30,6 +30,7 @@
 import android.media.ISpatializer;
 import android.media.ISpatializerCallback;
 import android.media.ISpatializerHeadToSoundStagePoseCallback;
+import android.media.ISpatializerHeadTrackerAvailableCallback;
 import android.media.ISpatializerHeadTrackingCallback;
 import android.media.ISpatializerHeadTrackingModeCallback;
 import android.media.ISpatializerOutputCallback;
@@ -126,6 +127,7 @@
     private boolean mBinauralSupported = false;
     private int mActualHeadTrackingMode = Spatializer.HEAD_TRACKING_MODE_UNSUPPORTED;
     private int mDesiredHeadTrackingMode = Spatializer.HEAD_TRACKING_MODE_RELATIVE_WORLD;
+    private boolean mHeadTrackerAvailable = false;
     /**
      *  The desired head tracking mode when enabling head tracking, tracks mDesiredHeadTrackingMode,
      *  except when head tracking gets disabled through setting the desired mode to
@@ -137,6 +139,7 @@
     private @Nullable SpatializerCallback mSpatCallback;
     private @Nullable SpatializerHeadTrackingCallback mSpatHeadTrackingCallback;
     private @Nullable HelperDynamicSensorCallback mDynSensorCallback;
+    private boolean mIsHeadTrackingSupported = false;
 
     // default attributes and format that determine basic availability of spatialization
     private static final AudioAttributes DEFAULT_ATTRIBUTES = new AudioAttributes.Builder()
@@ -275,6 +278,7 @@
      */
     synchronized void reset(boolean featureEnabled) {
         Log.i(TAG, "Resetting");
+        releaseSpat();
         mState = STATE_UNINITIALIZED;
         mSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
         mCapableSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
@@ -810,8 +814,9 @@
             mSpat = AudioSystem.getSpatializer(mSpatCallback);
             try {
                 mSpat.setLevel((byte)  Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL);
+                mIsHeadTrackingSupported = mSpat.isHeadTrackingSupported();
                 //TODO: register heatracking callback only when sensors are registered
-                if (mSpat.isHeadTrackingSupported()) {
+                if (mIsHeadTrackingSupported) {
                     mSpat.registerHeadTrackingCallback(mSpatHeadTrackingCallback);
                 }
             } catch (RemoteException e) {
@@ -829,12 +834,16 @@
         if (mSpat != null) {
             mSpatCallback = null;
             try {
-                mSpat.registerHeadTrackingCallback(null);
+                if (mIsHeadTrackingSupported) {
+                    mSpat.registerHeadTrackingCallback(null);
+                }
+                mHeadTrackerAvailable = false;
                 mSpat.release();
-                mSpat = null;
             } catch (RemoteException e) {
                 Log.e(TAG, "Can't set release spatializer cleanly", e);
             }
+            mIsHeadTrackingSupported = false;
+            mSpat = null;
         }
     }
 
@@ -889,6 +898,18 @@
         mHeadTrackingModeCallbacks.unregister(callback);
     }
 
+    final RemoteCallbackList<ISpatializerHeadTrackerAvailableCallback> mHeadTrackerCallbacks =
+            new RemoteCallbackList<>();
+
+    synchronized void registerHeadTrackerAvailableCallback(
+            @NonNull ISpatializerHeadTrackerAvailableCallback cb, boolean register) {
+        if (register) {
+            mHeadTrackerCallbacks.register(cb);
+        } else {
+            mHeadTrackerCallbacks.unregister(cb);
+        }
+    }
+
     synchronized int[] getSupportedHeadTrackingModes() {
         switch (mState) {
             case STATE_UNINITIALIZED:
@@ -1089,6 +1110,10 @@
         return false;
     }
 
+    synchronized boolean isHeadTrackerAvailable() {
+        return mHeadTrackerAvailable;
+    }
+
     private boolean checkSpatForHeadTracking(String funcName) {
         switch (mState) {
             case STATE_UNINITIALIZED:
@@ -1104,7 +1129,7 @@
                 }
                 break;
         }
-        return true;
+        return mIsHeadTrackingSupported;
     }
 
     private void dispatchActualHeadTrackingMode(int newMode) {
@@ -1114,7 +1139,8 @@
                 mHeadTrackingModeCallbacks.getBroadcastItem(i)
                         .dispatchSpatializerActualHeadTrackingModeChanged(newMode);
             } catch (RemoteException e) {
-                Log.e(TAG, "Error in dispatchSpatializerActualHeadTrackingModeChanged", e);
+                Log.e(TAG, "Error in dispatchSpatializerActualHeadTrackingModeChanged("
+                        + newMode + ")", e);
             }
         }
         mHeadTrackingModeCallbacks.finishBroadcast();
@@ -1127,12 +1153,27 @@
                 mHeadTrackingModeCallbacks.getBroadcastItem(i)
                         .dispatchSpatializerDesiredHeadTrackingModeChanged(newMode);
             } catch (RemoteException e) {
-                Log.e(TAG, "Error in dispatchSpatializerDesiredHeadTrackingModeChanged", e);
+                Log.e(TAG, "Error in dispatchSpatializerDesiredHeadTrackingModeChanged("
+                        + newMode + ")", e);
             }
         }
         mHeadTrackingModeCallbacks.finishBroadcast();
     }
 
+    private void dispatchHeadTrackerAvailable(boolean available) {
+        final int nbCallbacks = mHeadTrackerCallbacks.beginBroadcast();
+        for (int i = 0; i < nbCallbacks; i++) {
+            try {
+                mHeadTrackerCallbacks.getBroadcastItem(i)
+                        .dispatchSpatializerHeadTrackerAvailable(available);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error in dispatchSpatializerHeadTrackerAvailable("
+                        + available + ")", e);
+            }
+        }
+        mHeadTrackerCallbacks.finishBroadcast();
+    }
+
     //------------------------------------------------------
     // head pose
     final RemoteCallbackList<ISpatializerHeadToSoundStagePoseCallback> mHeadPoseCallbacks =
@@ -1278,13 +1319,8 @@
             Log.e(TAG, "not " + action + " sensors, null spatializer");
             return;
         }
-        try {
-            if (!mSpat.isHeadTrackingSupported()) {
-                Log.e(TAG, "not " + action + " sensors, spatializer doesn't support headtracking");
-                return;
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "not " + action + " sensors, error querying headtracking", e);
+        if (!mIsHeadTrackingSupported) {
+            Log.e(TAG, "not " + action + " sensors, spatializer doesn't support headtracking");
             return;
         }
         int headHandle = -1;
@@ -1347,6 +1383,10 @@
         try {
             Log.i(TAG, "setHeadSensor:" + headHandle);
             mSpat.setHeadSensor(headHandle);
+            if (mHeadTrackerAvailable != (headHandle != -1)) {
+                mHeadTrackerAvailable = (headHandle != -1);
+                dispatchHeadTrackerAvailable(mHeadTrackerAvailable);
+            }
         } catch (Exception e) {
             Log.e(TAG, "Error calling setHeadSensor:" + headHandle, e);
         }
diff --git a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
index 1b2e606..1370fd8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
@@ -38,7 +38,7 @@
  */
 public abstract class BaseClientMonitor implements IBinder.DeathRecipient {
 
-    private static final String TAG = "Biometrics/ClientMonitor";
+    private static final String TAG = "BaseClientMonitor";
     protected static final boolean DEBUG = true;
 
     // Counter used to distinguish between ClientMonitor instances to help debugging.
@@ -120,8 +120,18 @@
     }
 
     /**
+     * Sets the lifecycle callback before the operation is started via
+     * {@link #start(ClientMonitorCallback)} when the client must wait for a cookie before starting.
+     *
+     * @param callback lifecycle callback (typically same callback used for starting the operation)
+     */
+    public void waitForCookie(@NonNull ClientMonitorCallback callback) {
+        mCallback = callback;
+    }
+
+    /**
      * Starts the ClientMonitor's lifecycle.
-     * @param callback invoked when the operation is complete (succeeds, fails, etc)
+     * @param callback invoked when the operation is complete (succeeds, fails, etc.)
      */
     public void start(@NonNull ClientMonitorCallback callback) {
         mCallback = wrapCallbackForStart(callback);
@@ -246,12 +256,12 @@
     }
 
     /** Unique request id. */
-    public final long getRequestId() {
+    public long getRequestId() {
         return mRequestId;
     }
 
     /** If a unique id has been set via {@link #setRequestId(long)} */
-    public final boolean hasRequestId() {
+    public boolean hasRequestId() {
         return mRequestId > 0;
     }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index d0ec447..19a93f3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -285,7 +285,7 @@
 
         // Not all operations start immediately. BiometricPrompt waits for its operation
         // to arrive at the head of the queue, before pinging it to start.
-        final int cookie = mCurrentOperation.isReadyToStart();
+        final int cookie = mCurrentOperation.isReadyToStart(mInternalCallback);
         if (cookie == 0) {
             if (!mCurrentOperation.start(mInternalCallback)) {
                 // Note down current length of queue
@@ -463,6 +463,18 @@
         return mCurrentOperation != null ? mCurrentOperation.getClientMonitor() : null;
     }
 
+    /** The current operation if the requestId is set and matches. */
+    @Deprecated
+    @Nullable
+    public BaseClientMonitor getCurrentClientIfMatches(long requestId) {
+        if (mCurrentOperation != null) {
+            if (mCurrentOperation.isMatchingRequestId(requestId)) {
+                return mCurrentOperation.getClientMonitor();
+            }
+        }
+        return null;
+    }
+
     public int getCurrentPendingCount() {
         return mPendingOperations.size();
     }
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java b/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java
index 15f0cad..968146a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java
@@ -123,11 +123,12 @@
      *
      * @return cookie or 0 if ready/started
      */
-    public int isReadyToStart() {
+    public int isReadyToStart(@NonNull ClientMonitorCallback callback) {
         if (mState == STATE_WAITING_FOR_COOKIE || mState == STATE_WAITING_IN_QUEUE) {
             final int cookie = mClientMonitor.getCookie();
             if (cookie != 0) {
                 mState = STATE_WAITING_FOR_COOKIE;
+                mClientMonitor.waitForCookie(getWrappedCallback(callback));
             }
             return cookie;
         }
@@ -137,7 +138,7 @@
 
     /**
      * Start this operation without waiting for a cookie
-     * (i.e. {@link #isReadyToStart() returns zero}
+     * (i.e. {@link #isReadyToStart(ClientMonitorCallback)}  returns zero}
      *
      * @param callback lifecycle callback
      * @return if this operation started
diff --git a/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java b/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
index 0087178..aeb6b6e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
+++ b/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
@@ -84,7 +84,8 @@
                     };
 
             try {
-                mUdfpsOverlayController.get().showUdfpsOverlay(sensorId, reason, callback);
+                mUdfpsOverlayController.get().showUdfpsOverlay(
+                        client.getRequestId(), sensorId, reason, callback);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote exception when showing the UDFPS overlay", e);
             }
diff --git a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
index 4f90020..a099977 100644
--- a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
@@ -57,30 +57,25 @@
     @Nullable private StopUserClient<?> mStopUserClient;
 
     private class ClientFinishedCallback implements ClientMonitorCallback {
-        private final BaseClientMonitor mOwner;
+        @NonNull private final BaseClientMonitor mOwner;
 
-        ClientFinishedCallback(BaseClientMonitor owner) {
+        ClientFinishedCallback(@NonNull BaseClientMonitor owner) {
             mOwner = owner;
         }
 
         @Override
         public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) {
             mHandler.post(() -> {
-                if (mOwner != clientMonitor) {
-                    Slog.e(getTag(), "[Wrong client finished], actual: "
-                            + clientMonitor + ", expected: " + mOwner);
-                    return;
-                }
-
                 Slog.d(getTag(), "[Client finished] " + clientMonitor + ", success: " + success);
                 if (mCurrentOperation != null && mCurrentOperation.isFor(mOwner)) {
                     mCurrentOperation = null;
-                    startNextOperationIfIdle();
                 } else {
-                    // can usually be ignored (hal died, etc.)
-                    Slog.d(getTag(), "operation is already null or different (reset?): "
+                    // can happen if the hal dies and is usually okay
+                    // do not unset the current operation that may be newer
+                    Slog.w(getTag(), "operation is already null or different (reset?): "
                             + mCurrentOperation);
                 }
+                startNextOperationIfIdle();
             });
         }
     }
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
index 7765ab3..9ae6750 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -136,8 +136,8 @@
         try {
             if (mSensorPrivacyManager != null
                     && mSensorPrivacyManager
-                    .isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA,
-                    getTargetUserId())) {
+                    .isSensorPrivacyEnabled(SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE,
+                    SensorPrivacyManager.Sensors.CAMERA)) {
                 onError(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
                         0 /* vendorCode */);
                 mCallback.onClientFinished(this, false /* success */);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
index efedcf8..ded1810 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
@@ -96,7 +96,8 @@
     protected void startHalOperation() {
         if (mSensorPrivacyManager != null
                 && mSensorPrivacyManager
-                .isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA, getTargetUserId())) {
+                .isSensorPrivacyEnabled(SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE,
+                    SensorPrivacyManager.Sensors.CAMERA)) {
             onError(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
             mCallback.onClientFinished(this, false /* success */);
             return;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
index 8d76e9f..1935a5b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
@@ -109,7 +109,8 @@
 
         if (mSensorPrivacyManager != null
                 && mSensorPrivacyManager
-                .isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA, getTargetUserId())) {
+                .isSensorPrivacyEnabled(SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE,
+                SensorPrivacyManager.Sensors.CAMERA)) {
             onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
             mCallback.onClientFinished(this, false /* success */);
             return;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index b4befd2..e8d8fb8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -928,7 +928,8 @@
         }
 
         @Override
-        public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
+        public void onPointerDown(long requestId, int sensorId, int x, int y,
+                float minor, float major) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
 
             final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -936,11 +937,11 @@
                 Slog.w(TAG, "No matching provider for onFingerDown, sensorId: " + sensorId);
                 return;
             }
-            provider.onPointerDown(sensorId, x, y, minor, major);
+            provider.onPointerDown(requestId, sensorId, x, y, minor, major);
         }
 
         @Override
-        public void onPointerUp(int sensorId) {
+        public void onPointerUp(long requestId, int sensorId) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
 
             final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -948,11 +949,11 @@
                 Slog.w(TAG, "No matching provider for onFingerUp, sensorId: " + sensorId);
                 return;
             }
-            provider.onPointerUp(sensorId);
+            provider.onPointerUp(requestId, sensorId);
         }
 
         @Override
-        public void onUiReady(int sensorId) {
+        public void onUiReady(long requestId, int sensorId) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
 
             final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -960,7 +961,7 @@
                 Slog.w(TAG, "No matching provider for onUiReady, sensorId: " + sensorId);
                 return;
             }
-            provider.onUiReady(sensorId);
+            provider.onUiReady(requestId, sensorId);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index 0bdc4eb..9cdbdc9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -142,11 +142,11 @@
 
     long getAuthenticatorId(int sensorId, int userId);
 
-    void onPointerDown(int sensorId, int x, int y, float minor, float major);
+    void onPointerDown(long requestId, int sensorId, int x, int y, float minor, float major);
 
-    void onPointerUp(int sensorId);
+    void onPointerUp(long requestId, int sensorId);
 
-    void onUiReady(int sensorId);
+    void onUiReady(long requestId, int sensorId);
 
     void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller);
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index f810bca..1fac8a8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -580,39 +580,37 @@
     }
 
     @Override
-    public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
+    public void onPointerDown(long requestId, int sensorId, int x, int y,
+            float minor, float major) {
         final BaseClientMonitor client =
-                mSensors.get(sensorId).getScheduler().getCurrentClient();
+                mSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(requestId);
         if (!(client instanceof Udfps)) {
             Slog.e(getTag(), "onPointerDown received during client: " + client);
             return;
         }
-        final Udfps udfps = (Udfps) client;
-        udfps.onPointerDown(x, y, minor, major);
+        ((Udfps) client).onPointerDown(x, y, minor, major);
     }
 
     @Override
-    public void onPointerUp(int sensorId) {
+    public void onPointerUp(long requestId, int sensorId) {
         final BaseClientMonitor client =
-                mSensors.get(sensorId).getScheduler().getCurrentClient();
+                mSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(requestId);
         if (!(client instanceof Udfps)) {
             Slog.e(getTag(), "onPointerUp received during client: " + client);
             return;
         }
-        final Udfps udfps = (Udfps) client;
-        udfps.onPointerUp();
+        ((Udfps) client).onPointerUp();
     }
 
     @Override
-    public void onUiReady(int sensorId) {
+    public void onUiReady(long requestId, int sensorId) {
         final BaseClientMonitor client =
-                mSensors.get(sensorId).getScheduler().getCurrentClient();
+                mSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(requestId);
         if (!(client instanceof Udfps)) {
             Slog.e(getTag(), "onUiReady received during client: " + client);
             return;
         }
-        final Udfps udfps = (Udfps) client;
-        udfps.onUiReady();
+        ((Udfps) client).onUiReady();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 9d60859..1d2a365 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -792,36 +792,34 @@
     }
 
     @Override
-    public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
-        final BaseClientMonitor client = mScheduler.getCurrentClient();
+    public void onPointerDown(long requestId, int sensorId, int x, int y,
+            float minor, float major) {
+        final BaseClientMonitor client = mScheduler.getCurrentClientIfMatches(requestId);
         if (!(client instanceof Udfps)) {
             Slog.w(TAG, "onFingerDown received during client: " + client);
             return;
         }
-        final Udfps udfps = (Udfps) client;
-        udfps.onPointerDown(x, y, minor, major);
+        ((Udfps) client).onPointerDown(x, y, minor, major);
     }
 
     @Override
-    public void onPointerUp(int sensorId) {
-        final BaseClientMonitor client = mScheduler.getCurrentClient();
+    public void onPointerUp(long requestId, int sensorId) {
+        final BaseClientMonitor client = mScheduler.getCurrentClientIfMatches(requestId);
         if (!(client instanceof Udfps)) {
             Slog.w(TAG, "onFingerDown received during client: " + client);
             return;
         }
-        final Udfps udfps = (Udfps) client;
-        udfps.onPointerUp();
+        ((Udfps) client).onPointerUp();
     }
 
     @Override
-    public void onUiReady(int sensorId) {
-        final BaseClientMonitor client = mScheduler.getCurrentClient();
+    public void onUiReady(long requestId, int sensorId) {
+        final BaseClientMonitor client = mScheduler.getCurrentClientIfMatches(requestId);
         if (!(client instanceof Udfps)) {
             Slog.w(TAG, "onUiReady received during client: " + client);
             return;
         }
-        final Udfps udfps = (Udfps) client;
-        udfps.onUiReady();
+        ((Udfps) client).onUiReady();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
index 149526f..a4e343e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
@@ -441,7 +441,8 @@
     }
 
     @Override
-    public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
+    public void onPointerDown(long requestId, int sensorId, int x, int y, float minor,
+            float major) {
         mHandler.post(() -> {
             Slog.d(TAG, "onFingerDown");
             final AuthenticationConsumer lastAuthenticatedConsumer =
@@ -488,7 +489,7 @@
     }
 
     @Override
-    public void onPointerUp(int sensorId) {
+    public void onPointerUp(long requestId, int sensorId) {
         mHandler.post(() -> {
             Slog.d(TAG, "onFingerUp");
 
diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
index 108e7bc..b9efdf5 100644
--- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
+++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
@@ -71,7 +71,6 @@
 import java.time.ZoneOffset;
 import java.time.ZonedDateTime;
 import java.time.temporal.ChronoUnit;
-import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.TimeUnit;
@@ -222,8 +221,10 @@
                         "Can't get TelephonyManager for subId %d", mSubId));
             }
 
-            subscriberId = Objects.requireNonNull(tele.getSubscriberId(),
-                    "Null subscriber Id for subId " + mSubId);
+            subscriberId = tele.getSubscriberId();
+            if (subscriberId == null) {
+                throw new IllegalStateException("Null subscriber Id for subId " + mSubId);
+            }
             mNetworkTemplate = new NetworkTemplate.Builder(NetworkTemplate.MATCH_MOBILE)
                     .setSubscriberIds(Set.of(subscriberId))
                     .setMeteredness(NetworkStats.METERED_YES)
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index c0df095..a6da4a6 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -75,6 +75,7 @@
 import android.net.UidRangeParcel;
 import android.net.UnderlyingNetworkInfo;
 import android.net.VpnManager;
+import android.net.VpnProfileState;
 import android.net.VpnService;
 import android.net.VpnTransportInfo;
 import android.net.ipsec.ike.ChildSessionCallback;
@@ -3438,6 +3439,45 @@
         }
     }
 
+    private @VpnProfileState.State int getStateFromLegacyState(int legacyState) {
+        switch (legacyState) {
+            case LegacyVpnInfo.STATE_CONNECTING:
+                return VpnProfileState.STATE_CONNECTING;
+            case LegacyVpnInfo.STATE_CONNECTED:
+                return VpnProfileState.STATE_CONNECTED;
+            case LegacyVpnInfo.STATE_DISCONNECTED:
+                return VpnProfileState.STATE_DISCONNECTED;
+            case LegacyVpnInfo.STATE_FAILED:
+                return VpnProfileState.STATE_FAILED;
+            default:
+                Log.wtf(TAG, "Unhandled state " + legacyState
+                        + ", treat it as STATE_DISCONNECTED");
+                return VpnProfileState.STATE_DISCONNECTED;
+        }
+    }
+
+    private VpnProfileState makeVpnProfileState() {
+        // TODO: mSessionKey will be moved to Ikev2VpnRunner once aosp/2007077 is merged, so after
+        //  merging aosp/2007077, here should check Ikev2VpnRunner is null or not. Session key will
+        //  be null if Ikev2VpnRunner is null.
+        return new VpnProfileState(getStateFromLegacyState(mLegacyState), mSessionKey, mAlwaysOn,
+                mLockdown);
+    }
+
+    /**
+     * Retrieve the VpnProfileState for the profile provisioned by the given package.
+     *
+     * @return the VpnProfileState with current information, or null if there was no profile
+     *         provisioned by the given package.
+     */
+    @Nullable
+    public synchronized VpnProfileState getProvisionedVpnProfileState(
+            @NonNull String packageName) {
+        requireNonNull(packageName, "No package name provided");
+        enforceNotRestrictedUser();
+        return isCurrentIkev2VpnLocked(packageName) ? makeVpnProfileState() : null;
+    }
+
     /**
      * Proxy to allow testing
      *
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index fadcce9..954b930 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -20,6 +20,7 @@
 
 import android.Manifest;
 import android.accounts.Account;
+import android.accounts.AccountManagerInternal;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -28,7 +29,10 @@
 import android.app.ActivityManagerInternal;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
+import android.app.compat.CompatChanges;
 import android.app.job.JobInfo;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -106,6 +110,13 @@
      */
     private static final long BACKGROUND_OBSERVER_DELAY = 10 * DateUtils.SECOND_IN_MILLIS;
 
+    /**
+     * Enables checking for account access for the calling uid on all sync-related APIs.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.S_V2)
+    public static final long ACCOUNT_ACCESS_CHECK_CHANGE_ID = 201794303L;
+
     public static class Lifecycle extends SystemService {
         private ContentService mService;
 
@@ -157,6 +168,8 @@
     private SyncManager mSyncManager = null;
     private final Object mSyncManagerLock = new Object();
 
+    private final AccountManagerInternal mAccountManagerInternal;
+
     private static final BinderDeathDispatcher<IContentObserver> sObserverDeathDispatcher =
             new BinderDeathDispatcher<>();
 
@@ -317,6 +330,8 @@
         localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
         mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL,
                 localeFilter, null, null);
+
+        mAccountManagerInternal = LocalServices.getService(AccountManagerInternal.class);
     }
 
     void onBootPhase(int phase) {
@@ -593,6 +608,10 @@
         final int callingUid = Binder.getCallingUid();
         final int callingPid = Binder.getCallingPid();
 
+        if (!hasAccountAccess(true, account, callingUid)) {
+            return;
+        }
+
         validateExtras(callingUid, extras);
         final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callingUid, extras);
 
@@ -642,11 +661,14 @@
     @Override
     public void syncAsUser(SyncRequest request, int userId, String callingPackage) {
         enforceCrossUserPermission(userId, "no permission to request sync as user: " + userId);
+
         final int callingUid = Binder.getCallingUid();
         final int callingPid = Binder.getCallingPid();
+        if (!hasAccountAccess(true, request.getAccount(), callingUid)) {
+            return;
+        }
 
         final Bundle extras = request.getBundle();
-
         validateExtras(callingUid, extras);
         final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callingUid, extras);
 
@@ -853,6 +875,9 @@
                 "no permission to read the sync settings for user " + userId);
         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
                 "no permission to read the sync settings");
+        if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
+            return false;
+        }
 
         final long identityToken = clearCallingIdentity();
         try {
@@ -882,8 +907,13 @@
                 "no permission to write the sync settings");
         enforceCrossUserPermission(userId,
                 "no permission to modify the sync settings for user " + userId);
+
         final int callingUid = Binder.getCallingUid();
         final int callingPid = Binder.getCallingPid();
+        if (!hasAccountAccess(true, account, callingUid)) {
+            return;
+        }
+
         final int syncExemptionFlag = getSyncExemptionForCaller(callingUid);
 
         final long identityToken = clearCallingIdentity();
@@ -912,7 +942,11 @@
         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
                 "no permission to write the sync settings");
 
-        validateExtras(Binder.getCallingUid(), extras);
+        final int callingUid = Binder.getCallingUid();
+        if (!hasAccountAccess(true, account, callingUid)) {
+            return;
+        }
+        validateExtras(callingUid, extras);
 
         int userId = UserHandle.getCallingUserId();
 
@@ -942,9 +976,11 @@
         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
                 "no permission to write the sync settings");
 
-        validateExtras(Binder.getCallingUid(), extras);
-
         final int callingUid = Binder.getCallingUid();
+        if (!hasAccountAccess(true, account, callingUid)) {
+            return;
+        }
+        validateExtras(callingUid, extras);
 
         int userId = UserHandle.getCallingUserId();
         final long identityToken = clearCallingIdentity();
@@ -969,6 +1005,9 @@
         }
         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
                 "no permission to read the sync settings");
+        if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
+            return new ArrayList<>(); // return a new empty list for consistent behavior
+        }
 
         int userId = UserHandle.getCallingUserId();
         final long identityToken = clearCallingIdentity();
@@ -995,6 +1034,9 @@
                 "no permission to read the sync settings for user " + userId);
         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
                 "no permission to read the sync settings");
+        if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
+            return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE; // to keep behavior consistent
+        }
 
         final long identityToken = clearCallingIdentity();
         try {
@@ -1031,6 +1073,9 @@
         syncable = normalizeSyncable(syncable);
         final int callingUid = Binder.getCallingUid();
         final int callingPid = Binder.getCallingPid();
+        if (!hasAccountAccess(true, account, callingUid)) {
+            return;
+        }
 
         final long identityToken = clearCallingIdentity();
         try {
@@ -1103,6 +1148,10 @@
     public boolean isSyncActive(Account account, String authority, ComponentName cname) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
                 "no permission to read the sync stats");
+        if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
+            return false;
+        }
+
         int userId = UserHandle.getCallingUserId();
         final long identityToken = clearCallingIdentity();
         try {
@@ -1165,6 +1214,9 @@
                 "no permission to read the sync stats for user " + userId);
         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
                 "no permission to read the sync stats");
+        if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
+            return null;
+        }
 
         final long identityToken = clearCallingIdentity();
         try {
@@ -1196,6 +1248,10 @@
                 "no permission to read the sync stats");
         enforceCrossUserPermission(userId,
                 "no permission to retrieve the sync settings for user " + userId);
+        if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
+            return false;
+        }
+
         final long identityToken = clearCallingIdentity();
         SyncManager syncManager = getSyncManager();
         if (syncManager == null) return false;
@@ -1405,6 +1461,32 @@
                 Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
     }
 
+    /**
+     * Checks to see if the given account is accessible by the provided uid.
+     *
+     * @param checkCompatFlag whether to check if the ACCOUNT_ACCESS_CHECK_CHANGE_ID flag is enabled
+     * @param account the account trying to be accessed
+     * @param uid the uid trying to access the account
+     * @return {@code true} if the account is accessible by the given uid, {@code false} otherwise
+     */
+    private boolean hasAccountAccess(boolean checkCompatFlag, Account account, int uid) {
+        if (account == null) {
+            // If the account is null, it means to check for all accounts hence skip the check here.
+            return true;
+        }
+        if (checkCompatFlag
+                && !CompatChanges.isChangeEnabled(ACCOUNT_ACCESS_CHECK_CHANGE_ID, uid)) {
+            return true;
+        }
+
+        final long identityToken = clearCallingIdentity();
+        try {
+            return mAccountManagerInternal.hasAccountAccess(account, uid);
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
     private static int normalizeSyncable(int syncable) {
         if (syncable > 0) {
             return SyncStorageEngine.AuthorityInfo.SYNCABLE;
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 7cb2921..cb04ddf 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -156,9 +156,15 @@
 
         mMode = mode;
 
+        DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
+        if (displayInfo == null) {
+            // displayInfo can be null if the associated display has been removed. There
+            // is a delay between the display being removed and ColorFade being dismissed.
+            return false;
+        }
+
         // Get the display size and layer stack.
         // This is not expected to change while the color fade surface is showing.
-        DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
         mDisplayLayerStack = displayInfo.layerStack;
         mDisplayWidth = displayInfo.getNaturalWidth();
         mDisplayHeight = displayInfo.getNaturalHeight();
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 311fa7c..76d71e2 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -131,7 +131,7 @@
      * Only used for mirroring started from MediaProjection.
      */
     @Nullable
-    public Point getDisplaySurfaceDefaultSize() {
+    public Point getDisplaySurfaceDefaultSizeLocked() {
         return null;
     }
 
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 064e307..d12c621 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -30,9 +30,8 @@
 import android.util.Spline;
 import android.view.DisplayAddress;
 
-import com.android.internal.annotations.VisibleForTesting;
-
 import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.display.BrightnessSynchronizer;
 import com.android.server.display.config.BrightnessThresholds;
 import com.android.server.display.config.BrightnessThrottlingMap;
@@ -296,9 +295,9 @@
      * @return A configuration instance for the specified display.
      */
     public static DisplayDeviceConfig create(Context context, long physicalDisplayId,
-            boolean isDefaultDisplay) {
+            boolean isFirstDisplay) {
         final DisplayDeviceConfig config = createWithoutDefaultValues(context, physicalDisplayId,
-                isDefaultDisplay);
+                isFirstDisplay);
 
         config.copyUninitializedValuesFromSecondaryConfig(loadDefaultConfigurationXml(context));
         return config;
@@ -323,7 +322,7 @@
     }
 
     private static DisplayDeviceConfig createWithoutDefaultValues(Context context,
-            long physicalDisplayId, boolean isDefaultDisplay) {
+            long physicalDisplayId, boolean isFirstDisplay) {
         DisplayDeviceConfig config;
 
         config = loadConfigFromDirectory(context, Environment.getProductDirectory(),
@@ -341,7 +340,7 @@
         // If no config can be loaded from any ddc xml at all,
         // prepare a whole config using the global config.xml.
         // Guaranteed not null
-        return create(context, isDefaultDisplay);
+        return create(context, isFirstDisplay);
     }
 
     private static DisplayConfiguration loadDefaultConfigurationXml(Context context) {
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index a311ba1..edaa18a 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -39,7 +39,7 @@
      * Flag: Indicates that this display device should be considered the default display
      * device of the system.
      */
-    public static final int FLAG_DEFAULT_DISPLAY = 1 << 0;
+    public static final int FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY = 1 << 0;
 
     /**
      * Flag: Indicates that the orientation of this display device is coupled to the
@@ -538,8 +538,8 @@
 
     private static String flagsToString(int flags) {
         StringBuilder msg = new StringBuilder();
-        if ((flags & FLAG_DEFAULT_DISPLAY) != 0) {
-            msg.append(", FLAG_DEFAULT_DISPLAY");
+        if ((flags & FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY) != 0) {
+            msg.append(", FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY");
         }
         if ((flags & FLAG_ROTATES_WITH_CONTENT) != 0) {
             msg.append(", FLAG_ROTATES_WITH_CONTENT");
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index e21edc9..932717a 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -397,8 +397,7 @@
     private final ArrayList<DisplayViewport> mTempViewports = new ArrayList<>();
 
     // The default color mode for default displays. Overrides the usual
-    // Display.Display.COLOR_MODE_DEFAULT for displays with the
-    // DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY flag set.
+    // Display.Display.COLOR_MODE_DEFAULT for local displays.
     private final int mDefaultDisplayDefaultColorMode;
 
     // Lists of UIDs that are present on the displays. Maps displayId -> array of UIDs.
@@ -1682,8 +1681,7 @@
         if (display.getPrimaryDisplayDeviceLocked() == device) {
             int colorMode = mPersistentDataStore.getColorMode(device);
             if (colorMode == Display.COLOR_MODE_INVALID) {
-                if ((device.getDisplayDeviceInfoLocked().flags
-                     & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) {
+                if (display.getDisplayIdLocked() == Display.DEFAULT_DISPLAY) {
                     colorMode = mDefaultDisplayDefaultColorMode;
                 } else {
                     colorMode = Display.COLOR_MODE_DEFAULT;
@@ -3880,8 +3878,8 @@
                 if (device == null) {
                     return null;
                 }
+                return device.getDisplaySurfaceDefaultSizeLocked();
             }
-            return device.getDisplaySurfaceDefaultSize();
         }
 
         @Override
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 9067f2e..f819e56 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -129,7 +129,8 @@
     private static final int MSG_STOP = 9;
     private static final int MSG_UPDATE_BRIGHTNESS = 10;
     private static final int MSG_UPDATE_RBC = 11;
-    private static final int MSG_STATSD_HBM_BRIGHTNESS = 12;
+    private static final int MSG_BRIGHTNESS_RAMP_DONE = 12;
+    private static final int MSG_STATSD_HBM_BRIGHTNESS = 13;
 
     private static final int PROXIMITY_UNKNOWN = -1;
     private static final int PROXIMITY_NEGATIVE = 0;
@@ -1050,9 +1051,8 @@
         @Override
         public void onAnimationEnd() {
             sendUpdatePowerState();
-
-            final float brightness = mPowerState.getScreenBrightness();
-            reportStats(brightness);
+            Message msg = mHandler.obtainMessage(MSG_BRIGHTNESS_RAMP_DONE);
+            mHandler.sendMessage(msg);
         }
     };
 
@@ -1066,6 +1066,12 @@
             mCallbacks.releaseSuspendBlocker();
             mUnfinishedBusiness = false;
         }
+
+        final float brightness = mPowerState != null
+            ? mPowerState.getScreenBrightness()
+            : PowerManager.BRIGHTNESS_MIN;
+        reportStats(brightness);
+
         if (mPowerState != null) {
             mPowerState.stop();
             mPowerState = null;
@@ -2580,6 +2586,10 @@
     }
 
     private void reportStats(float brightness) {
+        if (mLastStatsBrightness == brightness) {
+            return;
+        }
+
         float hbmTransitionPoint = PowerManager.BRIGHTNESS_MAX;
         synchronized(mCachedBrightnessInfo) {
             if (mCachedBrightnessInfo.hbmTransitionPoint == null) {
@@ -2680,6 +2690,13 @@
                     handleRbcChanged(strengthChanged == 1, justActivated == 1);
                     break;
 
+                case MSG_BRIGHTNESS_RAMP_DONE:
+                    if (mPowerState != null)  {
+                        final float brightness = mPowerState.getScreenBrightness();
+                        reportStats(brightness);
+                    }
+                    break;
+
                 case MSG_STATSD_HBM_BRIGHTNESS:
                     logHbmBrightnessStats(Float.intBitsToFloat(msg.arg1), msg.arg2);
                     break;
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 7a0cf4b..eaa1d4b 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -73,6 +73,8 @@
 
     private final SurfaceControlProxy mSurfaceControlProxy;
 
+    private final boolean mIsBootDisplayModeSupported;
+
     // Called with SyncRoot lock held.
     public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
             Context context, Handler handler, Listener listener) {
@@ -85,6 +87,7 @@
         super(syncRoot, context, handler, listener, TAG);
         mInjector = injector;
         mSurfaceControlProxy = mInjector.getSurfaceControlProxy();
+        mIsBootDisplayModeSupported = mSurfaceControlProxy.getBootDisplayModeSupport();
     }
 
     @Override
@@ -138,9 +141,9 @@
             LocalDisplayDevice device = mDevices.get(physicalDisplayId);
             if (device == null) {
                 // Display was added.
-                final boolean isDefaultDisplay = mDevices.size() == 0;
+                final boolean isFirstDisplay = mDevices.size() == 0;
                 device = new LocalDisplayDevice(displayToken, physicalDisplayId, staticInfo,
-                        dynamicInfo, modeSpecs, isDefaultDisplay);
+                        dynamicInfo, modeSpecs, isFirstDisplay);
                 mDevices.put(physicalDisplayId, device);
                 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
             } else if (device.updateDisplayPropertiesLocked(staticInfo, dynamicInfo,
@@ -184,7 +187,7 @@
         private final ArrayList<Integer> mSupportedColorModes = new ArrayList<>();
         private final DisplayModeDirector.DesiredDisplayModeSpecs mDisplayModeSpecs =
                 new DisplayModeDirector.DesiredDisplayModeSpecs();
-        private final boolean mIsDefaultDisplay;
+        private final boolean mIsFirstDisplay;
         private final BacklightAdapter mBacklightAdapter;
         private final SidekickInternal mSidekickInternal;
 
@@ -223,14 +226,14 @@
         LocalDisplayDevice(IBinder displayToken, long physicalDisplayId,
                 SurfaceControl.StaticDisplayInfo staticDisplayInfo,
                 SurfaceControl.DynamicDisplayInfo dynamicInfo,
-                SurfaceControl.DesiredDisplayModeSpecs modeSpecs, boolean isDefaultDisplay) {
+                SurfaceControl.DesiredDisplayModeSpecs modeSpecs, boolean isFirstDisplay) {
             super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + physicalDisplayId,
                     getContext());
             mPhysicalDisplayId = physicalDisplayId;
-            mIsDefaultDisplay = isDefaultDisplay;
+            mIsFirstDisplay = isFirstDisplay;
             updateDisplayPropertiesLocked(staticDisplayInfo, dynamicInfo, modeSpecs);
             mSidekickInternal = LocalServices.getService(SidekickInternal.class);
-            mBacklightAdapter = new BacklightAdapter(displayToken, isDefaultDisplay,
+            mBacklightAdapter = new BacklightAdapter(displayToken, isFirstDisplay,
                     mSurfaceControlProxy);
             mActiveDisplayModeAtStartId = dynamicInfo.activeDisplayModeId;
         }
@@ -349,8 +352,7 @@
 
                 if (preferredRecord != null) {
                     int preferredModeId = preferredRecord.mMode.getModeId();
-                    if (mSurfaceControlProxy.getBootDisplayModeSupport()
-                            && mSystemPreferredModeId != preferredModeId) {
+                    if (mIsBootDisplayModeSupported && mSystemPreferredModeId != preferredModeId) {
                         mSystemPreferredModeId = preferredModeId;
                         preferredModeChanged = true;
                     }
@@ -478,7 +480,7 @@
             // Load display device config
             final Context context = getOverlayContext();
             mDisplayDeviceConfig = DisplayDeviceConfig.create(context, mPhysicalDisplayId,
-                    mIsDefaultDisplay);
+                    mIsFirstDisplay);
 
             // Load brightness HWC quirk
             mBacklightAdapter.setForceSurfaceControl(mDisplayDeviceConfig.hasQuirk(
@@ -650,9 +652,9 @@
 
                 final Resources res = getOverlayContext().getResources();
 
-                if (mIsDefaultDisplay) {
-                    mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY;
+                mInfo.flags |= DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY;
 
+                if (mIsFirstDisplay) {
                     if (res.getBoolean(com.android.internal.R.bool.config_mainBuiltInDisplayIsRound)
                             || (Build.IS_EMULATOR
                             && SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) {
@@ -900,7 +902,7 @@
             }
             updateDeviceInfoLocked();
 
-            if (!mSurfaceControlProxy.getBootDisplayModeSupport()) {
+            if (!mIsBootDisplayModeSupported) {
                 return;
             }
             if (mUserPreferredModeId == INVALID_MODE_ID) {
@@ -1436,9 +1438,9 @@
 
         /**
          * @param displayToken Token for display associated with this backlight.
-         * @param isDefaultDisplay {@code true} if it is the default display.
+         * @param isFirstDisplay {@code true} if it is the first display.
          */
-        BacklightAdapter(IBinder displayToken, boolean isDefaultDisplay,
+        BacklightAdapter(IBinder displayToken, boolean isFirstDisplay,
                 SurfaceControlProxy surfaceControlProxy) {
             mDisplayToken = displayToken;
             mSurfaceControlProxy = surfaceControlProxy;
@@ -1446,7 +1448,7 @@
             mUseSurfaceControlBrightness = mSurfaceControlProxy
                     .getDisplayBrightnessSupport(mDisplayToken);
 
-            if (!mUseSurfaceControlBrightness && isDefaultDisplay) {
+            if (!mUseSurfaceControlBrightness && isFirstDisplay) {
                 LightsManager lights = LocalServices.getService(LightsManager.class);
                 mBacklight = lights.getLight(LightsManager.LIGHT_ID_BACKLIGHT);
             } else {
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index add0a9f..70c9e23 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -16,6 +16,8 @@
 
 package com.android.server.display;
 
+import static android.view.Display.DEFAULT_DISPLAY;
+
 import android.annotation.NonNull;
 import android.content.Context;
 import android.hardware.devicestate.DeviceStateManager;
@@ -204,6 +206,7 @@
                 if (DEBUG) {
                     Slog.d(TAG, "Display device removed: " + device.getDisplayDeviceInfoLocked());
                 }
+                handleDisplayDeviceRemovedLocked(device);
                 updateLogicalDisplaysLocked();
                 break;
         }
@@ -529,12 +532,12 @@
 
     private void handleDisplayDeviceAddedLocked(DisplayDevice device) {
         DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();
-        // Internal Displays need to have additional initialization.
-        // This initializes a default dynamic display layout for INTERNAL
-        // devices, which is used as a fallback in case no static layout definitions
+        // The default Display needs to have additional initialization.
+        // This initializes a default dynamic display layout for the default
+        // device, which is used as a fallback in case no static layout definitions
         // exist or cannot be loaded.
-        if (deviceInfo.type == Display.TYPE_INTERNAL) {
-            initializeInternalDisplayDeviceLocked(device);
+        if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY) != 0) {
+            initializeDefaultDisplayDeviceLocked(device);
         }
 
         // Create a logical display for the new display device
@@ -545,6 +548,38 @@
         updateLogicalDisplaysLocked();
     }
 
+    private void handleDisplayDeviceRemovedLocked(DisplayDevice device) {
+        final Layout layout = mDeviceStateToLayoutMap.get(DeviceStateToLayoutMap.STATE_DEFAULT);
+        Layout.Display layoutDisplay = layout.getById(DEFAULT_DISPLAY);
+        if (layoutDisplay == null) {
+            return;
+        }
+        DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();
+
+        if (layoutDisplay.getAddress().equals(deviceInfo.address)) {
+            layout.removeDisplayLocked(DEFAULT_DISPLAY);
+
+            // Need to find another local display and make it default
+            for (int i = 0; i < mLogicalDisplays.size(); i++) {
+                LogicalDisplay nextDisplay = mLogicalDisplays.valueAt(i);
+                DisplayDevice nextDevice = nextDisplay.getPrimaryDisplayDeviceLocked();
+                if (nextDevice == null) {
+                    continue;
+                }
+                DisplayDeviceInfo nextDeviceInfo = nextDevice.getDisplayDeviceInfoLocked();
+
+                if ((nextDeviceInfo.flags
+                        & DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY) != 0
+                        && !nextDeviceInfo.address.equals(deviceInfo.address)) {
+                    layout.createDisplayLocked(nextDeviceInfo.address,
+                            /* isDefault= */ true, /* isEnabled= */ true);
+                    applyLayoutLocked();
+                    return;
+                }
+            }
+        }
+    }
+
     /**
      * Updates the rest of the display system once all the changes are applied for display
      * devices and logical displays. The includes releasing invalid/empty LogicalDisplays,
@@ -900,16 +935,18 @@
         return isOwnDisplayGroup ? mNextNonDefaultGroupId++ : Display.DEFAULT_DISPLAY_GROUP;
     }
 
-    private void initializeInternalDisplayDeviceLocked(DisplayDevice device) {
+    private void initializeDefaultDisplayDeviceLocked(DisplayDevice device) {
         // We always want to make sure that our default layout creates a logical
-        // display for every internal display device that is found.
-        // To that end, when we are notified of a new internal display, we add it to
+        // display for the default display device that is found.
+        // To that end, when we are notified of a new default display, we add it to
         // the default layout definition if it is not already there.
         final Layout layout = mDeviceStateToLayoutMap.get(DeviceStateToLayoutMap.STATE_DEFAULT);
+        if (layout.getById(DEFAULT_DISPLAY) != null) {
+            // The layout should only have one default display
+            return;
+        }
         final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
-        final boolean isDefault = (info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0;
-        final boolean isEnabled = isDefault || mSupportsConcurrentInternalDisplays;
-        layout.createDisplayLocked(info.address, isDefault, isEnabled);
+        layout.createDisplayLocked(info.address, /* isDefault= */ true, /* isEnabled= */ true);
     }
 
     private int assignLayerStackLocked(int displayId) {
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index ea31374..dde8831 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -302,7 +302,7 @@
         }
 
         @Override
-        public Point getDisplaySurfaceDefaultSize() {
+        public Point getDisplaySurfaceDefaultSizeLocked() {
             if (mSurface == null) {
                 return null;
             }
diff --git a/services/core/java/com/android/server/display/layout/Layout.java b/services/core/java/com/android/server/display/layout/Layout.java
index e53aec1..7e16ea8 100644
--- a/services/core/java/com/android/server/display/layout/Layout.java
+++ b/services/core/java/com/android/server/display/layout/Layout.java
@@ -67,7 +67,7 @@
         // See if we're dealing with the "default" display
         if (isDefault && getById(DEFAULT_DISPLAY) != null) {
             Slog.w(TAG, "Ignoring attempt to add a second default display: " + address);
-            isDefault = false;
+            return null;
         }
 
         // Assign a logical display ID and create the new display.
@@ -75,10 +75,20 @@
         // different layouts, a logical display can be destroyed and later recreated with the
         // same logical display ID.
         final int logicalDisplayId = assignDisplayIdLocked(isDefault);
-        final Display layout = new Display(address, logicalDisplayId, isEnabled);
+        final Display display = new Display(address, logicalDisplayId, isEnabled);
 
-        mDisplays.add(layout);
-        return layout;
+        mDisplays.add(display);
+        return display;
+    }
+
+    /**
+     * @param id The ID of the display to remove.
+     */
+    public void removeDisplayLocked(int id) {
+        Display display = getById(id);
+        if (display != null) {
+            mDisplays.remove(display);
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 22d32a6..50f5536 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -467,7 +467,9 @@
         }
         mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN;
         mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
-        mAtmInternal.notifyDreamStateChanged(false);
+        mHandler.post(() -> {
+            mAtmInternal.notifyDreamStateChanged(false);
+        });
     }
 
     private void checkPermission(String permission) {
diff --git a/services/core/java/com/android/server/hdmi/GiveFeaturesAction.java b/services/core/java/com/android/server/hdmi/GiveFeaturesAction.java
deleted file mode 100644
index 4542565..0000000
--- a/services/core/java/com/android/server/hdmi/GiveFeaturesAction.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.hdmi;
-
-import android.hardware.hdmi.HdmiControlManager;
-import android.hardware.hdmi.IHdmiControlCallback;
-import android.hardware.tv.cec.V1_0.SendMessageResult;
-
-/**
- * Sends <Give Features> to a target device. This action succeeds if the device responds with
- * <Report Features> within {@link HdmiConfig.TIMEOUT_MS}.
- *
- * This action does not update the CEC network directly; an incoming <Report Features> message
- * should be handled separately by {@link HdmiCecNetwork}.
- */
-public class GiveFeaturesAction extends HdmiCecFeatureAction {
-    private static final String TAG = "GiveFeaturesAction";
-
-    private static final int STATE_WAITING_FOR_REPORT_FEATURES = 1;
-
-    private final int mTargetAddress;
-
-    public GiveFeaturesAction(HdmiCecLocalDevice source, int targetAddress,
-            IHdmiControlCallback callback) {
-        super(source, callback);
-
-        mTargetAddress = targetAddress;
-    }
-
-    boolean start() {
-        sendCommand(HdmiCecMessageBuilder.buildGiveFeatures(getSourceAddress(), mTargetAddress),
-                result -> {
-                    if (result == SendMessageResult.SUCCESS) {
-                        mState = STATE_WAITING_FOR_REPORT_FEATURES;
-                        addTimer(STATE_WAITING_FOR_REPORT_FEATURES, HdmiConfig.TIMEOUT_MS);
-                    } else {
-                        finishWithCallback(HdmiControlManager.RESULT_COMMUNICATION_FAILED);
-                    }
-                });
-        return true;
-    }
-
-    boolean processCommand(HdmiCecMessage cmd) {
-        if (mState != STATE_WAITING_FOR_REPORT_FEATURES) {
-            return false;
-        }
-        if (cmd instanceof ReportFeaturesMessage) {
-            return handleReportFeatures((ReportFeaturesMessage) cmd);
-        }
-        return false;
-    }
-
-    private boolean handleReportFeatures(ReportFeaturesMessage cmd) {
-        if (cmd.getSource() == mTargetAddress) {
-            // No need to update the network, since it should already have processed this message.
-            finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
-            return true;
-        }
-        return false;
-    }
-
-    void handleTimerEvent(int state) {
-        finishWithCallback(HdmiControlManager.RESULT_COMMUNICATION_FAILED);
-    }
-}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
index 6497174..185eaa9 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
@@ -19,6 +19,7 @@
 import static com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
 
 import android.annotation.Nullable;
+import android.hardware.hdmi.DeviceFeatures;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiPortInfo;
@@ -512,6 +513,9 @@
         }
 
         switch (message.getOpcode()) {
+            case Constants.MESSAGE_FEATURE_ABORT:
+                handleFeatureAbort(message);
+                break;
             case Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS:
                 handleReportPhysicalAddress(message);
                 break;
@@ -544,6 +548,38 @@
     }
 
     @ServiceThreadOnly
+    private void handleFeatureAbort(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+
+        if (message.getParams().length < 2) {
+            return;
+        }
+
+        int originalOpcode = message.getParams()[0] & 0xFF;
+        int reason = message.getParams()[1] & 0xFF;
+
+         // Check if we received <Feature Abort> in response to <Set Audio Volume Level>.
+         // This provides information on whether the source supports the message.
+        if (originalOpcode == Constants.MESSAGE_SET_AUDIO_VOLUME_LEVEL) {
+
+            @DeviceFeatures.FeatureSupportStatus int featureSupport =
+                    reason == Constants.ABORT_UNRECOGNIZED_OPCODE
+                            ? DeviceFeatures.FEATURE_NOT_SUPPORTED
+                            : DeviceFeatures.FEATURE_SUPPORT_UNKNOWN;
+
+            HdmiDeviceInfo currentDeviceInfo = getCecDeviceInfo(message.getSource());
+            HdmiDeviceInfo newDeviceInfo = currentDeviceInfo.toBuilder()
+                    .updateDeviceFeatures(
+                            currentDeviceInfo.getDeviceFeatures().toBuilder()
+                                    .setSetAudioVolumeLevelSupport(featureSupport)
+                                    .build()
+                    )
+                    .build();
+            updateCecDevice(newDeviceInfo);
+        }
+    }
+
+    @ServiceThreadOnly
     private void handleCecVersion(HdmiCecMessage message) {
         assertRunOnServiceThread();
 
diff --git a/services/core/java/com/android/server/hdmi/SetAudioVolumeLevelDiscoveryAction.java b/services/core/java/com/android/server/hdmi/SetAudioVolumeLevelDiscoveryAction.java
index 5154669..96fd003 100644
--- a/services/core/java/com/android/server/hdmi/SetAudioVolumeLevelDiscoveryAction.java
+++ b/services/core/java/com/android/server/hdmi/SetAudioVolumeLevelDiscoveryAction.java
@@ -16,7 +16,6 @@
 
 package com.android.server.hdmi;
 
-import static android.hardware.hdmi.DeviceFeatures.FEATURE_NOT_SUPPORTED;
 import static android.hardware.hdmi.DeviceFeatures.FEATURE_SUPPORTED;
 
 import static com.android.server.hdmi.Constants.MESSAGE_SET_AUDIO_VOLUME_LEVEL;
@@ -78,13 +77,13 @@
     }
 
     private boolean handleFeatureAbort(HdmiCecMessage cmd) {
+        if (cmd.getParams().length < 2) {
+            return false;
+        }
         int originalOpcode = cmd.getParams()[0] & 0xFF;
         if (originalOpcode == MESSAGE_SET_AUDIO_VOLUME_LEVEL && cmd.getSource() == mTargetAddress) {
-            if (updateAvcSupport(FEATURE_NOT_SUPPORTED)) {
-                finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
-            } else {
-                finishWithCallback(HdmiControlManager.RESULT_EXCEPTION);
-            }
+            // No need to update the network, since it should already have processed this message.
+            finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
             return true;
         }
         return false;
@@ -107,7 +106,7 @@
      */
     private boolean updateAvcSupport(
             @DeviceFeatures.FeatureSupportStatus int setAudioVolumeLevelSupport) {
-        HdmiCecNetwork network = source().mService.getHdmiCecNetwork();
+        HdmiCecNetwork network = localDevice().mService.getHdmiCecNetwork();
         HdmiDeviceInfo currentDeviceInfo = network.getCecDeviceInfo(mTargetAddress);
 
         if (currentDeviceInfo == null) {
diff --git a/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java b/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
index e6fd409..e62c5c1 100644
--- a/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
+++ b/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
@@ -245,4 +245,13 @@
             logRemoteException(e);
         }
     }
+
+    @AnyThread
+    void finishStylusHandwriting() {
+        try {
+            mTarget.finishStylusHandwriting();
+        } catch (RemoteException e) {
+            logRemoteException(e);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index 29dcdfa..a2d3588 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.inputmethodservice.InputMethodService;
 import android.os.IBinder;
 import android.view.inputmethod.InlineSuggestionsRequest;
 import android.view.inputmethod.InputMethodInfo;
@@ -150,6 +151,12 @@
     public abstract void updateImeWindowStatus(boolean disableImeIcon);
 
     /**
+     * Finish stylus handwriting by calling {@link InputMethodService#finishStylusHandwriting()} if
+     * there is an ongoing handwriting session.
+     */
+    public abstract void maybeFinishStylusHandwriting();
+
+    /**
      * Callback when the IInputMethodSession from the accessibility service with the specified
      * accessibilityConnectionId is created.
      *
@@ -239,6 +246,10 @@
                 @Override
                 public void unbindAccessibilityFromCurrentClient(int accessibilityConnectionId) {
                 }
+
+                @Override
+                public void maybeFinishStylusHandwriting() {
+                }
             };
 
     /**
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 77dcbd3..d6131d1 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -49,6 +49,7 @@
 import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
 
 import static com.android.server.inputmethod.InputMethodBindingController.TIME_TO_RECONNECT;
+import static com.android.server.inputmethod.InputMethodUtils.isSoftInputModeStateVisibleAllowed;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
@@ -165,6 +166,7 @@
 import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.os.TransferPipe;
+import com.android.internal.util.ConcurrentUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.view.IInlineSuggestionsRequestCallback;
 import com.android.internal.view.IInlineSuggestionsResponseCallback;
@@ -178,6 +180,7 @@
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
+import com.android.server.SystemServerInitThreadPool;
 import com.android.server.SystemService;
 import com.android.server.inputmethod.InputMethodManagerInternal.InputMethodListListener;
 import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
@@ -187,6 +190,8 @@
 import com.android.server.utils.PriorityDump;
 import com.android.server.wm.WindowManagerInternal;
 
+import com.google.android.collect.Sets;
+
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -201,8 +206,10 @@
 import java.util.Locale;
 import java.util.Objects;
 import java.util.OptionalInt;
+import java.util.Set;
 import java.util.WeakHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Future;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -230,6 +237,7 @@
 
     private static final int MSG_RESET_HANDWRITING = 1090;
     private static final int MSG_START_HANDWRITING = 1100;
+    private static final int MSG_FINISH_HANDWRITING = 1110;
 
     private static final int MSG_UNBIND_CLIENT = 3000;
     private static final int MSG_UNBIND_ACCESSIBILITY_SERVICE = 3001;
@@ -267,6 +275,14 @@
      */
     private final boolean mPreventImeStartupUnlessTextEditor;
 
+    /**
+     * These IMEs are known not to behave well when evicted from memory and thus are exempt
+     * from the IME startup avoidance behavior that is enabled by
+     * {@link #mPreventImeStartupUnlessTextEditor}.
+     */
+    @NonNull
+    private final Set<String> mNonPreemptibleInputMethods;
+
     @UserIdInt
     private int mLastSwitchUserId;
 
@@ -339,6 +355,9 @@
     @GuardedBy("ImfLock.class")
     @Nullable
     private OverlayableSystemBooleanResourceWrapper mImeDrawsImeNavBarRes;
+    @GuardedBy("ImfLock.class")
+    @Nullable
+    Future<?> mImeDrawsImeNavBarResLazyInitFuture;
 
     static class SessionState {
         final ClientState client;
@@ -1692,6 +1711,8 @@
         mBindingController = new InputMethodBindingController(this);
         mPreventImeStartupUnlessTextEditor = mRes.getBoolean(
                 com.android.internal.R.bool.config_preventImeStartupUnlessTextEditor);
+        mNonPreemptibleInputMethods = Sets.newHashSet(mRes.getStringArray(
+                com.android.internal.R.array.config_nonPreemptibleInputMethods));
         mHwController = new HandwritingModeController(thread.getLooper(),
                 new InkWindowInitializer());
     }
@@ -1728,7 +1749,7 @@
     }
 
     @GuardedBy("ImfLock.class")
-    private void recreateImeDrawsImeNavBarResIfNecessary(@UserIdInt int targetUserId) {
+    private void maybeInitImeNavbarConfigLocked(@UserIdInt int targetUserId) {
         // Currently, com.android.internal.R.bool.config_imeDrawsImeNavBar is overlaid only for the
         // profile parent user.
         // TODO(b/221443458): See if we can make OverlayManager be aware of profile groups.
@@ -1772,7 +1793,7 @@
         if (DEBUG) Slog.d(TAG, "Switching user stage 1/3. newUserId=" + newUserId
                 + " currentUserId=" + mSettings.getCurrentUserId());
 
-        recreateImeDrawsImeNavBarResIfNecessary(newUserId);
+        maybeInitImeNavbarConfigLocked(newUserId);
 
         // ContentObserver should be registered again when the user is changed
         mSettingsObserver.registerContentObserverLocked(newUserId);
@@ -1878,7 +1899,22 @@
                     });
                 }
 
-                recreateImeDrawsImeNavBarResIfNecessary(currentUserId);
+                // TODO(b/32343335): The entire systemRunning() method needs to be revisited.
+                mImeDrawsImeNavBarResLazyInitFuture = SystemServerInitThreadPool.submit(() -> {
+                    // Note that the synchronization block below guarantees that the task
+                    // can never be completed before the returned Future<?> object is assigned to
+                    // the "mImeDrawsImeNavBarResLazyInitFuture" field.
+                    synchronized (ImfLock.class) {
+                        mImeDrawsImeNavBarResLazyInitFuture = null;
+                        if (currentUserId != mSettings.getCurrentUserId()) {
+                            // This means that the current user is already switched to other user
+                            // before the background task is executed. In this scenario the relevant
+                            // field should already be initialized.
+                            return;
+                        }
+                        maybeInitImeNavbarConfigLocked(currentUserId);
+                    }
+                }, "Lazily initialize IMMS#mImeDrawsImeNavBarRes");
 
                 mMyPackageMonitor.register(mContext, null, UserHandle.ALL, true);
                 mSettingsObserver.registerContentObserverLocked(currentUserId);
@@ -2548,7 +2584,7 @@
             @StartInputFlags int startInputFlags, @StartInputReason int startInputReason,
             int unverifiedTargetSdkVersion) {
         // If no method is currently selected, do nothing.
-        String selectedMethodId = getSelectedMethodIdLocked();
+        final String selectedMethodId = getSelectedMethodIdLocked();
         if (selectedMethodId == null) {
             return InputBindResult.NO_IME;
         }
@@ -2592,10 +2628,8 @@
         mCurAttribute = attribute;
 
         // If configured, we want to avoid starting up the IME if it is not supposed to be showing
-        if (mPreventImeStartupUnlessTextEditor
-                && !InputMethodUtils.isSoftInputModeStateVisibleAllowed(unverifiedTargetSdkVersion,
-                startInputFlags)
-                && !mShowRequested) {
+        if (shouldPreventImeStartupLocked(selectedMethodId, startInputFlags,
+                unverifiedTargetSdkVersion)) {
             if (DEBUG) {
                 Slog.d(TAG, "Avoiding IME startup and unbinding current input method.");
             }
@@ -2637,6 +2671,34 @@
     }
 
     @GuardedBy("ImfLock.class")
+    private boolean shouldPreventImeStartupLocked(
+            @NonNull String selectedMethodId,
+            @StartInputFlags int startInputFlags,
+            int unverifiedTargetSdkVersion) {
+        // Fast-path for the majority of cases
+        if (!mPreventImeStartupUnlessTextEditor) {
+            return false;
+        }
+
+        final boolean imeVisibleAllowed =
+                isSoftInputModeStateVisibleAllowed(unverifiedTargetSdkVersion, startInputFlags);
+
+        return !(imeVisibleAllowed
+                || mShowRequested
+                || isNonPreemptibleImeLocked(selectedMethodId));
+    }
+
+    /** Return {@code true} if the given IME is non-preemptible like the tv remote service. */
+    @GuardedBy("ImfLock.class")
+    private boolean isNonPreemptibleImeLocked(@NonNull  String selectedMethodId) {
+        final InputMethodInfo imi = mMethodMap.get(selectedMethodId);
+        if (imi != null) {
+            return mNonPreemptibleInputMethods.contains(imi.getPackageName());
+        }
+        return false;
+    }
+
+    @GuardedBy("ImfLock.class")
     private boolean isSelectedMethodBoundLocked() {
         String curId = getCurIdLocked();
         return curId != null && curId.equals(getSelectedMethodIdLocked())
@@ -2988,6 +3050,11 @@
     @GuardedBy("ImfLock.class")
     @InputMethodNavButtonFlags
     private int getInputMethodNavButtonFlagsLocked() {
+        if (mImeDrawsImeNavBarResLazyInitFuture != null) {
+            // TODO(b/225366708): Avoid Future.get(), which is internally used here.
+            ConcurrentUtils.waitForFutureNoInterrupt(mImeDrawsImeNavBarResLazyInitFuture,
+                    "Waiting for the lazy init of mImeDrawsImeNavBarRes");
+        }
         final boolean canImeDrawsImeNavBar =
                 mImeDrawsImeNavBarRes != null && mImeDrawsImeNavBarRes.get();
         final boolean shouldShowImeSwitcherWhenImeIsShown = shouldShowImeSwitcherLocked(
@@ -3826,7 +3893,7 @@
             case LayoutParams.SOFT_INPUT_STATE_VISIBLE:
                 if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
                     if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
-                    if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
+                    if (isSoftInputModeStateVisibleAllowed(
                             unverifiedTargetSdkVersion, startInputFlags)) {
                         if (attribute != null) {
                             res = startInputUncheckedLocked(cs, inputContext, attribute,
@@ -3844,7 +3911,7 @@
                 break;
             case LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
                 if (DEBUG) Slog.v(TAG, "Window asks to always show input");
-                if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
+                if (isSoftInputModeStateVisibleAllowed(
                         unverifiedTargetSdkVersion, startInputFlags)) {
                     if (!sameWindowFocused) {
                         if (attribute != null) {
@@ -4430,7 +4497,7 @@
     }
 
     @BinderThread
-    private void finishStylusHandwriting(int requestId) {
+    private void resetStylusHandwriting(int requestId) {
         synchronized (ImfLock.class) {
             final OptionalInt curRequest = mHwController.getCurrentRequestId();
             if (!curRequest.isPresent() || curRequest.getAsInt() != requestId) {
@@ -4797,6 +4864,14 @@
                     }
                 }
                 return true;
+            case MSG_FINISH_HANDWRITING:
+                synchronized (ImfLock.class) {
+                    IInputMethodInvoker curMethod = getCurMethodLocked();
+                    if (curMethod != null && mHwController.getCurrentRequestId().isPresent()) {
+                        curMethod.finishStylusHandwriting();
+                    }
+                }
+                return true;
         }
         return false;
     }
@@ -5435,6 +5510,12 @@
                 }
             }
         }
+
+        @Override
+        public void maybeFinishStylusHandwriting() {
+            mHandler.removeMessages(MSG_FINISH_HANDWRITING);
+            mHandler.obtainMessage(MSG_FINISH_HANDWRITING).sendToTarget();
+        }
     }
 
     @BinderThread
@@ -6388,8 +6469,8 @@
 
         @BinderThread
         @Override
-        public void finishStylusHandwriting(int requestId) {
-            mImms.finishStylusHandwriting(requestId);
+        public void resetStylusHandwriting(int requestId) {
+            mImms.resetStylusHandwriting(requestId);
         }
     }
 }
diff --git a/services/core/java/com/android/server/locales/LocaleManagerService.java b/services/core/java/com/android/server/locales/LocaleManagerService.java
index 176c08c..924db6a 100644
--- a/services/core/java/com/android/server/locales/LocaleManagerService.java
+++ b/services/core/java/com/android/server/locales/LocaleManagerService.java
@@ -22,12 +22,14 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.ILocaleManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
+import android.content.res.Configuration;
 import android.os.Binder;
 import android.os.HandlerThread;
 import android.os.LocaleList;
@@ -154,6 +156,12 @@
         }
 
         @Override
+        @NonNull
+        public LocaleList getSystemLocales() throws RemoteException {
+            return LocaleManagerService.this.getSystemLocales();
+        }
+
+        @Override
         public void onShellCommand(FileDescriptor in, FileDescriptor out,
                 FileDescriptor err, String[] args, ShellCallback callback,
                 ResultReceiver resultReceiver) {
@@ -426,6 +434,32 @@
         return null;
     }
 
+    /**
+     * Returns the current system locales.
+     */
+    @NonNull
+    public LocaleList getSystemLocales() throws RemoteException {
+        final long token = Binder.clearCallingIdentity();
+        try {
+            return getSystemLocalesUnchecked();
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    @NonNull
+    private LocaleList getSystemLocalesUnchecked() throws RemoteException {
+        LocaleList systemLocales = null;
+        Configuration conf = ActivityManager.getService().getConfiguration();
+        if (conf != null) {
+            systemLocales = conf.getLocales();
+        }
+        if (systemLocales == null) {
+            systemLocales = LocaleList.getEmptyLocaleList();
+        }
+        return systemLocales;
+    }
+
     private void logMetric(@NonNull AppLocaleChangedAtomRecord atomRecordForMetrics) {
         FrameworkStatsLog.write(FrameworkStatsLog.APPLICATION_LOCALES_CHANGED,
                 atomRecordForMetrics.mCallingUid,
diff --git a/services/core/java/com/android/server/locales/TEST_MAPPING b/services/core/java/com/android/server/locales/TEST_MAPPING
index 27d2851..160542b 100644
--- a/services/core/java/com/android/server/locales/TEST_MAPPING
+++ b/services/core/java/com/android/server/locales/TEST_MAPPING
@@ -9,10 +9,13 @@
       ]
     },
     {
-      "name": "CtsLocaleManagerTestCases"
-    },
-    {
       "name": "CtsLocaleManagerHostTestCases"
     }
+  ],
+  "postsubmit": [
+    // TODO(b/225192026): Move back to presubmit after b/225192026 is fixed
+    {
+      "name": "CtsLocaleManagerTestCases"
+    }
   ]
 }
diff --git a/services/core/java/com/android/server/location/LocationPermissions.java b/services/core/java/com/android/server/location/LocationPermissions.java
index be702d9..ca2ff60 100644
--- a/services/core/java/com/android/server/location/LocationPermissions.java
+++ b/services/core/java/com/android/server/location/LocationPermissions.java
@@ -19,7 +19,6 @@
 import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
 import static android.Manifest.permission.ACCESS_FINE_LOCATION;
 import static android.Manifest.permission.LOCATION_BYPASS;
-import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
 import android.annotation.IntDef;
@@ -134,15 +133,11 @@
      * perissions.
      */
     public static void enforceBypassPermission(Context context, int uid, int pid) {
-        if (context.checkPermission(WRITE_SECURE_SETTINGS, pid, uid) == PERMISSION_GRANTED) {
-            // TODO: disallow WRITE_SECURE_SETTINGS permission.
-            return;
-        }
         if (context.checkPermission(LOCATION_BYPASS, pid, uid) == PERMISSION_GRANTED) {
             return;
         }
         throw new SecurityException("uid" + uid + " does not have " + LOCATION_BYPASS
-                + "or " + WRITE_SECURE_SETTINGS + ".");
+                + ".");
     }
 
     /**
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index cd2ba39..8407a11 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -1184,6 +1184,7 @@
                 mAlarmManager.cancel(mBatchingAlarm);
                 mBatchingAlarm = null;
             }
+            mGnssNative.flushBatch();
             mGnssNative.stopBatch();
             mBatchingStarted = false;
         }
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 3db11d8..135af2d 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -252,8 +252,6 @@
 
     private final RebootEscrowManager mRebootEscrowManager;
 
-    private boolean mFirstCallToVold;
-
     // Current password metric for all users on the device. Updated when user unlocks
     // the device or changes password. Removed when user is stopped.
     @GuardedBy("this")
@@ -373,7 +371,7 @@
             LockscreenCredential profileUserPassword) {
         if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + profileUserId);
         // Only for profiles that shares credential with parent
-        if (!isCredentialSharedWithParent(profileUserId)) {
+        if (!isCredentialSharableWithParent(profileUserId)) {
             return;
         }
         // Do not tie profile when work challenge is enabled
@@ -597,8 +595,6 @@
         mStrongAuth = injector.getStrongAuth();
         mActivityManager = injector.getActivityManager();
 
-        mFirstCallToVold = true;
-
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_USER_ADDED);
         filter.addAction(Intent.ACTION_USER_STARTING);
@@ -689,19 +685,19 @@
     }
 
     private String getEncryptionNotificationTitle() {
-        return mInjector.getDevicePolicyManager().getString(
+        return mInjector.getDevicePolicyManager().getResources().getString(
                 PROFILE_ENCRYPTED_TITLE,
                 () -> mContext.getString(R.string.profile_encrypted_title));
     }
 
     private String getEncryptionNotificationDetail() {
-        return mInjector.getDevicePolicyManager().getString(
+        return mInjector.getDevicePolicyManager().getResources().getString(
                 PROFILE_ENCRYPTED_DETAIL,
                 () -> mContext.getString(R.string.profile_encrypted_detail));
     }
 
     private String getEncryptionNotificationMessage() {
-        return mInjector.getDevicePolicyManager().getString(
+        return mInjector.getDevicePolicyManager().getResources().getString(
                 PROFILE_ENCRYPTED_MESSAGE,
                 () -> mContext.getString(R.string.profile_encrypted_message));
     }
@@ -789,7 +785,7 @@
     private void ensureProfileKeystoreUnlocked(int userId) {
         final KeyStore ks = KeyStore.getInstance();
         if (ks.state(userId) == KeyStore.State.LOCKED
-                && isCredentialSharedWithParent(userId)
+                && isCredentialSharableWithParent(userId)
                 && hasUnifiedChallenge(userId)) {
             Slog.i(TAG, "Profile got unlocked, will unlock its keystore");
             // If boot took too long and the password in vold got expired, parent keystore will
@@ -810,7 +806,7 @@
                 // Hide notification first, as tie managed profile lock takes time
                 hideEncryptionNotification(new UserHandle(userId));
 
-                if (isCredentialSharedWithParent(userId)) {
+                if (isCredentialSharableWithParent(userId)) {
                     tieProfileLockIfNecessary(userId, LockscreenCredential.createNone());
                 }
 
@@ -1077,7 +1073,7 @@
         final int userCount = users.size();
         for (int i = 0; i < userCount; i++) {
             UserInfo user = users.get(i);
-            if (isCredentialSharedWithParent(user.id)
+            if (isCredentialSharableWithParent(user.id)
                     && !getSeparateProfileChallengeEnabledInternal(user.id)) {
                 success &= SyntheticPasswordCrypto.migrateLockSettingsKey(
                         PROFILE_KEY_NAME_ENCRYPT + user.id);
@@ -1471,7 +1467,7 @@
             Thread.currentThread().interrupt();
         }
 
-        if (isCredentialSharedWithParent(userId)) {
+        if (isCredentialSharableWithParent(userId)) {
             if (!hasUnifiedChallenge(userId)) {
                 mBiometricDeferredQueue.processPendingLockoutResets();
             }
@@ -1480,7 +1476,7 @@
 
         for (UserInfo profile : mUserManager.getProfiles(userId)) {
             if (profile.id == userId) continue;
-            if (!isCredentialSharedWithParent(profile.id)) continue;
+            if (!isCredentialSharableWithParent(profile.id)) continue;
 
             if (hasUnifiedChallenge(profile.id)) {
                 if (mUserManager.isUserRunning(profile.id)) {
@@ -1517,7 +1513,7 @@
     }
 
     private Map<Integer, LockscreenCredential> getDecryptedPasswordsForAllTiedProfiles(int userId) {
-        if (isCredentialSharedWithParent(userId)) {
+        if (isCredentialSharableWithParent(userId)) {
             return null;
         }
         Map<Integer, LockscreenCredential> result = new ArrayMap<>();
@@ -1525,7 +1521,7 @@
         final int size = profiles.size();
         for (int i = 0; i < size; i++) {
             final UserInfo profile = profiles.get(i);
-            if (!isCredentialSharedWithParent(profile.id)) {
+            if (!isCredentialSharableWithParent(profile.id)) {
                 continue;
             }
             final int profileUserId = profile.id;
@@ -1560,7 +1556,7 @@
      */
     private void synchronizeUnifiedWorkChallengeForProfiles(int userId,
             Map<Integer, LockscreenCredential> profilePasswordMap) {
-        if (isCredentialSharedWithParent(userId)) {
+        if (isCredentialSharableWithParent(userId)) {
             return;
         }
         final boolean isSecure = isUserSecure(userId);
@@ -1569,7 +1565,7 @@
         for (int i = 0; i < size; i++) {
             final UserInfo profile = profiles.get(i);
             final int profileUserId = profile.id;
-            if (isCredentialSharedWithParent(profileUserId)) {
+            if (isCredentialSharableWithParent(profileUserId)) {
                 if (getSeparateProfileChallengeEnabledInternal(profileUserId)) {
                     continue;
                 }
@@ -1596,12 +1592,12 @@
     }
 
     private boolean isProfileWithUnifiedLock(int userId) {
-        return isCredentialSharedWithParent(userId)
+        return isCredentialSharableWithParent(userId)
                 && !getSeparateProfileChallengeEnabledInternal(userId);
     }
 
     private boolean isProfileWithSeparatedLock(int userId) {
-        return isCredentialSharedWithParent(userId)
+        return isCredentialSharableWithParent(userId)
                 && getSeparateProfileChallengeEnabledInternal(userId);
     }
 
@@ -1719,7 +1715,7 @@
                 setSeparateProfileChallengeEnabledLocked(userId, true, /* unused */ null);
                 notifyPasswordChanged(credential, userId);
             }
-            if (isCredentialSharedWithParent(userId)) {
+            if (isCredentialSharableWithParent(userId)) {
                 // Make sure the profile doesn't get locked straight after setting work challenge.
                 setDeviceUnlockedForUser(userId);
             }
@@ -1734,7 +1730,7 @@
 
     /**
      * @param savedCredential if the user is a profile with
-     * {@link UserManager#isCredentialSharedWithParent()} with unified challenge and
+     * {@link UserManager#isCredentialSharableWithParent()} with unified challenge and
      *   savedCredential is empty, LSS will try to re-derive the profile password internally.
      *     TODO (b/80170828): Fix this so profile password is always passed in.
      * @param isLockTiedToParent is {@code true} if {@code userId} is a profile and its new
@@ -1910,8 +1906,8 @@
         }
     }
 
-    protected boolean isCredentialSharedWithParent(int userId) {
-        return getUserManagerFromCache(userId).isCredentialSharedWithParent();
+    protected boolean isCredentialSharableWithParent(int userId) {
+        return getUserManagerFromCache(userId).isCredentialSharableWithParent();
     }
 
     private VerifyCredentialResponse convertResponse(GateKeeperResponse gateKeeperResponse) {
@@ -2161,7 +2157,7 @@
         final List<UserInfo> profiles = mUserManager.getProfiles(userId);
         for (UserInfo pi : profiles) {
             // Unlock profile which shares credential with parent with unified lock
-            if (isCredentialSharedWithParent(pi.id)
+            if (isCredentialSharableWithParent(pi.id)
                     && !getSeparateProfileChallengeEnabledInternal(pi.id)
                     && mStorage.hasChildProfileLock(pi.id)) {
                 try {
@@ -2474,77 +2470,6 @@
         });
     }
 
-    private LockscreenCredential createPattern(String patternString) {
-        final byte[] patternBytes = patternString.getBytes();
-        LockscreenCredential pattern = LockscreenCredential.createPattern(
-                LockPatternUtils.byteArrayToPattern(patternBytes));
-        Arrays.fill(patternBytes, (byte) 0);
-        return pattern;
-    }
-
-    @Override
-    public boolean checkVoldPassword(int userId) {
-        if (!mFirstCallToVold) {
-            return false;
-        }
-        mFirstCallToVold = false;
-
-        checkPasswordReadPermission();
-
-        // There's no guarantee that this will safely connect, but if it fails
-        // we will simply show the lock screen when we shouldn't, so relatively
-        // benign. There is an outside chance something nasty would happen if
-        // this service restarted before vold stales out the password in this
-        // case. The nastiness is limited to not showing the lock screen when
-        // we should, within the first minute of decrypting the phone if this
-        // service can't connect to vold, it restarts, and then the new instance
-        // does successfully connect.
-        final IStorageManager service = mInjector.getStorageManager();
-        // TODO(b/120484642): Update vold to return a password as a byte array
-        String password;
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            password = service.getPassword();
-            service.clearPassword();
-        } catch (RemoteException e) {
-            Slog.w(TAG, "vold getPassword() failed", e);
-            return false;
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-        if (TextUtils.isEmpty(password)) {
-            return false;
-        }
-
-        try {
-            final LockscreenCredential credential;
-            switch (getCredentialTypeInternal(userId)) {
-                case CREDENTIAL_TYPE_PATTERN:
-                    credential = createPattern(password);
-                    break;
-                case CREDENTIAL_TYPE_PIN:
-                    credential = LockscreenCredential.createPin(password);
-                    break;
-                case CREDENTIAL_TYPE_PASSWORD:
-                    credential = LockscreenCredential.createPassword(password);
-                    break;
-                default:
-                    credential = null;
-                    Slog.e(TAG, "Unknown credential type");
-            }
-
-            if (credential != null
-                    && checkCredential(credential, userId, null /* progressCallback */)
-                                .getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
-                return true;
-            }
-        } catch (Exception e) {
-            Slog.e(TAG, "checkVoldPassword failed: ", e);
-        }
-
-        return false;
-    }
-
     private void removeUser(int userId, boolean unknownUser) {
         Slog.i(TAG, "RemoveUser: " + userId);
         removeBiometricsForUser(userId);
@@ -2555,7 +2480,7 @@
         mManagedProfilePasswordCache.removePassword(userId);
 
         gateKeeperClearSecureUserId(userId);
-        if (unknownUser || isCredentialSharedWithParent(userId)) {
+        if (unknownUser || isCredentialSharableWithParent(userId)) {
             removeKeystoreProfileKey(userId);
         }
         // Clean up storage last, this is to ensure that cleanupDataForReusedUserIdIfNecessary()
@@ -3275,7 +3200,7 @@
      * Returns a fixed pseudorandom byte string derived from the user's synthetic password.
      * This is used to salt the password history hash to protect the hash against offline
      * bruteforcing, since rederiving this value requires a successful authentication.
-     * If user is a profile with {@link UserManager#isCredentialSharedWithParent()} true and with
+     * If user is a profile with {@link UserManager#isCredentialSharableWithParent()} true and with
      * unified challenge, currentCredential is ignored.
      */
     @Override
diff --git a/services/core/java/com/android/server/logcat/LogAccessDialogActivity.java b/services/core/java/com/android/server/logcat/LogAccessDialogActivity.java
index 7116ca3..8be90e0c 100644
--- a/services/core/java/com/android/server/logcat/LogAccessDialogActivity.java
+++ b/services/core/java/com/android/server/logcat/LogAccessDialogActivity.java
@@ -22,6 +22,7 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.RemoteException;
@@ -56,7 +57,7 @@
     private AlertDialog.Builder mAlertDialog;
     private AlertDialog mAlert;
 
-    private static final int DIALOG_TIME_OUT = 300000;
+    private static final int DIALOG_TIME_OUT = Build.IS_DEBUGGABLE ? 60000 : 300000;
     private static final int MSG_DISMISS_DIALOG = 0;
 
 
diff --git a/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java b/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java
index 1ae7ac0..df612e6 100644
--- a/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java
+++ b/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.media.MediaMetrics;
+import android.media.metrics.BundleSession;
 import android.media.metrics.IMediaMetricsManager;
 import android.media.metrics.NetworkEvent;
 import android.media.metrics.PlaybackErrorEvent;
@@ -187,11 +188,33 @@
                 return;
             }
 
-            int atomid = metrics.getInt("KEY_STATSD_ATOM_NUMBER");
+            int atomid = metrics.getInt(BundleSession.KEY_STATSD_ATOM);
             switch (atomid) {
                 default:
                     return;
                 // to be extended as we define statsd atoms
+                case 322: // MediaPlaybackStateEvent
+                    // pattern for the keys:
+                    // <statsd event> - <fieldname>
+                    // match types to what stats will want
+                    String _sessionId = metrics.getString("playbackstateevent-sessionid");
+                    int _state = metrics.getInt("playbackstateevent-state", -1);
+                    long _lifetime = metrics.getLong("playbackstateevent-lifetime", -1);
+                    if (_sessionId == null || _state < 0 || _lifetime < 0) {
+                        Slog.d(TAG, "dropping incomplete data for atom 322: _sessionId: "
+                                        + _sessionId + " _state: " + _state
+                                        + " _lifetime: " + _lifetime);
+                        return;
+                    }
+                    StatsEvent statsEvent = StatsEvent.newBuilder()
+                            .setAtomId(322)
+                            .writeString(_sessionId)
+                            .writeInt(_state)
+                            .writeLong(_lifetime)
+                            .usePooledBuffer()
+                            .build();
+                    StatsLog.write(statsEvent);
+                    return;
             }
         }
 
@@ -227,6 +250,13 @@
         }
 
         @Override
+        public void releaseSessionId(String sessionId, int userId) {
+            // De-authorize this session-id in the native mediametrics service.
+            // TODO: plumbing to the native mediametrics service
+            Slog.v(TAG, "Releasing sessionId " + sessionId + " for userId " + userId + " [NOP]");
+        }
+
+        @Override
         public String getPlaybackSessionId(int userId) {
             return getSessionIdInternal(userId);
         }
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 3ce8e46..1937852 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -45,6 +45,7 @@
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.Slog;
+import android.window.WindowContainerToken;
 
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
@@ -410,6 +411,7 @@
         private IBinder mToken;
         private IBinder.DeathRecipient mDeathEater;
         private boolean mRestoreSystemAlertWindow;
+        private WindowContainerToken mTaskRecordingWindowContainerToken = null;
 
         MediaProjection(int type, int uid, String packageName, int targetSdkVersion,
                 boolean isPrivileged) {
@@ -568,7 +570,7 @@
             }
         }
 
-        @Override
+        @Override // Binder call
         public void registerCallback(IMediaProjectionCallback callback) {
             if (callback == null) {
                 throw new IllegalArgumentException("callback must not be null");
@@ -576,7 +578,7 @@
             mCallbackDelegate.add(callback);
         }
 
-        @Override
+        @Override // Binder call
         public void unregisterCallback(IMediaProjectionCallback callback) {
             if (callback == null) {
                 throw new IllegalArgumentException("callback must not be null");
@@ -584,6 +586,17 @@
             mCallbackDelegate.remove(callback);
         }
 
+        @Override // Binder call
+        public void setTaskRecordingWindowContainerToken(WindowContainerToken token) {
+            // TODO(b/221417940) set the task id to record from sysui, for the package chosen.
+            mTaskRecordingWindowContainerToken = token;
+        }
+
+        @Override // Binder call
+        public WindowContainerToken getTaskRecordingWindowContainerToken() {
+            return mTaskRecordingWindowContainerToken;
+        }
+
         public MediaProjectionInfo getProjectionInfo() {
             return new MediaProjectionInfo(packageName, userHandle);
         }
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 9f573c2..953b6ae 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -26,6 +26,8 @@
 import static android.Manifest.permission.OBSERVE_NETWORK_POLICY;
 import static android.Manifest.permission.READ_PHONE_STATE;
 import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
+import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
+import static android.app.ActivityManager.isProcStateConsideredInteraction;
 import static android.app.PendingIntent.FLAG_IMMUTABLE;
 import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
 import static android.content.Intent.ACTION_PACKAGE_ADDED;
@@ -90,6 +92,8 @@
 import static android.net.NetworkPolicyManager.RULE_REJECT_RESTRICTED_MODE;
 import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
 import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED;
+import static android.net.NetworkPolicyManager.allowedReasonsToString;
+import static android.net.NetworkPolicyManager.blockedReasonsToString;
 import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode;
 import static android.net.NetworkPolicyManager.isProcStateAllowedWhileInLowPowerStandby;
 import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground;
@@ -160,6 +164,7 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.database.ContentObserver;
@@ -594,7 +599,7 @@
     @GuardedBy("mUidRulesFirstLock")
     private final SparseArray<UidState> mUidState = new SparseArray<>();
 
-    @GuardedBy("mUidRulesFirstLock")
+    @GuardedBy("mUidBlockedState")
     private final SparseArray<UidBlockedState> mUidBlockedState = new SparseArray<>();
 
     /** Objects used temporarily while computing the new blocked state for each uid. */
@@ -3930,7 +3935,9 @@
 
                 final SparseBooleanArray knownUids = new SparseBooleanArray();
                 collectKeys(mUidState, knownUids);
-                collectKeys(mUidBlockedState, knownUids);
+                synchronized (mUidBlockedState) {
+                    collectKeys(mUidBlockedState, knownUids);
+                }
 
                 fout.println("Status for all known UIDs:");
                 fout.increaseIndent();
@@ -3948,12 +3955,14 @@
                         fout.print(uidState.toString());
                     }
 
-                    final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
-                    if (uidBlockedState == null) {
-                        fout.print(" blocked_state={null}");
-                    } else {
-                        fout.print(" blocked_state=");
-                        fout.print(uidBlockedState.toString());
+                    synchronized (mUidBlockedState) {
+                        final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
+                        if (uidBlockedState == null) {
+                            fout.print(" blocked_state={null}");
+                        } else {
+                            fout.print(" blocked_state=");
+                            fout.print(uidBlockedState);
+                        }
                     }
                     fout.println();
                 }
@@ -4035,14 +4044,14 @@
                         isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState)
                                 != isProcStateAllowedWhileIdleOrPowerSaveMode(newUidState);
                 if (allowedWhileIdleOrPowerSaveModeChanged) {
-                    updateRuleForAppIdleUL(uid);
+                    updateRuleForAppIdleUL(uid, procState);
                     if (mDeviceIdleMode) {
                         updateRuleForDeviceIdleUL(uid);
                     }
                     if (mRestrictPower) {
                         updateRuleForRestrictPowerUL(uid);
                     }
-                    updateRulesForPowerRestrictionsUL(uid);
+                    updateRulesForPowerRestrictionsUL(uid, procState);
                 }
                 if (mLowPowerStandbyActive) {
                     boolean allowedInLpsChanged =
@@ -4050,7 +4059,7 @@
                                     != isProcStateAllowedWhileInLowPowerStandby(newUidState);
                     if (allowedInLpsChanged) {
                         if (!allowedWhileIdleOrPowerSaveModeChanged) {
-                            updateRulesForPowerRestrictionsUL(uid);
+                            updateRulesForPowerRestrictionsUL(uid, procState);
                         }
                         updateRuleForLowPowerStandbyUL(uid);
                     }
@@ -4094,7 +4103,7 @@
                     "updateNetworkStats: " + uid + "/" + (uidForeground ? "F" : "B"));
         }
         try {
-            mNetworkStats.setUidForeground(uid, uidForeground);
+            mNetworkStats.noteUidForeground(uid, uidForeground);
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
         }
@@ -4128,9 +4137,9 @@
         mUidFirewallRestrictedModeRules.clear();
         forEachUid("updateRestrictedModeAllowlist", uid -> {
             synchronized (mUidRulesFirstLock) {
-                final UidBlockedState uidBlockedState = updateBlockedReasonsForRestrictedModeUL(
+                final int effectiveBlockedReasons = updateBlockedReasonsForRestrictedModeUL(
                         uid);
-                final int newFirewallRule = getRestrictedModeFirewallRule(uidBlockedState);
+                final int newFirewallRule = getRestrictedModeFirewallRule(effectiveBlockedReasons);
 
                 // setUidFirewallRulesUL will allowlist all uids that are passed to it, so only add
                 // non-default rules.
@@ -4150,7 +4159,7 @@
     @VisibleForTesting
     @GuardedBy("mUidRulesFirstLock")
     void updateRestrictedModeForUidUL(int uid) {
-        final UidBlockedState uidBlockedState = updateBlockedReasonsForRestrictedModeUL(uid);
+        final int effectiveBlockedReasons = updateBlockedReasonsForRestrictedModeUL(uid);
 
         // if restricted networking mode is on, and the app has an access exemption, the uid rule
         // will not change, but the firewall rule will have to be updated.
@@ -4158,37 +4167,48 @@
             // Note: setUidFirewallRule also updates mUidFirewallRestrictedModeRules.
             // In this case, default firewall rules can also be added.
             setUidFirewallRuleUL(FIREWALL_CHAIN_RESTRICTED, uid,
-                    getRestrictedModeFirewallRule(uidBlockedState));
+                    getRestrictedModeFirewallRule(effectiveBlockedReasons));
         }
     }
 
     @GuardedBy("mUidRulesFirstLock")
-    private UidBlockedState updateBlockedReasonsForRestrictedModeUL(int uid) {
-        final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
-                mUidBlockedState, uid);
-        final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
-        if (mRestrictedNetworkingMode) {
-            uidBlockedState.blockedReasons |= BLOCKED_REASON_RESTRICTED_MODE;
-        } else {
-            uidBlockedState.blockedReasons &= ~BLOCKED_REASON_RESTRICTED_MODE;
-        }
-        if (hasRestrictedModeAccess(uid)) {
-            uidBlockedState.allowedReasons |= ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
-        } else {
-            uidBlockedState.allowedReasons &= ~ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
-        }
-        uidBlockedState.updateEffectiveBlockedReasons();
-        if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) {
-            postBlockedReasonsChangedMsg(uid,
-                    uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons);
+    private int updateBlockedReasonsForRestrictedModeUL(int uid) {
+        final boolean hasRestrictedModeAccess = hasRestrictedModeAccess(uid);
+        final int oldEffectiveBlockedReasons;
+        final int newEffectiveBlockedReasons;
+        final int uidRules;
+        synchronized (mUidBlockedState) {
+            final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
+                    mUidBlockedState, uid);
+            oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+            if (mRestrictedNetworkingMode) {
+                uidBlockedState.blockedReasons |= BLOCKED_REASON_RESTRICTED_MODE;
+            } else {
+                uidBlockedState.blockedReasons &= ~BLOCKED_REASON_RESTRICTED_MODE;
+            }
+            if (hasRestrictedModeAccess) {
+                uidBlockedState.allowedReasons |= ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
+            } else {
+                uidBlockedState.allowedReasons &= ~ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
+            }
+            uidBlockedState.updateEffectiveBlockedReasons();
 
-            postUidRulesChangedMsg(uid, uidBlockedState.deriveUidRules());
+            newEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+            uidRules = oldEffectiveBlockedReasons == newEffectiveBlockedReasons
+                    ? RULE_NONE
+                    : uidBlockedState.deriveUidRules();
         }
-        return uidBlockedState;
+        if (oldEffectiveBlockedReasons != newEffectiveBlockedReasons) {
+            postBlockedReasonsChangedMsg(uid,
+                    newEffectiveBlockedReasons, oldEffectiveBlockedReasons);
+
+            postUidRulesChangedMsg(uid, uidRules);
+        }
+        return newEffectiveBlockedReasons;
     }
 
-    private static int getRestrictedModeFirewallRule(UidBlockedState uidBlockedState) {
-        if ((uidBlockedState.effectiveBlockedReasons & BLOCKED_REASON_RESTRICTED_MODE) != 0) {
+    private static int getRestrictedModeFirewallRule(int effectiveBlockedReasons) {
+        if ((effectiveBlockedReasons & BLOCKED_REASON_RESTRICTED_MODE) != 0) {
             // rejected in restricted mode, this is the default behavior.
             return FIREWALL_RULE_DEFAULT;
         } else {
@@ -4292,12 +4312,10 @@
                 mUidFirewallLowPowerStandbyModeRules.clear();
                 for (int i = mUidState.size() - 1; i >= 0; i--) {
                     final int uid = mUidState.keyAt(i);
-                    UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
-                    if (hasInternetPermissionUL(uid) && uidBlockedState != null
-                            && (uidBlockedState.effectiveBlockedReasons
+                    final int effectiveBlockedReasons = getEffectiveBlockedReasons(uid);
+                    if (hasInternetPermissionUL(uid) && (effectiveBlockedReasons
                                     & BLOCKED_REASON_LOW_POWER_STANDBY) == 0) {
-                        mUidFirewallLowPowerStandbyModeRules.put(mUidBlockedState.keyAt(i),
-                                FIREWALL_RULE_ALLOW);
+                        mUidFirewallLowPowerStandbyModeRules.put(uid, FIREWALL_RULE_ALLOW);
                     }
                 }
                 setUidFirewallRulesUL(FIREWALL_CHAIN_LOW_POWER_STANDBY,
@@ -4316,10 +4334,9 @@
             return;
         }
 
-        final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
-        if (mUidState.contains(uid) && uidBlockedState != null
-                && (uidBlockedState.effectiveBlockedReasons & BLOCKED_REASON_LOW_POWER_STANDBY)
-                == 0) {
+        final int effectiveBlockedReasons = getEffectiveBlockedReasons(uid);
+        if (mUidState.contains(uid)
+                && (effectiveBlockedReasons & BLOCKED_REASON_LOW_POWER_STANDBY) == 0) {
             mUidFirewallLowPowerStandbyModeRules.put(uid, FIREWALL_RULE_ALLOW);
             setUidFirewallRuleUL(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid, FIREWALL_RULE_ALLOW);
         } else {
@@ -4411,7 +4428,7 @@
     }
 
     @GuardedBy("mUidRulesFirstLock")
-    void updateRuleForAppIdleUL(int uid) {
+    void updateRuleForAppIdleUL(int uid, int uidProcessState) {
         if (!isUidValidForDenylistRulesUL(uid)) return;
 
         if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) {
@@ -4419,7 +4436,7 @@
         }
         try {
             int appId = UserHandle.getAppId(uid);
-            if (!mPowerSaveTempWhitelistAppIds.get(appId) && isUidIdle(uid)
+            if (!mPowerSaveTempWhitelistAppIds.get(appId) && isUidIdle(uid, uidProcessState)
                     && !isUidForegroundOnRestrictPowerUL(uid)) {
                 setUidFirewallRuleUL(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DENY);
                 if (LOGD) Log.d(TAG, "updateRuleForAppIdleUL DENY " + uid);
@@ -4448,9 +4465,8 @@
             if (!isUidValidForDenylistRulesUL(uid)) {
                 continue;
             }
-            final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
-                    mUidBlockedState, uid);
-            if (!enableChain && (uidBlockedState.blockedReasons & ~BLOCKED_METERED_REASON_MASK)
+            final int blockedReasons = getBlockedReasons(uid);
+            if (!enableChain && (blockedReasons & ~BLOCKED_METERED_REASON_MASK)
                     == BLOCKED_REASON_NONE) {
                 // Chain isn't enabled and the uid had no restrictions to begin with.
                 continue;
@@ -4526,9 +4542,7 @@
         }
         try {
             // update rules for all installed applications
-            final PackageManager pm = mContext.getPackageManager();
             final List<UserInfo> users;
-            final List<ApplicationInfo> apps;
 
             Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "list-users");
             try {
@@ -4536,26 +4550,30 @@
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
             }
-            Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "list-uids");
+            Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "iterate-uids");
             try {
-                apps = pm.getInstalledApplications(
-                        PackageManager.MATCH_ANY_USER | PackageManager.MATCH_DISABLED_COMPONENTS
-                                | PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
+                final PackageManagerInternal packageManagerInternal = LocalServices.getService(
+                        PackageManagerInternal.class);
+                final int usersSize = users.size();
+                for (int i = 0; i < usersSize; ++i) {
+                    final int userId = users.get(i).id;
+                    final SparseBooleanArray sharedAppIdsHandled = new SparseBooleanArray();
+                    packageManagerInternal.forEachInstalledPackage(androidPackage -> {
+                        final int appId = androidPackage.getUid();
+                        if (androidPackage.getSharedUserId() != null) {
+                            if (sharedAppIdsHandled.indexOfKey(appId) < 0) {
+                                sharedAppIdsHandled.put(appId, true);
+                            } else {
+                                return;
+                            }
+                        }
+                        final int uid = UserHandle.getUid(userId, appId);
+                        consumer.accept(uid);
+                    }, userId);
+                }
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
             }
-
-            final int usersSize = users.size();
-            final int appsSize = apps.size();
-            for (int i = 0; i < usersSize; i++) {
-                final UserInfo user = users.get(i);
-                for (int j = 0; j < appsSize; j++) {
-                    final ApplicationInfo app = apps.get(j);
-                    final int uid = UserHandle.getUid(user.id, app.uid);
-                    consumer.accept(uid);
-                }
-            }
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
         }
@@ -4569,7 +4587,7 @@
             final UserInfo user = users.get(i);
             int uid = UserHandle.getUid(user.id, appId);
             // Update external firewall rules.
-            updateRuleForAppIdleUL(uid);
+            updateRuleForAppIdleUL(uid, PROCESS_STATE_UNKNOWN);
             updateRuleForDeviceIdleUL(uid);
             updateRuleForRestrictPowerUL(uid);
             // Update internal rules.
@@ -4617,7 +4635,7 @@
                 } else {
                     mAppIdleTempWhitelistAppIds.delete(uid);
                 }
-                updateRuleForAppIdleUL(uid);
+                updateRuleForAppIdleUL(uid, PROCESS_STATE_UNKNOWN);
                 updateRulesForPowerRestrictionsUL(uid);
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -4643,7 +4661,15 @@
     /** Returns if the UID is currently considered idle. */
     @VisibleForTesting
     boolean isUidIdle(int uid) {
+        return isUidIdle(uid, PROCESS_STATE_UNKNOWN);
+    }
+
+    private boolean isUidIdle(int uid, int uidProcessState) {
         synchronized (mUidRulesFirstLock) {
+            if (uidProcessState != PROCESS_STATE_UNKNOWN && isProcStateConsideredInteraction(
+                    uidProcessState)) {
+                return false;
+            }
             if (mAppIdleTempWhitelistAppIds.get(uid)) {
                 // UID is temporarily allowlisted.
                 return false;
@@ -4692,7 +4718,9 @@
     @GuardedBy("mUidRulesFirstLock")
     private void onUidDeletedUL(int uid) {
         // First cleanup in-memory state synchronously...
-        mUidBlockedState.delete(uid);
+        synchronized (mUidBlockedState) {
+            mUidBlockedState.delete(uid);
+        }
         mUidPolicy.delete(uid);
         mUidFirewallStandbyRules.delete(uid);
         mUidFirewallDozableRules.delete(uid);
@@ -4728,7 +4756,7 @@
     private void updateRestrictionRulesForUidUL(int uid) {
         // Methods below only changes the firewall rules for the power-related modes.
         updateRuleForDeviceIdleUL(uid);
-        updateRuleForAppIdleUL(uid);
+        updateRuleForAppIdleUL(uid, PROCESS_STATE_UNKNOWN);
         updateRuleForRestrictPowerUL(uid);
 
         // If the uid has the necessary permissions, then it should be added to the restricted mode
@@ -4804,11 +4832,6 @@
         final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
         final boolean isForeground = isUidForegroundOnRestrictBackgroundUL(uid);
         final boolean isRestrictedByAdmin = isRestrictedByAdminUL(uid);
-        final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
-                mUidBlockedState, uid);
-        final UidBlockedState previousUidBlockedState = getOrCreateUidBlockedStateForUid(
-                mTmpUidBlockedState, uid);
-        previousUidBlockedState.copyFrom(uidBlockedState);
 
         final boolean isDenied = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
         final boolean isAllowed = (uidPolicy & POLICY_ALLOW_METERED_BACKGROUND) != 0;
@@ -4823,18 +4846,47 @@
         newAllowedReasons |= (isForeground ? ALLOWED_METERED_REASON_FOREGROUND : 0);
         newAllowedReasons |= (isAllowed ? ALLOWED_METERED_REASON_USER_EXEMPTED : 0);
 
-        uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
-                & ~BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
-        uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
-                & ~ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
-        uidBlockedState.updateEffectiveBlockedReasons();
-        final int oldEffectiveBlockedReasons = previousUidBlockedState.effectiveBlockedReasons;
-        final int newEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+        final int oldEffectiveBlockedReasons;
+        final int newEffectiveBlockedReasons;
+        final int oldAllowedReasons;
+        final int uidRules;
+        synchronized (mUidBlockedState) {
+            final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
+                    mUidBlockedState, uid);
+            final UidBlockedState previousUidBlockedState = getOrCreateUidBlockedStateForUid(
+                    mTmpUidBlockedState, uid);
+            previousUidBlockedState.copyFrom(uidBlockedState);
+
+            uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
+                    & ~BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
+            uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
+                    & ~ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
+            uidBlockedState.updateEffectiveBlockedReasons();
+
+            oldEffectiveBlockedReasons = previousUidBlockedState.effectiveBlockedReasons;
+            newEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+            oldAllowedReasons = previousUidBlockedState.allowedReasons;
+            uidRules = (oldEffectiveBlockedReasons == newEffectiveBlockedReasons)
+                    ? RULE_NONE : uidBlockedState.deriveUidRules();
+
+            if (LOGV) {
+                Log.v(TAG, "updateRuleForRestrictBackgroundUL(" + uid + ")"
+                        + ": isForeground=" + isForeground
+                        + ", isDenied=" + isDenied
+                        + ", isAllowed=" + isAllowed
+                        + ", isRestrictedByAdmin=" + isRestrictedByAdmin
+                        + ", oldBlockedState=" + previousUidBlockedState
+                        + ", newBlockedState=" + uidBlockedState
+                        + ", newBlockedMeteredReasons=" + blockedReasonsToString(newBlockedReasons)
+                        + ", newAllowedMeteredReasons=" + allowedReasonsToString(
+                                newAllowedReasons));
+            }
+        }
         if (oldEffectiveBlockedReasons != newEffectiveBlockedReasons) {
             postBlockedReasonsChangedMsg(uid,
                     newEffectiveBlockedReasons, oldEffectiveBlockedReasons);
 
-            postUidRulesChangedMsg(uid, uidBlockedState.deriveUidRules());
+            postUidRulesChangedMsg(uid, uidRules);
         }
 
         // Note that the conditionals below are for avoiding unnecessary calls to netd.
@@ -4850,29 +4902,11 @@
         }
         final int allowlistReasons = ALLOWED_METERED_REASON_FOREGROUND
                 | ALLOWED_METERED_REASON_USER_EXEMPTED;
-        final int oldAllowedReasons = previousUidBlockedState.allowedReasons;
         if ((oldAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE
                 || (newAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE) {
             setMeteredNetworkAllowlist(uid,
                     (newAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE);
         }
-
-        if (LOGV) {
-            Log.v(TAG, "updateRuleForRestrictBackgroundUL(" + uid + ")"
-                    + ": isForeground=" +isForeground
-                    + ", isDenied=" + isDenied
-                    + ", isAllowed=" + isAllowed
-                    + ", isRestrictedByAdmin=" + isRestrictedByAdmin
-                    + ", oldBlockedState=" + previousUidBlockedState.toString()
-                    + ", newBlockedState=" + uidBlockedState.toString()
-                    + ", oldBlockedMeteredReasons=" + NetworkPolicyManager.blockedReasonsToString(
-                    uidBlockedState.blockedReasons & BLOCKED_METERED_REASON_MASK)
-                    + ", oldBlockedMeteredEffectiveReasons="
-                    + NetworkPolicyManager.blockedReasonsToString(
-                    uidBlockedState.effectiveBlockedReasons & BLOCKED_METERED_REASON_MASK)
-                    + ", oldAllowedMeteredReasons=" + NetworkPolicyManager.blockedReasonsToString(
-                    uidBlockedState.allowedReasons & BLOCKED_METERED_REASON_MASK));
-        }
     }
 
     /**
@@ -4896,7 +4930,12 @@
      */
     @GuardedBy("mUidRulesFirstLock")
     private void updateRulesForPowerRestrictionsUL(int uid) {
-        updateRulesForPowerRestrictionsUL(uid, isUidIdle(uid));
+        updateRulesForPowerRestrictionsUL(uid, PROCESS_STATE_UNKNOWN);
+    }
+
+    @GuardedBy("mUidRulesFirstLock")
+    private void updateRulesForPowerRestrictionsUL(int uid, int uidProcState) {
+        updateRulesForPowerRestrictionsUL(uid, isUidIdle(uid, uidProcState));
     }
 
     /**
@@ -4932,56 +4971,66 @@
 
         final boolean isWhitelisted = isWhitelistedFromPowerSaveUL(uid, mDeviceIdleMode);
 
-        final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
-                mUidBlockedState, uid);
-        final UidBlockedState previousUidBlockedState = getOrCreateUidBlockedStateForUid(
-                mTmpUidBlockedState, uid);
-        previousUidBlockedState.copyFrom(uidBlockedState);
+        final int oldEffectiveBlockedReasons;
+        final int newEffectiveBlockedReasons;
+        final int uidRules;
+        synchronized (mUidBlockedState) {
+            final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
+                    mUidBlockedState, uid);
+            final UidBlockedState previousUidBlockedState = getOrCreateUidBlockedStateForUid(
+                    mTmpUidBlockedState, uid);
+            previousUidBlockedState.copyFrom(uidBlockedState);
 
-        int newBlockedReasons = BLOCKED_REASON_NONE;
-        int newAllowedReasons = ALLOWED_REASON_NONE;
-        newBlockedReasons |= (mRestrictPower ? BLOCKED_REASON_BATTERY_SAVER : 0);
-        newBlockedReasons |= (mDeviceIdleMode ? BLOCKED_REASON_DOZE : 0);
-        newBlockedReasons |= (mLowPowerStandbyActive ? BLOCKED_REASON_LOW_POWER_STANDBY : 0);
-        newBlockedReasons |= (isUidIdle ? BLOCKED_REASON_APP_STANDBY : 0);
-        newBlockedReasons |= (uidBlockedState.blockedReasons & BLOCKED_REASON_RESTRICTED_MODE);
+            int newBlockedReasons = BLOCKED_REASON_NONE;
+            int newAllowedReasons = ALLOWED_REASON_NONE;
+            newBlockedReasons |= (mRestrictPower ? BLOCKED_REASON_BATTERY_SAVER : 0);
+            newBlockedReasons |= (mDeviceIdleMode ? BLOCKED_REASON_DOZE : 0);
+            newBlockedReasons |= (mLowPowerStandbyActive ? BLOCKED_REASON_LOW_POWER_STANDBY : 0);
+            newBlockedReasons |= (isUidIdle ? BLOCKED_REASON_APP_STANDBY : 0);
+            newBlockedReasons |= (uidBlockedState.blockedReasons & BLOCKED_REASON_RESTRICTED_MODE);
 
-        newAllowedReasons |= (isSystem(uid) ? ALLOWED_REASON_SYSTEM : 0);
-        newAllowedReasons |= (isForeground ? ALLOWED_REASON_FOREGROUND : 0);
-        newAllowedReasons |= (isTop ? ALLOWED_REASON_TOP : 0);
-        newAllowedReasons |= (isWhitelistedFromPowerSaveUL(uid, true)
-                ? ALLOWED_REASON_POWER_SAVE_ALLOWLIST : 0);
-        newAllowedReasons |= (isWhitelistedFromPowerSaveExceptIdleUL(uid)
-                ? ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST : 0);
-        newAllowedReasons |= (uidBlockedState.allowedReasons
-                & ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS);
-        newAllowedReasons |= (isAllowlistedFromLowPowerStandbyUL(uid))
-                ? ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST : 0;
+            newAllowedReasons |= (isSystem(uid) ? ALLOWED_REASON_SYSTEM : 0);
+            newAllowedReasons |= (isForeground ? ALLOWED_REASON_FOREGROUND : 0);
+            newAllowedReasons |= (isTop ? ALLOWED_REASON_TOP : 0);
+            newAllowedReasons |= (isWhitelistedFromPowerSaveUL(uid, true)
+                    ? ALLOWED_REASON_POWER_SAVE_ALLOWLIST : 0);
+            newAllowedReasons |= (isWhitelistedFromPowerSaveExceptIdleUL(uid)
+                    ? ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST : 0);
+            newAllowedReasons |= (uidBlockedState.allowedReasons
+                    & ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS);
+            newAllowedReasons |= (isAllowlistedFromLowPowerStandbyUL(uid))
+                    ? ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST : 0;
 
-        uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
-                & BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
-        uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
-                & ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
-        uidBlockedState.updateEffectiveBlockedReasons();
-        if (previousUidBlockedState.effectiveBlockedReasons
-                != uidBlockedState.effectiveBlockedReasons) {
-            postBlockedReasonsChangedMsg(uid,
-                    uidBlockedState.effectiveBlockedReasons,
-                    previousUidBlockedState.effectiveBlockedReasons);
+            uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
+                    & BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
+            uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
+                    & ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
+            uidBlockedState.updateEffectiveBlockedReasons();
 
-            postUidRulesChangedMsg(uid, uidBlockedState.deriveUidRules());
+            if (LOGV) {
+                Log.v(TAG, "updateRulesForPowerRestrictionsUL(" + uid + ")"
+                        + ", isIdle: " + isUidIdle
+                        + ", mRestrictPower: " + mRestrictPower
+                        + ", mDeviceIdleMode: " + mDeviceIdleMode
+                        + ", isForeground=" + isForeground
+                        + ", isTop=" + isTop
+                        + ", isWhitelisted=" + isWhitelisted
+                        + ", oldUidBlockedState=" + previousUidBlockedState
+                        + ", newUidBlockedState=" + uidBlockedState);
+            }
+
+            oldEffectiveBlockedReasons = previousUidBlockedState.effectiveBlockedReasons;
+            newEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+            uidRules = oldEffectiveBlockedReasons == newEffectiveBlockedReasons
+                    ? RULE_NONE
+                    : uidBlockedState.deriveUidRules();
         }
+        if (oldEffectiveBlockedReasons != newEffectiveBlockedReasons) {
+            postBlockedReasonsChangedMsg(uid,
+                    oldEffectiveBlockedReasons,
+                    newEffectiveBlockedReasons);
 
-        if (LOGV) {
-            Log.v(TAG, "updateRulesForPowerRestrictionsUL(" + uid + ")"
-                    + ", isIdle: " + isUidIdle
-                    + ", mRestrictPower: " + mRestrictPower
-                    + ", mDeviceIdleMode: " + mDeviceIdleMode
-                    + ", isForeground=" + isForeground
-                    + ", isTop=" + isTop
-                    + ", isWhitelisted=" + isWhitelisted
-                    + ", oldUidBlockedState=" + previousUidBlockedState.toString()
-                    + ", newUidBlockedState=" + uidBlockedState.toString());
+            postUidRulesChangedMsg(uid, uidRules);
         }
     }
 
@@ -4994,7 +5043,7 @@
                         PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
                 synchronized (mUidRulesFirstLock) {
                     mLogger.appIdleStateChanged(uid, idle);
-                    updateRuleForAppIdleUL(uid);
+                    updateRuleForAppIdleUL(uid, PROCESS_STATE_UNKNOWN);
                     updateRulesForPowerRestrictionsUL(uid);
                 }
             } catch (NameNotFoundException nnfe) {
@@ -5420,7 +5469,12 @@
         if (LOGV) Slog.v(TAG, "setMeteredNetworkDenylist " + uid + ": " + enable);
         try {
             mNetworkManager.setUidOnMeteredNetworkDenylist(uid, enable);
-            mLogger.meteredAllowlistChanged(uid, enable);
+            mLogger.meteredDenylistChanged(uid, enable);
+            if (Process.isApplicationUid(uid)) {
+                final int sdkSandboxUid = Process.toSdkSandboxUid(uid);
+                mNetworkManager.setUidOnMeteredNetworkDenylist(sdkSandboxUid, enable);
+                mLogger.meteredDenylistChanged(sdkSandboxUid, enable);
+            }
         } catch (IllegalStateException e) {
             Log.wtf(TAG, "problem setting denylist (" + enable + ") rules for " + uid, e);
         } catch (RemoteException e) {
@@ -5432,7 +5486,12 @@
         if (LOGV) Slog.v(TAG, "setMeteredNetworkAllowlist " + uid + ": " + enable);
         try {
             mNetworkManager.setUidOnMeteredNetworkAllowlist(uid, enable);
-            mLogger.meteredDenylistChanged(uid, enable);
+            mLogger.meteredAllowlistChanged(uid, enable);
+            if (Process.isApplicationUid(uid)) {
+                final int sdkSandboxUid = Process.toSdkSandboxUid(uid);
+                mNetworkManager.setUidOnMeteredNetworkAllowlist(sdkSandboxUid, enable);
+                mLogger.meteredAllowlistChanged(sdkSandboxUid, enable);
+            }
         } catch (IllegalStateException e) {
             Log.wtf(TAG, "problem setting allowlist (" + enable + ") rules for " + uid, e);
         } catch (RemoteException e) {
@@ -5471,12 +5530,31 @@
         }
     }
 
+    private void addSdkSandboxUidsIfNeeded(SparseIntArray uidRules) {
+        final int size = uidRules.size();
+        final SparseIntArray sdkSandboxUids = new SparseIntArray();
+        for (int index = 0; index < size; index++) {
+            final int uid = uidRules.keyAt(index);
+            final int rule = uidRules.valueAt(index);
+            if (Process.isApplicationUid(uid)) {
+                sdkSandboxUids.put(Process.toSdkSandboxUid(uid), rule);
+            }
+        }
+
+        for (int index = 0; index < sdkSandboxUids.size(); index++) {
+            final int uid = sdkSandboxUids.keyAt(index);
+            final int rule = sdkSandboxUids.valueAt(index);
+            uidRules.put(uid, rule);
+        }
+    }
+
     /**
      * Set uid rules on a particular firewall chain. This is going to synchronize the rules given
      * here to netd.  It will clean up dead rules and make sure the target chain only contains rules
      * specified here.
      */
     private void setUidFirewallRulesUL(int chain, SparseIntArray uidRules) {
+        addSdkSandboxUidsIfNeeded(uidRules);
         try {
             int size = uidRules.size();
             int[] uids = new int[size];
@@ -5519,6 +5597,11 @@
             try {
                 mNetworkManager.setFirewallUidRule(chain, uid, rule);
                 mLogger.uidFirewallRuleChanged(chain, uid, rule);
+                if (Process.isApplicationUid(uid)) {
+                    final int sdkSandboxUid = Process.toSdkSandboxUid(uid);
+                    mNetworkManager.setFirewallUidRule(chain, sdkSandboxUid, rule);
+                    mLogger.uidFirewallRuleChanged(chain, sdkSandboxUid, rule);
+                }
             } catch (IllegalStateException e) {
                 Log.wtf(TAG, "problem setting firewall uid rules", e);
             } catch (RemoteException e) {
@@ -5555,15 +5638,16 @@
      */
     private void resetUidFirewallRules(int uid) {
         try {
-            mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_DEFAULT);
-            mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DEFAULT);
-            mNetworkManager
-                    .setFirewallUidRule(FIREWALL_CHAIN_POWERSAVE, uid, FIREWALL_RULE_DEFAULT);
-            mNetworkManager
-                    .setFirewallUidRule(FIREWALL_CHAIN_RESTRICTED, uid, FIREWALL_RULE_DEFAULT);
-            mNetworkManager
-                    .setFirewallUidRule(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid,
-                            FIREWALL_RULE_DEFAULT);
+            mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_DOZABLE, uid,
+                    FIREWALL_RULE_DEFAULT);
+            mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_STANDBY, uid,
+                    FIREWALL_RULE_DEFAULT);
+            mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_POWERSAVE, uid,
+                    FIREWALL_RULE_DEFAULT);
+            mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_RESTRICTED, uid,
+                    FIREWALL_RULE_DEFAULT);
+            mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid,
+                    FIREWALL_RULE_DEFAULT);
             mNetworkManager.setUidOnMeteredNetworkAllowlist(uid, false);
             mLogger.meteredAllowlistChanged(uid, false);
             mNetworkManager.setUidOnMeteredNetworkDenylist(uid, false);
@@ -5573,6 +5657,9 @@
         } catch (RemoteException e) {
             // ignored; service lives in system_server
         }
+        if (Process.isApplicationUid(uid)) {
+            resetUidFirewallRules(Process.toSdkSandboxUid(uid));
+        }
     }
 
     @Deprecated
@@ -5728,7 +5815,7 @@
 
         mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
         int blockedReasons;
-        synchronized (mUidRulesFirstLock) {
+        synchronized (mUidBlockedState) {
             final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
             blockedReasons = uidBlockedState == null
                     ? BLOCKED_REASON_NONE : uidBlockedState.effectiveBlockedReasons;
@@ -5746,7 +5833,7 @@
     @Override
     public boolean isUidRestrictedOnMeteredNetworks(int uid) {
         mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
-        synchronized (mUidRulesFirstLock) {
+        synchronized (mUidBlockedState) {
             final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
             int blockedReasons = uidBlockedState == null
                     ? BLOCKED_REASON_NONE : uidBlockedState.effectiveBlockedReasons;
@@ -5994,10 +6081,6 @@
         return restrictedUids != null && restrictedUids.contains(uid);
     }
 
-    private static boolean hasRule(int uidRules, int rule) {
-        return (uidRules & rule) != 0;
-    }
-
     private static boolean getBooleanDefeatingNullable(@Nullable PersistableBundle bundle,
             String key, boolean defaultValue) {
         return (bundle != null) ? bundle.getBoolean(key, defaultValue) : defaultValue;
@@ -6013,16 +6096,39 @@
         return uidBlockedState;
     }
 
+    private int getEffectiveBlockedReasons(int uid) {
+        synchronized (mUidBlockedState) {
+            final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
+            return uidBlockedState == null
+                    ? BLOCKED_REASON_NONE
+                    : uidBlockedState.effectiveBlockedReasons;
+        }
+    }
+
+    private int getBlockedReasons(int uid) {
+        synchronized (mUidBlockedState) {
+            final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
+            return uidBlockedState == null
+                    ? BLOCKED_REASON_NONE
+                    : uidBlockedState.blockedReasons;
+        }
+    }
+
     @VisibleForTesting
     static final class UidBlockedState {
         public int blockedReasons;
         public int allowedReasons;
         public int effectiveBlockedReasons;
 
+        private UidBlockedState(int blockedReasons, int allowedReasons,
+                int effectiveBlockedReasons) {
+            this.blockedReasons = blockedReasons;
+            this.allowedReasons = allowedReasons;
+            this.effectiveBlockedReasons = effectiveBlockedReasons;
+        }
+
         UidBlockedState() {
-            blockedReasons = BLOCKED_REASON_NONE;
-            allowedReasons = ALLOWED_REASON_NONE;
-            effectiveBlockedReasons = BLOCKED_REASON_NONE;
+            this(BLOCKED_REASON_NONE, ALLOWED_REASON_NONE, BLOCKED_REASON_NONE);
         }
 
         void updateEffectiveBlockedReasons() {
@@ -6259,7 +6365,7 @@
                 }
             }
             if (LOGV) {
-                Slog.v(TAG, "uidBlockedState=" + this.toString()
+                Slog.v(TAG, "uidBlockedState=" + this
                         + " -> uidRule=" + uidRulesToString(uidRule));
             }
             return uidRule;
diff --git a/services/core/java/com/android/server/notification/GroupHelper.java b/services/core/java/com/android/server/notification/GroupHelper.java
index 4f26809..273afcc 100644
--- a/services/core/java/com/android/server/notification/GroupHelper.java
+++ b/services/core/java/com/android/server/notification/GroupHelper.java
@@ -42,7 +42,7 @@
     private final int mAutoGroupAtCount;
 
     // count the number of ongoing notifications per group
-    // userId -> (package name -> (group Id -> (set of notification keys)))
+    // userId|packageName -> (set of ongoing notifications that aren't in an app group)
     final ArrayMap<String, ArraySet<String>>
             mOngoingGroupCount = new ArrayMap<>();
 
@@ -55,52 +55,43 @@
         mCallback = callback;
     }
 
-    private String generatePackageGroupKey(int userId, String pkg, String group) {
-        return userId + "|" + pkg + "|" + group;
+    private String generatePackageKey(int userId, String pkg) {
+        return userId + "|" + pkg;
     }
 
     @VisibleForTesting
-    protected int getOngoingGroupCount(int userId, String pkg, String group) {
-        String key = generatePackageGroupKey(userId, pkg, group);
+    protected int getOngoingGroupCount(int userId, String pkg) {
+        String key = generatePackageKey(userId, pkg);
         return mOngoingGroupCount.getOrDefault(key, new ArraySet<>(0)).size();
     }
 
-    private void addToOngoingGroupCount(StatusBarNotification sbn, boolean add) {
-        if (sbn.getNotification().isGroupSummary()) return;
-        if (!sbn.isOngoing() && add) return;
-        String group = sbn.getGroup();
-        if (group == null) return;
-        int userId = sbn.getUser().getIdentifier();
-        String key = generatePackageGroupKey(userId, sbn.getPackageName(), group);
+    private void updateOngoingGroupCount(StatusBarNotification sbn, boolean add) {
+        if (sbn.getNotification().isGroupSummary()) {
+            return;
+        }
+        String key = generatePackageKey(sbn.getUserId(), sbn.getPackageName());
         ArraySet<String> notifications = mOngoingGroupCount.getOrDefault(key, new ArraySet<>(0));
         if (add) {
             notifications.add(sbn.getKey());
             mOngoingGroupCount.put(key, notifications);
         } else {
             notifications.remove(sbn.getKey());
-            // we dont need to put it back if it is default
+            // we don't need to put it back if it is default
         }
-        String combinedKey = generatePackageGroupKey(userId, sbn.getPackageName(), group);
+
         boolean needsOngoingFlag = notifications.size() > 0;
-        mCallback.updateAutogroupSummary(userId, sbn.getPackageName(), needsOngoingFlag);
+        mCallback.updateAutogroupSummary(sbn.getUserId(), sbn.getPackageName(), needsOngoingFlag);
     }
 
-    public void onNotificationUpdated(StatusBarNotification childSbn,
-            boolean autogroupSummaryExists) {
-        if (childSbn.getGroup() != AUTOGROUP_KEY
-                || childSbn.getNotification().isGroupSummary()) return;
-        if (childSbn.isOngoing()) {
-            addToOngoingGroupCount(childSbn, true);
-        } else {
-            addToOngoingGroupCount(childSbn, false);
-        }
+    public void onNotificationUpdated(StatusBarNotification childSbn) {
+        updateOngoingGroupCount(childSbn, childSbn.isOngoing() && !childSbn.isAppGroup());
     }
 
     public void onNotificationPosted(StatusBarNotification sbn, boolean autogroupSummaryExists) {
-        if (DEBUG) Log.i(TAG, "POSTED " + sbn.getKey());
         try {
+            updateOngoingGroupCount(sbn, sbn.isOngoing() && !sbn.isAppGroup());
+
             List<String> notificationsToGroup = new ArrayList<>();
-            if (autogroupSummaryExists) addToOngoingGroupCount(sbn, true);
             if (!sbn.isAppGroup()) {
                 // Not grouped by the app, add to the list of notifications for the app;
                 // send grouping update if app exceeds the autogrouping limit.
@@ -134,6 +125,7 @@
                 // Grouped, but not by us. Send updates to un-autogroup, if we grouped it.
                 maybeUngroup(sbn, false, sbn.getUserId());
             }
+
         } catch (Exception e) {
             Slog.e(TAG, "Failure processing new notification", e);
         }
@@ -141,7 +133,7 @@
 
     public void onNotificationRemoved(StatusBarNotification sbn) {
         try {
-            addToOngoingGroupCount(sbn, false);
+            updateOngoingGroupCount(sbn, false);
             maybeUngroup(sbn, true, sbn.getUserId());
         } catch (Exception e) {
             Slog.e(TAG, "Error processing canceled notification", e);
@@ -189,7 +181,8 @@
     private void adjustAutogroupingSummary(int userId, String packageName, String triggeringKey,
             boolean summaryNeeded) {
         if (summaryNeeded) {
-            mCallback.addAutoGroupSummary(userId, packageName, triggeringKey);
+            mCallback.addAutoGroupSummary(userId, packageName, triggeringKey,
+                    getOngoingGroupCount(userId, packageName) > 0);
         } else {
             mCallback.removeAutoGroupSummary(userId, packageName);
         }
@@ -209,7 +202,8 @@
     protected interface Callback {
         void addAutoGroup(String key);
         void removeAutoGroup(String key);
-        void addAutoGroupSummary(int userId, String pkg, String triggeringKey);
+        void addAutoGroupSummary(int userId, String pkg, String triggeringKey,
+                boolean needsOngoingFlag);
         void removeAutoGroupSummary(int user, String pkg);
         void updateAutogroupSummary(int userId, String pkg, boolean needsOngoingFlag);
     }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 265ad7d..326a5f2 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -630,6 +630,7 @@
     private int mWarnRemoteViewsSizeBytes;
     private int mStripRemoteViewsSizeBytes;
     final boolean mEnableAppSettingMigration;
+    private boolean mForceUserSetOnUpgrade;
 
     private MetricsLogger mMetricsLogger;
     private TriPredicate<String, Integer, String> mAllowedManagedServicePackages;
@@ -2294,6 +2295,7 @@
 
         mMsgPkgsAllowedAsConvos = Set.of(getStringArrayResource(
                 com.android.internal.R.array.config_notificationMsgPkgsAllowedAsConvos));
+
         mStatsManager = statsManager;
 
         mToastRateLimiter = toastRateLimiter;
@@ -2386,6 +2388,9 @@
 
         WorkerHandler handler = new WorkerHandler(Looper.myLooper());
 
+        mForceUserSetOnUpgrade = getContext().getResources().getBoolean(
+                R.bool.config_notificationForceUserSetOnUpgrade);
+
         init(handler, new RankingHandlerWorker(mRankingThread.getLooper()),
                 AppGlobals.getPackageManager(), getContext().getPackageManager(),
                 getLocalService(LightsManager.class),
@@ -2414,7 +2419,8 @@
                 LocalServices.getService(ActivityManagerInternal.class),
                 createToastRateLimiter(), new PermissionHelper(LocalServices.getService(
                         PermissionManagerServiceInternal.class), AppGlobals.getPackageManager(),
-                        AppGlobals.getPermissionManager(), mEnableAppSettingMigration),
+                        AppGlobals.getPermissionManager(), mEnableAppSettingMigration,
+                        mForceUserSetOnUpgrade),
                 LocalServices.getService(UsageStatsManagerInternal.class));
 
         publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
@@ -2551,8 +2557,10 @@
             }
 
             @Override
-            public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
-                NotificationRecord r = createAutoGroupSummary(userId, pkg, triggeringKey);
+            public void addAutoGroupSummary(int userId, String pkg, String triggeringKey,
+                    boolean needsOngoingFlag) {
+                NotificationRecord r = createAutoGroupSummary(
+                        userId, pkg, triggeringKey, needsOngoingFlag);
                 if (r != null) {
                     final boolean isAppForeground =
                             mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND;
@@ -5733,6 +5741,7 @@
     void removeAutogroupKeyLocked(String key) {
         NotificationRecord r = mNotificationsByKey.get(key);
         if (r == null) {
+            Slog.w(TAG, "Failed to remove autogroup " + key);
             return;
         }
         if (r.getSbn().getOverrideGroupKey() != null) {
@@ -5772,7 +5781,8 @@
     }
 
     // Creates a 'fake' summary for a package that has exceeded the solo-notification limit.
-    NotificationRecord createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
+    NotificationRecord createAutoGroupSummary(int userId, String pkg, String triggeringKey,
+            boolean needsOngoingFlag) {
         NotificationRecord summaryRecord = null;
         boolean isPermissionFixed = mPermissionHelper.isMigrationEnabled()
                 ? mPermissionHelper.isPermissionFixed(pkg, userId) : false;
@@ -5812,6 +5822,7 @@
                                 .setGroup(GroupHelper.AUTOGROUP_KEY)
                                 .setFlag(FLAG_AUTOGROUP_SUMMARY, true)
                                 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
+                                .setFlag(FLAG_ONGOING_EVENT, needsOngoingFlag)
                                 .setColor(adjustedSbn.getNotification().color)
                                 .setLocalOnly(true)
                                 .build();
@@ -6069,6 +6080,7 @@
                     pw.println("  mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
                     pw.println("  hideSilentStatusBar="
                             + mPreferencesHelper.shouldHideSilentStatusIcons());
+                    pw.println("  mForceUserSetOnUpgrade=" + mForceUserSetOnUpgrade);
                 }
                 pw.println("  mArchive=" + mArchive.toString());
                 mArchive.dumpImpl(pw, filter);
@@ -7349,17 +7361,16 @@
                         mListeners.notifyPostedLocked(r, old);
                         if ((oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup()))
                                 && !isCritical(r)) {
-                            mHandler.post(new Runnable() {
-                                @Override
-                                public void run() {
+                            mHandler.post(() -> {
+                                synchronized (mNotificationLock) {
                                     mGroupHelper.onNotificationPosted(
                                             n, hasAutoGroupSummaryLocked(n));
                                 }
                             });
                         } else if (oldSbn != null) {
                             final NotificationRecord finalRecord = r;
-                            mHandler.post(() -> mGroupHelper.onNotificationUpdated(
-                                    finalRecord.getSbn(), hasAutoGroupSummaryLocked(n)));
+                            mHandler.post(() ->
+                                    mGroupHelper.onNotificationUpdated(finalRecord.getSbn()));
                         }
                     } else {
                         Slog.e(TAG, "Not posting notification without small icon: " + notification);
@@ -10422,10 +10433,10 @@
                 boolean isPrimary, boolean enabled, boolean userSet) {
             super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled, userSet);
 
-            getContext().sendBroadcastAsUser(
+            mContext.sendBroadcastAsUser(
                     new Intent(ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED)
                             .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
-                    UserHandle.ALL, null);
+                    UserHandle.of(userId), null);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/notification/PermissionHelper.java b/services/core/java/com/android/server/notification/PermissionHelper.java
index e551f10..b4230c1 100644
--- a/services/core/java/com/android/server/notification/PermissionHelper.java
+++ b/services/core/java/com/android/server/notification/PermissionHelper.java
@@ -57,13 +57,16 @@
     private final IPermissionManager mPermManager;
     // TODO (b/194833441): Remove when the migration is enabled
     private final boolean mMigrationEnabled;
+    private final boolean mForceUserSetOnUpgrade;
 
     public PermissionHelper(PermissionManagerServiceInternal pmi, IPackageManager packageManager,
-            IPermissionManager permManager, boolean migrationEnabled) {
+            IPermissionManager permManager, boolean migrationEnabled,
+            boolean forceUserSetOnUpgrade) {
         mPmi = pmi;
         mPackageManager = packageManager;
         mPermManager = permManager;
         mMigrationEnabled = migrationEnabled;
+        mForceUserSetOnUpgrade = forceUserSetOnUpgrade;
     }
 
     public boolean isMigrationEnabled() {
@@ -223,8 +226,9 @@
             return;
         }
         if (!isPermissionFixed(pkgPerm.packageName, pkgPerm.userId)) {
+            boolean userSet = mForceUserSetOnUpgrade ? true : pkgPerm.userModifiedSettings;
             setNotificationPermission(pkgPerm.packageName, pkgPerm.userId, pkgPerm.granted,
-                    pkgPerm.userSet, !pkgPerm.userSet);
+                    userSet, !userSet);
         }
     }
 
@@ -305,13 +309,13 @@
         public final String packageName;
         public final @UserIdInt int userId;
         public final boolean granted;
-        public final boolean userSet;
+        public final boolean userModifiedSettings;
 
         public PackagePermission(String pkg, int userId, boolean granted, boolean userSet) {
             this.packageName = pkg;
             this.userId = userId;
             this.granted = granted;
-            this.userSet = userSet;
+            this.userModifiedSettings = userSet;
         }
 
         @Override
@@ -319,13 +323,14 @@
             if (this == o) return true;
             if (o == null || getClass() != o.getClass()) return false;
             PackagePermission that = (PackagePermission) o;
-            return userId == that.userId && granted == that.granted && userSet == that.userSet
+            return userId == that.userId && granted == that.granted && userModifiedSettings
+                    == that.userModifiedSettings
                     && Objects.equals(packageName, that.packageName);
         }
 
         @Override
         public int hashCode() {
-            return Objects.hash(packageName, userId, granted, userSet);
+            return Objects.hash(packageName, userId, granted, userModifiedSettings);
         }
 
         @Override
@@ -334,7 +339,7 @@
                     "packageName='" + packageName + '\'' +
                     ", userId=" + userId +
                     ", granted=" + granted +
-                    ", userSet=" + userSet +
+                    ", userSet=" + userModifiedSettings +
                     '}';
         }
     }
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 1f7d65e..75d7a1f 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -601,8 +601,10 @@
                 out.attribute(null, ATT_NAME, r.pkg);
                 if (!notifPermissions.isEmpty()) {
                     Pair<Integer, String> app = new Pair(r.uid, r.pkg);
+                    final Pair<Boolean, Boolean> permission = notifPermissions.get(app);
                     out.attributeInt(null, ATT_IMPORTANCE,
-                            notifPermissions.get(app).first ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE);
+                            permission != null && permission.first ? IMPORTANCE_DEFAULT
+                                    : IMPORTANCE_NONE);
                     notifPermissions.remove(app);
                 } else {
                     if (r.importance != DEFAULT_IMPORTANCE) {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 93f1b47..9e0c975 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -104,6 +104,7 @@
 
     // The amount of time rules instances can exist without their owning app being installed.
     private static final int RULE_INSTANCE_GRACE_PERIOD = 1000 * 60 * 60 * 72;
+    static final int RULE_LIMIT_PER_PACKAGE = 100;
 
     // pkg|userId => uid
     protected final ArrayMap<String, Integer> mRulesUidCache = new ArrayMap<>();
@@ -329,10 +330,10 @@
             int newRuleInstanceCount = getCurrentInstanceCount(automaticZenRule.getOwner())
                     + getCurrentInstanceCount(automaticZenRule.getConfigurationActivity())
                     + 1;
-            if (ruleInstanceLimit > 0 && ruleInstanceLimit < newRuleInstanceCount) {
+            if (newRuleInstanceCount > RULE_LIMIT_PER_PACKAGE
+                    || (ruleInstanceLimit > 0 && ruleInstanceLimit < newRuleInstanceCount)) {
                 throw new IllegalArgumentException("Rule instance limit exceeded");
             }
-
         }
 
         ZenModeConfig newConfig;
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 76d3d23..a91c55f 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -520,7 +520,7 @@
         @Override
         public List<ActiveApexInfo> getActiveApexInfos() {
             final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
-                    Trace.TRACE_TAG_APEX_MANAGER);
+                    Trace.TRACE_TAG_PACKAGE_MANAGER);
             synchronized (mLock) {
                 if (mActiveApexInfosCache == null) {
                     t.traceBegin("getActiveApexInfos_noCache");
diff --git a/services/core/java/com/android/server/pm/ApkChecksums.java b/services/core/java/com/android/server/pm/ApkChecksums.java
index aa467e7..2824585 100644
--- a/services/core/java/com/android/server/pm/ApkChecksums.java
+++ b/services/core/java/com/android/server/pm/ApkChecksums.java
@@ -34,6 +34,7 @@
 import android.content.pm.ApkChecksum;
 import android.content.pm.Checksum;
 import android.content.pm.IOnChecksumsReadyListener;
+import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.Signature;
 import android.content.pm.SigningDetails.SignatureSchemeVersion;
@@ -62,6 +63,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.security.VerityUtils;
+import com.android.server.LocalServices;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 
 import java.io.ByteArrayOutputStream;
diff --git a/services/core/java/com/android/server/pm/AppIdSettingMap.java b/services/core/java/com/android/server/pm/AppIdSettingMap.java
index bbef237..b41a0b8 100644
--- a/services/core/java/com/android/server/pm/AppIdSettingMap.java
+++ b/services/core/java/com/android/server/pm/AppIdSettingMap.java
@@ -17,46 +17,131 @@
 package com.android.server.pm;
 
 import android.os.Process;
+import android.util.Log;
 
+import com.android.server.utils.WatchedArrayList;
 import com.android.server.utils.WatchedSparseArray;
+import com.android.server.utils.Watcher;
 
 /**
- * A wrapper over {@link WatchedSparseArray} that tracks the current maximum App ID.
+ * A wrapper over {@link WatchedArrayList} that tracks the current (app ID -> SettingBase) mapping
+ * for non-system apps. Also tracks system app settings in an {@link WatchedSparseArray}.
  */
-public class AppIdSettingMap extends WatchedSparseArray<SettingBase> {
-    private int mCurrentMaxAppId;
+final class AppIdSettingMap {
+    /**
+     * We use an ArrayList instead of an SparseArray for non system apps because the number of apps
+     * might be big, and only ArrayList gives us a constant lookup time. For a given app ID, the
+     * index to the corresponding SettingBase object is (appId - FIRST_APPLICATION_ID). If an app ID
+     * doesn't exist (i.e., app is not installed), we fill the corresponding entry with null.
+     */
+    private WatchedArrayList<SettingBase> mNonSystemSettings = new WatchedArrayList<>();
+    private WatchedSparseArray<SettingBase> mSystemSettings = new WatchedSparseArray<>();
+    private int mFirstAvailableAppId = Process.FIRST_APPLICATION_UID;
 
-    @Override
-    public void put(int key, SettingBase value) {
-        if (key > mCurrentMaxAppId) {
-            mCurrentMaxAppId = key;
+    /** Returns true if the requested AppID was valid and not already registered. */
+    public boolean registerExistingAppId(int appId, SettingBase setting, Object name) {
+        if (appId >= Process.FIRST_APPLICATION_UID) {
+            int size = mNonSystemSettings.size();
+            final int index = appId - Process.FIRST_APPLICATION_UID;
+            // fill the array until our index becomes valid
+            while (index >= size) {
+                mNonSystemSettings.add(null);
+                size++;
+            }
+            if (mNonSystemSettings.get(index) != null) {
+                PackageManagerService.reportSettingsProblem(Log.WARN,
+                        "Adding duplicate app id: " + appId
+                                + " name=" + name);
+                return false;
+            }
+            mNonSystemSettings.set(index, setting);
+        } else {
+            if (mSystemSettings.get(appId) != null) {
+                PackageManagerService.reportSettingsProblem(Log.WARN,
+                        "Adding duplicate shared id: " + appId
+                                + " name=" + name);
+                return false;
+            }
+            mSystemSettings.put(appId, setting);
         }
-        super.put(key, value);
+        return true;
     }
 
-    @Override
+    public SettingBase getSetting(int appId) {
+        if (appId >= Process.FIRST_APPLICATION_UID) {
+            final int size = mNonSystemSettings.size();
+            final int index = appId - Process.FIRST_APPLICATION_UID;
+            return index < size ? mNonSystemSettings.get(index) : null;
+        } else {
+            return mSystemSettings.get(appId);
+        }
+    }
+
+    public void removeSetting(int appId) {
+        if (appId >= Process.FIRST_APPLICATION_UID) {
+            final int size = mNonSystemSettings.size();
+            final int index = appId - Process.FIRST_APPLICATION_UID;
+            if (index < size) {
+                mNonSystemSettings.set(index, null);
+            }
+        } else {
+            mSystemSettings.remove(appId);
+        }
+        setFirstAvailableAppId(appId + 1);
+    }
+
+    // This should be called (at least) whenever an application is removed
+    private void setFirstAvailableAppId(int uid) {
+        if (uid > mFirstAvailableAppId) {
+            mFirstAvailableAppId = uid;
+        }
+    }
+
+    public void replaceSetting(int appId, SettingBase setting) {
+        if (appId >= Process.FIRST_APPLICATION_UID) {
+            final int size = mNonSystemSettings.size();
+            final int index = appId - Process.FIRST_APPLICATION_UID;
+            if (index < size) {
+                mNonSystemSettings.set(index, setting);
+            } else {
+                PackageManagerService.reportSettingsProblem(Log.WARN,
+                        "Error in package manager settings: calling replaceAppIdLpw to"
+                                + " replace SettingBase at appId=" + appId
+                                + " but nothing is replaced.");
+            }
+        } else {
+            mSystemSettings.put(appId, setting);
+        }
+    }
+
+    /** Returns a new AppID or -1 if we could not find an available AppID to assign */
+    public int acquireAndRegisterNewAppId(SettingBase obj) {
+        final int size = mNonSystemSettings.size();
+        for (int i = mFirstAvailableAppId - Process.FIRST_APPLICATION_UID; i < size; i++) {
+            if (mNonSystemSettings.get(i) == null) {
+                mNonSystemSettings.set(i, obj);
+                return Process.FIRST_APPLICATION_UID + i;
+            }
+        }
+
+        // None left?
+        if (size > (Process.LAST_APPLICATION_UID - Process.FIRST_APPLICATION_UID)) {
+            return -1;
+        }
+
+        mNonSystemSettings.add(obj);
+        return Process.FIRST_APPLICATION_UID + size;
+    }
+
     public AppIdSettingMap snapshot() {
         AppIdSettingMap l = new AppIdSettingMap();
-        snapshot(l, this);
+        mNonSystemSettings.snapshot(l.mNonSystemSettings, mNonSystemSettings);
+        mSystemSettings.snapshot(l.mSystemSettings, mSystemSettings);
         return l;
     }
 
-    /**
-     * @return the maximum of all the App IDs that have been added to the map. 0 if map is empty.
-     */
-    public int getCurrentMaxAppId() {
-        return mCurrentMaxAppId;
-    }
-
-    /**
-     * @return the next available App ID that has not been added to the map
-     */
-    public int getNextAvailableAppId() {
-        if (mCurrentMaxAppId == 0) {
-            // No app id has been added yet
-            return Process.FIRST_APPLICATION_UID;
-        } else {
-            return mCurrentMaxAppId + 1;
-        }
+    public void registerObserver(Watcher observer) {
+        mNonSystemSettings.registerObserver(observer);
+        mSystemSettings.registerObserver(observer);
     }
 }
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index d117967..152c745 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -52,6 +52,7 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.function.QuadFunction;
 import com.android.server.FgThread;
+import com.android.server.LocalServices;
 import com.android.server.compat.CompatChange;
 import com.android.server.om.OverlayReferenceMapper;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -486,12 +487,12 @@
     }
 
     /** Builder method for an AppsFilter */
-    public static AppsFilter create(
-            PackageManagerInternal pms, PackageManagerServiceInjector injector) {
+    public static AppsFilter create(@NonNull PackageManagerServiceInjector injector,
+            @NonNull PackageManagerInternal pmInt) {
         final boolean forceSystemAppsQueryable =
                 injector.getContext().getResources()
                         .getBoolean(R.bool.config_forceSystemPackagesQueryable);
-        final FeatureConfigImpl featureConfig = new FeatureConfigImpl(pms, injector);
+        final FeatureConfigImpl featureConfig = new FeatureConfigImpl(pmInt, injector);
         final String[] forcedQueryablePackageNames;
         if (forceSystemAppsQueryable) {
             // all system apps already queryable, no need to read and parse individual exceptions
@@ -512,7 +513,7 @@
         };
         AppsFilter appsFilter = new AppsFilter(stateProvider, featureConfig,
                 forcedQueryablePackageNames, forceSystemAppsQueryable, null,
-                injector.getBackgroundExecutor(), pms);
+                injector.getBackgroundExecutor(), pmInt);
         featureConfig.setAppsFilter(appsFilter);
         return appsFilter;
     }
@@ -1329,7 +1330,9 @@
                                 + callingUid + " -> " + targetUid);
                         return true;
                     }
-                    return mShouldFilterCache.valueAt(callingIndex, targetIndex);
+                    if (!mShouldFilterCache.valueAt(callingIndex, targetIndex)) {
+                        return false;
+                    }
                 } else {
                     if (!shouldFilterApplicationInternal(
                             callingUid, callingSetting, targetPkgSetting, userId)) {
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index ecbb4a9..d26a1ac 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -19,6 +19,7 @@
 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.job.JobInfo;
 import android.app.job.JobParameters;
@@ -252,7 +253,8 @@
      *
      * <p>This is only for shell command and only root or shell user can use this.
      *
-     * @param packageNames dex optimize the passed packages or all packages if null
+     * @param packageNames dex optimize the passed packages in the given order, or all packages in
+     *         the default order if null
      *
      * @return true if dex optimization is complete. false if the task is cancelled or if there was
      *         an error.
@@ -267,11 +269,11 @@
                 resetStatesForNewDexOptRunLocked(Thread.currentThread());
             }
             PackageManagerService pm = mInjector.getPackageManagerService();
-            ArraySet<String> packagesToOptimize;
+            List<String> packagesToOptimize;
             if (packageNames == null) {
-                packagesToOptimize = mDexOptHelper.getOptimizablePackages();
+                packagesToOptimize = mDexOptHelper.getOptimizablePackages(pm.snapshotComputer());
             } else {
-                packagesToOptimize = new ArraySet<>(packageNames);
+                packagesToOptimize = packageNames;
             }
             return runIdleOptimization(pm, packagesToOptimize, /* isPostBootUpdate= */ false);
         } finally {
@@ -334,7 +336,7 @@
             return false;
         }
 
-        ArraySet<String> pkgs = mDexOptHelper.getOptimizablePackages();
+        List<String> pkgs = mDexOptHelper.getOptimizablePackages(pm.snapshotComputer());
         if (pkgs.isEmpty()) {
             Slog.i(TAG, "No packages to optimize");
             markPostBootUpdateCompleted(params);
@@ -524,7 +526,7 @@
     }
 
     /** Returns true if completed */
-    private boolean runIdleOptimization(PackageManagerService pm, ArraySet<String> pkgs,
+    private boolean runIdleOptimization(PackageManagerService pm, List<String> pkgs,
             boolean isPostBootUpdate) {
         synchronized (mLock) {
             mLastExecutionStartTimeMs = SystemClock.elapsedRealtime();
@@ -556,8 +558,8 @@
     }
 
     /** Gets the size of a package. */
-    private long getPackageSize(PackageManagerService pm, String pkg) {
-        PackageInfo info = pm.snapshotComputer().getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM);
+    private long getPackageSize(@NonNull Computer snapshot, String pkg) {
+        PackageInfo info = snapshot.getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM);
         long size = 0;
         if (info != null && info.applicationInfo != null) {
             File path = Paths.get(info.applicationInfo.sourceDir).toFile();
@@ -580,10 +582,9 @@
     }
 
     @Status
-    private int idleOptimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
+    private int idleOptimizePackages(PackageManagerService pm, List<String> pkgs,
             long lowStorageThreshold, boolean isPostBootUpdate) {
         ArraySet<String> updatedPackages = new ArraySet<>();
-        ArraySet<String> updatedPackagesDueToSecondaryDex = new ArraySet<>();
 
         try {
             boolean supportSecondaryDex = mInjector.supportSecondaryDex();
@@ -605,8 +606,9 @@
                 Slog.d(TAG, "Should Downgrade " + shouldDowngrade);
             }
             if (shouldDowngrade) {
+                final Computer snapshot = pm.snapshotComputer();
                 Set<String> unusedPackages =
-                        pm.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis);
+                        snapshot.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis);
                 if (DEBUG) {
                     Slog.d(TAG, "Unsused Packages " + String.join(",", unusedPackages));
                 }
@@ -618,7 +620,7 @@
                             // Should be aborted by the scheduler.
                             return abortCode;
                         }
-                        @DexOptResult int downgradeResult = downgradePackage(pm, pkg,
+                        @DexOptResult int downgradeResult = downgradePackage(snapshot, pm, pkg,
                                 /* isForPrimaryDex= */ true, isPostBootUpdate);
                         if (downgradeResult == PackageDexOptimizer.DEX_OPT_PERFORMED) {
                             updatedPackages.add(pkg);
@@ -629,7 +631,7 @@
                             return status;
                         }
                         if (supportSecondaryDex) {
-                            downgradeResult = downgradePackage(pm, pkg,
+                            downgradeResult = downgradePackage(snapshot, pm, pkg,
                                     /* isForPrimaryDex= */false, isPostBootUpdate);
                             status = convertPackageDexOptimizerStatusToInternal(downgradeResult);
                             if (status != STATUS_OK) {
@@ -638,25 +640,12 @@
                         }
                     }
 
-                    pkgs = new ArraySet<>(pkgs);
+                    pkgs = new ArrayList<>(pkgs);
                     pkgs.removeAll(unusedPackages);
                 }
             }
 
-            @Status int primaryResult = optimizePackages(pkgs, lowStorageThreshold,
-                    /*isForPrimaryDex=*/ true, updatedPackages, isPostBootUpdate);
-            if (primaryResult != STATUS_OK) {
-                return primaryResult;
-            }
-
-            if (!supportSecondaryDex) {
-                return STATUS_OK;
-            }
-
-            @Status int secondaryResult = optimizePackages(pkgs, lowStorageThreshold,
-                    /*isForPrimaryDex*/ false, updatedPackagesDueToSecondaryDex,
-                    isPostBootUpdate);
-            return secondaryResult;
+            return optimizePackages(pkgs, lowStorageThreshold, updatedPackages, isPostBootUpdate);
         } finally {
             // Always let the pinner service know about changes.
             notifyPinService(updatedPackages);
@@ -668,8 +657,10 @@
     }
 
     @Status
-    private int optimizePackages(ArraySet<String> pkgs, long lowStorageThreshold,
-            boolean isForPrimaryDex, ArraySet<String> updatedPackages, boolean isPostBootUpdate) {
+    private int optimizePackages(List<String> pkgs, long lowStorageThreshold,
+            ArraySet<String> updatedPackages, boolean isPostBootUpdate) {
+        boolean supportSecondaryDex = mInjector.supportSecondaryDex();
+
         for (String pkg : pkgs) {
             int abortCode = abortIdleOptimizations(lowStorageThreshold);
             if (abortCode != STATUS_OK) {
@@ -677,11 +668,23 @@
                 return abortCode;
             }
 
-            @DexOptResult int result = optimizePackage(pkg, isForPrimaryDex, isPostBootUpdate);
-            if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) {
+            @DexOptResult int primaryResult =
+                    optimizePackage(pkg, true /* isForPrimaryDex */, isPostBootUpdate);
+            if (primaryResult == PackageDexOptimizer.DEX_OPT_PERFORMED) {
                 updatedPackages.add(pkg);
-            } else if (result != PackageDexOptimizer.DEX_OPT_SKIPPED) {
-                return convertPackageDexOptimizerStatusToInternal(result);
+            } else if (primaryResult != PackageDexOptimizer.DEX_OPT_SKIPPED) {
+                return convertPackageDexOptimizerStatusToInternal(primaryResult);
+            }
+
+            if (!supportSecondaryDex) {
+                continue;
+            }
+
+            @DexOptResult int secondaryResult =
+                    optimizePackage(pkg, false /* isForPrimaryDex */, isPostBootUpdate);
+            if (secondaryResult != PackageDexOptimizer.DEX_OPT_PERFORMED
+                    && secondaryResult != PackageDexOptimizer.DEX_OPT_SKIPPED) {
+                return convertPackageDexOptimizerStatusToInternal(secondaryResult);
             }
         }
         return STATUS_OK;
@@ -696,8 +699,8 @@
      * @return PackageDexOptimizer.DEX_*
      */
     @DexOptResult
-    private int downgradePackage(PackageManagerService pm, String pkg, boolean isForPrimaryDex,
-            boolean isPostBootUpdate) {
+    private int downgradePackage(@NonNull Computer snapshot, PackageManagerService pm, String pkg,
+            boolean isForPrimaryDex, boolean isPostBootUpdate) {
         if (DEBUG) {
             Slog.d(TAG, "Downgrading " + pkg);
         }
@@ -709,15 +712,15 @@
         if (!isPostBootUpdate) {
             dexoptFlags |= DexoptOptions.DEXOPT_IDLE_BACKGROUND_JOB;
         }
-        long package_size_before = getPackageSize(pm, pkg);
+        long package_size_before = getPackageSize(snapshot, pkg);
         int result = PackageDexOptimizer.DEX_OPT_SKIPPED;
         if (isForPrimaryDex || PLATFORM_PACKAGE_NAME.equals(pkg)) {
             // This applies for system apps or if packages location is not a directory, i.e.
             // monolithic install.
-            if (!pm.canHaveOatDir(pkg)) {
+            if (!pm.canHaveOatDir(snapshot, pkg)) {
                 // For apps that don't have the oat directory, instead of downgrading,
                 // remove their compiler artifacts from dalvik cache.
-                pm.deleteOatArtifactsOfPackage(pkg);
+                pm.deleteOatArtifactsOfPackage(snapshot, pkg);
             } else {
                 result = performDexOptPrimary(pkg, reason, dexoptFlags);
             }
@@ -726,8 +729,9 @@
         }
 
         if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) {
+            final Computer newSnapshot = pm.snapshotComputer();
             FrameworkStatsLog.write(FrameworkStatsLog.APP_DOWNGRADED, pkg, package_size_before,
-                    getPackageSize(pm, pkg), /*aggressive=*/ false);
+                    getPackageSize(newSnapshot, pkg), /*aggressive=*/ false);
         }
         return result;
     }
diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java
index 6103d68..8e85301 100644
--- a/services/core/java/com/android/server/pm/Computer.java
+++ b/services/core/java/com/android/server/pm/Computer.java
@@ -58,10 +58,6 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
 import java.util.List;
 import java.util.Set;
 
@@ -92,92 +88,69 @@
  * and other managers (like PermissionManager) mean deadlock is possible.  On the
  * other hand, not overriding in {@link ComputerLocked} may leave a function walking
  * unstable data.
- *
- * To coax developers to consider such issues carefully, all methods in
- * {@link Computer} must be annotated with <code>@LiveImplementation(override =
- * MANDATORY)</code> or <code>LiveImplementation(locked = NOT_ALLOWED)</code>.  A unit
- * test verifies the annotation and that the annotation corresponds to the code in
- * {@link ComputerEngine} and {@link ComputerLocked}.
  */
 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
 public interface Computer extends PackageDataSnapshot {
 
     /**
-     * Every method must be annotated.
-     */
-    @Target({ ElementType.METHOD })
-    @Retention(RetentionPolicy.RUNTIME)
-    @interface LiveImplementation {
-        // A Computer method must be annotated with one of the following values:
-        //   MANDATORY - the method must be overridden in ComputerEngineLive.  The
-        //     format of the override is a call to the super method, wrapped in a
-        //     synchronization block.
-        //   NOT_ALLOWED - the method may not appear in the live computer.  It must
-        //     be final in the ComputerEngine.
-        int MANDATORY = 1;
-        int NOT_ALLOWED = 2;
-        int override() default MANDATORY;
-        String rationale() default "";
-    }
-
-    /**
      * Administrative statistics: record that the snapshot has been used.  Every call
      * to use() increments the usage counter.
      */
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     default void use() {
     }
     /**
      * Fetch the snapshot usage counter.
      * @return The number of times this snapshot was used.
      */
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     default int getUsed() {
         return 0;
     }
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType,
             @PackageManager.ResolveInfoFlagsBits long flags,
             @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags,
             int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType,
             long flags, int userId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent, String resolvedType,
             long flags, int userId, int callingUid, boolean includeInstantApps);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
     @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(Intent intent,
             String resolvedType, long flags, int filterCallingUid, int userId,
             boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
             String instantAppPkgName);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     ActivityInfo getActivityInfo(ComponentName component, long flags, int userId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+
+    /**
+     * Important: The provided filterCallingUid is used exclusively to filter out activities
+     * that can be seen based on user state. It's typically the original caller uid prior
+     * to clearing. Because it can only be provided by trusted code, its value can be
+     * trusted and will be used as-is; unlike userId which will be validated by this method.
+     */
     ActivityInfo getActivityInfoInternal(ComponentName component, long flags,
             int filterCallingUid, int userId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
     AndroidPackage getPackage(String packageName);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
     AndroidPackage getPackage(int uid);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     ApplicationInfo generateApplicationInfoFromSettings(String packageName, long flags,
             int filterCallingUid, int userId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     ApplicationInfo getApplicationInfo(String packageName, long flags, int userId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+
+    /**
+     * Important: The provided filterCallingUid is used exclusively to filter out applications
+     * that can be seen based on user state. It's typically the original caller uid prior
+     * to clearing. Because it can only be provided by trusted code, its value can be
+     * trusted and will be used as-is; unlike userId which will be validated by this method.
+     */
     ApplicationInfo getApplicationInfoInternal(String packageName, long flags,
             int filterCallingUid, int userId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+
+    /**
+     * Report the 'Home' activity which is currently set as "always use this one". If non is set
+     * then reports the most likely home activity or null if there are more than one.
+     */
     ComponentName getDefaultHomeActivity(int userId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates, int userId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent, String resolvedType,
             long flags, int sourceUserId, int parentUserId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     Intent getHomeIntent();
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(Intent intent,
             String resolvedType, int userId);
 
@@ -192,15 +165,11 @@
      * @param intent
      * @return A filtered list of resolved activities.
      */
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     List<ResolveInfo> applyPostResolutionFilter(@NonNull List<ResolveInfo> resolveInfos,
             String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid,
             boolean resolveForStart, int userId, Intent intent);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     PackageInfo generatePackageInfo(PackageStateInternal ps, long flags, int userId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     PackageInfo getPackageInfo(String packageName, long flags, int userId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     PackageInfo getPackageInfoInternal(String packageName, long versionCode, long flags,
             int filterCallingUid, int userId);
 
@@ -209,79 +178,69 @@
      * known {@link PackageState} instances without a {@link PackageState#getAndroidPackage()}
      * will not be represented.
      */
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
     String[] getAllAvailablePackageNames();
 
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     PackageStateInternal getPackageStateInternal(String packageName);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
     PackageStateInternal getPackageStateInternal(String packageName, int callingUid);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
-    @Nullable PackageState getPackageStateCopied(@NonNull String packageName);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     ParceledListSlice<PackageInfo> getInstalledPackages(long flags, int userId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter,
             int sourceUserId, int targetUserId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     ServiceInfo getServiceInfo(ComponentName component, long flags, int userId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     SharedLibraryInfo getSharedLibraryInfo(String name, long version);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
     String getInstantAppPackageName(int callingUid);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     String resolveExternalPackageName(AndroidPackage pkg);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     String resolveInternalPackageName(String packageName, long versionCode);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     String[] getPackagesForUid(int uid);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     UserInfo getProfileParent(int userId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     boolean canViewInstantApps(int callingUid, int userId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     boolean filterSharedLibPackage(@Nullable PackageStateInternal ps, int uid, int userId,
             long flags);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     boolean isCallerSameApp(String packageName, int uid);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     boolean isComponentVisibleToInstantApp(@Nullable ComponentName component);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     boolean isComponentVisibleToInstantApp(@Nullable ComponentName component,
             @PackageManager.ComponentType int type);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
-    boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, int userId,
+
+    /**
+     * From Android R, camera intents have to match system apps. The only exception to this is if
+     * the DPC has set the camera persistent preferred activity. This case was introduced
+     * because it is important that the DPC has the ability to set both system and non-system
+     * camera persistent preferred activities.
+     *
+     * @return {@code true} if the intent is a camera intent and the persistent preferred
+     * activity was not set by the DPC.
+     */
+    boolean isImplicitImageCaptureIntentAndNotSetByDpc(Intent intent, int userId,
             String resolvedType, long flags);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     boolean isInstantApp(String packageName, int userId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     boolean isInstantAppInternal(String packageName, @UserIdInt int userId, int callingUid);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     boolean shouldFilterApplication(@Nullable PackageStateInternal ps, int callingUid,
             @Nullable ComponentName component, @PackageManager.ComponentType int componentType,
             int userId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     boolean shouldFilterApplication(@Nullable PackageStateInternal ps, int callingUid,
             int userId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     boolean shouldFilterApplication(@NonNull SharedUserSetting sus, int callingUid,
             int userId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     int checkUidPermission(String permName, int uid);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
     int getPackageUidInternal(String packageName, long flags, int userId, int callingUid);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     long updateFlagsForApplication(long flags, int userId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     long updateFlagsForComponent(long flags, int userId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     long updateFlagsForPackage(long flags, int userId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+
+    /**
+     * Update given flags when being used to request {@link ResolveInfo}.
+     * <p>Instant apps are resolved specially, depending upon context. Minimally,
+     * {@code}flags{@code} must have the {@link PackageManager#MATCH_INSTANT}
+     * flag set. However, this flag is only honoured in three circumstances:
+     * <ul>
+     * <li>when called from a system process</li>
+     * <li>when the caller holds the permission {@code android.permission.ACCESS_INSTANT_APPS}</li>
+     * <li>when resolution occurs to start an activity with a {@code android.intent.action.VIEW}
+     * action and a {@code android.intent.category.BROWSABLE} category</li>
+     * </ul>
+     */
     long updateFlagsForResolve(long flags, int userId, int callingUid, boolean wantInstantApps,
             boolean isImplicitImageCaptureIntentAndNotSetByDpc);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     long updateFlagsForResolve(long flags, int userId, int callingUid, boolean wantInstantApps,
             boolean onlyExposedExplicitly, boolean isImplicitImageCaptureIntentAndNotSetByDpc);
 
@@ -299,117 +258,99 @@
      * @param checkShell whether to prevent shell from access if there's a debugging restriction
      * @param message the message to log on security exception
      */
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
             boolean requireFullPermission, boolean checkShell, String message);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+
+    /**
+     * Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS
+     * or INTERACT_ACROSS_USERS_FULL permissions, if the {@code userId} is not for the caller.
+     *
+     * @param checkShell whether to prevent shell from access if there's a debugging restriction
+     * @param message the message to log on security exception
+     */
     void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
             boolean requireFullPermission, boolean checkShell, String message);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
             boolean requireFullPermission, boolean checkShell,
             boolean requirePermissionWhenSameUser, String message);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
     SigningDetails getSigningDetails(@NonNull String packageName);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
     SigningDetails getSigningDetails(int uid);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
     boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
     boolean filterAppAccess(String packageName, int callingUid, int userId);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
     boolean filterAppAccess(int uid, int callingUid);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
     void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
     PackageManagerService.FindPreferredActivityBodyResult findPreferredActivityInternal(
             Intent intent, String resolvedType, long flags, List<ResolveInfo> query, boolean always,
             boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered);
-    @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
-    ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType, long flags,
+    ResolveInfo findPersistentPreferredActivity(Intent intent, String resolvedType, long flags,
             List<ResolveInfo> query, boolean debug, int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     PreferredIntentResolver getPreferredActivities(@UserIdInt int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
     ArrayMap<String, ? extends PackageStateInternal> getPackageStates();
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     String getRenamedPackage(@NonNull String packageName);
 
     /**
      * @return set of packages to notify
      */
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
     ArraySet<String> getNotifyPackagesForReplacedReceived(@NonNull String[] packages);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @PackageManagerService.PackageStartability
     int getPackageStartability(boolean safeMode, @NonNull String packageName, int callingUid,
             @UserIdInt int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     boolean isPackageAvailable(String packageName, @UserIdInt int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
     String[] currentToCanonicalPackageNames(@NonNull String[] names);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
     String[] canonicalToCurrentPackageNames(@NonNull String[] names);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
     int[] getPackageGids(@NonNull String packageName,
             @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     int getTargetSdkVersion(@NonNull String packageName);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     boolean activitySupportsIntent(@NonNull ComponentName resolveComponentName,
             @NonNull ComponentName component, @NonNull Intent intent, String resolvedType);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     ActivityInfo getReceiverInfo(@NonNull ComponentName component,
             @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     ParceledListSlice<SharedLibraryInfo> getSharedLibraries(@NonNull String packageName,
             @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     boolean canRequestPackageInstalls(@NonNull String packageName, int callingUid,
             int userId, boolean throwIfPermNotDeclared);
 
-    @Computer.LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
+    /**
+     * Returns true if the system or user is explicitly preventing an otherwise valid installer to
+     * complete an install. This includes checks like unknown sources and user restrictions.
+     */
     boolean isInstallDisabledForPackage(@NonNull String packageName, int uid,
             @UserIdInt int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     List<VersionedPackage> getPackagesUsingSharedLibrary(@NonNull SharedLibraryInfo libInfo,
             @PackageManager.PackageInfoFlagsBits long flags, int callingUid, @UserIdInt int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     ParceledListSlice<SharedLibraryInfo> getDeclaredSharedLibraries(
             @NonNull String packageName, @PackageManager.PackageInfoFlagsBits long flags,
             @UserIdInt int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     ProviderInfo getProviderInfo(@NonNull ComponentName component,
             @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     String[] getSystemSharedLibraryNames();
 
@@ -417,136 +358,103 @@
      * @return the state if the given package has a state and isn't filtered by visibility.
      * Provides no guarantee that the package is in any usable state.
      */
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     PackageStateInternal getPackageStateFiltered(@NonNull String packageName, int callingUid,
             @UserIdInt int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     int checkSignatures(@NonNull String pkg1, @NonNull String pkg2);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     int checkUidSignatures(int uid1, int uid2);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     boolean hasSigningCertificate(@NonNull String packageName, @NonNull byte[] certificate,
             @PackageManager.CertificateInputType int type);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     boolean hasUidSigningCertificate(int uid, @NonNull byte[] certificate,
             @PackageManager.CertificateInputType int type);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
     List<String> getAllPackages();
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     String getNameForUid(int uid);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     String[] getNamesForUids(@NonNull int[] uids);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     int getUidForSharedUser(@NonNull String sharedUserName);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     int getFlagsForUid(int uid);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     int getPrivateFlagsForUid(int uid);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     boolean isUidPrivileged(int uid);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
     String[] getAppOpPermissionPackages(@NonNull String permissionName);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
     ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(@NonNull String[] permissions,
             @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
     List<ApplicationInfo> getInstalledApplications(
             @PackageManager.ApplicationInfoFlagsBits long flags, @UserIdInt int userId,
             int callingUid);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     ProviderInfo resolveContentProvider(@NonNull String name,
             @PackageManager.ResolveInfoFlagsBits long flags, @UserIdInt int userId, int callingUid);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     ProviderInfo getGrantImplicitAccessProviderInfo(int recipientUid,
             @NonNull String visibleAuthority);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     void querySyncProviders(boolean safeMode, @NonNull List<String> outNames,
             @NonNull List<ProviderInfo> outInfo);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
     ParceledListSlice<ProviderInfo> queryContentProviders(@Nullable String processName, int uid,
             @PackageManager.ComponentInfoFlagsBits long flags, @Nullable String metaDataKey);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     InstrumentationInfo getInstrumentationInfo(@NonNull ComponentName component, int flags);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
     ParceledListSlice<InstrumentationInfo> queryInstrumentation(
             @NonNull String targetPackage, int flags);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
     List<PackageStateInternal> findSharedNonSystemLibraries(
             @NonNull PackageStateInternal pkgSetting);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     boolean getApplicationHiddenSettingAsUser(@NonNull String packageName, @UserIdInt int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     boolean isPackageSuspendedForUser(@NonNull String packageName, @UserIdInt int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     boolean isSuspendingAnyPackages(@NonNull String suspendingPackage, @UserIdInt int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
     ParceledListSlice<IntentFilter> getAllIntentFilters(@NonNull String packageName);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     boolean getBlockUninstallForUser(@NonNull String packageName, @UserIdInt int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     SparseArray<int[]> getBroadcastAllowList(@NonNull String packageName, @UserIdInt int[] userIds,
             boolean isInstantApp);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     String getInstallerPackageName(@NonNull String packageName);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     InstallSourceInfo getInstallSourceInfo(@NonNull String packageName);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @PackageManager.EnabledState
     int getApplicationEnabledSetting(@NonNull String packageName, @UserIdInt int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @PackageManager.EnabledState
     int getComponentEnabledSetting(@NonNull ComponentName component, int callingUid,
             @UserIdInt int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @PackageManager.EnabledState
     int getComponentEnabledSettingInternal(@NonNull ComponentName component, int callingUid,
             @UserIdInt int userId);
@@ -557,25 +465,19 @@
      * are all effectively enabled for the given component. Or if the component cannot be found,
      * returns false.
      */
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     boolean isComponentEffectivelyEnabled(@NonNull ComponentInfo componentInfo,
             @UserIdInt int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     KeySet getKeySetByAlias(@NonNull String packageName, @NonNull String alias);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     KeySet getSigningKeySet(@NonNull String packageName);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     boolean isPackageSignedByKeySet(@NonNull String packageName, @NonNull KeySet ks);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     boolean isPackageSignedByKeySetExactly(@NonNull String packageName, @NonNull KeySet ks);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     int[] getVisibilityAllowList(@NonNull String packageName, @UserIdInt int userId);
 
@@ -585,49 +487,37 @@
      * package visibility filtering is enabled on it. If the UID is part of a shared user ID,
      * return {@code true} if any one application belongs to the shared user ID meets the criteria.
      */
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     boolean canQueryPackage(int callingUid, @Nullable String targetPackageName);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     int getPackageUid(@NonNull String packageName, @PackageManager.PackageInfoFlagsBits long flags,
             @UserIdInt int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     boolean canAccessComponent(int callingUid, @NonNull ComponentName component,
             @UserIdInt int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     boolean isCallerInstallerOfRecord(@NonNull AndroidPackage pkg, int callingUid);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @PackageManager.InstallReason
     int getInstallReason(@NonNull String packageName, @UserIdInt int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     boolean canPackageQuery(@NonNull String sourcePackageName, @NonNull String targetPackageName,
             @UserIdInt int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     boolean canForwardTo(@NonNull Intent intent, @Nullable String resolvedType,
             @UserIdInt int sourceUserId, @UserIdInt int targetUserId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
     List<ApplicationInfo> getPersistentApplications(boolean safeMode, int flags);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
     SparseArray<String> getAppsWithSharedUserIds();
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
     String[] getSharedUserPackagesForPackage(@NonNull String packageName, @UserIdInt int userId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
     Set<String> getUnusedPackages(long downgradeTimeThresholdMillis);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     CharSequence getHarmfulAppWarning(@NonNull String packageName, @UserIdInt int userId);
 
@@ -638,55 +528,49 @@
      *
      * @return The filtered packages
      */
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
     String[] filterOnlySystemPackages(@Nullable String... pkgNames);
 
     // The methods in this block should be removed once SettingBase is interface snapshotted
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
     List<AndroidPackage> getPackagesForAppId(int appId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     int getUidTargetSdkVersion(int uid);
 
     /**
      * @see PackageManagerInternal#getProcessesForUid(int)
      */
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     ArrayMap<String, ProcessInfo> getProcessesForUid(int uid);
     // End block
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     boolean getBlockUninstall(@UserIdInt int userId, @NonNull String packageName);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
     WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> getSharedLibraries();
 
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     Pair<PackageStateInternal, SharedUserApi> getPackageOrSharedUser(int appId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     SharedUserApi getSharedUser(int sharedUserAppIde);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
     ArraySet<PackageStateInternal> getSharedUserPackages(int sharedUserAppId);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @NonNull
     ComponentResolverApi getComponentResolver();
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     PackageStateInternal getDisabledSystemPackage(@NonNull String packageName);
 
-    @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
     @Nullable
     ResolveInfo getInstantAppInstallerInfo();
+
+    @NonNull
+    WatchedArrayMap<String, Integer> getFrozenPackages();
+
+    @Nullable
+    ComponentName getInstantAppInstallerComponent();
 }
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 0c9855b..4abfd34 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -129,8 +129,6 @@
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
-import com.android.server.pm.pkg.PackageState;
-import com.android.server.pm.pkg.PackageStateImpl;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageStateUtils;
 import com.android.server.pm.pkg.PackageUserStateInternal;
@@ -466,7 +464,7 @@
 
         flags = updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart,
                 comp != null || pkgName != null /*onlyExposedExplicitly*/,
-                isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+                isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId, resolvedType,
                         flags));
         List<ResolveInfo> list = Collections.emptyList();
         boolean skipPostResolution = false;
@@ -1431,7 +1429,8 @@
         if (userId == UserHandle.USER_SYSTEM) {
             return resolveInfos;
         }
-        for (int i = resolveInfos.size() - 1; i >= 0; i--) {
+
+        for (int i = CollectionUtils.size(resolveInfos) - 1; i >= 0; i--) {
             ResolveInfo info = resolveInfos.get(i);
             if ((info.activityInfo.flags & ActivityInfo.FLAG_SYSTEM_USER_ONLY) != 0) {
                 resolveInfos.remove(i);
@@ -1722,15 +1721,6 @@
         return mSettings.getPackage(packageName);
     }
 
-    @Nullable
-    public PackageState getPackageStateCopied(@NonNull String packageName) {
-        int callingUid = Binder.getCallingUid();
-        packageName = resolveInternalPackageNameInternalLocked(
-                packageName, PackageManager.VERSION_CODE_HIGHEST, callingUid);
-        PackageStateInternal pkgSetting = mSettings.getPackage(packageName);
-        return pkgSetting == null ? null : PackageStateImpl.copy(pkgSetting);
-    }
-
     public final ParceledListSlice<PackageInfo> getInstalledPackages(long flags, int userId) {
         final int callingUid = Binder.getCallingUid();
         if (getInstantAppPackageName(callingUid) != null) {
@@ -2468,7 +2458,7 @@
      * @return {@code true} if the intent is a camera intent and the persistent preferred
      * activity was not set by the DPC.
      */
-    public final boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent,
+    public final boolean isImplicitImageCaptureIntentAndNotSetByDpc(Intent intent,
             int userId, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags) {
         return intent.isImplicitImageCaptureIntent() && !isPersistentPreferredActivitySetByDpm(
                 intent, userId, resolvedType, flags);
@@ -2647,6 +2637,13 @@
     public final boolean shouldFilterApplication(@Nullable PackageStateInternal ps,
             int callingUid, @Nullable ComponentName component,
             @PackageManager.ComponentType int componentType, int userId) {
+        if (Process.isSdkSandboxUid(callingUid)) {
+            int clientAppUid = Process.getAppUidForSdkSandboxUid(callingUid);
+            // SDK sandbox should be able to see it's client app
+            if (clientAppUid == UserHandle.getUid(userId, ps.getAppId())) {
+                return false;
+            }
+        }
         // if we're in an isolated process, get the real calling UID
         if (Process.isIsolated(callingUid)) {
             callingUid = getIsolatedOwner(callingUid);
@@ -3228,12 +3225,12 @@
 
         flags = updateFlagsForResolve(
                 flags, userId, callingUid, false /*includeInstantApps*/,
-                isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId,
+                isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId,
                         resolvedType, flags));
         intent = PackageManagerServiceUtils.updateIntentForResolve(intent);
 
         // Try to find a matching persistent preferred activity.
-        result.mPreferredResolveInfo = findPersistentPreferredActivityLP(intent,
+        result.mPreferredResolveInfo = findPersistentPreferredActivity(intent,
                 resolvedType, flags, query, debug, userId);
 
         // If a persistent preferred activity matched, use it.
@@ -3444,7 +3441,7 @@
                 userId, queryMayBeFiltered, callingUid, isDeviceProvisioned);
     }
 
-    public final ResolveInfo findPersistentPreferredActivityLP(Intent intent,
+    public final ResolveInfo findPersistentPreferredActivity(Intent intent,
             String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
             List<ResolveInfo> query, boolean debug, int userId) {
         final int n = query.size();
@@ -5418,7 +5415,7 @@
             }
             long flags = updateFlagsForResolve(0, parent.id, callingUid,
                     false /*includeInstantApps*/,
-                    isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, parent.id,
+                    isImplicitImageCaptureIntentAndNotSetByDpc(intent, parent.id,
                             resolvedType, 0));
             flags |= PackageManager.MATCH_DEFAULT_ONLY;
             CrossProfileDomainInfo xpDomainInfo = getCrossProfileDomainPreferredLpr(
@@ -5694,4 +5691,17 @@
     public ResolveInfo getInstantAppInstallerInfo() {
         return mInstantAppInstallerInfo;
     }
+
+    @NonNull
+    @Override
+    public WatchedArrayMap<String, Integer> getFrozenPackages() {
+        return mFrozenPackages;
+    }
+
+    @Nullable
+    @Override
+    public ComponentName getInstantAppInstallerComponent() {
+        return mLocalInstantAppInstallerActivity == null
+                ? null : mLocalInstantAppInstallerActivity.getComponentName();
+    }
 }
diff --git a/services/core/java/com/android/server/pm/ComputerLocked.java b/services/core/java/com/android/server/pm/ComputerLocked.java
index 5d89c7d..af196d5 100644
--- a/services/core/java/com/android/server/pm/ComputerLocked.java
+++ b/services/core/java/com/android/server/pm/ComputerLocked.java
@@ -16,62 +16,21 @@
 
 package com.android.server.pm;
 
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
 import android.content.ComponentName;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.ComponentInfo;
-import android.content.pm.InstallSourceInfo;
-import android.content.pm.InstrumentationInfo;
-import android.content.pm.KeySet;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ParceledListSlice;
-import android.content.pm.ProcessInfo;
-import android.content.pm.ProviderInfo;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.pm.SharedLibraryInfo;
-import android.content.pm.SigningDetails;
-import android.content.pm.VersionedPackage;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Pair;
-import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
-import com.android.server.pm.pkg.PackageState;
-import com.android.server.pm.pkg.PackageStateInternal;
-import com.android.server.pm.pkg.SharedUserApi;
-import com.android.server.pm.resolution.ComponentResolverApi;
-import com.android.server.utils.WatchedArrayMap;
-import com.android.server.utils.WatchedLongSparseArray;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
 
 /**
  * This subclass is the external interface to the live computer.  Some internal helper
- * methods are overridden to fetch live data instead of snapshot data.  For each
- * Computer interface that is overridden in this class, the override takes the PM lock
- * and then delegates to the live computer engine.  This is required because there are
- * no locks taken in the engine itself.
+ * methods are overridden to fetch live data instead of snapshot data.
  */
 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
 public final class ComputerLocked extends ComputerEngine {
-    private final Object mLock;
 
     ComputerLocked(PackageManagerService.Snapshot args) {
         super(args);
-        mLock = mService.mLock;
     }
 
     protected ComponentName resolveComponentName() {
@@ -83,814 +42,4 @@
     protected ApplicationInfo androidApplication() {
         return mService.getCoreAndroidApplication();
     }
-
-    public @NonNull List<ResolveInfo> queryIntentServicesInternalBody(Intent intent,
-            String resolvedType, int flags, int userId, int callingUid,
-            String instantAppPkgName) {
-        synchronized (mLock) {
-            return super.queryIntentServicesInternalBody(intent, resolvedType, flags, userId,
-                    callingUid, instantAppPkgName);
-        }
-    }
-    public @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(
-            Intent intent, String resolvedType, long flags, int filterCallingUid, int userId,
-            boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
-            String instantAppPkgName) {
-        synchronized (mLock) {
-            return super.queryIntentActivitiesInternalBody(intent, resolvedType, flags,
-                    filterCallingUid, userId, resolveForStart, allowDynamicSplits, pkgName,
-                    instantAppPkgName);
-        }
-    }
-    public ActivityInfo getActivityInfoInternalBody(ComponentName component, int flags,
-            int filterCallingUid, int userId) {
-        synchronized (mLock) {
-            return super.getActivityInfoInternalBody(component, flags, filterCallingUid,
-                    userId);
-        }
-    }
-    public AndroidPackage getPackage(String packageName) {
-        synchronized (mLock) {
-            return super.getPackage(packageName);
-        }
-    }
-    public AndroidPackage getPackage(int uid) {
-        synchronized (mLock) {
-            return super.getPackage(uid);
-        }
-    }
-    public ApplicationInfo getApplicationInfoInternalBody(String packageName, int flags,
-            int filterCallingUid, int userId) {
-        synchronized (mLock) {
-            return super.getApplicationInfoInternalBody(packageName, flags, filterCallingUid,
-                    userId);
-        }
-    }
-    public ArrayList<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPrBody(
-            Intent intent, int matchFlags, List<ResolveInfo> candidates,
-            CrossProfileDomainInfo xpDomainInfo, int userId, boolean debug) {
-        synchronized (mLock) {
-            return super.filterCandidatesWithDomainPreferredActivitiesLPrBody(intent,
-                    matchFlags, candidates, xpDomainInfo, userId, debug);
-        }
-    }
-    public PackageInfo getPackageInfoInternalBody(String packageName, long versionCode,
-            int flags, int filterCallingUid, int userId) {
-        synchronized (mLock) {
-            return super.getPackageInfoInternalBody(packageName, versionCode, flags,
-                    filterCallingUid, userId);
-        }
-    }
-
-    @Override
-    public String[] getAllAvailablePackageNames() {
-        synchronized (mLock) {
-            return super.getAllAvailablePackageNames();
-        }
-    }
-
-    public PackageStateInternal getPackageStateInternal(String packageName, int callingUid) {
-        synchronized (mLock) {
-            return super.getPackageStateInternal(packageName, callingUid);
-        }
-    }
-
-    @Nullable
-    public PackageState getPackageStateCopied(@NonNull String packageName) {
-        synchronized (mLock) {
-            return super.getPackageStateCopied(packageName);
-        }
-    }
-
-    public ParceledListSlice<PackageInfo> getInstalledPackagesBody(int flags, int userId,
-            int callingUid) {
-        synchronized (mLock) {
-            return super.getInstalledPackagesBody(flags, userId, callingUid);
-        }
-    }
-    public ServiceInfo getServiceInfoBody(ComponentName component, int flags, int userId,
-            int callingUid) {
-        synchronized (mLock) {
-            return super.getServiceInfoBody(component, flags, userId, callingUid);
-        }
-    }
-    public String getInstantAppPackageName(int callingUid) {
-        synchronized (mLock) {
-            return super.getInstantAppPackageName(callingUid);
-        }
-    }
-    public String[] getPackagesForUidInternalBody(int callingUid, int userId, int appId,
-            boolean isCallerInstantApp) {
-        synchronized (mLock) {
-            return super.getPackagesForUidInternalBody(callingUid, userId, appId,
-                    isCallerInstantApp);
-        }
-    }
-    public boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId,
-            int callingUid) {
-        synchronized (mLock) {
-            return super.isInstantAppInternalBody(packageName, userId, callingUid);
-        }
-    }
-    public boolean isInstantAppResolutionAllowedBody(Intent intent,
-            List<ResolveInfo> resolvedActivities, int userId, boolean skipPackageCheck,
-            int flags) {
-        synchronized (mLock) {
-            return super.isInstantAppResolutionAllowedBody(intent, resolvedActivities, userId,
-                    skipPackageCheck, flags);
-        }
-    }
-    public int getPackageUidInternal(String packageName, int flags, int userId,
-            int callingUid) {
-        synchronized (mLock) {
-            return super.getPackageUidInternal(packageName, flags, userId, callingUid);
-        }
-    }
-    public SigningDetails getSigningDetails(@NonNull String packageName) {
-        synchronized (mLock) {
-            return super.getSigningDetails(packageName);
-        }
-    }
-    public SigningDetails getSigningDetails(int uid) {
-        synchronized (mLock) {
-            return super.getSigningDetails(uid);
-        }
-    }
-    public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
-        synchronized (mLock) {
-            return super.filterAppAccess(pkg, callingUid, userId);
-        }
-    }
-    public boolean filterAppAccess(String packageName, int callingUid, int userId) {
-        synchronized (mLock) {
-            return super.filterAppAccess(packageName, callingUid, userId);
-        }
-    }
-    public boolean filterAppAccess(int uid, int callingUid) {
-        synchronized (mLock) {
-            return super.filterAppAccess(uid, callingUid);
-        }
-    }
-    public void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
-        synchronized (mLock) {
-            super.dump(type, fd, pw, dumpState);
-        }
-    }
-    public PackageManagerService.FindPreferredActivityBodyResult findPreferredActivityBody(
-            Intent intent, String resolvedType, int flags, List<ResolveInfo> query, boolean always,
-            boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered,
-            int callingUid, boolean isDeviceProvisioned) {
-        synchronized (mLock) {
-            return super.findPreferredActivityBody(intent, resolvedType, flags, query, always,
-                    removeMatches, debug, userId, queryMayBeFiltered, callingUid,
-                    isDeviceProvisioned);
-        }
-    }
-
-    @Override
-    public PreferredIntentResolver getPreferredActivities(int userId) {
-        synchronized (mLock) {
-            return super.getPreferredActivities(userId);
-        }
-    }
-
-    @NonNull
-    @Override
-    public ArrayMap<String, ? extends PackageStateInternal> getPackageStates() {
-        synchronized (mLock) {
-            return super.getPackageStates();
-        }
-    }
-
-    @Nullable
-    @Override
-    public String getRenamedPackage(@NonNull String packageName) {
-        synchronized (mLock) {
-            return super.getRenamedPackage(packageName);
-        }
-    }
-
-    @NonNull
-    @Override
-    public ArraySet<String> getNotifyPackagesForReplacedReceived(@NonNull String[] packages) {
-        synchronized (mLock) {
-            return super.getNotifyPackagesForReplacedReceived(packages);
-        }
-    }
-
-    @Override
-    public int getPackageStartability(boolean safeMode, @NonNull String packageName, int callingUid,
-            @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.getPackageStartability(safeMode, packageName, callingUid, userId);
-        }
-    }
-
-    @Override
-    public boolean isPackageAvailable(String packageName, @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.isPackageAvailable(packageName, userId);
-        }
-    }
-
-    @Override
-    public String[] currentToCanonicalPackageNames(String[] names) {
-        synchronized (mLock) {
-            return super.currentToCanonicalPackageNames(names);
-        }
-    }
-
-    @Override
-    public String[] canonicalToCurrentPackageNames(String[] names) {
-        synchronized (mLock) {
-            return super.canonicalToCurrentPackageNames(names);
-        }
-    }
-
-    @Override
-    public int[] getPackageGids(@NonNull String packageName,
-            @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.getPackageGids(packageName, flags, userId);
-        }
-    }
-
-    @Override
-    public int getTargetSdkVersion(@NonNull String packageName) {
-        synchronized (mLock) {
-            return super.getTargetSdkVersion(packageName);
-        }
-    }
-
-    @Override
-    public boolean activitySupportsIntent(@NonNull ComponentName resolveComponentName,
-            @NonNull ComponentName component, @NonNull Intent intent, String resolvedType) {
-        synchronized (mLock) {
-            return super.activitySupportsIntent(resolveComponentName, component, intent,
-                    resolvedType);
-        }
-    }
-
-    @Nullable
-    @Override
-    public ActivityInfo getReceiverInfo(@NonNull ComponentName component,
-            @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.getReceiverInfo(component, flags, userId);
-        }
-    }
-
-    @Nullable
-    @Override
-    public ParceledListSlice<SharedLibraryInfo> getSharedLibraries(@NonNull String packageName,
-            @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.getSharedLibraries(packageName, flags, userId);
-        }
-    }
-
-    @Override
-    public boolean canRequestPackageInstalls(@NonNull String packageName, int callingUid,
-            @UserIdInt int userId, boolean throwIfPermNotDeclared) {
-        synchronized (mLock) {
-            return super.canRequestPackageInstalls(packageName, callingUid, userId,
-                    throwIfPermNotDeclared);
-        }
-    }
-
-    @Override
-    public List<VersionedPackage> getPackagesUsingSharedLibrary(@NonNull SharedLibraryInfo libInfo,
-            @PackageManager.PackageInfoFlagsBits long flags, int callingUid,
-            @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.getPackagesUsingSharedLibrary(libInfo, flags, callingUid, userId);
-        }
-    }
-
-    @Nullable
-    @Override
-    public ParceledListSlice<SharedLibraryInfo> getDeclaredSharedLibraries(
-            @NonNull String packageName, @PackageManager.PackageInfoFlagsBits long flags,
-            @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.getDeclaredSharedLibraries(packageName, flags, userId);
-        }
-    }
-
-    @Nullable
-    @Override
-    public ProviderInfo getProviderInfo(@NonNull ComponentName component,
-            @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.getProviderInfo(component, flags, userId);
-        }
-    }
-
-    @Nullable
-    @Override
-    public String[] getSystemSharedLibraryNames() {
-        synchronized (mLock) {
-            return super.getSystemSharedLibraryNames();
-        }
-    }
-
-    @Override
-    public int checkSignatures(@NonNull String pkg1,
-            @NonNull String pkg2) {
-        synchronized (mLock) {
-            return super.checkSignatures(pkg1, pkg2);
-        }
-    }
-
-    @Override
-    public int checkUidSignatures(int uid1, int uid2) {
-        synchronized (mLock) {
-            return super.checkUidSignatures(uid1, uid2);
-        }
-    }
-
-    @Override
-    public boolean hasSigningCertificate(@NonNull String packageName, @NonNull byte[] certificate,
-            int type) {
-        synchronized (mLock) {
-            return super.hasSigningCertificate(packageName, certificate, type);
-        }
-    }
-
-    @Override
-    public boolean hasUidSigningCertificate(int uid, @NonNull byte[] certificate, int type) {
-        synchronized (mLock) {
-            return super.hasUidSigningCertificate(uid, certificate, type);
-        }
-    }
-
-    @Override
-    public List<String> getAllPackages() {
-        synchronized (mLock) {
-            return super.getAllPackages();
-        }
-    }
-
-    @Nullable
-    @Override
-    public String getNameForUid(int uid) {
-        synchronized (mLock) {
-            return super.getNameForUid(uid);
-        }
-    }
-
-    @Nullable
-    @Override
-    public String[] getNamesForUids(int[] uids) {
-        synchronized (mLock) {
-            return super.getNamesForUids(uids);
-        }
-    }
-
-    @Override
-    public int getUidForSharedUser(@NonNull String sharedUserName) {
-        synchronized (mLock) {
-            return super.getUidForSharedUser(sharedUserName);
-        }
-    }
-
-    @Override
-    public int getFlagsForUid(int uid) {
-        synchronized (mLock) {
-            return super.getFlagsForUid(uid);
-        }
-    }
-
-    @Override
-    public int getPrivateFlagsForUid(int uid) {
-        synchronized (mLock) {
-            return super.getPrivateFlagsForUid(uid);
-        }
-    }
-
-    @Override
-    public boolean isUidPrivileged(int uid) {
-        synchronized (mLock) {
-            return super.isUidPrivileged(uid);
-        }
-    }
-
-    @NonNull
-    @Override
-    public String[] getAppOpPermissionPackages(@NonNull String permissionName) {
-        synchronized (mLock) {
-            return super.getAppOpPermissionPackages(permissionName);
-        }
-    }
-
-    @NonNull
-    @Override
-    public ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
-            @NonNull String[] permissions, @PackageManager.PackageInfoFlagsBits long flags,
-            @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.getPackagesHoldingPermissions(permissions, flags, userId);
-        }
-    }
-
-    @NonNull
-    @Override
-    public List<ApplicationInfo> getInstalledApplications(
-            @PackageManager.ApplicationInfoFlagsBits long flags, @UserIdInt int userId,
-            int callingUid) {
-        synchronized (mLock) {
-            return super.getInstalledApplications(flags, userId, callingUid);
-        }
-    }
-
-    @Nullable
-    @Override
-    public ProviderInfo resolveContentProvider(@NonNull String name,
-            @PackageManager.ResolveInfoFlagsBits long flags, @UserIdInt int userId,
-            int callingUid) {
-        synchronized (mLock) {
-            return super.resolveContentProvider(name, flags, userId, callingUid);
-        }
-    }
-
-    @Nullable
-    @Override
-    public ProviderInfo getGrantImplicitAccessProviderInfo(int recipientUid,
-            @NonNull String visibleAuthority) {
-        synchronized (mLock) {
-            return super.getGrantImplicitAccessProviderInfo(recipientUid, visibleAuthority);
-        }
-    }
-
-    @Override
-    public void querySyncProviders(boolean safeMode, @NonNull List<String> outNames,
-            @NonNull List<ProviderInfo> outInfo) {
-        synchronized (mLock) {
-            super.querySyncProviders(safeMode, outNames, outInfo);
-        }
-    }
-
-    @NonNull
-    @Override
-    public ParceledListSlice<ProviderInfo> queryContentProviders(@Nullable String processName,
-            int uid, @PackageManager.ComponentInfoFlagsBits long flags,
-            @Nullable String metaDataKey) {
-        synchronized (mLock) {
-            return super.queryContentProviders(processName, uid, flags, metaDataKey);
-        }
-    }
-
-    @Nullable
-    @Override
-    public InstrumentationInfo getInstrumentationInfo(@NonNull ComponentName component, int flags) {
-        synchronized (mLock) {
-            return super.getInstrumentationInfo(component, flags);
-        }
-    }
-
-    @NonNull
-    @Override
-    public ParceledListSlice<InstrumentationInfo> queryInstrumentation(
-            @NonNull String targetPackage, int flags) {
-        synchronized (mLock) {
-            return super.queryInstrumentation(targetPackage, flags);
-        }
-    }
-
-    @NonNull
-    @Override
-    public List<PackageStateInternal> findSharedNonSystemLibraries(
-            @NonNull PackageStateInternal pkgSetting) {
-        synchronized (mLock) {
-            return super.findSharedNonSystemLibraries(pkgSetting);
-        }
-    }
-
-    @Override
-    public boolean getApplicationHiddenSettingAsUser(@NonNull String packageName,
-            @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.getApplicationHiddenSettingAsUser(packageName, userId);
-        }
-    }
-
-    @Override
-    public boolean isPackageSuspendedForUser(@NonNull String packageName, @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.isPackageSuspendedForUser(packageName, userId);
-        }
-    }
-
-    @Override
-    public boolean isSuspendingAnyPackages(@NonNull String suspendingPackage,
-            @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.isSuspendingAnyPackages(suspendingPackage, userId);
-        }
-    }
-
-    @NonNull
-    @Override
-    public ParceledListSlice<IntentFilter> getAllIntentFilters(@NonNull String packageName) {
-        synchronized (mLock) {
-            return super.getAllIntentFilters(packageName);
-        }
-    }
-
-    @Override
-    public boolean getBlockUninstallForUser(@NonNull String packageName, @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.getBlockUninstallForUser(packageName, userId);
-        }
-    }
-
-    @Nullable
-    @Override
-    public SparseArray<int[]> getBroadcastAllowList(@NonNull String packageName,
-            @UserIdInt int[] userIds, boolean isInstantApp) {
-        synchronized (mLock) {
-            return super.getBroadcastAllowList(packageName, userIds, isInstantApp);
-        }
-    }
-
-    @Nullable
-    @Override
-    public String getInstallerPackageName(@NonNull String packageName) {
-        synchronized (mLock) {
-            return super.getInstallerPackageName(packageName);
-        }
-    }
-
-    @Nullable
-    @Override
-    public InstallSourceInfo getInstallSourceInfo(@NonNull String packageName) {
-        synchronized (mLock) {
-            return super.getInstallSourceInfo(packageName);
-        }
-    }
-
-    @Override
-    public int getApplicationEnabledSetting(@NonNull String packageName, @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.getApplicationEnabledSetting(packageName, userId);
-        }
-    }
-
-    @Override
-    public int getComponentEnabledSetting(@NonNull ComponentName component, int callingUid,
-            @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.getComponentEnabledSetting(component, callingUid, userId);
-        }
-    }
-
-    @Override
-    public int getComponentEnabledSettingInternal(@NonNull ComponentName component, int callingUid,
-            @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.getComponentEnabledSettingInternal(component, callingUid, userId);
-        }
-    }
-
-    @Override
-    public boolean isComponentEffectivelyEnabled(@NonNull ComponentInfo componentInfo,
-            @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.isComponentEffectivelyEnabled(componentInfo, userId);
-        }
-    }
-
-    @Nullable
-    @Override
-    public KeySet getKeySetByAlias(@NonNull String packageName, @NonNull String alias) {
-        synchronized (mLock) {
-            return super.getKeySetByAlias(packageName, alias);
-        }
-    }
-
-    @Nullable
-    @Override
-    public KeySet getSigningKeySet(@NonNull String packageName) {
-        synchronized (mLock) {
-            return super.getSigningKeySet(packageName);
-        }
-    }
-
-    @Override
-    public boolean isPackageSignedByKeySet(@NonNull String packageName, @NonNull KeySet ks) {
-        synchronized (mLock) {
-            return super.isPackageSignedByKeySet(packageName, ks);
-        }
-    }
-
-    @Override
-    public boolean isPackageSignedByKeySetExactly(@NonNull String packageName, @NonNull KeySet ks) {
-        synchronized (mLock) {
-            return super.isPackageSignedByKeySetExactly(packageName, ks);
-        }
-    }
-
-    @Nullable
-    @Override
-    public int[] getVisibilityAllowList(@NonNull String packageName, @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.getVisibilityAllowList(packageName, userId);
-        }
-    }
-
-    @Override
-    public boolean canQueryPackage(int callingUid, @Nullable String targetPackageName) {
-        synchronized (mLock) {
-            return super.canQueryPackage(callingUid, targetPackageName);
-        }
-    }
-
-    @Override
-    public int getPackageUid(@NonNull String packageName,
-            @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.getPackageUid(packageName, flags, userId);
-        }
-    }
-
-    @Override
-    public boolean canAccessComponent(int callingUid, @NonNull ComponentName component,
-            @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.canAccessComponent(callingUid, component, userId);
-        }
-    }
-
-    @Override
-    public boolean isCallerInstallerOfRecord(@NonNull AndroidPackage pkg, int callingUid) {
-        synchronized (mLock) {
-            return super.isCallerInstallerOfRecord(pkg, callingUid);
-        }
-    }
-
-    @Override
-    public int getInstallReason(@NonNull String packageName, @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.getInstallReason(packageName, userId);
-        }
-    }
-
-    @Override
-    public boolean canPackageQuery(@NonNull String sourcePackageName,
-            @NonNull String targetPackageName, @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.canPackageQuery(sourcePackageName, targetPackageName, userId);
-        }
-    }
-
-    @Override
-    public boolean canForwardTo(@NonNull Intent intent, @Nullable String resolvedType,
-            @UserIdInt int sourceUserId, @UserIdInt int targetUserId) {
-        synchronized (mLock) {
-            return super.canForwardTo(intent, resolvedType, sourceUserId, targetUserId);
-        }
-    }
-
-    @NonNull
-    @Override
-    public List<ApplicationInfo> getPersistentApplications(boolean safeMode, int flags) {
-        synchronized (mLock) {
-            return super.getPersistentApplications(safeMode, flags);
-        }
-    }
-
-    @NonNull
-    @Override
-    public SparseArray<String> getAppsWithSharedUserIds() {
-        synchronized (mLock) {
-            return super.getAppsWithSharedUserIds();
-        }
-    }
-
-    @NonNull
-    @Override
-    public String[] getSharedUserPackagesForPackage(@NonNull String packageName,
-            @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.getSharedUserPackagesForPackage(packageName, userId);
-        }
-    }
-
-    @NonNull
-    @Override
-    public Set<String> getUnusedPackages(long downgradeTimeThresholdMillis) {
-        synchronized (mLock) {
-            return super.getUnusedPackages(downgradeTimeThresholdMillis);
-        }
-    }
-
-    @Nullable
-    @Override
-    public CharSequence getHarmfulAppWarning(@NonNull String packageName, @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.getHarmfulAppWarning(packageName, userId);
-        }
-    }
-
-    @NonNull
-    @Override
-    public String[] filterOnlySystemPackages(@Nullable String... pkgNames) {
-        synchronized (mLock) {
-            return super.filterOnlySystemPackages(pkgNames);
-        }
-    }
-
-    @NonNull
-    @Override
-    public List<AndroidPackage> getPackagesForAppId(int appId) {
-        synchronized (mLock) {
-            return super.getPackagesForAppId(appId);
-        }
-    }
-
-    @Override
-    public int getUidTargetSdkVersion(int uid) {
-        synchronized (mLock) {
-            return super.getUidTargetSdkVersion(uid);
-        }
-    }
-
-    @Nullable
-    @Override
-    public ArrayMap<String, ProcessInfo> getProcessesForUid(int uid) {
-        synchronized (mLock) {
-            return super.getProcessesForUid(uid);
-        }
-    }
-
-    @Override
-    public PackageStateInternal getPackageStateFiltered(@NonNull String packageName, int callingUid,
-            @UserIdInt int userId) {
-        synchronized (mLock) {
-            return super.getPackageStateFiltered(packageName, callingUid, userId);
-        }
-    }
-
-    @Override
-    public boolean getBlockUninstall(@UserIdInt int userId, @NonNull String packageName) {
-        synchronized (mLock) {
-            return super.getBlockUninstall(userId, packageName);
-        }
-    }
-
-    @NonNull
-    @Override
-    public WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> getSharedLibraries() {
-        synchronized (mLock) {
-            return super.getSharedLibraries();
-        }
-    }
-
-    @Nullable
-    @Override
-    public Pair<PackageStateInternal, SharedUserApi> getPackageOrSharedUser(int appId) {
-        synchronized (mLock) {
-            return super.getPackageOrSharedUser(appId);
-        }
-    }
-
-    @Nullable
-    @Override
-    public SharedUserApi getSharedUser(int sharedUserAppId) {
-        synchronized (mLock) {
-            return super.getSharedUser(sharedUserAppId);
-        }
-    }
-
-    @NonNull
-    @Override
-    public ArraySet<PackageStateInternal> getSharedUserPackages(int sharedUserAppId) {
-        synchronized (mLock) {
-            return super.getSharedUserPackages(sharedUserAppId);
-        }
-    }
-
-    @NonNull
-    @Override
-    public ComponentResolverApi getComponentResolver() {
-        synchronized (mLock) {
-            return super.getComponentResolver();
-        }
-    }
-
-    @Nullable
-    @Override
-    public PackageStateInternal getDisabledSystemPackage(@NonNull String packageName) {
-        synchronized (mLock) {
-            return super.getDisabledSystemPackage(packageName);
-        }
-    }
-
-    @Nullable
-    @Override
-    public ResolveInfo getInstantAppInstallerInfo() {
-        synchronized (mLock) {
-            return super.getInstantAppInstallerInfo();
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/pm/ComputerTracker.java b/services/core/java/com/android/server/pm/ComputerTracker.java
deleted file mode 100644
index 216ad71..0000000
--- a/services/core/java/com/android/server/pm/ComputerTracker.java
+++ /dev/null
@@ -1,1327 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.pm;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.ComponentInfo;
-import android.content.pm.InstallSourceInfo;
-import android.content.pm.InstrumentationInfo;
-import android.content.pm.KeySet;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
-import android.content.pm.ParceledListSlice;
-import android.content.pm.ProcessInfo;
-import android.content.pm.ProviderInfo;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.pm.SharedLibraryInfo;
-import android.content.pm.SigningDetails;
-import android.content.pm.UserInfo;
-import android.content.pm.VersionedPackage;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Pair;
-import android.util.SparseArray;
-
-import com.android.server.pm.parsing.pkg.AndroidPackage;
-import com.android.server.pm.pkg.PackageState;
-import com.android.server.pm.pkg.PackageStateInternal;
-import com.android.server.pm.pkg.SharedUserApi;
-import com.android.server.pm.resolution.ComponentResolverApi;
-import com.android.server.utils.WatchedArrayMap;
-import com.android.server.utils.WatchedLongSparseArray;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * This subclass delegates to methods in a Computer after reference-counting the computer.
- */
-public final class ComputerTracker implements Computer {
-
-    // The number of times a thread reused a computer in its stack instead of fetching
-    // a snapshot computer.
-    private final AtomicInteger mReusedSnapshot = new AtomicInteger(0);
-
-    private final PackageManagerService mService;
-    ComputerTracker(PackageManagerService s) {
-        mService = s;
-    }
-
-    private ThreadComputer snapshot() {
-        ThreadComputer current = PackageManagerService.sThreadComputer.get();
-        if (current.mRefCount > 0) {
-            current.acquire();
-            mReusedSnapshot.incrementAndGet();
-        } else {
-            current.acquire(mService.snapshotComputer());
-        }
-        return current;
-    }
-
-    public @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
-            String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
-            @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags,
-            int filterCallingUid, int userId, boolean resolveForStart,
-            boolean allowDynamicSplits) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.queryIntentActivitiesInternal(intent, resolvedType, flags,
-                    privateResolveFlags, filterCallingUid, userId, resolveForStart,
-                    allowDynamicSplits);
-        } finally {
-            current.release();
-        }
-    }
-    public @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
-            String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.queryIntentActivitiesInternal(intent, resolvedType, flags,
-                    userId);
-        } finally {
-            current.release();
-        }
-    }
-    public @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
-            String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId,
-            int callingUid, boolean includeInstantApps) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.queryIntentServicesInternal(intent, resolvedType, flags,
-                    userId, callingUid, includeInstantApps);
-        } finally {
-            current.release();
-        }
-    }
-    public @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(
-            Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
-            int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits,
-            String pkgName, String instantAppPkgName) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.queryIntentActivitiesInternalBody(intent, resolvedType,
-                    flags, filterCallingUid, userId, resolveForStart, allowDynamicSplits,
-                    pkgName, instantAppPkgName);
-        } finally {
-            current.release();
-        }
-    }
-    public ActivityInfo getActivityInfo(ComponentName component,
-            @PackageManager.ComponentInfoFlagsBits long flags, int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getActivityInfo(component, flags, userId);
-        } finally {
-            current.release();
-        }
-    }
-    public ActivityInfo getActivityInfoInternal(ComponentName component,
-            @PackageManager.ComponentInfoFlagsBits long flags,
-            int filterCallingUid, int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getActivityInfoInternal(component, flags, filterCallingUid,
-                    userId);
-        } finally {
-            current.release();
-        }
-    }
-    public AndroidPackage getPackage(String packageName) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getPackage(packageName);
-        } finally {
-            current.release();
-        }
-    }
-    public AndroidPackage getPackage(int uid) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getPackage(uid);
-        } finally {
-            current.release();
-        }
-    }
-    public ApplicationInfo generateApplicationInfoFromSettings(String packageName,
-            long flags, int filterCallingUid, int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.generateApplicationInfoFromSettings(packageName, flags,
-                    filterCallingUid, userId);
-        } finally {
-            current.release();
-        }
-    }
-    public ApplicationInfo getApplicationInfo(String packageName,
-            @PackageManager.ApplicationInfoFlagsBits long flags, int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getApplicationInfo(packageName, flags, userId);
-        } finally {
-            current.release();
-        }
-    }
-    public ApplicationInfo getApplicationInfoInternal(String packageName,
-            @PackageManager.ApplicationInfoFlagsBits long flags, int filterCallingUid, int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getApplicationInfoInternal(packageName, flags,
-                    filterCallingUid, userId);
-        } finally {
-            current.release();
-        }
-    }
-    public ComponentName getDefaultHomeActivity(int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getDefaultHomeActivity(userId);
-        } finally {
-            current.release();
-        }
-    }
-    public ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
-            int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getHomeActivitiesAsUser(allHomeCandidates, userId);
-        } finally {
-            current.release();
-        }
-    }
-    public CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent,
-            String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int sourceUserId,
-            int parentUserId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getCrossProfileDomainPreferredLpr(intent, resolvedType,
-                    flags, sourceUserId, parentUserId);
-        } finally {
-            current.release();
-        }
-    }
-    public Intent getHomeIntent() {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getHomeIntent();
-        } finally {
-            current.release();
-        }
-    }
-    public List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(
-            Intent intent, String resolvedType, int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getMatchingCrossProfileIntentFilters(intent, resolvedType,
-                    userId);
-        } finally {
-            current.release();
-        }
-    }
-    public List<ResolveInfo> applyPostResolutionFilter(
-            @NonNull List<ResolveInfo> resolveInfos,
-            String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid,
-            boolean resolveForStart, int userId, Intent intent) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.applyPostResolutionFilter(resolveInfos, ephemeralPkgName,
-                    allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent);
-        } finally {
-            current.release();
-        }
-    }
-    public PackageInfo generatePackageInfo(PackageStateInternal ps,
-            @PackageManager.PackageInfoFlagsBits long flags, int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.generatePackageInfo(ps, flags, userId);
-        } finally {
-            current.release();
-        }
-    }
-    public PackageInfo getPackageInfo(String packageName,
-            @PackageManager.PackageInfoFlagsBits long flags, int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getPackageInfo(packageName, flags, userId);
-        } finally {
-            current.release();
-        }
-    }
-    public PackageInfo getPackageInfoInternal(String packageName, long versionCode,
-            long flags, int filterCallingUid, int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getPackageInfoInternal(packageName, versionCode, flags,
-                    filterCallingUid, userId);
-        } finally {
-            current.release();
-        }
-    }
-    public PackageStateInternal getPackageStateInternal(String packageName) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getPackageStateInternal(packageName);
-        } finally {
-            current.release();
-        }
-    }
-    public PackageStateInternal getPackageStateInternal(String packageName, int callingUid) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getPackageStateInternal(packageName, callingUid);
-        } finally {
-            current.release();
-        }
-    }
-
-    @Nullable
-    public PackageState getPackageStateCopied(@NonNull String packageName) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getPackageStateCopied(packageName);
-        } finally {
-            current.release();
-        }
-    }
-
-    public ParceledListSlice<PackageInfo> getInstalledPackages(long flags, int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getInstalledPackages(flags, userId);
-        } finally {
-            current.release();
-        }
-    }
-    public ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter,
-            int sourceUserId, int targetUserId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.createForwardingResolveInfoUnchecked(filter, sourceUserId,
-                    targetUserId);
-        } finally {
-            current.release();
-        }
-    }
-    public ServiceInfo getServiceInfo(ComponentName component,
-            @PackageManager.ComponentInfoFlagsBits long flags, int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getServiceInfo(component, flags, userId);
-        } finally {
-            current.release();
-        }
-    }
-    public SharedLibraryInfo getSharedLibraryInfo(String name, long version) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getSharedLibraryInfo(name, version);
-        } finally {
-            current.release();
-        }
-    }
-    public SigningDetails getSigningDetails(@NonNull String packageName) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getSigningDetails(packageName);
-        } finally {
-            current.release();
-        }
-    }
-    public SigningDetails getSigningDetails(int uid) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getSigningDetails(uid);
-        } finally {
-            current.release();
-        }
-    }
-    public String getInstantAppPackageName(int callingUid) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getInstantAppPackageName(callingUid);
-        } finally {
-            current.release();
-        }
-    }
-    public String resolveExternalPackageName(AndroidPackage pkg) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.resolveExternalPackageName(pkg);
-        } finally {
-            current.release();
-        }
-    }
-    public String resolveInternalPackageName(String packageName, long versionCode) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.resolveInternalPackageName(packageName, versionCode);
-        } finally {
-            current.release();
-        }
-    }
-    public String[] getPackagesForUid(int uid) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getPackagesForUid(uid);
-        } finally {
-            current.release();
-        }
-    }
-    public UserInfo getProfileParent(int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getProfileParent(userId);
-        } finally {
-            current.release();
-        }
-    }
-    public boolean canViewInstantApps(int callingUid, int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.canViewInstantApps(callingUid, userId);
-        } finally {
-            current.release();
-        }
-    }
-    public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.filterAppAccess(pkg, callingUid, userId);
-        } finally {
-            current.release();
-        }
-    }
-    public boolean filterAppAccess(String packageName, int callingUid, int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.filterAppAccess(packageName, callingUid, userId);
-        } finally {
-            current.release();
-        }
-    }
-    public boolean filterAppAccess(int uid, int callingUid) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.filterAppAccess(uid, callingUid);
-        } finally {
-            current.release();
-        }
-    }
-    public boolean filterSharedLibPackage(@Nullable PackageStateInternal ps, int uid,
-            int userId, @PackageManager.ComponentInfoFlagsBits long flags) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.filterSharedLibPackage(ps, uid, userId, flags);
-        } finally {
-            current.release();
-        }
-    }
-    public boolean isCallerSameApp(String packageName, int uid) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.isCallerSameApp(packageName, uid);
-        } finally {
-            current.release();
-        }
-    }
-    public boolean isComponentVisibleToInstantApp(@Nullable ComponentName component) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.isComponentVisibleToInstantApp(component);
-        } finally {
-            current.release();
-        }
-    }
-    public boolean isComponentVisibleToInstantApp(@Nullable ComponentName component,
-            @PackageManager.ComponentType int type) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.isComponentVisibleToInstantApp(component, type);
-        } finally {
-            current.release();
-        }
-    }
-    public boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent,
-            int userId, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent,
-                    userId, resolvedType, flags);
-        } finally {
-            current.release();
-        }
-    }
-    public boolean isInstantApp(String packageName, int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.isInstantApp(packageName, userId);
-        } finally {
-            current.release();
-        }
-    }
-    public boolean isInstantAppInternal(String packageName, @UserIdInt int userId,
-            int callingUid) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.isInstantAppInternal(packageName, userId, callingUid);
-        } finally {
-            current.release();
-        }
-    }
-    public boolean isSameProfileGroup(@UserIdInt int callerUserId,
-            @UserIdInt int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.isSameProfileGroup(callerUserId, userId);
-        } finally {
-            current.release();
-        }
-    }
-    public boolean shouldFilterApplication(@NonNull SharedUserSetting sus,
-            int callingUid, int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.shouldFilterApplication(sus, callingUid, userId);
-        } finally {
-            current.release();
-        }
-    }
-    public boolean shouldFilterApplication(@Nullable PackageStateInternal ps,
-            int callingUid, @Nullable ComponentName component,
-            @PackageManager.ComponentType int componentType, int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.shouldFilterApplication(ps, callingUid, component,
-                    componentType, userId);
-        } finally {
-            current.release();
-        }
-    }
-    public boolean shouldFilterApplication(@Nullable PackageStateInternal ps,
-            int callingUid, int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.shouldFilterApplication(ps, callingUid, userId);
-        } finally {
-            current.release();
-        }
-    }
-    public int checkUidPermission(String permName, int uid) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.checkUidPermission(permName, uid);
-        } finally {
-            current.release();
-        }
-    }
-    public int getPackageUidInternal(String packageName,
-            @PackageManager.PackageInfoFlagsBits long flags, int userId, int callingUid) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.getPackageUidInternal(packageName, flags, userId,
-                    callingUid);
-        } finally {
-            current.release();
-        }
-    }
-    public long updateFlagsForApplication(long flags, int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.updateFlagsForApplication(flags, userId);
-        } finally {
-            current.release();
-        }
-    }
-    public long updateFlagsForComponent(long flags, int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.updateFlagsForComponent(flags, userId);
-        } finally {
-            current.release();
-        }
-    }
-    public long updateFlagsForPackage(long flags, int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.updateFlagsForPackage(flags, userId);
-        } finally {
-            current.release();
-        }
-    }
-    public long updateFlagsForResolve(long flags, int userId, int callingUid,
-            boolean wantInstantApps, boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.updateFlagsForResolve(flags, userId, callingUid,
-                    wantInstantApps, isImplicitImageCaptureIntentAndNotSetByDpc);
-        } finally {
-            current.release();
-        }
-    }
-    public long updateFlagsForResolve(long flags, int userId, int callingUid,
-            boolean wantInstantApps, boolean onlyExposedExplicitly,
-            boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.updateFlagsForResolve(flags, userId, callingUid,
-                    wantInstantApps, onlyExposedExplicitly,
-                    isImplicitImageCaptureIntentAndNotSetByDpc);
-        } finally {
-            current.release();
-        }
-    }
-    public void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
-        ThreadComputer current = snapshot();
-        try {
-            current.mComputer.dump(type, fd, pw, dumpState);
-        } finally {
-            current.release();
-        }
-    }
-    public void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
-            boolean requireFullPermission, boolean checkShell, String message) {
-        ThreadComputer current = snapshot();
-        try {
-            current.mComputer.enforceCrossUserOrProfilePermission(callingUid, userId,
-                    requireFullPermission, checkShell, message);
-        } finally {
-            current.release();
-        }
-    }
-    public void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
-            boolean requireFullPermission, boolean checkShell, String message) {
-        ThreadComputer current = snapshot();
-        try {
-            current.mComputer.enforceCrossUserPermission(callingUid, userId,
-                    requireFullPermission, checkShell, message);
-        } finally {
-            current.release();
-        }
-    }
-    public void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
-            boolean requireFullPermission, boolean checkShell,
-            boolean requirePermissionWhenSameUser, String message) {
-        ThreadComputer current = snapshot();
-        try {
-            current.mComputer.enforceCrossUserPermission(callingUid, userId,
-                    requireFullPermission, checkShell, requirePermissionWhenSameUser, message);
-        } finally {
-            current.release();
-        }
-    }
-    public PackageManagerService.FindPreferredActivityBodyResult findPreferredActivityInternal(
-            Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
-            List<ResolveInfo> query, boolean always, boolean removeMatches, boolean debug,
-            int userId, boolean queryMayBeFiltered) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.findPreferredActivityInternal(intent, resolvedType, flags,
-                    query, always, removeMatches, debug, userId, queryMayBeFiltered);
-        } finally {
-            current.release();
-        }
-    }
-    public ResolveInfo findPersistentPreferredActivityLP(Intent intent,
-            String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
-            List<ResolveInfo> query, boolean debug, int userId) {
-        ThreadComputer current = snapshot();
-        try {
-            return current.mComputer.findPersistentPreferredActivityLP(intent, resolvedType,
-                    flags, query, debug, userId);
-        } finally {
-            current.release();
-        }
-    }
-
-    @Override
-    public String[] getAllAvailablePackageNames() {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getAllAvailablePackageNames();
-        }
-    }
-
-    @Override
-    public PreferredIntentResolver getPreferredActivities(int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getPreferredActivities(userId);
-        }
-    }
-
-    @NonNull
-    @Override
-    public ArrayMap<String, ? extends PackageStateInternal> getPackageStates() {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getPackageStates();
-        }
-    }
-
-    @Nullable
-    @Override
-    public String getRenamedPackage(@NonNull String packageName) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getRenamedPackage(packageName);
-        }
-    }
-
-    @NonNull
-    @Override
-    public ArraySet<String> getNotifyPackagesForReplacedReceived(@NonNull String[] packages) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getNotifyPackagesForReplacedReceived(packages);
-        }
-    }
-
-    @Override
-    public int getPackageStartability(boolean safeMode, @NonNull String packageName, int callingUid,
-            @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getPackageStartability(safeMode, packageName, callingUid,
-                    userId);
-        }
-    }
-
-    @Override
-    public boolean isPackageAvailable(String packageName, @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.isPackageAvailable(packageName, userId);
-        }
-    }
-
-    @Override
-    public String[] currentToCanonicalPackageNames(String[] names) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.currentToCanonicalPackageNames(names);
-        }
-    }
-
-    @Override
-    public String[] canonicalToCurrentPackageNames(String[] names) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.canonicalToCurrentPackageNames(names);
-        }
-    }
-
-    @Override
-    public int[] getPackageGids(@NonNull String packageName,
-            @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getPackageGids(packageName, flags, userId);
-        }
-    }
-
-    @Override
-    public int getTargetSdkVersion(@NonNull String packageName) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getTargetSdkVersion(packageName);
-        }
-    }
-
-    @Override
-    public boolean activitySupportsIntent(@NonNull ComponentName resolveComponentName,
-            @NonNull ComponentName component, @NonNull Intent intent, String resolvedType) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.activitySupportsIntent(resolveComponentName, component, intent,
-                    resolvedType);
-        }
-    }
-
-    @Nullable
-    @Override
-    public ActivityInfo getReceiverInfo(@NonNull ComponentName component,
-            @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getReceiverInfo(component, flags, userId);
-        }
-    }
-
-    @Nullable
-    @Override
-    public ParceledListSlice<SharedLibraryInfo> getSharedLibraries(@NonNull String packageName,
-            @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getSharedLibraries(packageName, flags, userId);
-        }
-    }
-
-    @Override
-    public boolean canRequestPackageInstalls(@NonNull String packageName, int callingUid,
-            @UserIdInt int userId, boolean throwIfPermNotDeclared) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.canRequestPackageInstalls(packageName, callingUid, userId,
-                    throwIfPermNotDeclared);
-        }
-    }
-
-    @Override
-    public boolean isInstallDisabledForPackage(@NonNull String packageName, int uid,
-            @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.isInstallDisabledForPackage(packageName, uid, userId);
-        }
-    }
-
-    @Override
-    public List<VersionedPackage> getPackagesUsingSharedLibrary(@NonNull SharedLibraryInfo libInfo,
-            @PackageManager.PackageInfoFlagsBits long flags, int callingUid,
-            @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getPackagesUsingSharedLibrary(libInfo, flags, callingUid,
-                    userId);
-        }
-    }
-
-    @Nullable
-    @Override
-    public ParceledListSlice<SharedLibraryInfo> getDeclaredSharedLibraries(
-            @NonNull String packageName, @PackageManager.PackageInfoFlagsBits long flags,
-            @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getDeclaredSharedLibraries(packageName, flags, userId);
-        }
-    }
-
-    @Nullable
-    @Override
-    public ProviderInfo getProviderInfo(@NonNull ComponentName component,
-            @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getProviderInfo(component, flags, userId);
-        }
-    }
-
-    @Nullable
-    @Override
-    public String[] getSystemSharedLibraryNames() {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getSystemSharedLibraryNames();
-        }
-    }
-
-    @Override
-    public int checkSignatures(@NonNull String pkg1,
-            @NonNull String pkg2) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.checkSignatures(pkg1, pkg2);
-        }
-    }
-
-    @Override
-    public int checkUidSignatures(int uid1, int uid2) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.checkUidSignatures(uid1, uid2);
-        }
-    }
-
-    @Override
-    public boolean hasSigningCertificate(@NonNull String packageName, @NonNull byte[] certificate,
-            int type) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.hasSigningCertificate(packageName, certificate, type);
-        }
-    }
-
-    @Override
-    public boolean hasUidSigningCertificate(int uid, @NonNull byte[] certificate, int type) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.hasUidSigningCertificate(uid, certificate, type);
-        }
-    }
-
-    @Override
-    public List<String> getAllPackages() {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getAllPackages();
-        }
-    }
-
-    @Nullable
-    @Override
-    public String getNameForUid(int uid) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getNameForUid(uid);
-        }
-    }
-
-    @Nullable
-    @Override
-    public String[] getNamesForUids(int[] uids) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getNamesForUids(uids);
-        }
-    }
-
-    @Override
-    public int getUidForSharedUser(@NonNull String sharedUserName) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getUidForSharedUser(sharedUserName);
-        }
-    }
-
-    @Override
-    public int getFlagsForUid(int uid) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getFlagsForUid(uid);
-        }
-    }
-
-    @Override
-    public int getPrivateFlagsForUid(int uid) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getPrivateFlagsForUid(uid);
-        }
-    }
-
-    @Override
-    public boolean isUidPrivileged(int uid) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.isUidPrivileged(uid);
-        }
-    }
-
-    @NonNull
-    @Override
-    public String[] getAppOpPermissionPackages(@NonNull String permissionName) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getAppOpPermissionPackages(permissionName);
-        }
-    }
-
-    @NonNull
-    @Override
-    public ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
-            @NonNull String[] permissions, @PackageManager.PackageInfoFlagsBits long flags,
-            @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getPackagesHoldingPermissions(permissions, flags, userId);
-        }
-    }
-
-    @NonNull
-    @Override
-    public List<ApplicationInfo> getInstalledApplications(
-            @PackageManager.ApplicationInfoFlagsBits long flags, @UserIdInt int userId,
-            int callingUid) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getInstalledApplications(flags, userId, callingUid);
-        }
-    }
-
-    @Nullable
-    @Override
-    public ProviderInfo resolveContentProvider(@NonNull String name,
-            @PackageManager.ResolveInfoFlagsBits long flags, @UserIdInt int userId,
-            int callingUid) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.resolveContentProvider(name, flags, userId, callingUid);
-        }
-    }
-
-    @Nullable
-    @Override
-    public ProviderInfo getGrantImplicitAccessProviderInfo(int recipientUid,
-            @NonNull String visibleAuthority) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getGrantImplicitAccessProviderInfo(recipientUid,
-                    visibleAuthority);
-        }
-    }
-
-    @Override
-    public void querySyncProviders(boolean safeMode, @NonNull List<String> outNames,
-            @NonNull List<ProviderInfo> outInfo) {
-        try (ThreadComputer current = snapshot()) {
-            current.mComputer.querySyncProviders(safeMode, outNames, outInfo);
-        }
-    }
-
-    @NonNull
-    @Override
-    public ParceledListSlice<ProviderInfo> queryContentProviders(@Nullable String processName,
-            int uid, @PackageManager.ComponentInfoFlagsBits long flags,
-            @Nullable String metaDataKey) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.queryContentProviders(processName, uid, flags, metaDataKey);
-        }
-    }
-
-    @Nullable
-    @Override
-    public InstrumentationInfo getInstrumentationInfo(@NonNull ComponentName component, int flags) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getInstrumentationInfo(component, flags);
-        }
-    }
-
-    @NonNull
-    @Override
-    public ParceledListSlice<InstrumentationInfo> queryInstrumentation(
-            @NonNull String targetPackage, int flags) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.queryInstrumentation(targetPackage, flags);
-        }
-    }
-
-    @NonNull
-    @Override
-    public List<PackageStateInternal> findSharedNonSystemLibraries(
-            @NonNull PackageStateInternal pkgSetting) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.findSharedNonSystemLibraries(pkgSetting);
-        }
-    }
-
-    @Override
-    public boolean getApplicationHiddenSettingAsUser(@NonNull String packageName,
-            @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getApplicationHiddenSettingAsUser(packageName, userId);
-        }
-    }
-
-    @Override
-    public boolean isPackageSuspendedForUser(@NonNull String packageName, @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.isPackageSuspendedForUser(packageName, userId);
-        }
-    }
-
-    @Override
-    public boolean isSuspendingAnyPackages(@NonNull String suspendingPackage,
-            @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.isSuspendingAnyPackages(suspendingPackage, userId);
-        }
-    }
-
-    @NonNull
-    @Override
-    public ParceledListSlice<IntentFilter> getAllIntentFilters(@NonNull String packageName) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getAllIntentFilters(packageName);
-        }
-    }
-
-    @Override
-    public boolean getBlockUninstallForUser(@NonNull String packageName, @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getBlockUninstallForUser(packageName, userId);
-        }
-    }
-
-    @Nullable
-    @Override
-    public SparseArray<int[]> getBroadcastAllowList(@NonNull String packageName,
-            @UserIdInt int[] userIds, boolean isInstantApp) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getBroadcastAllowList(packageName, userIds, isInstantApp);
-        }
-    }
-
-    @Nullable
-    @Override
-    public String getInstallerPackageName(@NonNull String packageName) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getInstallerPackageName(packageName);
-        }
-    }
-
-    @Nullable
-    @Override
-    public InstallSourceInfo getInstallSourceInfo(@NonNull String packageName) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getInstallSourceInfo(packageName);
-        }
-    }
-
-    @Override
-    public int getApplicationEnabledSetting(@NonNull String packageName, @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getApplicationEnabledSetting(packageName, userId);
-        }
-    }
-
-    @Override
-    public int getComponentEnabledSetting(@NonNull ComponentName component, int callingUid,
-            @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getComponentEnabledSetting(component, callingUid, userId);
-        }
-    }
-
-    @Override
-    public int getComponentEnabledSettingInternal(@NonNull ComponentName component, int callingUid,
-            @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getComponentEnabledSettingInternal(
-                    component, callingUid, userId);
-        }
-    }
-
-    @Override
-    public boolean isComponentEffectivelyEnabled(@NonNull ComponentInfo componentInfo,
-            @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.isComponentEffectivelyEnabled(componentInfo, userId);
-        }
-    }
-
-    @Nullable
-    @Override
-    public KeySet getKeySetByAlias(@NonNull String packageName, @NonNull String alias) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getKeySetByAlias(packageName, alias);
-        }
-    }
-
-    @Nullable
-    @Override
-    public KeySet getSigningKeySet(@NonNull String packageName) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getSigningKeySet(packageName);
-        }
-    }
-
-    @Override
-    public boolean isPackageSignedByKeySet(@NonNull String packageName, @NonNull KeySet ks) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.isPackageSignedByKeySet(packageName, ks);
-        }
-    }
-
-    @Override
-    public boolean isPackageSignedByKeySetExactly(@NonNull String packageName, @NonNull KeySet ks) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.isPackageSignedByKeySetExactly(packageName, ks);
-        }
-    }
-
-    @Nullable
-    @Override
-    public int[] getVisibilityAllowList(@NonNull String packageName, @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getVisibilityAllowList(packageName, userId);
-        }
-    }
-
-    @Override
-    public boolean canQueryPackage(int callingUid, @Nullable String targetPackageName) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.canQueryPackage(callingUid, targetPackageName);
-        }
-    }
-
-    @Override
-    public int getPackageUid(@NonNull String packageName,
-            @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getPackageUid(packageName, flags, userId);
-        }
-    }
-
-    @Override
-    public boolean canAccessComponent(int callingUid, @NonNull ComponentName component,
-            @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.canAccessComponent(callingUid, component, userId);
-        }
-    }
-
-    @Override
-    public boolean isCallerInstallerOfRecord(@NonNull AndroidPackage pkg, int callingUid) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.isCallerInstallerOfRecord(pkg, callingUid);
-        }
-    }
-
-    @Override
-    public int getInstallReason(@NonNull String packageName, @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getInstallReason(packageName, userId);
-        }
-    }
-
-    @Override
-    public boolean canPackageQuery(@NonNull String sourcePackageName,
-            @NonNull String targetPackageName, @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.canPackageQuery(sourcePackageName, targetPackageName, userId);
-        }
-    }
-
-    @Override
-    public boolean canForwardTo(@NonNull Intent intent, @Nullable String resolvedType,
-            @UserIdInt int sourceUserId, @UserIdInt int targetUserId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.canForwardTo(intent, resolvedType, sourceUserId, targetUserId);
-        }
-    }
-
-    @NonNull
-    @Override
-    public List<ApplicationInfo> getPersistentApplications(boolean safeMode, int flags) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getPersistentApplications(safeMode, flags);
-        }
-    }
-
-    @NonNull
-    @Override
-    public SparseArray<String> getAppsWithSharedUserIds() {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getAppsWithSharedUserIds();
-        }
-    }
-
-    @NonNull
-    @Override
-    public String[] getSharedUserPackagesForPackage(@NonNull String packageName,
-            @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getSharedUserPackagesForPackage(packageName, userId);
-        }
-    }
-
-    @NonNull
-    @Override
-    public Set<String> getUnusedPackages(long downgradeTimeThresholdMillis) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getUnusedPackages(downgradeTimeThresholdMillis);
-        }
-    }
-
-    @Nullable
-    @Override
-    public CharSequence getHarmfulAppWarning(@NonNull String packageName, @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getHarmfulAppWarning(packageName, userId);
-        }
-    }
-
-    @NonNull
-    @Override
-    public String[] filterOnlySystemPackages(@Nullable String... pkgNames) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.filterOnlySystemPackages(pkgNames);
-        }
-    }
-
-    @NonNull
-    @Override
-    public List<AndroidPackage> getPackagesForAppId(int appId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getPackagesForAppId(appId);
-        }
-    }
-
-    @Override
-    public int getUidTargetSdkVersion(int uid) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getUidTargetSdkVersion(uid);
-        }
-    }
-
-    @Nullable
-    @Override
-    public ArrayMap<String, ProcessInfo> getProcessesForUid(int uid) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getProcessesForUid(uid);
-        }
-    }
-
-    @Override
-    public PackageStateInternal getPackageStateFiltered(@NonNull String packageName, int callingUid,
-            @UserIdInt int userId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getPackageStateFiltered(packageName, callingUid, userId);
-        }
-    }
-
-    @Override
-    public boolean getBlockUninstall(@UserIdInt int userId, @NonNull String packageName) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getBlockUninstall(userId, packageName);
-        }
-    }
-
-    @NonNull
-    @Override
-    public WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> getSharedLibraries() {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getSharedLibraries();
-        }
-    }
-
-    @Nullable
-    @Override
-    public Pair<PackageStateInternal, SharedUserApi> getPackageOrSharedUser(int appId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getPackageOrSharedUser(appId);
-        }
-    }
-
-    @Nullable
-    @Override
-    public SharedUserApi getSharedUser(int sharedUserAppId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getSharedUser(sharedUserAppId);
-        }
-    }
-
-    @NonNull
-    @Override
-    public ArraySet<PackageStateInternal> getSharedUserPackages(int sharedUserAppId) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getSharedUserPackages(sharedUserAppId);
-        }
-    }
-
-    @NonNull
-    @Override
-    public ComponentResolverApi getComponentResolver() {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getComponentResolver();
-        }
-    }
-
-    @Nullable
-    @Override
-    public PackageStateInternal getDisabledSystemPackage(@NonNull String packageName) {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getDisabledSystemPackage(packageName);
-        }
-    }
-
-    @Nullable
-    @Override
-    public ResolveInfo getInstantAppInstallerInfo() {
-        try (ThreadComputer current = snapshot()) {
-            return current.mComputer.getInstantAppInstallerInfo();
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
index b307984..89f8be2 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
@@ -112,7 +112,9 @@
             String callingFeatureId,
             ComponentName component,
             @UserIdInt int userId,
-            boolean launchMainActivity) throws RemoteException {
+            boolean launchMainActivity,
+            IBinder targetTask,
+            Bundle options) throws RemoteException {
         Objects.requireNonNull(callingPackage);
         Objects.requireNonNull(component);
 
@@ -145,8 +147,12 @@
         if (launchMainActivity) {
             launchIntent.setAction(Intent.ACTION_MAIN);
             launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-            launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                    | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+            if (targetTask == null) {
+                launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+            } else {
+                launchIntent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+            }
             // Only package name is set here, as opposed to component name, because intent action
             // and category are ignored if component name is present while we are resolving intent.
             launchIntent.setPackage(component.getPackageName());
@@ -170,15 +176,20 @@
         }
         verifyActivityCanHandleIntentAndExported(launchIntent, component, callingUid, userId);
 
+        // Always show the cross profile animation
+        if (options == null) {
+            options = ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle();
+        } else {
+            options.putAll(ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle());
+        }
+
         launchIntent.setPackage(null);
         launchIntent.setComponent(component);
         mInjector.getActivityTaskManagerInternal().startActivityAsUser(
                 caller, callingPackage, callingFeatureId, launchIntent,
-                /* resultTo= */ null,
-                Intent.FLAG_ACTIVITY_NEW_TASK,
-                launchMainActivity
-                        ? ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle()
-                        : null,
+                targetTask,
+                /* startFlags= */ 0,
+                options,
                 userId);
     }
 
@@ -225,6 +236,13 @@
 
         verifyActivityCanHandleIntent(launchIntent, callingUid, userId);
 
+        // Always show the cross profile animation
+        if (options == null) {
+            options = ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle();
+        } else {
+            options.putAll(ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle());
+        }
+
         mInjector.getActivityTaskManagerInternal()
                 .startActivityAsUser(
                         caller,
diff --git a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
index a3134a0..cac9323 100644
--- a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
+++ b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
@@ -246,7 +246,7 @@
     private static final DefaultCrossProfileIntentFilter MEDIA_CAPTURE =
             new DefaultCrossProfileIntentFilter.Builder(
                     DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
-                    /* flags= */0,
+                    /* flags= */ ONLY_IF_NO_MATCH_FOUND,
                     /* letsPersonalDataIntoProfile= */ true)
                     .addAction(MediaStore.ACTION_IMAGE_CAPTURE)
                     .addAction(MediaStore.ACTION_IMAGE_CAPTURE_SECURE)
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index 664c7bb..dc4dd12 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -43,6 +43,7 @@
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
 import android.content.pm.SharedLibraryInfo;
+import android.content.pm.UserInfo;
 import android.content.pm.VersionedPackage;
 import android.net.Uri;
 import android.os.Binder;
@@ -147,6 +148,7 @@
         final SparseArray<TempUserState> priorUserStates;
         /** enabled state of the uninstalled application */
         synchronized (mPm.mLock) {
+            final Computer computer = mPm.snapshotComputer();
             uninstalledPs = mPm.mSettings.getPackageLPr(packageName);
             if (uninstalledPs == null) {
                 Slog.w(TAG, "Not removing non-existent package " + packageName);
@@ -160,6 +162,15 @@
                 return PackageManager.DELETE_FAILED_INTERNAL_ERROR;
             }
 
+            if (PackageManagerServiceUtils.isSystemApp(uninstalledPs)) {
+                UserInfo userInfo = mUserManagerInternal.getUserInfo(userId);
+                if (userInfo == null || !userInfo.isAdmin()) {
+                    Slog.w(TAG, "Not removing package " + packageName
+                            + " as only admin user may downgrade system apps");
+                    return PackageManager.DELETE_FAILED_USER_RESTRICTED;
+                }
+            }
+
             disabledSystemPs = mPm.mSettings.getDisabledSystemPkgLPr(packageName);
             // Static shared libs can be declared by any package, so let us not
             // allow removing a package if it provides a lib others depend on.
@@ -170,10 +181,10 @@
             if (pkg != null) {
                 SharedLibraryInfo libraryInfo = null;
                 if (pkg.getStaticSharedLibName() != null) {
-                    libraryInfo = mPm.getSharedLibraryInfo(pkg.getStaticSharedLibName(),
+                    libraryInfo = computer.getSharedLibraryInfo(pkg.getStaticSharedLibName(),
                             pkg.getStaticSharedLibVersion());
                 } else if (pkg.getSdkLibName() != null) {
-                    libraryInfo = mPm.getSharedLibraryInfo(pkg.getSdkLibName(),
+                    libraryInfo = computer.getSharedLibraryInfo(pkg.getSdkLibName(),
                             pkg.getSdkLibVersionMajor());
                 }
 
@@ -183,7 +194,7 @@
                             continue;
                         }
                         List<VersionedPackage> libClientPackages =
-                                mPm.getPackagesUsingSharedLibrary(libraryInfo,
+                                computer.getPackagesUsingSharedLibrary(libraryInfo,
                                         MATCH_KNOWN_PACKAGES, Process.SYSTEM_UID, currUserId);
                         if (!ArrayUtils.isEmpty(libClientPackages)) {
                             Slog.w(TAG, "Not removing package " + pkg.getManifestPackageName()
@@ -454,11 +465,11 @@
         if (affectedUserIds == null) {
             affectedUserIds = mPm.resolveUserIds(userId);
         }
+        final Computer snapshot = mPm.snapshotComputer();
         for (final int affectedUserId : affectedUserIds) {
             if (hadSuspendAppsPermission.get(affectedUserId)) {
-                mPm.unsuspendForSuspendingPackage(mPm.snapshotComputer(), packageName,
-                        affectedUserId);
-                mPm.removeAllDistractingPackageRestrictions(affectedUserId);
+                mPm.unsuspendForSuspendingPackage(snapshot, packageName, affectedUserId);
+                mPm.removeAllDistractingPackageRestrictions(snapshot, affectedUserId);
             }
         }
 
@@ -621,7 +632,8 @@
         final int callingUid = Binder.getCallingUid();
         mPm.mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.DELETE_PACKAGES, null);
-        final boolean canViewInstantApps = mPm.canViewInstantApps(callingUid, userId);
+        final Computer snapshot = mPm.snapshotComputer();
+        final boolean canViewInstantApps = snapshot.canViewInstantApps(callingUid, userId);
         Preconditions.checkNotNull(versionedPackage);
         Preconditions.checkNotNull(observer);
         Preconditions.checkArgumentInRange(versionedPackage.getLongVersionCode(),
@@ -644,12 +656,13 @@
         }
 
         // Normalize package name to handle renamed packages and static libs
-        final String internalPackageName = mPm.resolveInternalPackageName(packageName, versionCode);
+        final String internalPackageName =
+                snapshot.resolveInternalPackageName(packageName, versionCode);
 
         final int uid = Binder.getCallingUid();
-        if (!isOrphaned(internalPackageName)
+        if (!isOrphaned(snapshot, internalPackageName)
                 && !allowSilentUninstall
-                && !isCallerAllowedToSilentlyUninstall(uid, internalPackageName)) {
+                && !isCallerAllowedToSilentlyUninstall(snapshot, uid, internalPackageName)) {
             mPm.mHandler.post(() -> {
                 try {
                     final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
@@ -680,8 +693,7 @@
             return;
         }
 
-        if (!deleteAllUsers && mPm.mIPackageManager
-                .getBlockUninstallForUser(internalPackageName, userId)) {
+        if (!deleteAllUsers && snapshot.getBlockUninstallForUser(internalPackageName, userId)) {
             mPm.mHandler.post(() -> {
                 try {
                     observer.onPackageDeleted(packageName,
@@ -756,44 +768,45 @@
         });
     }
 
-    private boolean isOrphaned(String packageName) {
-        final PackageStateInternal packageState = mPm.getPackageStateInternal(packageName);
+    private boolean isOrphaned(@NonNull Computer snapshot, String packageName) {
+        final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
         return packageState != null && packageState.getInstallSource().isOrphaned;
     }
 
-    private boolean isCallerAllowedToSilentlyUninstall(int callingUid, String pkgName) {
+    private boolean isCallerAllowedToSilentlyUninstall(@NonNull Computer snapshot, int callingUid,
+            String pkgName) {
         if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID
                 || UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
             return true;
         }
         final int callingUserId = UserHandle.getUserId(callingUid);
         // If the caller installed the pkgName, then allow it to silently uninstall.
-        if (callingUid == mPm.mIPackageManager.getPackageUid(
-                mPm.mIPackageManager.getInstallerPackageName(pkgName), 0, callingUserId)) {
+        if (callingUid == snapshot.getPackageUid(snapshot.getInstallerPackageName(pkgName), 0,
+                callingUserId)) {
             return true;
         }
 
         // Allow package verifier to silently uninstall.
-        if (mPm.mRequiredVerifierPackage != null && callingUid == mPm.mIPackageManager
+        if (mPm.mRequiredVerifierPackage != null && callingUid == snapshot
                 .getPackageUid(mPm.mRequiredVerifierPackage, 0, callingUserId)) {
             return true;
         }
 
         // Allow package uninstaller to silently uninstall.
-        if (mPm.mRequiredUninstallerPackage != null && callingUid == mPm.mIPackageManager
+        if (mPm.mRequiredUninstallerPackage != null && callingUid == snapshot
                 .getPackageUid(mPm.mRequiredUninstallerPackage, 0, callingUserId)) {
             return true;
         }
 
         // Allow storage manager to silently uninstall.
-        if (mPm.mStorageManagerPackage != null && callingUid == mPm.mIPackageManager.getPackageUid(
+        if (mPm.mStorageManagerPackage != null && callingUid == snapshot.getPackageUid(
                 mPm.mStorageManagerPackage, 0, callingUserId)) {
             return true;
         }
 
         // Allow caller having MANAGE_PROFILE_AND_DEVICE_OWNERS permission to silently
         // uninstall for device owner provisioning.
-        return mPm.mIPackageManager.checkUidPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS, callingUid)
+        return snapshot.checkUidPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS, callingUid)
                 == PERMISSION_GRANTED;
     }
 
@@ -899,8 +912,8 @@
         int installedForUsersCount = 0;
         synchronized (mPm.mLock) {
             // Normalize package name to handle renamed packages and static libs
-            final String internalPkgName = mPm.resolveInternalPackageName(packageName,
-                    versionCode);
+            final String internalPkgName = mPm.snapshotComputer()
+                    .resolveInternalPackageName(packageName, versionCode);
             final PackageSetting ps = mPm.mSettings.getPackageLPr(internalPkgName);
             if (ps != null) {
                 int[] installedUsers = ps.queryInstalledUsers(mUserManagerInternal.getUserIds(),
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index 74ea7cc..bb2ba5c 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -266,8 +266,9 @@
             return;
         }
 
+        final Computer snapshot = mPm.snapshotComputer();
         List<PackageStateInternal> pkgSettings =
-                getPackagesForDexopt(mPm.getPackageStates().values(), mPm);
+                getPackagesForDexopt(snapshot.getPackageStates().values(), mPm);
 
         List<AndroidPackage> pkgs = new ArrayList<>(pkgSettings.size());
         for (int index = 0; index < pkgSettings.size(); index++) {
@@ -282,17 +283,19 @@
         final int elapsedTimeSeconds =
                 (int) TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime);
 
+        final Computer newSnapshot = mPm.snapshotComputer();
+
         MetricsLogger.histogram(mPm.mContext, "opt_dialog_num_dexopted", stats[0]);
         MetricsLogger.histogram(mPm.mContext, "opt_dialog_num_skipped", stats[1]);
         MetricsLogger.histogram(mPm.mContext, "opt_dialog_num_failed", stats[2]);
-        MetricsLogger.histogram(
-                mPm.mContext, "opt_dialog_num_total", getOptimizablePackages().size());
+        MetricsLogger.histogram(mPm.mContext, "opt_dialog_num_total",
+                getOptimizablePackages(newSnapshot).size());
         MetricsLogger.histogram(mPm.mContext, "opt_dialog_time_s", elapsedTimeSeconds);
     }
 
-    public ArraySet<String> getOptimizablePackages() {
-        ArraySet<String> pkgs = new ArraySet<>();
-        mPm.forEachPackageState(packageState -> {
+    public List<String> getOptimizablePackages(@NonNull Computer snapshot) {
+        ArrayList<String> pkgs = new ArrayList<>();
+        mPm.forEachPackageState(snapshot, packageState -> {
             final AndroidPackage pkg = packageState.getPkg();
             if (pkg != null && mPm.mPackageDexOptimizer.canOptimizePackage(pkg)) {
                 pkgs.add(packageState.getPackageName());
@@ -302,10 +305,10 @@
     }
 
     /*package*/ boolean performDexOpt(DexoptOptions options) {
-        if (mPm.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+        final Computer snapshot = mPm.snapshotComputer();
+        if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
             return false;
-        } else if (mPm.mIPackageManager.isInstantApp(options.getPackageName(),
-                UserHandle.getCallingUserId())) {
+        } else if (snapshot.isInstantApp(options.getPackageName(), UserHandle.getCallingUserId())) {
             return false;
         }
 
@@ -417,10 +420,10 @@
                 mPm.getDexManager().getPackageUseInfoOrDefault(p.getPackageName()), options);
     }
 
-    public void forceDexOpt(String packageName) {
+    public void forceDexOpt(@NonNull Computer snapshot, String packageName) {
         PackageManagerServiceUtils.enforceSystemOrRoot("forceDexOpt");
 
-        final PackageStateInternal packageState = mPm.getPackageStateInternal(packageName);
+        final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
         final AndroidPackage pkg = packageState == null ? null : packageState.getPkg();
         if (packageState == null || pkg == null) {
             throw new IllegalArgumentException("Unknown package: " + packageName);
@@ -485,19 +488,21 @@
 
         ArrayList<PackageStateInternal> sortTemp = new ArrayList<>(remainingPkgSettings.size());
 
+        final Computer snapshot = packageManagerService.snapshotComputer();
+
         // Give priority to core apps.
-        applyPackageFilter(pkgSetting -> pkgSetting.getPkg().isCoreApp(), result,
+        applyPackageFilter(snapshot, pkgSetting -> pkgSetting.getPkg().isCoreApp(), result,
                 remainingPkgSettings, sortTemp, packageManagerService);
 
         // Give priority to system apps that listen for pre boot complete.
         Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
         final ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
-        applyPackageFilter(pkgSetting -> pkgNames.contains(pkgSetting.getPackageName()), result,
+        applyPackageFilter(snapshot, pkgSetting -> pkgNames.contains(pkgSetting.getPackageName()), result,
                 remainingPkgSettings, sortTemp, packageManagerService);
 
         // Give priority to apps used by other apps.
         DexManager dexManager = packageManagerService.getDexManager();
-        applyPackageFilter(pkgSetting ->
+        applyPackageFilter(snapshot, pkgSetting ->
                         dexManager.getPackageUseInfoOrDefault(pkgSetting.getPackageName())
                                 .isAnyCodePathUsedByOtherApps(),
                 result, remainingPkgSettings, sortTemp, packageManagerService);
@@ -535,7 +540,7 @@
             // No historical info. Take all.
             remainingPredicate = pkgSetting -> true;
         }
-        applyPackageFilter(remainingPredicate, result, remainingPkgSettings, sortTemp,
+        applyPackageFilter(snapshot, remainingPredicate, result, remainingPkgSettings, sortTemp,
                 packageManagerService);
 
         if (debug) {
@@ -550,7 +555,7 @@
     // package will be removed from {@code packages} and added to {@code result} with its
     // dependencies. If usage data is available, the positive packages will be sorted by usage
     // data (with {@code sortTemp} as temporary storage).
-    private static void applyPackageFilter(
+    private static void applyPackageFilter(@NonNull Computer snapshot,
             Predicate<PackageStateInternal> filter,
             Collection<PackageStateInternal> result,
             Collection<PackageStateInternal> packages,
@@ -568,8 +573,7 @@
         for (PackageStateInternal pkgSetting : sortTemp) {
             result.add(pkgSetting);
 
-            List<PackageStateInternal> deps =
-                    packageManagerService.findSharedNonSystemLibraries(pkgSetting);
+            List<PackageStateInternal> deps = snapshot.findSharedNonSystemLibraries(pkgSetting);
             if (!deps.isEmpty()) {
                 deps.removeAll(result);
                 result.addAll(deps);
diff --git a/services/core/java/com/android/server/pm/DomainVerificationConnection.java b/services/core/java/com/android/server/pm/DomainVerificationConnection.java
index db8c6dc..20e4dd8 100644
--- a/services/core/java/com/android/server/pm/DomainVerificationConnection.java
+++ b/services/core/java/com/android/server/pm/DomainVerificationConnection.java
@@ -21,7 +21,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
-import android.content.pm.PackageManagerInternal;
 import android.os.Binder;
 import android.os.Message;
 import android.os.UserHandle;
@@ -35,13 +34,10 @@
 public final class DomainVerificationConnection implements DomainVerificationService.Connection,
         DomainVerificationProxyV1.Connection, DomainVerificationProxyV2.Connection {
     final PackageManagerService mPm;
-    final PackageManagerInternal mPmInternal;
     final UserManagerInternal mUmInternal;
 
-    // TODO(b/198166813): remove PMS dependency
     DomainVerificationConnection(PackageManagerService pm) {
         mPm = pm;
-        mPmInternal = mPm.mInjector.getLocalService(PackageManagerInternal.class);
         mUmInternal = mPm.mInjector.getLocalService(UserManagerInternal.class);
     }
 
@@ -82,18 +78,18 @@
     @Override
     public boolean isCallerPackage(int callingUid, @NonNull String packageName) {
         final int callingUserId = UserHandle.getUserId(callingUid);
-        return callingUid == mPmInternal.getPackageUid(packageName, 0, callingUserId);
+        return callingUid == mPm.snapshotComputer().getPackageUid(packageName, 0, callingUserId);
     }
 
     @Nullable
     @Override
     public AndroidPackage getPackage(@NonNull String packageName) {
-        return mPmInternal.getPackage(packageName);
+        return mPm.snapshotComputer().getPackage(packageName);
     }
 
     @Override
     public boolean filterAppAccess(String packageName, int callingUid, int userId) {
-        return mPmInternal.filterAppAccess(packageName, callingUid, userId);
+        return mPm.snapshotComputer().filterAppAccess(packageName, callingUid, userId);
     }
 
     @Override
@@ -108,6 +104,6 @@
 
     @NonNull
     public Computer snapshot() {
-        return (Computer) mPmInternal.snapshot();
+        return mPm.snapshotComputer();
     }
 }
diff --git a/services/core/java/com/android/server/pm/DumpHelper.java b/services/core/java/com/android/server/pm/DumpHelper.java
index 05ef3c4..f83ef5a 100644
--- a/services/core/java/com/android/server/pm/DumpHelper.java
+++ b/services/core/java/com/android/server/pm/DumpHelper.java
@@ -55,6 +55,7 @@
 
     @NeverCompile // Avoid size overhead of debugging code.
     public void doDump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        final Computer snapshot = mPm.snapshotComputer();
         DumpState dumpState = new DumpState();
         ArraySet<String> permissionNames = null;
 
@@ -121,7 +122,7 @@
                 }
 
                 // Normalize package name to handle renamed packages and static libs
-                pkg = mPm.resolveInternalPackageName(pkg, PackageManager.VERSION_CODE_HIGHEST);
+                pkg = snapshot.resolveInternalPackageName(pkg, PackageManager.VERSION_CODE_HIGHEST);
 
                 pw.println(mPm.checkPermission(perm, pkg, user));
                 return;
@@ -243,7 +244,7 @@
 
         // Return if the package doesn't exist.
         if (packageName != null
-                && mPm.getPackageStateInternal(packageName) == null
+                && snapshot.getPackageStateInternal(packageName) == null
                 && !mPm.mApexManager.isApexPackage(packageName)) {
             pw.println("Unable to find package: " + packageName);
             return;
@@ -257,7 +258,7 @@
         if (!checkin
                 && dumpState.isDumping(DumpState.DUMP_VERSION)
                 && packageName == null) {
-            mPm.dumpComputer(DumpState.DUMP_VERSION, fd, pw, dumpState);
+            snapshot.dump(DumpState.DUMP_VERSION, fd, pw, dumpState);
         }
 
         if (!checkin
@@ -273,7 +274,7 @@
                 final String knownPackage = PackageManagerInternal.knownPackageToString(i);
                 ipw.print(knownPackage);
                 ipw.println(":");
-                final String[] pkgNames = mPm.getKnownPackageNamesInternal(i,
+                final String[] pkgNames = mPm.getKnownPackageNamesInternal(snapshot, i,
                         UserHandle.USER_SYSTEM);
                 ipw.increaseIndent();
                 if (ArrayUtils.isEmpty(pkgNames)) {
@@ -288,8 +289,6 @@
             ipw.decreaseIndent();
         }
 
-        final Computer snapshot = mPm.snapshotComputer();
-
         if (dumpState.isDumping(DumpState.DUMP_VERIFIERS)
                 && packageName == null) {
             final String requiredVerifierPackage = mPm.mRequiredVerifierPackage;
@@ -343,7 +342,7 @@
 
         if (dumpState.isDumping(DumpState.DUMP_LIBS)
                 && packageName == null) {
-            mPm.dumpComputer(DumpState.DUMP_LIBS, fd, pw, dumpState);
+            snapshot.dump(DumpState.DUMP_LIBS, fd, pw, dumpState);
         }
 
         if (dumpState.isDumping(DumpState.DUMP_FEATURES)
@@ -389,17 +388,17 @@
         }
 
         if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED)) {
-            mPm.dumpComputer(DumpState.DUMP_PREFERRED, fd, pw, dumpState);
+            snapshot.dump(DumpState.DUMP_PREFERRED, fd, pw, dumpState);
         }
 
         if (!checkin
                 && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML)
                 && packageName == null) {
-            mPm.dumpComputer(DumpState.DUMP_PREFERRED_XML, fd, pw, dumpState);
+            snapshot.dump(DumpState.DUMP_PREFERRED_XML, fd, pw, dumpState);
         }
 
         if (!checkin && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)) {
-            mPm.dumpComputer(DumpState.DUMP_DOMAIN_PREFERRED, fd, pw, dumpState);
+            snapshot.dump(DumpState.DUMP_DOMAIN_PREFERRED, fd, pw, dumpState);
         }
 
         if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
@@ -429,7 +428,7 @@
 
         if (!checkin
                 && dumpState.isDumping(DumpState.DUMP_QUERIES)) {
-            mPm.dumpComputer(DumpState.DUMP_QUERIES, fd, pw, dumpState);
+            snapshot.dump(DumpState.DUMP_QUERIES, fd, pw, dumpState);
         }
 
         if (dumpState.isDumping(DumpState.DUMP_SHARED_USERS)) {
@@ -529,12 +528,12 @@
 
         if (!checkin
                 && dumpState.isDumping(DumpState.DUMP_DEXOPT)) {
-            mPm.dumpComputer(DumpState.DUMP_DEXOPT, fd, pw, dumpState);
+            snapshot.dump(DumpState.DUMP_DEXOPT, fd, pw, dumpState);
         }
 
         if (!checkin
                 && dumpState.isDumping(DumpState.DUMP_COMPILER_STATS)) {
-            mPm.dumpComputer(DumpState.DUMP_COMPILER_STATS, fd, pw, dumpState);
+            snapshot.dump(DumpState.DUMP_COMPILER_STATS, fd, pw, dumpState);
         }
 
         if (dumpState.isDumping(DumpState.DUMP_MESSAGES)
@@ -581,7 +580,7 @@
             pw.println("    Known digesters list flag: "
                     + PackageManagerService.getKnownDigestersList());
 
-            PerUidReadTimeouts[] items = mPm.getPerUidReadTimeouts();
+            PerUidReadTimeouts[] items = mPm.getPerUidReadTimeouts(snapshot);
             pw.println("    Timeouts (" + items.length + "):");
             for (PerUidReadTimeouts item : items) {
                 pw.print("        (");
diff --git a/services/core/java/com/android/server/pm/IPackageManagerBase.java b/services/core/java/com/android/server/pm/IPackageManagerBase.java
new file mode 100644
index 0000000..e1aee6d
--- /dev/null
+++ b/services/core/java/com/android/server/pm/IPackageManagerBase.java
@@ -0,0 +1,1189 @@
+/*
+ * 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.server.pm;
+
+
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.UserIdInt;
+import android.app.role.RoleManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.IPackageDeleteObserver2;
+import android.content.pm.IPackageInstaller;
+import android.content.pm.IPackageManager;
+import android.content.pm.IPackageStatsObserver;
+import android.content.pm.InstallSourceInfo;
+import android.content.pm.InstrumentationInfo;
+import android.content.pm.IntentFilterVerificationInfo;
+import android.content.pm.KeySet;
+import android.content.pm.ModuleInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.VersionedPackage;
+import android.content.pm.dex.IArtManager;
+import android.os.Binder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.permission.PermissionManager;
+
+import com.android.internal.R;
+import com.android.internal.content.InstallLocationUtils;
+import com.android.internal.util.CollectionUtils;
+import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
+import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV1;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Contains all simply proxy methods which need a snapshot instance and just calls a method on it,
+ * with no additional logic. Separated with all methods marked final and deprecated to prevent their
+ * use from other methods which may need a snapshot for non-trivial reasons.
+ */
+public abstract class IPackageManagerBase extends IPackageManager.Stub {
+
+    @NonNull
+    private final PackageManagerService mService;
+
+    @NonNull
+    private final Context mContext;
+
+    @NonNull private final DexOptHelper mDexOptHelper;
+    @NonNull private final ModuleInfoProvider mModuleInfoProvider;
+    @NonNull private final PreferredActivityHelper mPreferredActivityHelper;
+    @NonNull private final ResolveIntentHelper mResolveIntentHelper;
+
+    @NonNull
+    private final DomainVerificationManagerInternal mDomainVerificationManager;
+
+    @NonNull
+    private final DomainVerificationConnection mDomainVerificationConnection;
+
+    @NonNull
+    private final PackageInstallerService mInstallerService;
+
+    @NonNull
+    private final PackageProperty mPackageProperty;
+
+    @NonNull
+    private final ComponentName mResolveComponentName;
+
+    @Nullable
+    private final ComponentName mInstantAppResolverSettingsComponent;
+
+    @NonNull
+    private final String mRequiredSupplementalProcessPackage;
+
+    @Nullable
+    private final String mServicesExtensionPackageName;
+
+    @Nullable
+    private final String mSharedSystemSharedLibraryPackageName;
+
+    public IPackageManagerBase(@NonNull PackageManagerService service, @NonNull Context context,
+            @NonNull DexOptHelper dexOptHelper, @NonNull ModuleInfoProvider moduleInfoProvider,
+            @NonNull PreferredActivityHelper preferredActivityHelper,
+            @NonNull ResolveIntentHelper resolveIntentHelper,
+            @NonNull DomainVerificationManagerInternal domainVerificationManager,
+            @NonNull DomainVerificationConnection domainVerificationConnection,
+            @NonNull PackageInstallerService installerService,
+            @NonNull PackageProperty packageProperty, @NonNull ComponentName resolveComponentName,
+            @Nullable ComponentName instantAppResolverSettingsComponent,
+            @NonNull String requiredSupplementalProcessPackage,
+            @Nullable String servicesExtensionPackageName,
+            @Nullable String sharedSystemSharedLibraryPackageName) {
+        mService = service;
+        mContext = context;
+        mDexOptHelper = dexOptHelper;
+        mModuleInfoProvider = moduleInfoProvider;
+        mPreferredActivityHelper = preferredActivityHelper;
+        mResolveIntentHelper = resolveIntentHelper;
+        mDomainVerificationManager = domainVerificationManager;
+        mDomainVerificationConnection = domainVerificationConnection;
+        mInstallerService = installerService;
+        mPackageProperty = packageProperty;
+        mResolveComponentName = resolveComponentName;
+        mInstantAppResolverSettingsComponent = instantAppResolverSettingsComponent;
+        mRequiredSupplementalProcessPackage = requiredSupplementalProcessPackage;
+        mServicesExtensionPackageName = servicesExtensionPackageName;
+        mSharedSystemSharedLibraryPackageName = sharedSystemSharedLibraryPackageName;
+    }
+
+    protected Computer snapshot() {
+        return mService.snapshotComputer();
+    }
+
+    @Override
+    @Deprecated
+    public final boolean activitySupportsIntent(ComponentName component, Intent intent,
+            String resolvedType) {
+        return snapshot().activitySupportsIntent(mResolveComponentName, component, intent,
+                resolvedType);
+    }
+
+    @Override
+    @Deprecated
+    public final void addCrossProfileIntentFilter(IntentFilter intentFilter, String ownerPackage,
+            int sourceUserId, int targetUserId, int flags) {
+        mService.addCrossProfileIntentFilter(snapshot(),
+                new WatchedIntentFilter(intentFilter), ownerPackage, sourceUserId, targetUserId,
+                flags);
+    }
+
+    // NOTE: Can't remove due to unsupported app usage
+    @Override
+    @Deprecated
+    public final boolean addPermission(PermissionInfo info) {
+        // Because this is accessed via the package manager service AIDL,
+        // go through the permission manager service AIDL
+        return mContext.getSystemService(PermissionManager.class).addPermission(info, false);
+    }
+
+    // NOTE: Can't remove due to unsupported app usage
+    @Override
+    @Deprecated
+    public final boolean addPermissionAsync(PermissionInfo info) {
+        // Because this is accessed via the package manager service AIDL,
+        // go through the permission manager service AIDL
+        return mContext.getSystemService(PermissionManager.class).addPermission(info, true);
+    }
+
+    @Override
+    @Deprecated
+    public final void addPersistentPreferredActivity(IntentFilter filter, ComponentName activity,
+            int userId) {
+        mPreferredActivityHelper.addPersistentPreferredActivity(new WatchedIntentFilter(filter),
+                activity, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final void addPreferredActivity(IntentFilter filter, int match,
+            ComponentName[] set, ComponentName activity, int userId, boolean removeExisting) {
+        mPreferredActivityHelper.addPreferredActivity(snapshot(),
+                new WatchedIntentFilter(filter), match, set, activity, true, userId,
+                "Adding preferred", removeExisting);
+    }
+
+    /*
+     * Returns if intent can be forwarded from the sourceUserId to the targetUserId
+     */
+    @Override
+    @Deprecated
+    public final boolean canForwardTo(@NonNull Intent intent, @Nullable String resolvedType,
+            @UserIdInt int sourceUserId, @UserIdInt int targetUserId) {
+        return snapshot().canForwardTo(intent, resolvedType, sourceUserId, targetUserId);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean canRequestPackageInstalls(String packageName, int userId) {
+        return snapshot().canRequestPackageInstalls(packageName, Binder.getCallingUid(), userId,
+                true /* throwIfPermNotDeclared*/);
+    }
+
+    @Override
+    @Deprecated
+    public final String[] canonicalToCurrentPackageNames(String[] names) {
+        return snapshot().canonicalToCurrentPackageNames(names);
+    }
+
+    // NOTE: Can't remove due to unsupported app usage
+    @Override
+    @Deprecated
+    public final int checkPermission(String permName, String pkgName, int userId) {
+        return mService.checkPermission(permName, pkgName, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final int checkSignatures(@NonNull String pkg1, @NonNull String pkg2) {
+        return snapshot().checkSignatures(pkg1, pkg2);
+    }
+
+    @Override
+    @Deprecated
+    public final int checkUidPermission(String permName, int uid) {
+        return snapshot().checkUidPermission(permName, uid);
+    }
+
+    @Override
+    @Deprecated
+    public final int checkUidSignatures(int uid1, int uid2) {
+        return snapshot().checkUidSignatures(uid1, uid2);
+    }
+
+    @Override
+    @Deprecated
+    public final void clearPackagePersistentPreferredActivities(String packageName, int userId) {
+        mPreferredActivityHelper.clearPackagePersistentPreferredActivities(packageName, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final void clearPackagePreferredActivities(String packageName) {
+        mPreferredActivityHelper.clearPackagePreferredActivities(snapshot(),
+                packageName);
+    }
+
+    @Override
+    @Deprecated
+    public final String[] currentToCanonicalPackageNames(String[] names) {
+        return snapshot().currentToCanonicalPackageNames(names);
+    }
+
+    @Override
+    @Deprecated
+    public final void deleteExistingPackageAsUser(VersionedPackage versionedPackage,
+            final IPackageDeleteObserver2 observer, final int userId) {
+        mService.deleteExistingPackageAsUser(versionedPackage, observer, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final void deletePackageAsUser(String packageName, int versionCode,
+            IPackageDeleteObserver observer, int userId, int flags) {
+        deletePackageVersioned(new VersionedPackage(packageName, versionCode),
+                new PackageManager.LegacyPackageDeleteObserver(observer).getBinder(), userId,
+                flags);
+    }
+
+    @Override
+    @Deprecated
+    public final void deletePackageVersioned(VersionedPackage versionedPackage,
+            final IPackageDeleteObserver2 observer, final int userId, final int deleteFlags) {
+        mService.deletePackageVersioned(versionedPackage, observer, userId, deleteFlags);
+    }
+
+    @Override
+    @Deprecated
+    public final ResolveInfo findPersistentPreferredActivity(Intent intent, int userId) {
+        return mPreferredActivityHelper.findPersistentPreferredActivity(snapshot(), intent, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final void forceDexOpt(String packageName) {
+        mDexOptHelper.forceDexOpt(snapshot(), packageName);
+    }
+
+    @Override
+    @Deprecated
+    public final ActivityInfo getActivityInfo(ComponentName component,
+            @PackageManager.ComponentInfoFlagsBits long flags, int userId) {
+        return snapshot().getActivityInfo(component, flags, userId);
+    }
+
+    @NonNull
+    @Override
+    @Deprecated
+    public final ParceledListSlice<IntentFilter> getAllIntentFilters(@NonNull String packageName) {
+        return snapshot().getAllIntentFilters(packageName);
+    }
+
+    @Override
+    @Deprecated
+    public final List<String> getAllPackages() {
+        return snapshot().getAllPackages();
+    }
+
+    // NOTE: Can't remove due to unsupported app usage
+    @NonNull
+    @Override
+    @Deprecated
+    public final String[] getAppOpPermissionPackages(@NonNull String permissionName) {
+        return snapshot().getAppOpPermissionPackages(permissionName);
+    }
+
+    @Override
+    @Deprecated
+    public final String getAppPredictionServicePackageName() {
+        return mService.mAppPredictionServicePackage;
+    }
+
+    @PackageManager.EnabledState
+    @Override
+    @Deprecated
+    public final int getApplicationEnabledSetting(@NonNull String packageName,
+            @UserIdInt int userId) {
+        return snapshot().getApplicationEnabledSetting(packageName, userId);
+    }
+
+    /**
+     * Returns true if application is not found or there was an error. Otherwise it returns the
+     * hidden state of the package for the given user.
+     */
+    @Override
+    @Deprecated
+    public final boolean getApplicationHiddenSettingAsUser(@NonNull String packageName,
+            @UserIdInt int userId) {
+        return snapshot().getApplicationHiddenSettingAsUser(packageName, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final ApplicationInfo getApplicationInfo(String packageName,
+            @PackageManager.ApplicationInfoFlagsBits long flags, int userId) {
+        return snapshot().getApplicationInfo(packageName, flags, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final IArtManager getArtManager() {
+        return mService.mArtManagerService;
+    }
+
+    @Override
+    @Deprecated
+    public final @Nullable
+    String getAttentionServicePackageName() {
+        return mService.ensureSystemPackageName(snapshot(),
+                mService.getPackageFromComponentString(R.string.config_defaultAttentionService));
+    }
+
+    @Override
+    @Deprecated
+    public final boolean getBlockUninstallForUser(@NonNull String packageName,
+            @UserIdInt int userId) {
+        return snapshot().getBlockUninstallForUser(packageName, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final int getComponentEnabledSetting(@NonNull ComponentName component, int userId) {
+        return snapshot().getComponentEnabledSetting(component, Binder.getCallingUid(), userId);
+    }
+
+    @Override
+    @Deprecated
+    public final String getContentCaptureServicePackageName() {
+        return mService.ensureSystemPackageName(snapshot(),
+                mService.getPackageFromComponentString(
+                        R.string.config_defaultContentCaptureService));
+    }
+
+    @Nullable
+    @Override
+    @Deprecated
+    public final ParceledListSlice<SharedLibraryInfo> getDeclaredSharedLibraries(
+            @NonNull String packageName, @PackageManager.PackageInfoFlagsBits long flags,
+            @NonNull int userId) {
+        return snapshot().getDeclaredSharedLibraries(packageName, flags, userId);
+    }
+
+    /**
+     * Non-Binder method, support for the backup/restore mechanism: write the default browser (etc)
+     * settings in its canonical XML format.  Returns the default browser XML representation as a
+     * byte array, or null if there is none.
+     */
+    @Override
+    @Deprecated
+    public final byte[] getDefaultAppsBackup(int userId) {
+        return mPreferredActivityHelper.getDefaultAppsBackup(userId);
+    }
+
+    @Override
+    @Deprecated
+    public final String getDefaultTextClassifierPackageName() {
+        return mService.mDefaultTextClassifierPackage;
+    }
+
+    @Override
+    @Deprecated
+    public final int getFlagsForUid(int uid) {
+        return snapshot().getFlagsForUid(uid);
+    }
+
+    @Nullable
+    @Override
+    @Deprecated
+    public final CharSequence getHarmfulAppWarning(@NonNull String packageName,
+            @UserIdInt int userId) {
+        return snapshot().getHarmfulAppWarning(packageName, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final ComponentName getHomeActivities(List<ResolveInfo> allHomeCandidates) {
+        final Computer snapshot = snapshot();
+        if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+            return null;
+        }
+        return snapshot.getHomeActivitiesAsUser(allHomeCandidates,
+                UserHandle.getCallingUserId());
+    }
+
+    @Deprecated
+    public final String getIncidentReportApproverPackageName() {
+        return mService.mIncidentReportApproverPackage;
+    }
+
+    @Override
+    @Deprecated
+    public final int getInstallLocation() {
+        // allow instant app access
+        return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
+                android.provider.Settings.Global.DEFAULT_INSTALL_LOCATION,
+                InstallLocationUtils.APP_INSTALL_AUTO);
+    }
+
+    @PackageManager.InstallReason
+    @Override
+    @Deprecated
+    public final int getInstallReason(@NonNull String packageName, @UserIdInt int userId) {
+        return snapshot().getInstallReason(packageName, userId);
+    }
+
+    @Override
+    @Nullable
+    @Deprecated
+    public final InstallSourceInfo getInstallSourceInfo(@NonNull String packageName) {
+        return snapshot().getInstallSourceInfo(packageName);
+    }
+
+    @Override
+    @Deprecated
+    public final ParceledListSlice<ApplicationInfo> getInstalledApplications(
+            @PackageManager.ApplicationInfoFlagsBits long flags, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        return new ParceledListSlice<>(
+                snapshot().getInstalledApplications(flags, userId, callingUid));
+    }
+
+    @Override
+    @Deprecated
+    public final List<ModuleInfo> getInstalledModules(int flags) {
+        return mModuleInfoProvider.getInstalledModules(flags);
+    }
+
+    @Override
+    @Deprecated
+    public final ParceledListSlice<PackageInfo> getInstalledPackages(
+            @PackageManager.PackageInfoFlagsBits long flags, int userId) {
+        return snapshot().getInstalledPackages(flags, userId);
+    }
+
+    @Nullable
+    @Override
+    @Deprecated
+    public final String getInstallerPackageName(@NonNull String packageName) {
+        return snapshot().getInstallerPackageName(packageName);
+    }
+
+    @Override
+    @Deprecated
+    public final ComponentName getInstantAppInstallerComponent() {
+        final Computer snapshot = snapshot();
+        if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+            return null;
+        }
+        return snapshot.getInstantAppInstallerComponent();
+    }
+
+    @Override
+    @Deprecated
+    public final @Nullable
+    ComponentName getInstantAppResolverComponent() {
+        final Computer snapshot = snapshot();
+        if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+            return null;
+        }
+        return mService.getInstantAppResolver(snapshot);
+    }
+
+    @Override
+    @Deprecated
+    public final ComponentName getInstantAppResolverSettingsComponent() {
+        return mInstantAppResolverSettingsComponent;
+    }
+
+    @Nullable
+    @Override
+    @Deprecated
+    public final InstrumentationInfo getInstrumentationInfo(@NonNull ComponentName component,
+            int flags) {
+        return snapshot().getInstrumentationInfo(component, flags);
+    }
+
+    @Override
+    @Deprecated
+    public final @NonNull
+    ParceledListSlice<IntentFilterVerificationInfo>
+    getIntentFilterVerifications(String packageName) {
+        return ParceledListSlice.emptyList();
+    }
+
+    @Override
+    @Deprecated
+    public final int getIntentVerificationStatus(String packageName, int userId) {
+        return mDomainVerificationManager.getLegacyState(packageName, userId);
+    }
+
+    @Nullable
+    @Override
+    @Deprecated
+    public final KeySet getKeySetByAlias(@NonNull String packageName, @NonNull String alias) {
+        return snapshot().getKeySetByAlias(packageName, alias);
+    }
+
+    @Override
+    @Deprecated
+    public final ModuleInfo getModuleInfo(String packageName,
+            @PackageManager.ModuleInfoFlags int flags) {
+        return mModuleInfoProvider.getModuleInfo(packageName, flags);
+    }
+
+    @Nullable
+    @Override
+    @Deprecated
+    public final String getNameForUid(int uid) {
+        return snapshot().getNameForUid(uid);
+    }
+
+    @Nullable
+    @Override
+    @Deprecated
+    public final String[] getNamesForUids(@NonNull int[] uids) {
+        return snapshot().getNamesForUids(uids);
+    }
+
+    @Override
+    @Deprecated
+    public final int[] getPackageGids(String packageName,
+            @PackageManager.PackageInfoFlagsBits long flags, int userId) {
+        return snapshot().getPackageGids(packageName, flags, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final PackageInfo getPackageInfo(String packageName,
+            @PackageManager.PackageInfoFlagsBits long flags, int userId) {
+        return snapshot().getPackageInfo(packageName, flags, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final PackageInfo getPackageInfoVersioned(VersionedPackage versionedPackage,
+            @PackageManager.PackageInfoFlagsBits long flags, int userId) {
+        return snapshot().getPackageInfoInternal(versionedPackage.getPackageName(),
+                versionedPackage.getLongVersionCode(), flags, Binder.getCallingUid(), userId);
+    }
+
+    @Override
+    @Deprecated
+    public final IPackageInstaller getPackageInstaller() {
+        // Return installer service for internal calls.
+        if (PackageManagerServiceUtils.isSystemOrRoot()) {
+            return mInstallerService;
+        }
+        final Computer snapshot = snapshot();
+        // Return null for InstantApps.
+        if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+            return null;
+        }
+        return mInstallerService;
+    }
+
+    @Override
+    @Deprecated
+    public final void getPackageSizeInfo(final String packageName, int userId,
+            final IPackageStatsObserver observer) {
+        throw new UnsupportedOperationException(
+                "Shame on you for calling the hidden API getPackageSizeInfo(). Shame!");
+    }
+
+    @Override
+    @Deprecated
+    public final int getPackageUid(@NonNull String packageName,
+            @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId) {
+        return snapshot().getPackageUid(packageName, flags, userId);
+    }
+
+    /**
+     * <em>IMPORTANT:</em> Not all packages returned by this method may be known
+     * to the system. There are two conditions in which this may occur:
+     * <ol>
+     *   <li>The package is on adoptable storage and the device has been removed</li>
+     *   <li>The package is being removed and the internal structures are partially updated</li>
+     * </ol>
+     * The second is an artifact of the current data structures and should be fixed. See
+     * b/111075456 for one such instance.
+     * This binder API is cached.  If the algorithm in this method changes,
+     * or if the underlying objecs (as returned by getSettingLPr()) change
+     * then the logic that invalidates the cache must be revisited.  See
+     * calls to invalidateGetPackagesForUidCache() to locate the points at
+     * which the cache is invalidated.
+     */
+    @Override
+    @Deprecated
+    public final String[] getPackagesForUid(int uid) {
+        final int callingUid = Binder.getCallingUid();
+        final int userId = UserHandle.getUserId(uid);
+        snapshot().enforceCrossUserOrProfilePermission(callingUid, userId,
+                /* requireFullPermission */ false,
+                /* checkShell */ false, "getPackagesForUid");
+        return snapshot().getPackagesForUid(uid);
+    }
+
+    @Override
+    @Deprecated
+    public final ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
+            @NonNull String[] permissions, @PackageManager.PackageInfoFlagsBits long flags,
+            @UserIdInt int userId) {
+        return snapshot().getPackagesHoldingPermissions(permissions, flags, userId);
+    }
+
+    // NOTE: Can't remove due to unsupported app usage
+    @Override
+    @Deprecated
+    public final PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags) {
+        return mService.getPermissionGroupInfo(groupName, flags);
+    }
+
+    @Override
+    @Deprecated
+    public final @NonNull
+    ParceledListSlice<ApplicationInfo> getPersistentApplications(int flags) {
+        final Computer snapshot = snapshot();
+        if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+            return ParceledListSlice.emptyList();
+        }
+        return new ParceledListSlice<>(snapshot.getPersistentApplications(isSafeMode(), flags));
+    }
+
+    @Override
+    @Deprecated
+    public final int getPreferredActivities(List<IntentFilter> outFilters,
+            List<ComponentName> outActivities, String packageName) {
+        return mPreferredActivityHelper.getPreferredActivities(snapshot(), outFilters,
+                outActivities, packageName);
+    }
+
+    /**
+     * Non-Binder method, support for the backup/restore mechanism: write the full set of preferred
+     * activities in its canonical XML format.  Returns the XML output as a byte array, or null if
+     * there is none.
+     */
+    @Override
+    @Deprecated
+    public final byte[] getPreferredActivityBackup(int userId) {
+        return mPreferredActivityHelper.getPreferredActivityBackup(userId);
+    }
+
+    @Override
+    @Deprecated
+    public final int getPrivateFlagsForUid(int uid) {
+        return snapshot().getPrivateFlagsForUid(uid);
+    }
+
+    @Override
+    @Deprecated
+    public final PackageManager.Property getProperty(String propertyName, String packageName,
+            String className) {
+        Objects.requireNonNull(propertyName);
+        Objects.requireNonNull(packageName);
+        PackageStateInternal packageState = snapshot().getPackageStateFiltered(packageName,
+                Binder.getCallingUid(), UserHandle.getCallingUserId());
+        if (packageState == null) {
+            return null;
+        }
+        return mPackageProperty.getProperty(propertyName, packageName, className);
+    }
+
+    @Nullable
+    @Override
+    @Deprecated
+    public final ProviderInfo getProviderInfo(@NonNull ComponentName component,
+            @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId) {
+        return snapshot().getProviderInfo(component, flags, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final ActivityInfo getReceiverInfo(ComponentName component,
+            @PackageManager.ComponentInfoFlagsBits long flags, int userId) {
+        return snapshot().getReceiverInfo(component, flags, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final @Nullable
+    String getRotationResolverPackageName() {
+        return mService.ensureSystemPackageName(snapshot(),
+                mService.getPackageFromComponentString(
+                        R.string.config_defaultRotationResolverService));
+    }
+
+    @Nullable
+    @Override
+    @Deprecated
+    public final ServiceInfo getServiceInfo(@NonNull ComponentName component,
+            @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId) {
+        return snapshot().getServiceInfo(component, flags, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final @NonNull
+    String getServicesSystemSharedLibraryPackageName() {
+        return mServicesExtensionPackageName;
+    }
+
+    @Override
+    @Deprecated
+    public final String getSetupWizardPackageName() {
+        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+            throw new SecurityException("Non-system caller");
+        }
+        return mService.mSetupWizardPackage;
+    }
+
+    @Override
+    @Deprecated
+    public final ParceledListSlice<SharedLibraryInfo> getSharedLibraries(String packageName,
+            @PackageManager.PackageInfoFlagsBits long flags, int userId) {
+        return snapshot().getSharedLibraries(packageName, flags, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final @NonNull
+    String getSharedSystemSharedLibraryPackageName() {
+        return mSharedSystemSharedLibraryPackageName;
+    }
+
+    @Nullable
+    @Override
+    @Deprecated
+    public final KeySet getSigningKeySet(@NonNull String packageName) {
+        return snapshot().getSigningKeySet(packageName);
+    }
+
+    @Override
+    @Deprecated
+    public final String getSdkSandboxPackageName() {
+        return mService.getSdkSandboxPackageName();
+    }
+
+    @Override
+    @Deprecated
+    public final String getSystemCaptionsServicePackageName() {
+        return mService.ensureSystemPackageName(snapshot(),
+                mService.getPackageFromComponentString(
+                        R.string.config_defaultSystemCaptionsService));
+    }
+
+    @Nullable
+    @Override
+    @Deprecated
+    public final String[] getSystemSharedLibraryNames() {
+        return snapshot().getSystemSharedLibraryNames();
+    }
+
+    @Override
+    @Deprecated
+    public final String getSystemTextClassifierPackageName() {
+        return mService.mSystemTextClassifierPackageName;
+    }
+
+    @Override
+    @Deprecated
+    public final int getTargetSdkVersion(@NonNull String packageName) {
+        return snapshot().getTargetSdkVersion(packageName);
+    }
+
+    @Override
+    @Deprecated
+    public final int getUidForSharedUser(@NonNull String sharedUserName) {
+        return snapshot().getUidForSharedUser(sharedUserName);
+    }
+
+    @SuppressLint("MissingPermission")
+    @Override
+    @Deprecated
+    public final String getWellbeingPackageName() {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            return CollectionUtils.firstOrNull(
+                    mContext.getSystemService(RoleManager.class).getRoleHolders(
+                            RoleManager.ROLE_SYSTEM_WELLBEING));
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    // NOTE: Can't remove due to unsupported app usage
+    @SuppressLint("MissingPermission")
+    @Override
+    @Deprecated
+    public final void grantRuntimePermission(String packageName, String permName,
+            final int userId) {
+        // Because this is accessed via the package manager service AIDL,
+        // go through the permission manager service AIDL
+        mContext.getSystemService(PermissionManager.class)
+                .grantRuntimePermission(packageName, permName, UserHandle.of(userId));
+    }
+
+    @Override
+    @Deprecated
+    public final boolean hasSigningCertificate(@NonNull String packageName,
+            @NonNull byte[] certificate,
+            @PackageManager.CertificateInputType int type) {
+        return snapshot().hasSigningCertificate(packageName, certificate, type);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean hasSystemFeature(String name, int version) {
+        return mService.hasSystemFeature(name, version);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean hasSystemUidErrors() {
+        // allow instant applications
+        return false;
+    }
+
+    @Override
+    @Deprecated
+    public final boolean hasUidSigningCertificate(int uid, @NonNull byte[] certificate,
+            @PackageManager.CertificateInputType int type) {
+        return snapshot().hasUidSigningCertificate(uid, certificate, type);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isDeviceUpgrading() {
+        return mService.isDeviceUpgrading();
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isFirstBoot() {
+        return mService.isFirstBoot();
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isInstantApp(String packageName, int userId) {
+        return snapshot().isInstantApp(packageName, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isOnlyCoreApps() {
+        return mService.isOnlyCoreApps();
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isPackageAvailable(String packageName, int userId) {
+        return snapshot().isPackageAvailable(packageName, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isPackageDeviceAdminOnAnyUser(String packageName) {
+        return mService.isPackageDeviceAdminOnAnyUser(snapshot(),
+                packageName);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isPackageSignedByKeySet(@NonNull String packageName, @NonNull KeySet ks) {
+        return snapshot().isPackageSignedByKeySet(packageName, ks);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isPackageSignedByKeySetExactly(@NonNull String packageName,
+            @NonNull KeySet ks) {
+        return snapshot().isPackageSignedByKeySetExactly(packageName, ks);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isPackageSuspendedForUser(@NonNull String packageName,
+            @UserIdInt int userId) {
+        return snapshot().isPackageSuspendedForUser(packageName, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isSafeMode() {
+        // allow instant applications
+        return mService.getSafeMode();
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isStorageLow() {
+        return mService.isStorageLow();
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isUidPrivileged(int uid) {
+        return snapshot().isUidPrivileged(uid);
+    }
+
+    /**
+     * Ask the package manager to perform a dex-opt with the given compiler filter.
+     * <p>
+     * Note: exposed only for the shell command to allow moving packages explicitly to a definite
+     * state.
+     */
+    @Override
+    @Deprecated
+    public final boolean performDexOptMode(String packageName,
+            boolean checkProfiles, String targetCompilerFilter, boolean force,
+            boolean bootComplete, String splitName) {
+        return mDexOptHelper.performDexOptMode(packageName, checkProfiles, targetCompilerFilter,
+                force, bootComplete, splitName);
+    }
+
+    /**
+     * Ask the package manager to perform a dex-opt with the given compiler filter on the secondary
+     * dex files belonging to the given package.
+     * <p>
+     * Note: exposed only for the shell command to allow moving packages explicitly to a definite
+     * state.
+     */
+    @Override
+    @Deprecated
+    public final boolean performDexOptSecondary(String packageName, String compilerFilter,
+            boolean force) {
+        return mDexOptHelper.performDexOptSecondary(packageName, compilerFilter, force);
+    }
+
+    @Override
+    @Deprecated
+    public final @NonNull
+    ParceledListSlice<ResolveInfo> queryIntentActivities(Intent intent,
+            String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
+        try {
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities");
+
+            return new ParceledListSlice<>(snapshot().queryIntentActivitiesInternal(intent,
+                    resolvedType, flags, userId));
+        } finally {
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+        }
+    }
+
+    @NonNull
+    @Override
+    @Deprecated
+    public final ParceledListSlice<ProviderInfo> queryContentProviders(@Nullable String processName,
+            int uid, @PackageManager.ComponentInfoFlagsBits long flags,
+            @Nullable String metaDataKey) {
+        return snapshot().queryContentProviders(processName, uid, flags, metaDataKey);
+    }
+
+    @NonNull
+    @Override
+    @Deprecated
+    public final ParceledListSlice<InstrumentationInfo> queryInstrumentation(
+            @NonNull String targetPackage, int flags) {
+        return snapshot().queryInstrumentation(targetPackage, flags);
+    }
+
+    @Override
+    @Deprecated
+    public final @NonNull
+    ParceledListSlice<ResolveInfo> queryIntentActivityOptions(
+            ComponentName caller, Intent[] specifics, String[] specificTypes, Intent intent,
+            String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
+        return new ParceledListSlice<>(mResolveIntentHelper.queryIntentActivityOptionsInternal(
+                snapshot(), caller, specifics, specificTypes, intent, resolvedType, flags,
+                userId));
+    }
+
+    @Override
+    @Deprecated
+    public final @NonNull
+    ParceledListSlice<ResolveInfo> queryIntentContentProviders(Intent intent,
+            String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
+        return new ParceledListSlice<>(mResolveIntentHelper.queryIntentContentProvidersInternal(
+                snapshot(), intent, resolvedType, flags, userId));
+    }
+
+    @Override
+    @Deprecated
+    public final @NonNull
+    ParceledListSlice<ResolveInfo> queryIntentReceivers(Intent intent,
+            String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
+        return new ParceledListSlice<>(mResolveIntentHelper.queryIntentReceiversInternal(
+                snapshot(), intent, resolvedType, flags, userId, Binder.getCallingUid()));
+    }
+
+    @Override
+    @Deprecated
+    public final @NonNull
+    ParceledListSlice<ResolveInfo> queryIntentServices(Intent intent,
+            String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        return new ParceledListSlice<>(snapshot().queryIntentServicesInternal(
+                intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/));
+    }
+
+    @Override
+    @Deprecated
+    public final void querySyncProviders(List<String> outNames, List<ProviderInfo> outInfo) {
+        snapshot().querySyncProviders(isSafeMode(), outNames, outInfo);
+    }
+
+    @Override
+    @Deprecated
+    public final void removePermission(String permName) {
+        // Because this is accessed via the package manager service AIDL,
+        // go through the permission manager service AIDL
+        mContext.getSystemService(PermissionManager.class).removePermission(permName);
+    }
+
+    @Override
+    @Deprecated
+    public final void replacePreferredActivity(IntentFilter filter, int match,
+            ComponentName[] set, ComponentName activity, int userId) {
+        mPreferredActivityHelper.replacePreferredActivity(snapshot(),
+                new WatchedIntentFilter(filter), match, set, activity, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final ProviderInfo resolveContentProvider(String name,
+            @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
+        return snapshot().resolveContentProvider(name, flags, userId, Binder.getCallingUid());
+    }
+
+    @Override
+    @Deprecated
+    public final void resetApplicationPreferences(int userId) {
+        mPreferredActivityHelper.resetApplicationPreferences(userId);
+    }
+
+    @Override
+    @Deprecated
+    public final ResolveInfo resolveIntent(Intent intent, String resolvedType,
+            @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
+        return mResolveIntentHelper.resolveIntentInternal(snapshot(), intent,
+                resolvedType, flags, 0 /*privateResolveFlags*/, userId, false,
+                Binder.getCallingUid());
+    }
+
+    @Override
+    @Deprecated
+    public final ResolveInfo resolveService(Intent intent, String resolvedType,
+            @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        return mResolveIntentHelper.resolveServiceInternal(snapshot(), intent,
+                resolvedType, flags, userId, callingUid);
+    }
+
+    @Override
+    @Deprecated
+    public final void restoreDefaultApps(byte[] backup, int userId) {
+        mPreferredActivityHelper.restoreDefaultApps(backup, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final void restorePreferredActivities(byte[] backup, int userId) {
+        mPreferredActivityHelper.restorePreferredActivities(backup, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final void setHomeActivity(ComponentName comp, int userId) {
+        mPreferredActivityHelper.setHomeActivity(snapshot(), comp, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final void setLastChosenActivity(Intent intent, String resolvedType, int flags,
+            IntentFilter filter, int match, ComponentName activity) {
+        mPreferredActivityHelper.setLastChosenActivity(snapshot(), intent, resolvedType,
+                flags, new WatchedIntentFilter(filter), match, activity);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean updateIntentVerificationStatus(String packageName, int status,
+            int userId) {
+        return mDomainVerificationManager.setLegacyUserState(packageName, userId, status);
+    }
+
+    @Override
+    @Deprecated
+    public final void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains) {
+        DomainVerificationProxyV1.queueLegacyVerifyResult(mContext, mDomainVerificationConnection,
+                id, verificationCode, failedDomains, Binder.getCallingUid());
+    }
+
+    @Override
+    @Deprecated
+    public final boolean canPackageQuery(@NonNull String sourcePackageName,
+            @NonNull String targetPackageName, @UserIdInt int userId) {
+        return snapshot().canPackageQuery(sourcePackageName, targetPackageName, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final void deletePreloadsFileCache() throws RemoteException {
+        mService.deletePreloadsFileCache();
+    }
+
+    @Override
+    @Deprecated
+    public final void setSystemAppHiddenUntilInstalled(String packageName, boolean hidden)
+            throws RemoteException {
+        mService.setSystemAppHiddenUntilInstalled(snapshot(), packageName, hidden);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean setSystemAppInstallState(String packageName,
+            boolean installed, int userId) throws RemoteException {
+        return mService.setSystemAppInstallState(snapshot(), packageName, installed, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final void finishPackageInstall(int token, boolean didLaunch) throws RemoteException {
+        mService.finishPackageInstall(token, didLaunch);
+    }
+}
diff --git a/services/core/java/com/android/server/pm/IncrementalProgressListener.java b/services/core/java/com/android/server/pm/IncrementalProgressListener.java
index fa11924..703bbda 100644
--- a/services/core/java/com/android/server/pm/IncrementalProgressListener.java
+++ b/services/core/java/com/android/server/pm/IncrementalProgressListener.java
@@ -33,7 +33,8 @@
 
     @Override
     public void onPackageLoadingProgressChanged(float progress) {
-        PackageStateInternal packageState = mPm.getPackageStateInternal(mPackageName);
+        PackageStateInternal packageState = mPm.snapshotComputer()
+                .getPackageStateInternal(mPackageName);
         if (packageState == null) {
             return;
         }
diff --git a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java b/services/core/java/com/android/server/pm/InitAppsHelper.java
similarity index 63%
rename from services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
rename to services/core/java/com/android/server/pm/InitAppsHelper.java
index 6dbe9b6..15f26e7 100644
--- a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InitAppsHelper.java
@@ -30,7 +30,9 @@
 import static com.android.server.pm.PackageManagerService.SCAN_REQUIRE_KNOWN;
 import static com.android.server.pm.PackageManagerService.SYSTEM_PARTITIONS;
 import static com.android.server.pm.PackageManagerService.TAG;
+import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.PARSE_CHECK_MAX_SDK_VERSION;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.pm.parsing.ApkLiteParseUtils;
 import android.os.Environment;
@@ -60,14 +62,24 @@
  * further cleanup and eventually all the installation/scanning related logic will go to another
  * class.
  */
-final class InitAndSystemPackageHelper {
+final class InitAppsHelper {
     private final PackageManagerService mPm;
-
     private final List<ScanPartition> mDirsToScanAsSystem;
     private final int mScanFlags;
     private final int mSystemParseFlags;
     private final int mSystemScanFlags;
     private final InstallPackageHelper mInstallPackageHelper;
+    private final ApexManager mApexManager;
+    private final ExecutorService mExecutorService;
+    /* Tracks how long system scan took */
+    private long mSystemScanTime;
+    /* Track of the number of cached system apps */
+    private int mCachedSystemApps;
+    /* Track of the number of system apps */
+    private int mSystemPackagesCount;
+    private final boolean mIsDeviceUpgrading;
+    private final boolean mIsOnlyCoreApps;
+    private final List<ScanPartition> mSystemPartitions;
 
     /**
      * Tracks new system packages [received in an OTA] that we expect to
@@ -75,21 +87,33 @@
      * are package location.
      */
     private final ArrayMap<String, File> mExpectingBetter = new ArrayMap<>();
+    /* Tracks of any system packages that no longer exist that needs to be pruned. */
+    private final List<String> mPossiblyDeletedUpdatedSystemApps = new ArrayList<>();
+    // Tracks of stub packages that must either be replaced with full versions in the /data
+    // partition or be disabled.
+    private final List<String> mStubSystemApps = new ArrayList<>();
 
     // TODO(b/198166813): remove PMS dependency
-    InitAndSystemPackageHelper(PackageManagerService pm) {
+    InitAppsHelper(PackageManagerService pm, ApexManager apexManager,
+            InstallPackageHelper installPackageHelper,
+            List<ScanPartition> systemPartitions) {
         mPm = pm;
-        mInstallPackageHelper = new InstallPackageHelper(pm);
+        mApexManager = apexManager;
+        mInstallPackageHelper = installPackageHelper;
+        mSystemPartitions = systemPartitions;
         mDirsToScanAsSystem = getSystemScanPartitions();
+        mIsDeviceUpgrading = mPm.isDeviceUpgrading();
+        mIsOnlyCoreApps = mPm.isOnlyCoreApps();
         // Set flag to monitor and not change apk file paths when scanning install directories.
         int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
-        if (mPm.isDeviceUpgrading() || mPm.isFirstBoot()) {
+        if (mIsDeviceUpgrading || mPm.isFirstBoot()) {
             mScanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
         } else {
             mScanFlags = scanFlags;
         }
         mSystemParseFlags = mPm.getDefParseFlags() | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
         mSystemScanFlags = scanFlags | SCAN_AS_SYSTEM;
+        mExecutorService = ParallelPackageParser.makeExecutorService();
     }
 
     private List<File> getFrameworkResApkSplitFiles() {
@@ -117,7 +141,7 @@
 
     private List<ScanPartition> getSystemScanPartitions() {
         final List<ScanPartition> scanPartitions = new ArrayList<>();
-        scanPartitions.addAll(mPm.mInjector.getSystemPartitions());
+        scanPartitions.addAll(mSystemPartitions);
         scanPartitions.addAll(getApexScanPartitions());
         Slog.d(TAG, "Directories scanned as system partitions: " + scanPartitions);
         return scanPartitions;
@@ -125,8 +149,7 @@
 
     private List<ScanPartition> getApexScanPartitions() {
         final List<ScanPartition> scanPartitions = new ArrayList<>();
-        final List<ApexManager.ActiveApexInfo> activeApexInfos =
-                mPm.mApexManager.getActiveApexInfos();
+        final List<ApexManager.ActiveApexInfo> activeApexInfos = mApexManager.getActiveApexInfos();
         for (int i = 0; i < activeApexInfos.size(); i++) {
             final ScanPartition scanPartition = resolveApexToScanPartition(activeApexInfos.get(i));
             if (scanPartition != null) {
@@ -143,117 +166,134 @@
             if (apexInfo.preInstalledApexPath.getAbsolutePath().equals(
                     sp.getFolder().getAbsolutePath())
                     || apexInfo.preInstalledApexPath.getAbsolutePath().startsWith(
-                        sp.getFolder().getAbsolutePath() + File.separator)) {
+                    sp.getFolder().getAbsolutePath() + File.separator)) {
                 return new ScanPartition(apexInfo.apexDirectory, sp, SCAN_AS_APK_IN_APEX);
             }
         }
         return null;
     }
 
-    public OverlayConfig initPackages(
-            WatchedArrayMap<String, PackageSetting> packageSettings, int[] userIds,
-            long startTime) {
-        PackageParser2 packageParser = mPm.mInjector.getScanningCachingPackageParser();
-
-        ExecutorService executorService = ParallelPackageParser.makeExecutorService();
+    /**
+     * Install apps from system dirs.
+     */
+    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+    public OverlayConfig initSystemApps(PackageParser2 packageParser,
+            WatchedArrayMap<String, PackageSetting> packageSettings,
+            int[] userIds, long startTime) {
         // Prepare apex package info before scanning APKs, this information is needed when
         // scanning apk in apex.
-        mPm.mApexManager.scanApexPackagesTraced(packageParser, executorService);
+        mApexManager.scanApexPackagesTraced(packageParser, mExecutorService);
 
-        scanSystemDirs(packageParser, executorService);
+        scanSystemDirs(packageParser, mExecutorService);
         // Parse overlay configuration files to set default enable state, mutability, and
         // priority of system overlays.
         final ArrayMap<String, File> apkInApexPreInstalledPaths = new ArrayMap<>();
-        for (ApexManager.ActiveApexInfo apexInfo : mPm.mApexManager.getActiveApexInfos()) {
-            for (String packageName : mPm.mApexManager.getApksInApex(apexInfo.apexModuleName)) {
+        for (ApexManager.ActiveApexInfo apexInfo : mApexManager.getActiveApexInfos()) {
+            for (String packageName : mApexManager.getApksInApex(apexInfo.apexModuleName)) {
                 apkInApexPreInstalledPaths.put(packageName, apexInfo.preInstalledApexPath);
             }
         }
-        OverlayConfig overlayConfig = OverlayConfig.initializeSystemInstance(
-                consumer -> mPm.forEachPackage(
+        final OverlayConfig overlayConfig = OverlayConfig.initializeSystemInstance(
+                consumer -> mPm.forEachPackage(mPm.snapshotComputer(),
                         pkg -> consumer.accept(pkg, pkg.isSystem(),
-                          apkInApexPreInstalledPaths.get(pkg.getPackageName()))));
-        // Prune any system packages that no longer exist.
-        final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
-        // Stub packages must either be replaced with full versions in the /data
-        // partition or be disabled.
-        final List<String> stubSystemApps = new ArrayList<>();
+                                apkInApexPreInstalledPaths.get(pkg.getPackageName()))));
 
-        if (!mPm.isOnlyCoreApps()) {
+        if (!mIsOnlyCoreApps) {
             // do this first before mucking with mPackages for the "expecting better" case
-            updateStubSystemAppsList(stubSystemApps);
+            updateStubSystemAppsList(mStubSystemApps);
             mInstallPackageHelper.prepareSystemPackageCleanUp(packageSettings,
-                    possiblyDeletedUpdatedSystemApps, mExpectingBetter, userIds);
+                    mPossiblyDeletedUpdatedSystemApps, mExpectingBetter, userIds);
         }
 
-        final int cachedSystemApps = PackageCacher.sCachedPackageReadCount.get();
+        logSystemAppsScanningTime(startTime);
+        return overlayConfig;
+    }
+
+    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+    private void logSystemAppsScanningTime(long startTime) {
+        mCachedSystemApps = PackageCacher.sCachedPackageReadCount.get();
 
         // Remove any shared userIDs that have no associated packages
         mPm.mSettings.pruneSharedUsersLPw();
-        final long systemScanTime = SystemClock.uptimeMillis() - startTime;
-        final int systemPackagesCount = mPm.mPackages.size();
-        Slog.i(TAG, "Finished scanning system apps. Time: " + systemScanTime
-                + " ms, packageCount: " + systemPackagesCount
+        mSystemScanTime = SystemClock.uptimeMillis() - startTime;
+        mSystemPackagesCount = mPm.mPackages.size();
+        Slog.i(TAG, "Finished scanning system apps. Time: " + mSystemScanTime
+                + " ms, packageCount: " + mSystemPackagesCount
                 + " , timePerPackage: "
-                + (systemPackagesCount == 0 ? 0 : systemScanTime / systemPackagesCount)
-                + " , cached: " + cachedSystemApps);
-        if (mPm.isDeviceUpgrading() && systemPackagesCount > 0) {
+                + (mSystemPackagesCount == 0 ? 0 : mSystemScanTime / mSystemPackagesCount)
+                + " , cached: " + mCachedSystemApps);
+        if (mIsDeviceUpgrading && mSystemPackagesCount > 0) {
             //CHECKSTYLE:OFF IndentationCheck
             FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
                     BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME,
-                    systemScanTime / systemPackagesCount);
+                    mSystemScanTime / mSystemPackagesCount);
             //CHECKSTYLE:ON IndentationCheck
         }
+    }
 
-        if (!mPm.isOnlyCoreApps()) {
+    /**
+     * Install apps/updates from data dir and fix system apps that are affected.
+     */
+    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+    public void initNonSystemApps(PackageParser2 packageParser, @NonNull int[] userIds,
+            long startTime) {
+        if (!mIsOnlyCoreApps) {
             EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                     SystemClock.uptimeMillis());
             scanDirTracedLI(mPm.getAppInstallDir(), /* frameworkSplits= */ null, 0,
-                    mScanFlags | SCAN_REQUIRE_KNOWN, 0,
-                    packageParser, executorService);
-
+                    mScanFlags | SCAN_REQUIRE_KNOWN,
+                    packageParser, mExecutorService);
         }
 
-        List<Runnable> unfinishedTasks = executorService.shutdownNow();
+        List<Runnable> unfinishedTasks = mExecutorService.shutdownNow();
         if (!unfinishedTasks.isEmpty()) {
             throw new IllegalStateException("Not all tasks finished before calling close: "
                     + unfinishedTasks);
         }
-
-        if (!mPm.isOnlyCoreApps()) {
-            mInstallPackageHelper.cleanupDisabledPackageSettings(possiblyDeletedUpdatedSystemApps,
-                    userIds, mScanFlags);
-            mInstallPackageHelper.checkExistingBetterPackages(mExpectingBetter,
-                    stubSystemApps, mSystemScanFlags, mSystemParseFlags);
-
-            // Uncompress and install any stubbed system applications.
-            // This must be done last to ensure all stubs are replaced or disabled.
-            mInstallPackageHelper.installSystemStubPackages(stubSystemApps, mScanFlags);
-
-            final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get()
-                    - cachedSystemApps;
-
-            final long dataScanTime = SystemClock.uptimeMillis() - systemScanTime - startTime;
-            final int dataPackagesCount = mPm.mPackages.size() - systemPackagesCount;
-            Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime
-                    + " ms, packageCount: " + dataPackagesCount
-                    + " , timePerPackage: "
-                    + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
-                    + " , cached: " + cachedNonSystemApps);
-            if (mPm.isDeviceUpgrading() && dataPackagesCount > 0) {
-                //CHECKSTYLE:OFF IndentationCheck
-                FrameworkStatsLog.write(
-                        FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
-                        BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME,
-                        dataScanTime / dataPackagesCount);
-                //CHECKSTYLE:OFF IndentationCheck
-            }
+        if (!mIsOnlyCoreApps) {
+            fixSystemPackages(userIds);
+            logNonSystemAppScanningTime(startTime);
         }
         mExpectingBetter.clear();
-
         mPm.mSettings.pruneRenamedPackagesLPw();
-        packageParser.close();
-        return overlayConfig;
+    }
+
+    /**
+     * Clean up system packages now that some system package updates have been installed from
+     * the data dir. Also install system stub packages as the last step.
+     */
+    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+    private void fixSystemPackages(@NonNull int[] userIds) {
+        mInstallPackageHelper.cleanupDisabledPackageSettings(mPossiblyDeletedUpdatedSystemApps,
+                userIds, mScanFlags);
+        mInstallPackageHelper.checkExistingBetterPackages(mExpectingBetter,
+                mStubSystemApps, mSystemScanFlags, mSystemParseFlags);
+
+        // Uncompress and install any stubbed system applications.
+        // This must be done last to ensure all stubs are replaced or disabled.
+        mInstallPackageHelper.installSystemStubPackages(mStubSystemApps, mScanFlags);
+    }
+
+    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+    private void logNonSystemAppScanningTime(long startTime) {
+        final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get()
+                - mCachedSystemApps;
+
+        final long dataScanTime = SystemClock.uptimeMillis() - mSystemScanTime - startTime;
+        final int dataPackagesCount = mPm.mPackages.size() - mSystemPackagesCount;
+        Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime
+                + " ms, packageCount: " + dataPackagesCount
+                + " , timePerPackage: "
+                + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
+                + " , cached: " + cachedNonSystemApps);
+        if (mIsDeviceUpgrading && dataPackagesCount > 0) {
+            //CHECKSTYLE:OFF IndentationCheck
+            FrameworkStatsLog.write(
+                    FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
+                    BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME,
+                    dataScanTime / dataPackagesCount);
+            //CHECKSTYLE:OFF IndentationCheck
+        }
     }
 
     /**
@@ -273,13 +313,13 @@
                 continue;
             }
             scanDirTracedLI(partition.getOverlayFolder(), /* frameworkSplits= */ null,
-                    mSystemParseFlags, mSystemScanFlags | partition.scanFlag, 0,
+                    mSystemParseFlags, mSystemScanFlags | partition.scanFlag,
                     packageParser, executorService);
         }
 
         scanDirTracedLI(frameworkDir, null,
                 mSystemParseFlags,
-                mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
+                mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED,
                 packageParser, executorService);
         if (!mPm.mPackages.containsKey("android")) {
             throw new IllegalStateException(
@@ -291,11 +331,11 @@
             if (partition.getPrivAppFolder() != null) {
                 scanDirTracedLI(partition.getPrivAppFolder(), /* frameworkSplits= */ null,
                         mSystemParseFlags,
-                        mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
+                        mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag,
                         packageParser, executorService);
             }
             scanDirTracedLI(partition.getAppFolder(), /* frameworkSplits= */ null,
-                    mSystemParseFlags, mSystemScanFlags | partition.scanFlag, 0,
+                    mSystemParseFlags, mSystemScanFlags | partition.scanFlag,
                     packageParser, executorService);
         }
     }
@@ -313,12 +353,16 @@
 
     @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
     private void scanDirTracedLI(File scanDir, List<File> frameworkSplits,
-            final int parseFlags, int scanFlags,
-            long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
+            int parseFlags, int scanFlags,
+            PackageParser2 packageParser, ExecutorService executorService) {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
         try {
+            if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
+                // when scanning apk in apexes, we want to check the maxSdkVersion
+                parseFlags |= PARSE_CHECK_MAX_SDK_VERSION;
+            }
             mInstallPackageHelper.installPackagesFromDir(scanDir, frameworkSplits, parseFlags,
-                    scanFlags, currentTime, packageParser, executorService);
+                    scanFlags, packageParser, executorService);
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 8667ffd..870a11a 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -527,8 +527,10 @@
                     + android.Manifest.permission.INSTALL_PACKAGES + ".");
         }
         PackageSetting pkgSetting;
-        mPm.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
-                true /* checkShell */, "installExistingPackage for user " + userId);
+        final Computer preLockSnapshot = mPm.snapshotComputer();
+        preLockSnapshot.enforceCrossUserPermission(callingUid, userId,
+                true /* requireFullPermission */, true /* checkShell */,
+                "installExistingPackage for user " + userId);
         if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
             return PackageManager.INSTALL_FAILED_USER_RESTRICTED;
         }
@@ -543,11 +545,12 @@
 
             // writer
             synchronized (mPm.mLock) {
+                final Computer snapshot = mPm.snapshotComputer();
                 pkgSetting = mPm.mSettings.getPackageLPr(packageName);
                 if (pkgSetting == null) {
                     return PackageManager.INSTALL_FAILED_INVALID_URI;
                 }
-                if (!mPm.canViewInstantApps(callingUid, UserHandle.getUserId(callingUid))) {
+                if (!snapshot.canViewInstantApps(callingUid, UserHandle.getUserId(callingUid))) {
                     // only allow the existing package to be used if it's installed as a full
                     // application for at least one user
                     boolean installAllowed = false;
@@ -597,7 +600,8 @@
                         mAppDataHelper.prepareAppDataAfterInstallLIF(pkgSetting.getPkg());
                     }
                 }
-                mPm.sendPackageAddedForUser(packageName, pkgSetting, userId, DataLoaderType.NONE);
+                mPm.sendPackageAddedForUser(mPm.snapshotComputer(), packageName, pkgSetting, userId,
+                        DataLoaderType.NONE);
                 synchronized (mPm.mLock) {
                     mPm.updateSequenceNumberLP(pkgSetting, new int[]{ userId });
                 }
@@ -1902,8 +1906,8 @@
                 AndroidPackage oldPackage = mPm.mPackages.get(packageName);
 
                 // Set the update and install times
-                PackageStateInternal deletedPkgSetting = mPm.getPackageStateInternal(
-                        oldPackage.getPackageName());
+                PackageStateInternal deletedPkgSetting = mPm.snapshotComputer()
+                        .getPackageStateInternal(oldPackage.getPackageName());
                 reconciledPkg.mPkgSetting
                         .setFirstInstallTimeFromReplaced(deletedPkgSetting, request.mAllUsers)
                         .setLastUpdateTime(System.currentTimeMillis());
@@ -2571,9 +2575,10 @@
             size = i;
             mPm.mPendingBroadcasts.clear();
         }
+        final Computer snapshot = mPm.snapshotComputer();
         // Send broadcasts
         for (int i = 0; i < size; i++) {
-            mPm.sendPackageChangedBroadcast(packages[i], true /* dontKillApp */,
+            mPm.sendPackageChangedBroadcast(snapshot, packages[i], true /* dontKillApp */,
                     components[i], uids[i], null /* reason */);
         }
         Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
@@ -2592,7 +2597,7 @@
         final boolean update = res.mRemovedInfo != null && res.mRemovedInfo.mRemovedPackage != null;
         final String packageName = res.mName;
         final PackageStateInternal pkgSetting =
-                succeeded ? mPm.getPackageStateInternal(packageName) : null;
+                succeeded ? mPm.snapshotComputer().getPackageStateInternal(packageName) : null;
         final boolean removedBeforeUpdate = (pkgSetting == null)
                 || (pkgSetting.isSystem() && !pkgSetting.getPath().getPath().equals(
                 res.mPkg.getPath()));
@@ -2690,9 +2695,9 @@
                 // sendPackageAddedForNewUsers also deals with system apps
                 int appId = UserHandle.getAppId(res.mUid);
                 boolean isSystem = res.mPkg.isSystem();
-                mPm.sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,
-                        virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds,
-                        dataLoaderType);
+                mPm.sendPackageAddedForNewUsers(mPm.snapshotComputer(), packageName,
+                        isSystem || virtualPreload, virtualPreload /*startReceiver*/, appId,
+                        firstUserIds, firstInstantUserIds, dataLoaderType);
 
                 // Send added for users that don't see the package for the first time
                 Bundle extras = new Bundle();
@@ -2705,7 +2710,8 @@
                 final SparseArray<int[]> newBroadcastAllowList;
                 synchronized (mPm.mLock) {
                     newBroadcastAllowList = mPm.mAppsFilter.getVisibilityAllowList(
-                            mPm.getPackageStateInternal(packageName, Process.SYSTEM_UID),
+                            mPm.snapshotComputer()
+                                    .getPackageStateInternal(packageName, Process.SYSTEM_UID),
                             updateUserIds, mPm.mSettings.getPackagesLocked());
                 }
                 mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
@@ -2807,11 +2813,12 @@
                 }
             } else if (!ArrayUtils.isEmpty(res.mLibraryConsumers)) { // if static shared lib
                 // No need to kill consumers if it's installation of new version static shared lib.
+                final Computer snapshot = mPm.snapshotComputer();
                 final boolean dontKillApp = !update && res.mPkg.getStaticSharedLibName() != null;
                 for (int i = 0; i < res.mLibraryConsumers.size(); i++) {
                     AndroidPackage pkg = res.mLibraryConsumers.get(i);
                     // send broadcast that all consumers of the static shared library have changed
-                    mPm.sendPackageChangedBroadcast(pkg.getPackageName(), dontKillApp,
+                    mPm.sendPackageChangedBroadcast(snapshot, pkg.getPackageName(), dontKillApp,
                             new ArrayList<>(Collections.singletonList(pkg.getPackageName())),
                             pkg.getUid(), null);
                 }
@@ -3055,7 +3062,7 @@
         final RemovePackageHelper removePackageHelper = new RemovePackageHelper(mPm);
         removePackageHelper.removePackageLI(stubPkg, true /*chatty*/);
         try {
-            return scanSystemPackageTracedLI(scanFile, parseFlags, scanFlags, 0, null);
+            return scanSystemPackageTracedLI(scanFile, parseFlags, scanFlags, null);
         } catch (PackageManagerException e) {
             Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.getPackageName(),
                     e);
@@ -3187,7 +3194,7 @@
                         | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
         @PackageManagerService.ScanFlags int scanFlags = mPm.getSystemPackageScanFlags(codePath);
         final AndroidPackage pkg = scanSystemPackageTracedLI(
-                        codePath, parseFlags, scanFlags, 0 /*currentTime*/, null);
+                codePath, parseFlags, scanFlags, null);
 
         PackageSetting pkgSetting = mPm.mSettings.getPackageLPr(pkg.getPackageName());
 
@@ -3361,7 +3368,7 @@
                 mRemovePackageHelper.removePackageLI(pkg, true);
                 try {
                     final File codePath = new File(pkg.getPath());
-                    scanSystemPackageTracedLI(codePath, 0, scanFlags, 0, null);
+                    scanSystemPackageTracedLI(codePath, 0, scanFlags, null);
                 } catch (PackageManagerException e) {
                     Slog.e(TAG, "Failed to parse updated, ex-system package: "
                             + e.getMessage());
@@ -3382,7 +3389,7 @@
 
     @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
     public void installPackagesFromDir(File scanDir, List<File> frameworkSplits, int parseFlags,
-            int scanFlags, long currentTime, PackageParser2 packageParser,
+            int scanFlags, PackageParser2 packageParser,
             ExecutorService executorService) {
         final File[] files = scanDir.listFiles();
         if (ArrayUtils.isEmpty(files)) {
@@ -3425,7 +3432,7 @@
                             parseResult.parsedPackage);
                 }
                 try {
-                    addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags, currentTime,
+                    addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
                             null);
                 } catch (PackageManagerException e) {
                     errorCode = e.error;
@@ -3488,7 +3495,7 @@
 
             try {
                 final AndroidPackage newPkg = scanSystemPackageTracedLI(
-                        scanFile, reparseFlags, rescanFlags, 0, null);
+                        scanFile, reparseFlags, rescanFlags, null);
                 // We rescanned a stub, add it to the list of stubbed system packages
                 if (newPkg.isStub()) {
                     stubSystemApps.add(packageName);
@@ -3502,14 +3509,14 @@
 
     /**
      *  Traces a package scan.
-     *  @see #scanSystemPackageLI(File, int, int, long, UserHandle)
+     *  @see #scanSystemPackageLI(File, int, int, UserHandle)
      */
     @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
     public AndroidPackage scanSystemPackageTracedLI(File scanFile, final int parseFlags,
-            int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
+            int scanFlags, UserHandle user) throws PackageManagerException {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]");
         try {
-            return scanSystemPackageLI(scanFile, parseFlags, scanFlags, currentTime, user);
+            return scanSystemPackageLI(scanFile, parseFlags, scanFlags, user);
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
@@ -3521,7 +3528,7 @@
      */
     @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
     private AndroidPackage scanSystemPackageLI(File scanFile, int parseFlags, int scanFlags,
-            long currentTime, UserHandle user) throws PackageManagerException {
+            UserHandle user) throws PackageManagerException {
         if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
 
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
@@ -3537,7 +3544,7 @@
             PackageManagerService.renameStaticSharedLibraryPackage(parsedPackage);
         }
 
-        return addForInitLI(parsedPackage, parseFlags, scanFlags, currentTime, user);
+        return addForInitLI(parsedPackage, parseFlags, scanFlags, user);
     }
 
     /**
@@ -3556,11 +3563,11 @@
     @GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
     private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
             @ParsingPackageUtils.ParseFlags int parseFlags,
-            @PackageManagerService.ScanFlags int scanFlags, long currentTime,
+            @PackageManagerService.ScanFlags int scanFlags,
             @Nullable UserHandle user) throws PackageManagerException {
 
         final Pair<ScanResult, Boolean> scanResultPair = scanSystemPackageLI(
-                parsedPackage, parseFlags, scanFlags, currentTime, user);
+                parsedPackage, parseFlags, scanFlags, user);
         final ScanResult scanResult = scanResultPair.first;
         boolean shouldHideSystemApp = scanResultPair.second;
         if (scanResult.mSuccess) {
@@ -3755,7 +3762,7 @@
 
     private Pair<ScanResult, Boolean> scanSystemPackageLI(ParsedPackage parsedPackage,
             @ParsingPackageUtils.ParseFlags int parseFlags,
-            @PackageManagerService.ScanFlags int scanFlags, long currentTime,
+            @PackageManagerService.ScanFlags int scanFlags,
             @Nullable UserHandle user) throws PackageManagerException {
         final boolean scanSystemPartition =
                 (parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0;
@@ -3943,7 +3950,7 @@
         }
 
         final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags,
-                scanFlags | SCAN_UPDATE_SIGNATURE, currentTime, user, null);
+                scanFlags | SCAN_UPDATE_SIGNATURE, 0 /* currentTime */, user, null);
         return new Pair<>(scanResult, shouldHideSystemApp);
     }
 
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 76b9830..fff6662 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -27,6 +27,7 @@
 import android.os.CreateAppDataResult;
 import android.os.IBinder;
 import android.os.IInstalld;
+import android.os.ReconcileSdkDataArgs;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.storage.CrateMetadata;
@@ -88,6 +89,14 @@
      */
     public static final int PROFILE_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES = 3;
 
+    /**
+     * The results of {@code getOdexVisibility}. See
+     * {@link #getOdexVisibility(String, String, String)} for details.
+     */
+    public static final int ODEX_NOT_FOUND = 0;
+    public static final int ODEX_IS_PUBLIC = 1;
+    public static final int ODEX_IS_PRIVATE = 2;
+
 
     public static final int FLAG_STORAGE_DE = IInstalld.FLAG_STORAGE_DE;
     public static final int FLAG_STORAGE_CE = IInstalld.FLAG_STORAGE_CE;
@@ -215,6 +224,21 @@
         return result;
     }
 
+    static ReconcileSdkDataArgs buildReconcileSdkDataArgs(String uuid, String packageName,
+            List<String> subDirNames, int userId, int appId,
+            String seInfo, int flags) {
+        final ReconcileSdkDataArgs args = new ReconcileSdkDataArgs();
+        args.uuid = uuid;
+        args.packageName = packageName;
+        args.subDirNames = subDirNames;
+        args.userId = userId;
+        args.appId = appId;
+        args.previousAppId = 0;
+        args.seInfo = seInfo;
+        args.flags = flags;
+        return args;
+    }
+
     public @NonNull CreateAppDataResult createAppData(@NonNull CreateAppDataArgs args)
             throws InstallerException {
         if (!checkBeforeRemote()) {
@@ -247,6 +271,29 @@
         }
     }
 
+    void reconcileSdkData(@NonNull ReconcileSdkDataArgs args)
+            throws InstallerException {
+        if (!checkBeforeRemote()) {
+            return;
+        }
+        try {
+            mInstalld.reconcileSdkData(args);
+        } catch (Exception e) {
+            throw InstallerException.from(e);
+        }
+    }
+
+    /**
+     * Sets in Installd that it is first boot after data wipe
+     */
+    public void setFirstBoot() throws InstallerException {
+        try {
+            mInstalld.setFirstBoot();
+        } catch (RemoteException e) {
+            throw InstallerException.from(e);
+        }
+    }
+
     /**
      * Class that collects multiple {@code installd} operations together in an
      * attempt to more efficiently execute them in bulk.
@@ -838,6 +885,15 @@
         }
     }
 
+    /**
+     * Prepares the app profile for the package at the given path:
+     * <ul>
+     *   <li>Creates the current profile for the given user ID, unless the user ID is
+     *     {@code UserHandle.USER_NULL}.</li>
+     *   <li>Merges the profile from the dex metadata file (if present) into the reference
+     *     profile.</li>
+     * </ul>
+     */
     public boolean prepareAppProfile(String pkg, @UserIdInt int userId, @AppIdInt int appId,
             String profileName, String codePath, String dexMetadataPath) throws InstallerException {
         if (!checkBeforeRemote()) return false;
@@ -988,6 +1044,33 @@
         }
     }
 
+    /**
+     * Returns the visibility of the optimized artifacts.
+     *
+     * @param packageName name of the package.
+     * @param apkPath path to the APK.
+     * @param instructionSet instruction set of the optimized artifacts.
+     * @param outputPath path to the directory that contains the optimized artifacts (i.e., the
+     *   directory that {@link #dexopt} outputs to).
+     *
+     * @return {@link #ODEX_NOT_FOUND} if the optimized artifacts are not found, or
+     *   {@link #ODEX_IS_PUBLIC} if the optimized artifacts are accessible by all apps, or
+     *   {@link #ODEX_IS_PRIVATE} if the optimized artifacts are only accessible by this app.
+     *
+     * @throws InstallerException if failed to get the visibility of the optimized artifacts.
+     */
+    public int getOdexVisibility(String packageName, String apkPath, String instructionSet,
+            String outputPath) throws InstallerException {
+        if (!checkBeforeRemote()) return -1;
+        BlockGuard.getVmPolicy().onPathAccess(apkPath);
+        BlockGuard.getVmPolicy().onPathAccess(outputPath);
+        try {
+            return mInstalld.getOdexVisibility(packageName, apkPath, instructionSet, outputPath);
+        } catch (Exception e) {
+            throw InstallerException.from(e);
+        }
+    }
+
     public static class InstallerException extends Exception {
         public InstallerException(String detailMessage) {
             super(detailMessage);
diff --git a/services/core/java/com/android/server/pm/IntentResolverInterceptor.java b/services/core/java/com/android/server/pm/IntentResolverInterceptor.java
index 0ee07b6..5597c9a 100644
--- a/services/core/java/com/android/server/pm/IntentResolverInterceptor.java
+++ b/services/core/java/com/android/server/pm/IntentResolverInterceptor.java
@@ -21,14 +21,11 @@
 import android.Manifest;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
-import android.app.ActivityTaskManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
-import android.os.RemoteException;
 import android.provider.DeviceConfig;
-import android.util.Slog;
 
 import com.android.internal.R;
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
@@ -39,10 +36,8 @@
 
 /**
  * Service to register an {@code ActivityInterceptorCallback} that modifies any {@code Intent}
- * that's being used to launch a user-space {@code ChooserActivity}, by adding
- * EXTRA_PERMISSION_TOKEN, a Binder representing a single-use-only permission to invoke the
- * #startActivityAsCaller() API (which normally isn't available in user-space); and setting the
- * destination component to the delegated component when appropriate.
+ * that's being used to launch a user-space {@code ChooserActivity} by setting the destination
+ * component to the delegated component when appropriate.
  */
 public final class IntentResolverInterceptor {
     private static final String TAG = "IntentResolverIntercept";
@@ -92,7 +87,6 @@
 
     private Intent modifyChooserIntent(Intent intent) {
         intent.setComponent(getUnbundledChooserComponentName());
-        addStartActivityPermissionTokenToIntent(intent, getUnbundledChooserComponentName());
         return intent;
     }
 
@@ -103,18 +97,6 @@
                 || targetComponent.equals(getUnbundledChooserComponentName());
     }
 
-    private static Intent addStartActivityPermissionTokenToIntent(
-            Intent intent, ComponentName grantee) {
-        try {
-            intent.putExtra(
-                    ActivityTaskManager.EXTRA_PERMISSION_TOKEN,
-                    ActivityTaskManager.getService().requestStartActivityPermissionToken(grantee));
-        } catch (RemoteException e) {
-            Slog.w(TAG, "Failed to add permission token to chooser intent");
-        }
-        return intent;
-    }
-
     private static ComponentName getSystemChooserComponentName() {
         return new ComponentName("android", "com.android.internal.app.ChooserActivity");
     }
diff --git a/services/core/java/com/android/server/pm/ModuleInfoProvider.java b/services/core/java/com/android/server/pm/ModuleInfoProvider.java
index 0ffc1ed..230f555 100644
--- a/services/core/java/com/android/server/pm/ModuleInfoProvider.java
+++ b/services/core/java/com/android/server/pm/ModuleInfoProvider.java
@@ -16,6 +16,7 @@
 
 package com.android.server.pm;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.content.pm.IPackageManager;
 import android.content.pm.ModuleInfo;
@@ -25,6 +26,7 @@
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -58,7 +60,7 @@
     private static final String MODULE_METADATA_KEY = "android.content.pm.MODULE_METADATA";
 
     private final Context mContext;
-    private final IPackageManager mPackageManager;
+    private IPackageManager mPackageManager;
     private final ApexManager mApexManager;
     private final Map<String, ModuleInfo> mModuleInfo;
 
@@ -66,9 +68,8 @@
     private volatile boolean mMetadataLoaded;
     private volatile String mPackageName;
 
-    ModuleInfoProvider(Context context, IPackageManager packageManager) {
+    ModuleInfoProvider(Context context) {
         mContext = context;
-        mPackageManager = packageManager;
         mApexManager = ApexManager.getInstance();
         mModuleInfo = new ArrayMap<>();
     }
@@ -77,12 +78,20 @@
     public ModuleInfoProvider(
             XmlResourceParser metadata, Resources resources, ApexManager apexManager) {
         mContext = null;
-        mPackageManager = null;
         mApexManager = apexManager;
         mModuleInfo = new ArrayMap<>();
         loadModuleMetadata(metadata, resources);
     }
 
+    @NonNull
+    private IPackageManager getPackageManager() {
+        if (mPackageManager == null) {
+            mPackageManager = IPackageManager.Stub.asInterface(
+                    ServiceManager.getService("package"));
+        }
+        return mPackageManager;
+    }
+
     /** Called by the {@code PackageManager} when it has completed its boot sequence */
     public void systemReady() {
         mPackageName = mContext.getResources().getString(
@@ -95,7 +104,7 @@
         final Resources packageResources;
         final PackageInfo pi;
         try {
-            pi = mPackageManager.getPackageInfo(mPackageName,
+            pi =  getPackageManager().getPackageInfo(mPackageName,
                 PackageManager.GET_META_DATA, UserHandle.USER_SYSTEM);
 
             Context packageContext = mContext.createPackageContext(mPackageName, 0);
@@ -183,7 +192,7 @@
 
         List<PackageInfo> allPackages;
         try {
-            allPackages = mPackageManager.getInstalledPackages(
+            allPackages =  getPackageManager().getInstalledPackages(
                     flags | PackageManager.MATCH_APEX, UserHandle.getCallingUserId()).getList();
         } catch (RemoteException e) {
             Slog.w(TAG, "Unable to retrieve all package names", e);
diff --git a/services/core/java/com/android/server/pm/MovePackageHelper.java b/services/core/java/com/android/server/pm/MovePackageHelper.java
index 5fc90b1..c5ca06c 100644
--- a/services/core/java/com/android/server/pm/MovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/MovePackageHelper.java
@@ -57,6 +57,8 @@
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.PackageStateUtils;
 
 import java.io.File;
 import java.util.Objects;
@@ -77,81 +79,74 @@
         final StorageManager storage = mPm.mInjector.getSystemService(StorageManager.class);
         final PackageManager pm = mPm.mContext.getPackageManager();
 
-        final String currentVolumeUuid;
-        final File codeFile;
-        final InstallSource installSource;
-        final String packageAbiOverride;
-        final int appId;
-        final String seinfo;
-        final String label;
-        final int targetSdkVersion;
-        final PackageFreezer freezer;
-        final int[] installedUserIds;
-        final boolean isCurrentLocationExternal;
+        Computer snapshot = mPm.snapshotComputer();
+        final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
+        if (packageState == null
+                || packageState.getPkg() == null
+                || snapshot.shouldFilterApplication(packageState, callingUid, user.getIdentifier())) {
+            throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package");
+        }
+        final AndroidPackage pkg = packageState.getPkg();
+        if (pkg.isSystem()) {
+            throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE,
+                    "Cannot move system application");
+        }
+
+        final boolean isInternalStorage = VolumeInfo.ID_PRIVATE_INTERNAL.equals(volumeUuid);
+        final boolean allow3rdPartyOnInternal = mPm.mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_allow3rdPartyAppOnInternal);
+        if (isInternalStorage && !allow3rdPartyOnInternal) {
+            throw new PackageManagerException(MOVE_FAILED_3RD_PARTY_NOT_ALLOWED_ON_INTERNAL,
+                    "3rd party apps are not allowed on internal storage");
+        }
+
+
+        final String currentVolumeUuid = packageState.getVolumeUuid();
+
+        final File probe = new File(pkg.getPath());
+        final File probeOat = new File(probe, "oat");
+        if (!probe.isDirectory() || !probeOat.isDirectory()) {
+            throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
+                    "Move only supported for modern cluster style installs");
+        }
+
+        if (Objects.equals(currentVolumeUuid, volumeUuid)) {
+            throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
+                    "Package already moved to " + volumeUuid);
+        }
+        if (!pkg.isExternalStorage()
+                && mPm.isPackageDeviceAdminOnAnyUser(snapshot, packageName)) {
+            throw new PackageManagerException(MOVE_FAILED_DEVICE_ADMIN,
+                    "Device admin cannot be moved");
+        }
+
+        if (snapshot.getFrozenPackages().containsKey(packageName)) {
+            throw new PackageManagerException(MOVE_FAILED_OPERATION_PENDING,
+                    "Failed to move already frozen package");
+        }
+
+        final boolean isCurrentLocationExternal = pkg.isExternalStorage();
+        final File codeFile = new File(pkg.getPath());
+        final InstallSource installSource = packageState.getInstallSource();
+        final String packageAbiOverride = packageState.getCpuAbiOverride();
+        final int appId = UserHandle.getAppId(pkg.getUid());
+        final String seinfo = AndroidPackageUtils.getSeInfo(pkg, packageState);
+        final String label = String.valueOf(pm.getApplicationLabel(
+                AndroidPackageUtils.generateAppInfoWithoutState(pkg)));
+        final int targetSdkVersion = pkg.getTargetSdkVersion();
+        final int[] installedUserIds = PackageStateUtils.queryInstalledUsers(packageState,
+                mPm.mUserManager.getUserIds(), true);
         final String fromCodePath;
+        if (codeFile.getParentFile().getName().startsWith(
+                PackageManagerService.RANDOM_DIR_PREFIX)) {
+            fromCodePath = codeFile.getParentFile().getAbsolutePath();
+        } else {
+            fromCodePath = codeFile.getAbsolutePath();
+        }
 
-        // reader
+        final PackageFreezer freezer;
         synchronized (mPm.mLock) {
-            final AndroidPackage pkg = mPm.mPackages.get(packageName);
-            final PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
-            if (pkg == null
-                    || ps == null
-                    || mPm.shouldFilterApplication(ps, callingUid, user.getIdentifier())) {
-                throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package");
-            }
-            if (pkg.isSystem()) {
-                throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE,
-                        "Cannot move system application");
-            }
-
-            final boolean isInternalStorage = VolumeInfo.ID_PRIVATE_INTERNAL.equals(volumeUuid);
-            final boolean allow3rdPartyOnInternal = mPm.mContext.getResources().getBoolean(
-                    com.android.internal.R.bool.config_allow3rdPartyAppOnInternal);
-            if (isInternalStorage && !allow3rdPartyOnInternal) {
-                throw new PackageManagerException(MOVE_FAILED_3RD_PARTY_NOT_ALLOWED_ON_INTERNAL,
-                        "3rd party apps are not allowed on internal storage");
-            }
-
-            currentVolumeUuid = ps.getVolumeUuid();
-
-            final File probe = new File(pkg.getPath());
-            final File probeOat = new File(probe, "oat");
-            if (!probe.isDirectory() || !probeOat.isDirectory()) {
-                throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
-                        "Move only supported for modern cluster style installs");
-            }
-
-            if (Objects.equals(currentVolumeUuid, volumeUuid)) {
-                throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
-                        "Package already moved to " + volumeUuid);
-            }
-            if (!pkg.isExternalStorage() && mPm.isPackageDeviceAdminOnAnyUser(packageName)) {
-                throw new PackageManagerException(MOVE_FAILED_DEVICE_ADMIN,
-                        "Device admin cannot be moved");
-            }
-
-            if (mPm.mFrozenPackages.containsKey(packageName)) {
-                throw new PackageManagerException(MOVE_FAILED_OPERATION_PENDING,
-                        "Failed to move already frozen package");
-            }
-
-            isCurrentLocationExternal = pkg.isExternalStorage();
-            codeFile = new File(pkg.getPath());
-            installSource = ps.getInstallSource();
-            packageAbiOverride = ps.getCpuAbiOverride();
-            appId = UserHandle.getAppId(pkg.getUid());
-            seinfo = AndroidPackageUtils.getSeInfo(pkg, ps);
-            label = String.valueOf(pm.getApplicationLabel(
-                    AndroidPackageUtils.generateAppInfoWithoutState(pkg)));
-            targetSdkVersion = pkg.getTargetSdkVersion();
             freezer = mPm.freezePackage(packageName, "movePackageInternal");
-            installedUserIds = ps.queryInstalledUsers(mPm.mUserManager.getUserIds(), true);
-            if (codeFile.getParentFile().getName().startsWith(
-                    PackageManagerService.RANDOM_DIR_PREFIX)) {
-                fromCodePath = codeFile.getParentFile().getAbsolutePath();
-            } else {
-                fromCodePath = codeFile.getAbsolutePath();
-            }
         }
 
         final Bundle extras = new Bundle();
diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS
index c219f80..8534fab 100644
--- a/services/core/java/com/android/server/pm/OWNERS
+++ b/services/core/java/com/android/server/pm/OWNERS
@@ -15,7 +15,9 @@
 per-file AbstractStatsBase.java = file:dex/OWNERS
 per-file BackgroundDexOptService.java = file:dex/OWNERS
 per-file CompilerStats.java = file:dex/OWNERS
+per-file DexOptHelper.java = file:dex/OWNERS
 per-file DynamicCodeLoggingService.java = file:dex/OWNERS
+per-file Installer.java = file:dex/OWNERS
 per-file InstructionSets.java = file:dex/OWNERS
 per-file OtaDexoptService.java = file:dex/OWNERS
 per-file OtaDexoptShellCommand.java = file:dex/OWNERS
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index bd00914..cc4a760 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -131,8 +131,9 @@
         Predicate<PackageStateInternal> isPlatformPackage = pkgSetting ->
                 PLATFORM_PACKAGE_NAME.equals(pkgSetting.getPkg().getPackageName());
         // Important: the packages we need to run with ab-ota compiler-reason.
+        final Computer snapshot = mPackageManagerService.snapshotComputer();
         final Collection<? extends PackageStateInternal> allPackageStates =
-                mPackageManagerService.getPackageStates().values();
+                snapshot.getPackageStates().values();
         important = DexOptHelper.getPackagesForDexopt(allPackageStates,mPackageManagerService,
                 DEBUG_DEXOPT);
         // Remove Platform Package from A/B OTA b/160735835.
@@ -165,7 +166,7 @@
             Log.i(TAG, "Low on space, deleting oat files in an attempt to free up space: "
                     + DexOptHelper.packagesToString(others));
             for (PackageStateInternal pkg : others) {
-                mPackageManagerService.deleteOatArtifactsOfPackage(pkg.getPackageName());
+                mPackageManagerService.deleteOatArtifactsOfPackage(snapshot, pkg.getPackageName());
             }
         }
         long spaceAvailableNow = getAvailableSpace();
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 69d4987..27c6d9b 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -319,28 +319,42 @@
 
             String profileName = ArtManager.getProfileName(
                     i == 0 ? null : pkg.getSplitNames()[i - 1]);
+            final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary()
+                    || packageUseInfo.isUsedByOtherApps(path);
+            String compilerFilter = getRealCompilerFilter(pkg, options.getCompilerFilter());
+            // If the app is used by other apps, we must not use the existing profile because it
+            // may contain user data, unless the profile is newly created on install.
+            final boolean resetProfile = isProfileGuidedCompilerFilter(compilerFilter)
+                    && isUsedByOtherApps
+                    && options.getCompilationReason() != PackageManagerService.REASON_INSTALL;
 
             String dexMetadataPath = null;
-            if (options.isDexoptInstallWithDexMetadata()) {
+            if (options.isDexoptInstallWithDexMetadata() || resetProfile) {
                 File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(new File(path));
                 dexMetadataPath = dexMetadataFile == null
                         ? null : dexMetadataFile.getAbsolutePath();
             }
 
-            final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary()
-                    || packageUseInfo.isUsedByOtherApps(path);
-            final String compilerFilter = getRealCompilerFilter(pkg,
-                options.getCompilerFilter(), isUsedByOtherApps);
             // If we don't have to check for profiles updates assume
             // PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA which will be a no-op with respect to
             // profiles.
-            final int profileAnalysisResult = options.isCheckForProfileUpdates()
-                    ? analyseProfiles(pkg, sharedGid, profileName, compilerFilter)
-                    : PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA;
+            int profileAnalysisResult = PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA;
+            if (resetProfile) {
+                if (!resetProfile(pkg, profileName, path, dexMetadataPath)) {
+                    // Fall back to use the shared filter.
+                    compilerFilter =
+                            PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
+                                    PackageManagerService.REASON_SHARED);
+                }
+            } else if (options.isCheckForProfileUpdates()) {
+                profileAnalysisResult =
+                        analyseProfiles(pkg, sharedGid, profileName, compilerFilter);
+            }
 
             // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct
             // flags.
-            final int dexoptFlags = getDexFlags(pkg, pkgSetting, compilerFilter, options);
+            final int dexoptFlags = getDexFlags(pkg, pkgSetting, compilerFilter, resetProfile,
+                    options);
 
             for (String dexCodeIsa : dexCodeInstructionSets) {
                 int newResult = dexOptPath(pkg, pkgSetting, path, dexCodeIsa, compilerFilter,
@@ -391,6 +405,30 @@
     }
 
     /**
+     * Resets the profiles of the dex file at {@code path} belonging to the package {@code pkg} to
+     * the initial state as if the package is newly installed. Returns true on success, or false
+     * otherwise.
+     */
+    @GuardedBy("mInstallLock")
+    private boolean resetProfile(AndroidPackage pkg, String profileName, String path,
+            @Nullable String dexMetadataPath) {
+        if (dexMetadataPath != null) {
+            try {
+                mInstaller.clearAppProfiles(pkg.getPackageName(), profileName);
+                final int appId = UserHandle.getAppId(pkg.getUid());
+                mInstaller.prepareAppProfile(pkg.getPackageName(), UserHandle.USER_NULL,
+                        appId, profileName, path, dexMetadataPath);
+                return true;
+            } catch (InstallerException e) {
+                Slog.w(TAG, "Failed to reset profile", e);
+                return false;
+            }
+        } else {
+            return false;
+        }
+    }
+
+    /**
      * Performs dexopt on the {@code path} belonging to the package {@code pkg}.
      *
      * @return
@@ -405,15 +443,15 @@
             String classLoaderContext, int dexoptFlags, int uid,
             CompilerStats.PackageStats packageStats, boolean downgrade, String profileName,
             String dexMetadataPath, int compilationReason) {
-        int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, classLoaderContext,
-                profileAnalysisResult, downgrade);
+        String oatDir = getPackageOatDirIfSupported(pkg,
+                pkgSetting.getTransientState().isUpdatedSystemApp());
+
+        int dexoptNeeded = getDexoptNeeded(pkg.getPackageName(), path, isa, compilerFilter,
+                classLoaderContext, profileAnalysisResult, downgrade, dexoptFlags, oatDir);
         if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) {
             return DEX_OPT_SKIPPED;
         }
 
-        String oatDir = getPackageOatDirIfSupported(pkg,
-                pkgSetting.getTransientState().isUpdatedSystemApp());
-
         Log.i(TAG, "Running dexopt (dexoptNeeded=" + dexoptNeeded + ") on: " + path
                 + " pkg=" + pkg.getPackageName() + " isa=" + isa
                 + " dexoptFlags=" + printDexoptFlags(dexoptFlags)
@@ -456,6 +494,7 @@
     /**
      * Perform dexopt (if needed) on a system server code path).
      */
+    @GuardedBy("mInstallLock")
     @DexOptResult
     public int dexoptSystemServerPath(
             String dexPath, PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options) {
@@ -466,12 +505,15 @@
         int result = DEX_OPT_SKIPPED;
         for (String isa : dexUseInfo.getLoaderIsas()) {
             int dexoptNeeded = getDexoptNeeded(
+                    PackageManagerService.PLATFORM_PACKAGE_NAME,
                     dexPath,
                     isa,
                     options.getCompilerFilter(),
                     dexUseInfo.getClassLoaderContext(),
                     PROFILE_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES,
-                    /* downgrade= */ false);
+                    /* downgrade= */ false,
+                    dexoptFlags,
+                    /* oatDir= */ null);
 
             if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) {
                 continue;
@@ -714,7 +756,7 @@
     }
 
     /**
-     * Returns the compiler filter that should be used to optimize the package code.
+     * Returns the compiler filter that should be used to optimize the secondary dex.
      * The target filter will be updated if the package code is used by other apps
      * or if it has the safe mode flag set.
      */
@@ -754,12 +796,12 @@
     }
 
     /**
-     * Returns the compiler filter that should be used to optimize the package code.
-     * The target filter will be updated if the package code is used by other apps
-     * or if it has the safe mode flag set.
+     * Returns the compiler filter that should be used to optimize the primary dex.
+     * The target filter will be updated if the package has the safe mode flag set. Note that this
+     * method does NOT take other app use into account. The caller should be responsible for
+     * handling the case where the package code is used by other apps.
      */
-    private String getRealCompilerFilter(AndroidPackage pkg, String targetCompilerFilter,
-            boolean isUsedByOtherApps) {
+    private String getRealCompilerFilter(AndroidPackage pkg, String targetCompilerFilter) {
         // When an app or priv app is configured to run out of box, only verify it.
         if (pkg.isUseEmbeddedDex()
                 || (pkg.isPrivileged()
@@ -783,12 +825,6 @@
             return getSafeModeCompilerFilter(targetCompilerFilter);
         }
 
-        if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps) {
-            // If the dex files is used by other apps, apply the shared filter.
-            return PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
-                    PackageManagerService.REASON_SHARED);
-        }
-
         return targetCompilerFilter;
     }
 
@@ -799,14 +835,16 @@
     private int getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options) {
         return getDexFlags((info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0,
                 info.getHiddenApiEnforcementPolicy(), info.splitDependencies,
-                info.requestsIsolatedSplitLoading(), compilerFilter, options);
+                info.requestsIsolatedSplitLoading(), compilerFilter, false /* resetProfile */,
+                options);
     }
+
     private int getDexFlags(AndroidPackage pkg, @NonNull PackageStateInternal pkgSetting,
-            String compilerFilter, DexoptOptions options) {
+            String compilerFilter, boolean resetProfile, DexoptOptions options) {
         return getDexFlags(pkg.isDebuggable(),
                 AndroidPackageUtils.getHiddenApiEnforcementPolicy(pkg, pkgSetting),
                 pkg.getSplitDependencies(), pkg.isIsolatedSplitLoading(), compilerFilter,
-                options);
+                resetProfile, options);
     }
 
     /**
@@ -815,13 +853,15 @@
      */
     private int getDexFlags(boolean debuggable, int hiddenApiEnforcementPolicy,
             SparseArray<int[]> splitDependencies, boolean requestsIsolatedSplitLoading,
-            String compilerFilter, DexoptOptions options) {
+            String compilerFilter, boolean resetProfile, DexoptOptions options) {
         // Profile guide compiled oat files should not be public unles they are based
         // on profiles from dex metadata archives.
         // The flag isDexoptInstallWithDexMetadata applies only on installs when we know that
         // the user does not have an existing profile.
+        // The flag resetProfile applies only when the existing profile is already reset.
         boolean isProfileGuidedFilter = isProfileGuidedCompilerFilter(compilerFilter);
-        boolean isPublic = !isProfileGuidedFilter || options.isDexoptInstallWithDexMetadata();
+        boolean isPublic = !isProfileGuidedFilter || options.isDexoptInstallWithDexMetadata()
+                || resetProfile;
         int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
         // Some apps are executed with restrictions on hidden API usage. If this app is one
         // of them, pass a flag to dexopt to enable the same restrictions during compilation.
@@ -866,8 +906,19 @@
      * Assesses if there's a need to perform dexopt on {@code path} for the given
      * configuration (isa, compiler filter, profile).
      */
-    private int getDexoptNeeded(String path, String isa, String compilerFilter,
-            String classLoaderContext, int profileAnalysisResult, boolean downgrade) {
+    @GuardedBy("mInstallLock")
+    private int getDexoptNeeded(String packageName, String path, String isa, String compilerFilter,
+            String classLoaderContext, int profileAnalysisResult, boolean downgrade,
+            int dexoptFlags, String oatDir) {
+        final boolean shouldBePublic = (dexoptFlags & DEXOPT_PUBLIC) != 0;
+        // If the artifacts should be public while the current artifacts are not, we should
+        // re-compile anyway.
+        if (shouldBePublic && isOdexPrivate(packageName, path, isa, oatDir)) {
+            // Ensure compilation by pretending a compiler filter change on the apk/odex location
+            // (the reason for the '-'. A positive value means the 'oat' location).
+            return adjustDexoptNeeded(-DexFile.DEX2OAT_FOR_FILTER);
+        }
+
         int dexoptNeeded;
         try {
             // A profile guided optimizations with an empty profile is essentially 'verify' and
@@ -901,6 +952,18 @@
         return compilerFilter.endsWith("-profile");
     }
 
+    /** Returns true if the current artifacts of the app are private to the app itself. */
+    @GuardedBy("mInstallLock")
+    private boolean isOdexPrivate(String packageName, String path, String isa, String oatDir) {
+        try {
+            return mInstaller.getOdexVisibility(packageName, path, isa, oatDir)
+                    == Installer.ODEX_IS_PRIVATE;
+        } catch (Exception e) {
+            Slog.w(TAG, "Failed to get odex visibility for " + path, e);
+            return false;
+        }
+    }
+
     /**
      * Checks if there is an update on the profile information of the {@code pkg}.
      * If the compiler filter is not profile guided the method returns a safe default:
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 6613f01..002d500 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -597,8 +597,8 @@
             String installerAttributionTag, int userId)
             throws IOException {
         final int callingUid = Binder.getCallingUid();
-        mPm.enforceCrossUserPermission(
-                callingUid, userId, true, true, "createSession");
+        final Computer snapshot = mPm.snapshotComputer();
+        snapshot.enforceCrossUserPermission(callingUid, userId, true, true, "createSession");
 
         if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
             throw new SecurityException("User restriction prevents installing");
@@ -640,7 +640,8 @@
                 && params.installerPackageName.length() < SessionParams.MAX_PACKAGE_NAME_LENGTH)
                 ? params.installerPackageName : installerPackageName;
 
-        if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
+        if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)
+                || PackageInstallerSession.isSystemDataLoaderInstallation(params)) {
             params.installFlags |= PackageManager.INSTALL_FROM_ADB;
             // adb installs can override the installingPackageName, but not the
             // initiatingPackageName
@@ -663,11 +664,10 @@
             params.installFlags &= ~PackageManager.INSTALL_ALL_USERS;
             params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
             if ((params.installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0
-                    && !mPm.isCallerVerifier(callingUid)) {
+                    && !mPm.isCallerVerifier(snapshot, callingUid)) {
                 params.installFlags &= ~PackageManager.INSTALL_VIRTUAL_PRELOAD;
             }
-            if (mContext.checkCallingOrSelfPermission(
-                    Manifest.permission.INSTALL_TEST_ONLY_PACKAGE)
+            if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_TEST_ONLY_PACKAGE)
                     != PackageManager.PERMISSION_GRANTED) {
                 params.installFlags &= ~PackageManager.INSTALL_ALLOW_TEST;
             }
@@ -676,7 +676,7 @@
         String originatingPackageName = null;
         if (params.originatingUid != SessionParams.UID_UNKNOWN
                 && params.originatingUid != callingUid) {
-            String[] packages = mPm.mIPackageManager.getPackagesForUid(params.originatingUid);
+            String[] packages = snapshot.getPackagesForUid(params.originatingUid);
             if (packages != null && packages.length > 0) {
                 // Choose an arbitrary representative package in the case of a shared UID.
                 originatingPackageName = packages[0];
@@ -727,7 +727,7 @@
 
         if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0
                 && !isCalledBySystemOrShell(callingUid)
-                && (mPm.mIPackageManager.getFlagsForUid(callingUid) & ApplicationInfo.FLAG_SYSTEM)
+                && (snapshot.getFlagsForUid(callingUid) & ApplicationInfo.FLAG_SYSTEM)
                 == 0) {
             throw new SecurityException(
                     "Only system apps could use the PackageManager.INSTALL_INSTANT_APP flag.");
@@ -1038,11 +1038,12 @@
         return "smdl" + sessionId + ".tmp";
     }
 
-    private boolean shouldFilterSession(int uid, SessionInfo info) {
+    private boolean shouldFilterSession(@NonNull Computer snapshot, int uid, SessionInfo info) {
         if (info == null) {
             return false;
         }
-        return uid != info.getInstallerUid() && !mPm.canQueryPackage(uid, info.getAppPackageName());
+        return uid != info.getInstallerUid()
+                && !snapshot.canQueryPackage(uid, info.getAppPackageName());
     }
 
     @Override
@@ -1055,7 +1056,7 @@
                     ? session.generateInfoForCaller(true /* includeIcon */, callingUid)
                     : null;
         }
-        return shouldFilterSession(callingUid, result) ? null : result;
+        return shouldFilterSession(mPm.snapshotComputer(), callingUid, result) ? null : result;
     }
 
     @Override
@@ -1070,15 +1071,16 @@
                 }
             }
         }
-        result.removeIf(info -> shouldFilterSession(callingUid, info));
+        final Computer snapshot = mPm.snapshotComputer();
+        result.removeIf(info -> shouldFilterSession(snapshot, callingUid, info));
         return new ParceledListSlice<>(result);
     }
 
     @Override
     public ParceledListSlice<SessionInfo> getAllSessions(int userId) {
         final int callingUid = Binder.getCallingUid();
-        mPm.enforceCrossUserPermission(
-                callingUid, userId, true, false, "getAllSessions");
+        final Computer snapshot = mPm.snapshotComputer();
+        snapshot.enforceCrossUserPermission(callingUid, userId, true, false, "getAllSessions");
 
         final List<SessionInfo> result = new ArrayList<>();
         synchronized (mSessions) {
@@ -1090,15 +1092,16 @@
                 }
             }
         }
-        result.removeIf(info -> shouldFilterSession(callingUid, info));
+        result.removeIf(info -> shouldFilterSession(snapshot, callingUid, info));
         return new ParceledListSlice<>(result);
     }
 
     @Override
     public ParceledListSlice<SessionInfo> getMySessions(String installerPackageName, int userId) {
-        mPm.enforceCrossUserPermission(
-                Binder.getCallingUid(), userId, true, false, "getMySessions");
-        mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName);
+        final Computer snapshot = mPm.snapshotComputer();
+        final int callingUid = Binder.getCallingUid();
+        snapshot.enforceCrossUserPermission(callingUid, userId, true, false, "getMySessions");
+        mAppOps.checkPackage(callingUid, installerPackageName);
 
         final List<SessionInfo> result = new ArrayList<>();
         synchronized (mSessions) {
@@ -1120,8 +1123,9 @@
     @Override
     public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags,
                 IntentSender statusReceiver, int userId) {
+        final Computer snapshot = mPm.snapshotComputer();
         final int callingUid = Binder.getCallingUid();
-        mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
+        snapshot.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
         if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
             mAppOps.checkPackage(callingUid, callerPackageName);
         }
@@ -1154,8 +1158,7 @@
                     .setAdmin(callerPackageName)
                     .write();
         } else {
-            ApplicationInfo appInfo = mPm.mIPackageManager
-                    .getApplicationInfo(callerPackageName, 0, userId);
+            ApplicationInfo appInfo = snapshot.getApplicationInfo(callerPackageName, 0, userId);
             if (appInfo.targetSdkVersion >= Build.VERSION_CODES.P) {
                 mContext.enforceCallingOrSelfPermission(Manifest.permission.REQUEST_DELETE_PACKAGES,
                         null);
@@ -1174,7 +1177,8 @@
             String callerPackageName, IntentSender statusReceiver, int userId) {
         final int callingUid = Binder.getCallingUid();
         mContext.enforceCallingOrSelfPermission(Manifest.permission.DELETE_PACKAGES, null);
-        mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
+        final Computer snapshot = mPm.snapshotComputer();
+        snapshot.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
         if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
             mAppOps.checkPackage(callingUid, callerPackageName);
         }
@@ -1206,8 +1210,9 @@
 
     @Override
     public void registerCallback(IPackageInstallerCallback callback, int userId) {
-        mPm.enforceCrossUserPermission(
-                Binder.getCallingUid(), userId, true, false, "registerCallback");
+        final Computer snapshot = mPm.snapshotComputer();
+        snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+                "registerCallback");
         registerCallback(callback, eventUserId -> userId == eventUserId);
     }
 
@@ -1295,13 +1300,13 @@
         }
     }
 
-    private boolean shouldFilterSession(int uid, int sessionId) {
+    private boolean shouldFilterSession(@NonNull Computer snapshot, int uid, int sessionId) {
         final PackageInstallerSession session = getSession(sessionId);
         if (session == null) {
             return false;
         }
         return uid != session.getInstallerUid()
-                && !mPm.canQueryPackage(uid, session.getPackageName());
+                && !snapshot.canQueryPackage(uid, session.getPackageName());
     }
 
     static class PackageDeleteObserverAdapter extends PackageDeleteObserver {
@@ -1327,7 +1332,7 @@
 
         private String getDeviceOwnerDeletedPackageMsg() {
             DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
-            return dpm.getString(PACKAGE_DELETED_BY_DO,
+            return dpm.getResources().getString(PACKAGE_DELETED_BY_DO,
                     () -> mContext.getString(R.string.package_updated_device_owner));
         }
 
@@ -1454,11 +1459,12 @@
             final int sessionId = msg.arg1;
             final int userId = msg.arg2;
             final int n = mCallbacks.beginBroadcast();
+            final Computer snapshot = mPm.snapshotComputer();
             for (int i = 0; i < n; i++) {
                 final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i);
                 final BroadcastCookie cookie = (BroadcastCookie) mCallbacks.getBroadcastCookie(i);
                 if (cookie.userCheck.test(userId)
-                        && !shouldFilterSession(cookie.callingUid, sessionId)) {
+                        && !shouldFilterSession(snapshot, cookie.callingUid, sessionId)) {
                     try {
                         invokeCallback(callback, msg);
                     } catch (RemoteException ignored) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 35a7eaf..1efaa73 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -126,6 +126,7 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.EventLog;
 import android.util.ExceptionUtils;
 import android.util.IntArray;
 import android.util.MathUtils;
@@ -271,7 +272,7 @@
 
     /**
      * The default value of {@link #mValidatedTargetSdk} is {@link Integer#MAX_VALUE}. If {@link
-     * #mValidatedTargetSdk} is compared with {@link Build.VERSION_CODES#Q} before getting the
+     * #mValidatedTargetSdk} is compared with {@link Build.VERSION_CODES#R} before getting the
      * target sdk version from a validated apk in {@link #validateApkInstallLocked()}, the compared
      * result will not trigger any user action in
      * {@link #checkUserActionRequirement(PackageInstallerSession)}.
@@ -703,6 +704,18 @@
         }
     };
 
+    static boolean isDataLoaderInstallation(SessionParams params) {
+        return params.dataLoaderParams != null;
+    }
+
+    static boolean isSystemDataLoaderInstallation(SessionParams params) {
+        if (!isDataLoaderInstallation(params)) {
+            return false;
+        }
+        return SYSTEM_DATA_LOADER_PACKAGE.equals(
+                params.dataLoaderParams.getComponentName().getPackageName());
+    }
+
     private final Handler.Callback mHandlerCallback = new Handler.Callback() {
         @Override
         public boolean handleMessage(Message msg) {
@@ -742,7 +755,7 @@
     };
 
     private boolean isDataLoaderInstallation() {
-        return params.dataLoaderParams != null;
+        return isDataLoaderInstallation(this.params);
     }
 
     private boolean isStreamingInstallation() {
@@ -754,11 +767,7 @@
     }
 
     private boolean isSystemDataLoaderInstallation() {
-        if (!isDataLoaderInstallation()) {
-            return false;
-        }
-        return SYSTEM_DATA_LOADER_PACKAGE.equals(
-                this.params.dataLoaderParams.getComponentName().getPackageName());
+        return isSystemDataLoaderInstallation(this.params);
     }
 
     /**
@@ -859,7 +868,8 @@
             return USER_ACTION_NOT_NEEDED;
         }
 
-        if (mPm.isInstallDisabledForPackage(getInstallerPackageName(), mInstallerUid, userId)) {
+        if (snapshot.isInstallDisabledForPackage(getInstallerPackageName(), mInstallerUid,
+                userId)) {
             // show the installer to account for device poslicy or unknown sources use cases
             return USER_ACTION_REQUIRED;
         }
@@ -1256,13 +1266,21 @@
             return;
         }
 
-        final String initiatingPackageName = getInstallSource().initiatingPackageName;
+        final String installerPackageName;
+        if (!TextUtils.isEmpty(getInstallSource().initiatingPackageName)) {
+            installerPackageName = getInstallSource().initiatingPackageName;
+        } else {
+            installerPackageName = getInstallSource().installerPackageName;
+        }
+        if (TextUtils.isEmpty(installerPackageName)) {
+            throw new IllegalStateException("Installer package is empty.");
+        }
 
         final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
-        appOps.checkPackage(Binder.getCallingUid(), initiatingPackageName);
+        appOps.checkPackage(Binder.getCallingUid(), installerPackageName);
 
         final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
-        final AndroidPackage callingInstaller = pmi.getPackage(initiatingPackageName);
+        final AndroidPackage callingInstaller = pmi.getPackage(installerPackageName);
         if (callingInstaller == null) {
             throw new IllegalStateException("Can't obtain calling installer's package.");
         }
@@ -2065,7 +2083,7 @@
             }
 
             if (validatedTargetSdk != INVALID_TARGET_SDK_VERSION
-                    && validatedTargetSdk < Build.VERSION_CODES.Q) {
+                    && validatedTargetSdk < Build.VERSION_CODES.R) {
                 session.sendPendingUserActionIntent(target);
                 return true;
             }
@@ -2861,7 +2879,9 @@
                 inheritFileLocked(mResolvedBaseFile);
                 // Collect the requiredSplitTypes from base
                 CollectionUtils.addAll(requiredSplitTypes, existing.getBaseRequiredSplitTypes());
-            } else {
+            } else if ((params.installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
+                EventLog.writeEvent(0x534e4554, "219044664");
+
                 // Installing base.apk. Make sure the app is restarted.
                 params.setDontKillApp(false);
             }
@@ -3752,7 +3772,8 @@
         };
 
         if (!manualStartAndDestroy) {
-            final PerUidReadTimeouts[] perUidReadTimeouts = mPm.getPerUidReadTimeouts();
+            final PerUidReadTimeouts[] perUidReadTimeouts =
+                    mPm.getPerUidReadTimeouts(mPm.snapshotComputer());
 
             final StorageHealthCheckParams healthCheckParams = new StorageHealthCheckParams();
             healthCheckParams.blockedTimeoutMs = INCREMENTAL_STORAGE_BLOCKED_TIMEOUT_MS;
@@ -4283,9 +4304,9 @@
     private static String getDeviceOwnerInstalledPackageMsg(Context context, boolean update) {
         DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
         return update
-                ? dpm.getString(PACKAGE_UPDATED_BY_DO,
+                ? dpm.getResources().getString(PACKAGE_UPDATED_BY_DO,
                     () -> context.getString(R.string.package_updated_device_owner))
-                : dpm.getString(PACKAGE_INSTALLED_BY_DO,
+                : dpm.getResources().getString(PACKAGE_INSTALLED_BY_DO,
                     () -> context.getString(R.string.package_installed_device_owner));
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
new file mode 100644
index 0000000..2b73375
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
@@ -0,0 +1,751 @@
+/*
+ * 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.server.pm;
+
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+import static android.content.pm.PackageManager.RESTRICTION_NONE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.AuxiliaryResolveInfo;
+import android.content.pm.Checksum;
+import android.content.pm.IOnChecksumsReadyListener;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.ProcessInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.SuspendDialogInfo;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Process;
+import android.os.storage.StorageManager;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.SparseArray;
+
+import com.android.server.pm.dex.DexManager;
+import com.android.server.pm.dex.DynamicCodeLogger;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.AndroidPackageApi;
+import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.PackageStateUtils;
+import com.android.server.pm.pkg.SharedUserApi;
+import com.android.server.pm.pkg.component.ParsedMainComponent;
+import com.android.server.pm.pkg.mutate.PackageStateMutator;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * Internal manager variant of {@link IPackageManagerBase}. See that class for info.
+ * {@link PackageManagerInternal} should eventually passing in a snapshot instance, deprecating
+ * this class, but that requires much larger refactor.
+ */
+abstract class PackageManagerInternalBase extends PackageManagerInternal {
+
+    @NonNull
+    private final PackageManagerService mService;
+
+    public PackageManagerInternalBase(@NonNull PackageManagerService service) {
+        mService = service;
+    }
+
+    @NonNull protected abstract Context getContext();
+    @NonNull protected abstract PermissionManagerServiceInternal getPermissionManager();
+    @NonNull protected abstract AppDataHelper getAppDataHelper();
+    @NonNull protected abstract PackageObserverHelper getPackageObserverHelper();
+    @NonNull protected abstract ResolveIntentHelper getResolveIntentHelper();
+    @NonNull protected abstract SuspendPackageHelper getSuspendPackageHelper();
+    @NonNull protected abstract ProtectedPackages getProtectedPackages();
+    @NonNull protected abstract UserNeedsBadgingCache getUserNeedsBadging();
+    @NonNull protected abstract InstantAppRegistry getInstantAppRegistry();
+    @NonNull protected abstract ApexManager getApexManager();
+    @NonNull protected abstract DexManager getDexManager();
+
+    @Override
+    public final Computer snapshot() {
+        return mService.snapshotComputer();
+    }
+
+    @Override
+    @Deprecated
+    public final List<ApplicationInfo> getInstalledApplications(
+            @PackageManager.ApplicationInfoFlagsBits long flags, int userId, int callingUid) {
+        return snapshot().getInstalledApplications(flags, userId, callingUid);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isInstantApp(String packageName, int userId) {
+        return snapshot().isInstantApp(packageName, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final String getInstantAppPackageName(int uid) {
+        return snapshot().getInstantAppPackageName(uid);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
+        return snapshot().filterAppAccess(pkg, callingUid, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean filterAppAccess(String packageName, int callingUid, int userId) {
+        return snapshot().filterAppAccess(packageName, callingUid, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean filterAppAccess(int uid, int callingUid) {
+        return snapshot().filterAppAccess(uid, callingUid);
+    }
+
+    @Nullable
+    @Override
+    @Deprecated
+    public final int[] getVisibilityAllowList(@NonNull String packageName, int userId) {
+        return snapshot().getVisibilityAllowList(packageName, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean canQueryPackage(int callingUid, @Nullable String packageName) {
+        return snapshot().canQueryPackage(callingUid, packageName);
+    }
+
+    @Override
+    @Deprecated
+    public final AndroidPackage getPackage(String packageName) {
+        return snapshot().getPackage(packageName);
+    }
+
+    @Nullable
+    @Override
+    @Deprecated
+    public final AndroidPackageApi getAndroidPackage(@NonNull String packageName) {
+        return snapshot().getPackage(packageName);
+    }
+
+    @Override
+    @Deprecated
+    public final AndroidPackage getPackage(int uid) {
+        return snapshot().getPackage(uid);
+    }
+
+    @Override
+    @Deprecated
+    public final List<AndroidPackage> getPackagesForAppId(int appId) {
+        return snapshot().getPackagesForAppId(appId);
+    }
+
+    @Nullable
+    @Override
+    @Deprecated
+    public final PackageStateInternal getPackageStateInternal(String packageName) {
+        return snapshot().getPackageStateInternal(packageName);
+    }
+
+    @NonNull
+    @Override
+    @Deprecated
+    public final ArrayMap<String, ? extends PackageStateInternal> getPackageStates() {
+        return snapshot().getPackageStates();
+    }
+
+    @Override
+    @Deprecated
+    public final void removePackageListObserver(PackageListObserver observer) {
+        getPackageObserverHelper().removeObserver(observer);
+    }
+
+    @Override
+    @Deprecated
+    public final PackageStateInternal getDisabledSystemPackage(@NonNull String packageName) {
+        return snapshot().getDisabledSystemPackage(packageName);
+    }
+
+    @Override
+    @Deprecated
+    public final @NonNull String[] getKnownPackageNames(int knownPackage, int userId) {
+        return mService.getKnownPackageNamesInternal(snapshot(), knownPackage, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final void setKeepUninstalledPackages(final List<String> packageList) {
+        mService.setKeepUninstalledPackagesInternal(snapshot(), packageList);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isPermissionsReviewRequired(String packageName, int userId) {
+        return getPermissionManager().isPermissionsReviewRequired(packageName, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final PackageInfo getPackageInfo(String packageName,
+            @PackageManager.PackageInfoFlagsBits long flags, int filterCallingUid, int userId) {
+        return snapshot().getPackageInfoInternal(packageName,
+                PackageManager.VERSION_CODE_HIGHEST, flags, filterCallingUid, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final Bundle getSuspendedPackageLauncherExtras(String packageName, int userId) {
+        return getSuspendPackageHelper().getSuspendedPackageLauncherExtras(snapshot(), packageName,
+                userId, Binder.getCallingUid());
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isPackageSuspended(String packageName, int userId) {
+        return getSuspendPackageHelper().isPackageSuspended(snapshot(), packageName, userId,
+                Binder.getCallingUid());
+    }
+
+    @Override
+    @Deprecated
+    public final void removeNonSystemPackageSuspensions(String packageName, int userId) {
+        getSuspendPackageHelper().removeSuspensionsBySuspendingPackage(snapshot(),
+                new String[]{packageName},
+                (suspendingPackage) -> !PackageManagerService.PLATFORM_PACKAGE_NAME.equals(
+                        suspendingPackage),
+                userId);
+    }
+
+    @Override
+    @Deprecated
+    public final void removeDistractingPackageRestrictions(String packageName, int userId) {
+        mService.removeDistractingPackageRestrictions(snapshot(), new String[]{packageName},
+                userId);
+    }
+
+    @Override
+    @Deprecated
+    public final void removeAllDistractingPackageRestrictions(int userId) {
+        mService.removeAllDistractingPackageRestrictions(snapshot(), userId);
+    }
+
+    @Override
+    @Deprecated
+    public final String getSuspendingPackage(String suspendedPackage, int userId) {
+        return getSuspendPackageHelper().getSuspendingPackage(snapshot(), suspendedPackage, userId,
+                Binder.getCallingUid());
+    }
+
+    @Override
+    @Deprecated
+    public final SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage,
+            String suspendingPackage, int userId) {
+        return getSuspendPackageHelper().getSuspendedDialogInfo(snapshot(), suspendedPackage,
+                suspendingPackage, userId, Binder.getCallingUid());
+    }
+
+    @Override
+    @Deprecated
+    public final int getDistractingPackageRestrictions(String packageName, int userId) {
+        final PackageStateInternal packageState = getPackageStateInternal(packageName);
+        return (packageState == null) ? RESTRICTION_NONE
+                : packageState.getUserStateOrDefault(userId).getDistractionFlags();
+    }
+
+    @Override
+    @Deprecated
+    public final int getPackageUid(String packageName,
+            @PackageManager.PackageInfoFlagsBits long flags, int userId) {
+        return snapshot().getPackageUidInternal(packageName, flags, userId, Process.SYSTEM_UID);
+    }
+
+    @Override
+    @Deprecated
+    public final ApplicationInfo getApplicationInfo(String packageName,
+            @PackageManager.ApplicationInfoFlagsBits long flags, int filterCallingUid, int userId) {
+        return snapshot().getApplicationInfoInternal(packageName, flags, filterCallingUid, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final ActivityInfo getActivityInfo(ComponentName component,
+            @PackageManager.ComponentInfoFlagsBits long flags, int filterCallingUid, int userId) {
+        return snapshot().getActivityInfoInternal(component, flags, filterCallingUid, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final List<ResolveInfo> queryIntentActivities(
+            Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
+            int filterCallingUid, int userId) {
+        return snapshot().queryIntentActivitiesInternal(intent, resolvedType, flags, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final List<ResolveInfo> queryIntentReceivers(Intent intent,
+            String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
+            int filterCallingUid, int userId) {
+        return getResolveIntentHelper().queryIntentReceiversInternal(
+                snapshot(), intent, resolvedType, flags, userId, filterCallingUid);
+    }
+
+    @Override
+    @Deprecated
+    public final List<ResolveInfo> queryIntentServices(
+            Intent intent, @PackageManager.ResolveInfoFlagsBits long flags, int callingUid,
+            int userId) {
+        final String resolvedType = intent.resolveTypeIfNeeded(getContext().getContentResolver());
+        return snapshot().queryIntentServicesInternal(intent, resolvedType, flags, userId,
+                callingUid, false);
+    }
+
+    @Override
+    @Deprecated
+    public final ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
+            int userId) {
+        return snapshot().getHomeActivitiesAsUser(allHomeCandidates, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final ComponentName getDefaultHomeActivity(int userId) {
+        return snapshot().getDefaultHomeActivity(userId);
+    }
+
+    @Override
+    @Deprecated
+    public final ComponentName getSystemUiServiceComponent() {
+        return ComponentName.unflattenFromString(getContext().getResources().getString(
+                com.android.internal.R.string.config_systemUIServiceComponent));
+    }
+
+    @Override
+    @Deprecated
+    public final void setDeviceOwnerProtectedPackages(
+            String deviceOwnerPackageName, List<String> packageNames) {
+        getProtectedPackages().setDeviceOwnerProtectedPackages(
+                deviceOwnerPackageName, packageNames);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isPackageDataProtected(int userId, String packageName) {
+        return getProtectedPackages().isPackageDataProtected(userId, packageName);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isPackageStateProtected(String packageName, int userId) {
+        return getProtectedPackages().isPackageStateProtected(userId, packageName);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isPackageEphemeral(int userId, String packageName) {
+        final PackageStateInternal packageState = getPackageStateInternal(packageName);
+        return packageState != null
+                && packageState.getUserStateOrDefault(userId).isInstantApp();
+    }
+
+    @Override
+    @Deprecated
+    public final boolean wasPackageEverLaunched(String packageName, int userId) {
+        final PackageStateInternal packageState = getPackageStateInternal(packageName);
+        if (packageState == null) {
+            throw new IllegalArgumentException("Unknown package: " + packageName);
+        }
+        return !packageState.getUserStateOrDefault(userId).isNotLaunched();
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isEnabledAndMatches(ParsedMainComponent component, long flags, int userId) {
+        return PackageStateUtils.isEnabledAndMatches(
+                getPackageStateInternal(component.getPackageName()), component, flags, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean userNeedsBadging(int userId) {
+        return getUserNeedsBadging().get(userId);
+    }
+
+    @Override
+    @Deprecated
+    public final String getNameForUid(int uid) {
+        return snapshot().getNameForUid(uid);
+    }
+
+    @Override
+    @Deprecated
+    public final void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
+            Intent origIntent, String resolvedType, String callingPackage,
+            @Nullable String callingFeatureId, boolean isRequesterInstantApp,
+            Bundle verificationBundle, int userId) {
+        mService.requestInstantAppResolutionPhaseTwo(responseObj, origIntent,
+                resolvedType, callingPackage, callingFeatureId, isRequesterInstantApp,
+                verificationBundle, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final void grantImplicitAccess(int userId, Intent intent,
+            int recipientAppId, int visibleUid, boolean direct) {
+        grantImplicitAccess(userId, intent, recipientAppId, visibleUid, direct,
+                false /* retainOnUpdate */);
+    }
+
+    @Override
+    @Deprecated
+    public final void grantImplicitAccess(int userId, Intent intent,
+            int recipientAppId, int visibleUid, boolean direct, boolean retainOnUpdate) {
+        mService.grantImplicitAccess(snapshot(), userId, intent,
+                recipientAppId, visibleUid, direct, retainOnUpdate);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isInstantAppInstallerComponent(ComponentName component) {
+        final ActivityInfo instantAppInstallerActivity = mService.mInstantAppInstallerActivity;
+        return instantAppInstallerActivity != null
+                && instantAppInstallerActivity.getComponentName().equals(component);
+    }
+
+    @Override
+    @Deprecated
+    public final void pruneInstantApps() {
+        getInstantAppRegistry().pruneInstantApps(snapshot());
+    }
+
+    @Override
+    @Deprecated
+    public final String getSetupWizardPackageName() {
+        return mService.mSetupWizardPackage;
+    }
+
+    @Override
+    @Deprecated
+    public final ResolveInfo resolveIntent(Intent intent, String resolvedType,
+            @PackageManager.ResolveInfoFlagsBits long flags,
+            @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId,
+            boolean resolveForStart, int filterCallingUid) {
+        return getResolveIntentHelper().resolveIntentInternal(snapshot(),
+                intent, resolvedType, flags, privateResolveFlags, userId, resolveForStart,
+                filterCallingUid);
+    }
+
+    @Override
+    @Deprecated
+    public final ResolveInfo resolveService(Intent intent, String resolvedType,
+            @PackageManager.ResolveInfoFlagsBits long flags, int userId, int callingUid) {
+        return getResolveIntentHelper().resolveServiceInternal(snapshot(), intent,
+                resolvedType, flags, userId, callingUid);
+    }
+
+    @Override
+    @Deprecated
+    public final ProviderInfo resolveContentProvider(String name,
+            @PackageManager.ResolveInfoFlagsBits long flags, int userId, int callingUid) {
+        return snapshot().resolveContentProvider(name, flags, userId,callingUid);
+    }
+
+    @Override
+    @Deprecated
+    public final int getUidTargetSdkVersion(int uid) {
+        return snapshot().getUidTargetSdkVersion(uid);
+    }
+
+    @Override
+    @Deprecated
+    public final int getPackageTargetSdkVersion(String packageName) {
+        final PackageStateInternal packageState = getPackageStateInternal(packageName);
+        if (packageState != null && packageState.getPkg() != null) {
+            return packageState.getPkg().getTargetSdkVersion();
+        }
+        return Build.VERSION_CODES.CUR_DEVELOPMENT;
+    }
+
+    @Override
+    @Deprecated
+    public final boolean canAccessInstantApps(int callingUid, @UserIdInt int userId) {
+        return snapshot().canViewInstantApps(callingUid, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean canAccessComponent(int callingUid, @NonNull ComponentName component,
+            @UserIdInt int userId) {
+        return snapshot().canAccessComponent(callingUid, component, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean hasInstantApplicationMetadata(String packageName, int userId) {
+        return getInstantAppRegistry().hasInstantApplicationMetadata(packageName, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final SparseArray<String> getAppsWithSharedUserIds() {
+        return snapshot().getAppsWithSharedUserIds();
+    }
+
+    @Override
+    @NonNull
+    @Deprecated
+    public final String[] getSharedUserPackagesForPackage(String packageName, int userId) {
+        return snapshot().getSharedUserPackagesForPackage(packageName, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final ArrayMap<String, ProcessInfo> getProcessesForUid(int uid) {
+        return snapshot().getProcessesForUid(uid);
+    }
+
+    @Override
+    @Deprecated
+    public final int[] getPermissionGids(String permissionName, int userId) {
+        return getPermissionManager().getPermissionGids(permissionName, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isOnlyCoreApps() {
+        return mService.isOnlyCoreApps();
+    }
+
+    @Override
+    @Deprecated
+    public final void freeStorage(String volumeUuid, long bytes,
+            @StorageManager.AllocateFlags int flags) throws IOException {
+        mService.freeStorage(volumeUuid, bytes, flags);
+    }
+
+    @Override
+    @Deprecated
+    public final void freeAllAppCacheAboveQuota(@NonNull String volumeUuid) throws IOException {
+        mService.freeAllAppCacheAboveQuota(volumeUuid);
+    }
+
+    @Override
+    @Deprecated
+    public final void forEachPackageSetting(Consumer<PackageSetting> actionLocked) {
+        mService.forEachPackageSetting(actionLocked);
+    }
+
+    @Override
+    @Deprecated
+    public final void forEachPackageState(Consumer<PackageStateInternal> action) {
+        mService.forEachPackageState(snapshot(), action);
+    }
+
+    @Override
+    @Deprecated
+    public final void forEachPackage(Consumer<AndroidPackage> action) {
+        mService.forEachPackage(snapshot(), action);
+    }
+
+    @Override
+    @Deprecated
+    public final void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> action,
+            @UserIdInt int userId) {
+        mService.forEachInstalledPackage(snapshot(), action, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final ArraySet<String> getEnabledComponents(String packageName, int userId) {
+        final PackageStateInternal packageState = getPackageStateInternal(packageName);
+        if (packageState == null) {
+            return new ArraySet<>();
+        }
+        return packageState.getUserStateOrDefault(userId).getEnabledComponents();
+    }
+
+    @Override
+    @Deprecated
+    public final ArraySet<String> getDisabledComponents(String packageName, int userId) {
+        final PackageStateInternal packageState = getPackageStateInternal(packageName);
+        if (packageState == null) {
+            return new ArraySet<>();
+        }
+        return packageState.getUserStateOrDefault(userId).getDisabledComponents();
+    }
+
+    @Override
+    @Deprecated
+    public final @PackageManager.EnabledState int getApplicationEnabledState(
+            String packageName, int userId) {
+        final PackageStateInternal packageState = getPackageStateInternal(packageName);
+        if (packageState == null) {
+            return COMPONENT_ENABLED_STATE_DEFAULT;
+        }
+        return packageState.getUserStateOrDefault(userId).getEnabledState();
+    }
+
+    @Override
+    @Deprecated
+    public final @PackageManager.EnabledState int getComponentEnabledSetting(
+            @NonNull ComponentName componentName, int callingUid, int userId) {
+        return snapshot().getComponentEnabledSettingInternal(
+                componentName, callingUid, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final void setEnableRollbackCode(int token, int enableRollbackCode) {
+        mService.setEnableRollbackCode(token, enableRollbackCode);
+    }
+
+    @Override
+    @Deprecated
+    public final void finishPackageInstall(int token, boolean didLaunch) {
+        mService.finishPackageInstall(token, didLaunch);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isApexPackage(String packageName) {
+        return getApexManager().isApexPackage(packageName);
+    }
+
+    @Override
+    @Deprecated
+    public final List<String> getApksInApex(String apexPackageName) {
+        return getApexManager().getApksInApex(apexPackageName);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isCallerInstallerOfRecord(@NonNull AndroidPackage pkg, int callingUid) {
+        return snapshot().isCallerInstallerOfRecord(pkg, callingUid);
+    }
+
+    @Override
+    @Deprecated
+    public final List<String> getMimeGroup(String packageName, String mimeGroup) {
+        return mService.getMimeGroupInternal(snapshot(), packageName, mimeGroup);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isSystemPackage(@NonNull String packageName) {
+        return packageName.equals(mService.ensureSystemPackageName(snapshot(), packageName));
+    }
+
+    @Override
+    @Deprecated
+    public final void unsuspendForSuspendingPackage(final String packageName, int affectedUser) {
+        mService.unsuspendForSuspendingPackage(snapshot(), packageName, affectedUser);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isSuspendingAnyPackages(String suspendingPackage, int userId) {
+        return snapshot().isSuspendingAnyPackages(suspendingPackage, userId);
+    }
+
+    @Override
+    @Deprecated
+    public final void requestChecksums(@NonNull String packageName, boolean includeSplits,
+            @Checksum.TypeMask int optional, @Checksum.TypeMask int required,
+            @Nullable List trustedInstallers,
+            @NonNull IOnChecksumsReadyListener onChecksumsReadyListener, int userId,
+            @NonNull Executor executor, @NonNull Handler handler) {
+        mService.requestChecksumsInternal(snapshot(), packageName, includeSplits, optional,
+                required, trustedInstallers, onChecksumsReadyListener, userId, executor,
+                handler);
+    }
+
+    @Override
+    @Deprecated
+    public final boolean isPackageFrozen(@NonNull String packageName,
+            int callingUid, int userId) {
+        return snapshot().getPackageStartability(mService.getSafeMode(), packageName, callingUid, userId)
+                == PackageManagerService.PACKAGE_STARTABILITY_FROZEN;
+    }
+
+    @Override
+    @Deprecated
+    public final long deleteOatArtifactsOfPackage(String packageName) {
+        return mService.deleteOatArtifactsOfPackage(snapshot(), packageName);
+    }
+
+    @Override
+    @Deprecated
+    public final void reconcileAppsData(int userId, @StorageManager.StorageFlags int flags,
+            boolean migrateAppsData) {
+        getAppDataHelper().reconcileAppsData(userId, flags, migrateAppsData);
+    }
+
+    @Override
+    @NonNull
+    public ArraySet<PackageStateInternal> getSharedUserPackages(int sharedUserAppId) {
+        return snapshot().getSharedUserPackages(sharedUserAppId);
+    }
+
+    @Override
+    @Nullable
+    public SharedUserApi getSharedUserApi(int sharedUserAppId) {
+        return snapshot().getSharedUser(sharedUserAppId);
+    }
+
+    @NonNull
+    @Override
+    @Deprecated
+    public final PackageStateMutator.InitialState recordInitialState() {
+        return mService.recordInitialState();
+    }
+
+    @Nullable
+    @Override
+    @Deprecated
+    public final PackageStateMutator.Result commitPackageStateMutation(
+            @Nullable PackageStateMutator.InitialState state,
+            @NonNull Consumer<PackageStateMutator> consumer) {
+        return mService.commitPackageStateMutation(state, consumer);
+    }
+
+    @Override
+    @Deprecated
+    public final void shutdown() {
+        mService.shutdown();
+    }
+
+    @Override
+    @Deprecated
+    public final DynamicCodeLogger getDynamicCodeLogger() {
+        return getDexManager().getDynamicCodeLogger();
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageManagerLocal.java b/services/core/java/com/android/server/pm/PackageManagerLocal.java
index 7b76567..39cc37e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerLocal.java
+++ b/services/core/java/com/android/server/pm/PackageManagerLocal.java
@@ -16,8 +16,16 @@
 
 package com.android.server.pm;
 
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
 /**
  * In-process API for server side PackageManager related infrastructure.
  *
@@ -28,4 +36,48 @@
  */
 @SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
 public interface PackageManagerLocal {
+
+    /**
+     * Indicates if operation should include device encrypted storage.
+     */
+    int FLAG_STORAGE_DE = Installer.FLAG_STORAGE_DE;
+    /**
+     * Indicates if operation should include credential encrypted storage.
+     */
+    int FLAG_STORAGE_CE = Installer.FLAG_STORAGE_CE;
+
+    /**
+     * Constants for use with {@link #reconcileSdkData} to specify which storage areas should be
+     * included for operation.
+     *
+     * @hide
+     */
+    @IntDef(prefix = "FLAG_STORAGE_",  value = {
+            FLAG_STORAGE_DE,
+            FLAG_STORAGE_CE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface StorageFlags {}
+
+    /**
+     * Reconcile sdk data sub-directories for the given {@code packagName}.
+     *
+     * Sub directories are created if they do not exist already. If there is an existing per-
+     * sdk directory that is missing from {@code subDirNames}, then it is removed.
+     *
+     * Sdk package path is created if it doesn't exist before creating per-sdk directories.
+     *
+     * @param volumeUuid the volume in which the sdk data should be prepared.
+     * @param packageName package name of the app for which sdk data directory will be prepared.
+     * @param subDirNames names of sub directories that should be reconciled against.
+     * @param userId id of the user to whom the package belongs to.
+     * @param appId id of the package.
+     * @param previousAppId previous id of the package if package is being updated.
+     * @param flags flags from StorageManager to indicate which storage areas should be included.
+     * @param seInfo seInfo tag to be used for selinux policy.
+     * @throws IOException If any error occurs during the operation.
+     */
+    void reconcileSdkData(@Nullable String volumeUuid, @NonNull String packageName,
+            @NonNull List<String> subDirNames, int userId, int appId, int previousAppId,
+            @NonNull String seInfo, @StorageFlags int flags) throws IOException;
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e20a861..4c7243d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -29,7 +29,6 @@
 import static android.content.pm.PackageManager.MATCH_FACTORY_ONLY;
 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.content.pm.PackageManager.RESTRICTION_NONE;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
 import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
@@ -83,21 +82,15 @@
 import android.content.pm.IOnChecksumsReadyListener;
 import android.content.pm.IPackageChangeObserver;
 import android.content.pm.IPackageDataObserver;
-import android.content.pm.IPackageDeleteObserver;
 import android.content.pm.IPackageDeleteObserver2;
 import android.content.pm.IPackageInstallObserver2;
-import android.content.pm.IPackageInstaller;
 import android.content.pm.IPackageLoadingProgressCallback;
 import android.content.pm.IPackageManager;
 import android.content.pm.IPackageMoveObserver;
-import android.content.pm.IPackageStatsObserver;
 import android.content.pm.IncrementalStatesInfo;
 import android.content.pm.InstallSourceInfo;
 import android.content.pm.InstantAppInfo;
 import android.content.pm.InstantAppRequest;
-import android.content.pm.InstrumentationInfo;
-import android.content.pm.IntentFilterVerificationInfo;
-import android.content.pm.KeySet;
 import android.content.pm.ModuleInfo;
 import android.content.pm.PackageChangeEvent;
 import android.content.pm.PackageInfo;
@@ -109,11 +102,8 @@
 import android.content.pm.PackagePartitions;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.PermissionGroupInfo;
-import android.content.pm.PermissionInfo;
-import android.content.pm.ProcessInfo;
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.Signature;
 import android.content.pm.SigningDetails;
@@ -122,7 +112,6 @@
 import android.content.pm.UserInfo;
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.pm.VersionedPackage;
-import android.content.pm.dex.IArtManager;
 import android.content.pm.overlay.OverlayPaths;
 import android.content.pm.parsing.PackageLite;
 import android.content.res.Resources;
@@ -143,6 +132,7 @@
 import android.os.ParcelableException;
 import android.os.PersistableBundle;
 import android.os.Process;
+import android.os.ReconcileSdkDataArgs;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
@@ -213,7 +203,6 @@
 import com.android.server.pm.dex.ArtManagerService;
 import com.android.server.pm.dex.ArtUtils;
 import com.android.server.pm.dex.DexManager;
-import com.android.server.pm.dex.DynamicCodeLogger;
 import com.android.server.pm.dex.ViewCompiler;
 import com.android.server.pm.parsing.PackageCacher;
 import com.android.server.pm.parsing.PackageInfoUtils;
@@ -225,10 +214,7 @@
 import com.android.server.pm.permission.LegacyPermissionManagerService;
 import com.android.server.pm.permission.PermissionManagerService;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
-import com.android.server.pm.pkg.AndroidPackageApi;
-import com.android.server.pm.pkg.PackageState;
 import com.android.server.pm.pkg.PackageStateInternal;
-import com.android.server.pm.pkg.PackageStateUtils;
 import com.android.server.pm.pkg.PackageUserState;
 import com.android.server.pm.pkg.PackageUserStateInternal;
 import com.android.server.pm.pkg.SharedUserApi;
@@ -243,7 +229,6 @@
 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
 import com.android.server.pm.verify.domain.DomainVerificationService;
 import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;
-import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV1;
 import com.android.server.sdksandbox.SdkSandboxManagerLocal;
 import com.android.server.storage.DeviceStorageMonitorInternal;
 import com.android.server.utils.SnapshotCache;
@@ -413,7 +398,8 @@
     public @interface ScanFlags {}
 
     /**
-     * Used as the result code of the {@link #getPackageStartability}.
+     * Used as the result code of the {@link Computer#getPackageStartability(boolean, String, int,
+     * int)}.
      */
     @IntDef(value = {
         PACKAGE_STARTABILITY_OK,
@@ -426,40 +412,43 @@
     public @interface PackageStartability {}
 
     /**
-     * Used as the result code of the {@link #getPackageStartability} to indicate
-     * the given package is allowed to start.
+     * Used as the result code of the {@link Computer#getPackageStartability(boolean, String, int,
+     * int)} to indicate the given package is allowed to start.
      */
     public static final int PACKAGE_STARTABILITY_OK = 0;
 
     /**
-     * Used as the result code of the {@link #getPackageStartability} to indicate
-     * the given package is <b>not</b> allowed to start because it's not found
+     * Used as the result code of the {@link Computer#getPackageStartability(boolean, String, int,
+     * int)} to indicate the given package is <b>not</b> allowed to start because it's not found
      * (could be due to that package is invisible to the given user).
      */
     public static final int PACKAGE_STARTABILITY_NOT_FOUND = 1;
 
     /**
-     * Used as the result code of the {@link #getPackageStartability} to indicate
-     * the given package is <b>not</b> allowed to start because it's not a system app
-     * and the system is running in safe mode.
+     * Used as the result code of the {@link Computer#getPackageStartability(boolean, String, int,
+     * int)} to indicate the given package is <b>not</b> allowed to start because it's not a system
+     * app and the system is running in safe mode.
      */
     public static final int PACKAGE_STARTABILITY_NOT_SYSTEM = 2;
 
     /**
-     * Used as the result code of the {@link #getPackageStartability} to indicate
-     * the given package is <b>not</b> allowed to start because it's currently frozen.
+     * Used as the result code of the {@link Computer#getPackageStartability(boolean, String, int,
+     * int)} to indicate the given package is <b>not</b> allowed to start because it's currently
+     * frozen.
      */
     public static final int PACKAGE_STARTABILITY_FROZEN = 3;
 
     /**
-     * Used as the result code of the {@link #getPackageStartability} to indicate
-     * the given package is <b>not</b> allowed to start because it doesn't support
+     * Used as the result code of the {@link Computer#getPackageStartability(boolean, String, int,
+     * int)} to indicate the given package is <b>not</b> allowed to start because it doesn't support
      * direct boot.
      */
     public static final int PACKAGE_STARTABILITY_DIRECT_BOOT_UNSUPPORTED = 4;
 
     private static final String STATIC_SHARED_LIB_DELIMITER = "_";
-    /** Extension of the compressed packages */
+    /**
+     * Extension of the compressed packages
+     */
     public final static String COMPRESSED_EXTENSION = ".gz";
     /** Suffix of stub packages on the system partition */
     public final static String STUB_SUFFIX = "-Stub";
@@ -644,9 +633,6 @@
      */
     boolean mPromoteSystemApps;
 
-    // TODO: Make IPackageManager reference private to hide discouraged APIs
-    final IPackageManagerImpl mIPackageManager;
-    private final PackageManagerInternal mPmInternal;
     private final TestUtilityService mTestUtilityService;
 
     @Watched
@@ -949,7 +935,7 @@
     private final BroadcastHelper mBroadcastHelper;
     private final RemovePackageHelper mRemovePackageHelper;
     private final DeletePackageHelper mDeletePackageHelper;
-    private final InitAndSystemPackageHelper mInitAndSystemPackageHelper;
+    private final InitAppsHelper mInitAppsHelper;
     private final AppDataHelper mAppDataHelper;
     private final InstallPackageHelper mInstallPackageHelper;
     private final PreferredActivityHelper mPreferredActivityHelper;
@@ -1057,9 +1043,6 @@
     // A lock-free cache for frequently called functions.
     private volatile Computer mSnapshotComputer;
 
-    // A trampoline that directs callers to either the live or snapshot computer.
-    final ComputerTracker mComputer = new ComputerTracker(this);
-
     // If true, the snapshot is invalid (stale).  The attribute is static since it may be
     // set from outside classes.  The attribute may be set to true anywhere, although it
     // should only be set true while holding mLock.  However, the attribute id guaranteed
@@ -1088,6 +1071,8 @@
      * Return the cached computer.  The method will rebuild the cached computer if necessary.
      * The live computer will be returned if snapshots are disabled.
      */
+    @VisibleForTesting(visibility = Visibility.PACKAGE)
+    @NonNull
     public Computer snapshotComputer() {
         if (Thread.holdsLock(mLock)) {
             // If the current thread holds mLock then it may have modified state but not
@@ -1247,15 +1232,15 @@
             ApkChecksums.Injector injector = new ApkChecksums.Injector(
                     () -> mContext,
                     () -> handler,
-                    () -> mInjector.getIncrementalManager(),
-                    () -> mPmInternal);
+                    mInjector::getIncrementalManager,
+                    () -> mInjector.getLocalService(PackageManagerInternal.class));
             ApkChecksums.getChecksums(filesToChecksum, optional, required, installerPackageName,
                     trustedCerts, onChecksumsReadyListener, injector);
         });
     }
 
-    private void requestChecksumsInternal(@NonNull String packageName, boolean includeSplits,
-            @Checksum.TypeMask int optional, @Checksum.TypeMask int required,
+    void requestChecksumsInternal(@NonNull Computer snapshot, @NonNull String packageName,
+            boolean includeSplits, @Checksum.TypeMask int optional, @Checksum.TypeMask int required,
             @Nullable List trustedInstallers,
             @NonNull IOnChecksumsReadyListener onChecksumsReadyListener, int userId,
             @NonNull Executor executor, @NonNull Handler handler) {
@@ -1264,15 +1249,23 @@
         Objects.requireNonNull(executor);
         Objects.requireNonNull(handler);
 
-        final ApplicationInfo applicationInfo = getApplicationInfoInternal(packageName, 0,
+        final ApplicationInfo applicationInfo = snapshot.getApplicationInfoInternal(packageName, 0,
                 Binder.getCallingUid(), userId);
         if (applicationInfo == null) {
             throw new ParcelableException(new PackageManager.NameNotFoundException(packageName));
         }
-        final InstallSourceInfo installSourceInfo =
-                mIPackageManager.getInstallSourceInfo(packageName);
-        final String installerPackageName =
-                installSourceInfo != null ? installSourceInfo.getInitiatingPackageName() : null;
+
+        final InstallSourceInfo installSourceInfo = snapshot.getInstallSourceInfo(packageName);
+        final String installerPackageName;
+        if (installSourceInfo != null) {
+            if (!TextUtils.isEmpty(installSourceInfo.getInitiatingPackageName())) {
+                installerPackageName = installSourceInfo.getInitiatingPackageName();
+            } else {
+                installerPackageName = installSourceInfo.getInstallingPackageName();
+            }
+        } else {
+            installerPackageName = null;
+        }
 
         List<Pair<String, File>> filesToChecksum = new ArrayList<>();
 
@@ -1294,8 +1287,8 @@
             ApkChecksums.Injector injector = new ApkChecksums.Injector(
                     () -> mContext,
                     () -> handler,
-                    () -> mInjector.getIncrementalManager(),
-                    () -> mPmInternal);
+                    mInjector::getIncrementalManager,
+                    () -> mInjector.getLocalService(PackageManagerInternal.class));
             ApkChecksums.getChecksums(filesToChecksum, optional, required, installerPackageName,
                     trustedCerts, onChecksumsReadyListener, injector);
         });
@@ -1440,15 +1433,15 @@
                         RuntimePermissionsPersistence.createInstance(),
                         i.getPermissionManagerServiceInternal(),
                         domainVerificationService, lock),
-                (i, pm) -> AppsFilter.create(pm.mPmInternal, i),
+                (i, pm) -> AppsFilter.create(i, i.getLocalService(PackageManagerInternal.class)),
                 (i, pm) -> (PlatformCompat) ServiceManager.getService("platform_compat"),
                 (i, pm) -> SystemConfig.getInstance(),
                 (i, pm) -> new PackageDexOptimizer(i.getInstaller(), i.getInstallLock(),
                         i.getContext(), "*dexopt*"),
-                (i, pm) -> new DexManager(i.getContext(), pm.mIPackageManager,
-                        i.getPackageDexOptimizer(), i.getInstaller(), i.getInstallLock()),
-                (i, pm) -> new ArtManagerService(i.getContext(), pm.mIPackageManager,
+                (i, pm) -> new DexManager(i.getContext(), i.getPackageDexOptimizer(),
                         i.getInstaller(), i.getInstallLock()),
+                (i, pm) -> new ArtManagerService(i.getContext(), i.getInstaller(),
+                        i.getInstallLock()),
                 (i, pm) -> ApexManager.getInstance(),
                 (i, pm) -> new ViewCompiler(i.getInstallLock(), i.getInstaller()),
                 (i, pm) -> (IncrementalManager)
@@ -1470,7 +1463,7 @@
                         i.getContext(), pm, i::getScanningPackageParser),
                 (i, pm, cn) -> new InstantAppResolverConnection(
                         i.getContext(), cn, Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE),
-                (i, pm) -> new ModuleInfoProvider(i.getContext(), pm.mIPackageManager),
+                (i, pm) -> new ModuleInfoProvider(i.getContext()),
                 (i, pm) -> LegacyPermissionManagerService.create(i.getContext()),
                 (i, pm) -> domainVerificationService,
                 (i, pm) -> {
@@ -1498,13 +1491,15 @@
 
         final CompatChange.ChangeListener selinuxChangeListener = packageName -> {
             synchronized (m.mInstallLock) {
-                final PackageStateInternal packageState = m.getPackageStateInternal(packageName);
+                final Computer snapshot = m.snapshotComputer();
+                final PackageStateInternal packageState =
+                        snapshot.getPackageStateInternal(packageName);
                 if (packageState == null) {
                     Slog.e(TAG, "Failed to find package setting " + packageName);
                     return;
                 }
                 AndroidPackage pkg = packageState.getPkg();
-                SharedUserApi sharedUser = m.mComputer.getSharedUser(
+                SharedUserApi sharedUser = snapshot.getSharedUser(
                         packageState.getSharedUserAppId());
                 String oldSeInfo = AndroidPackageUtils.getSeInfo(pkg, packageState);
 
@@ -1531,11 +1526,12 @@
                 selinuxChangeListener);
 
         m.installAllowlistedSystemPackages();
-        ServiceManager.addService("package", m.mIPackageManager);
+        IPackageManagerImpl iPackageManager = m.new IPackageManagerImpl();
+        ServiceManager.addService("package", iPackageManager);
         final PackageManagerNative pmn = new PackageManagerNative(m);
         ServiceManager.addService("package_native", pmn);
         LocalManagerRegistry.addManager(PackageManagerLocal.class, m.new PackageManagerLocalImpl());
-        return Pair.create(m, m.mIPackageManager);
+        return Pair.create(m, iPackageManager);
     }
 
     /** Install/uninstall system packages for all users based on their user-type, as applicable. */
@@ -1641,8 +1637,6 @@
         mPackageDexOptimizer = testParams.packageDexOptimizer;
         mPackageParserCallback = testParams.packageParserCallback;
         mPendingBroadcasts = testParams.pendingPackageBroadcasts;
-        mIPackageManager = new IPackageManagerImpl();
-        mPmInternal = testParams.pmInternal;
         mTestUtilityService = testParams.testUtilityService;
         mProcessLoggingHandler = testParams.processLoggingHandler;
         mProtectedPackages = testParams.protectedPackages;
@@ -1685,7 +1679,7 @@
         mAppDataHelper = testParams.appDataHelper;
         mInstallPackageHelper = testParams.installPackageHelper;
         mRemovePackageHelper = testParams.removePackageHelper;
-        mInitAndSystemPackageHelper = testParams.initAndSystemPackageHelper;
+        mInitAppsHelper = testParams.initAndSystemPackageHelper;
         mDeletePackageHelper = testParams.deletePackageHelper;
         mPreferredActivityHelper = testParams.preferredActivityHelper;
         mResolveIntentHelper = testParams.resolveIntentHelper;
@@ -1703,7 +1697,6 @@
     public PackageManagerService(PackageManagerServiceInjector injector, boolean onlyCore,
             boolean factoryTest, final String buildFingerprint, final boolean isEngBuild,
             final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {
-        mIPackageManager = new IPackageManagerImpl();
         mIsEngBuild = isEngBuild;
         mIsUserDebugBuild = isUserDebugBuild;
         mSdkVersion = sdkVersion;
@@ -1734,10 +1727,9 @@
         t.traceBegin("createSubComponents");
 
         // Expose private service for system components to use.
-        mPmInternal = new PackageManagerInternalImpl();
+        LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());
         LocalServices.addService(TestUtilityService.class, this);
         mTestUtilityService = LocalServices.getService(TestUtilityService.class);
-        LocalServices.addService(PackageManagerInternal.class, mPmInternal);
         mUserManager = injector.getUserManagerService();
         mUserNeedsBadging = new UserNeedsBadgingCache(mUserManager);
         mComponentResolver = injector.getComponentResolver();
@@ -1755,7 +1747,7 @@
 
             @Override
             public boolean hasFeature(String feature) {
-                return PackageManagerService.this.mIPackageManager.hasSystemFeature(feature, 0);
+                return PackageManagerService.this.hasSystemFeature(feature, 0);
             }
         };
 
@@ -1837,7 +1829,8 @@
         mAppDataHelper = new AppDataHelper(this);
         mInstallPackageHelper = new InstallPackageHelper(this, mAppDataHelper);
         mRemovePackageHelper = new RemovePackageHelper(this, mAppDataHelper);
-        mInitAndSystemPackageHelper = new InitAndSystemPackageHelper(this);
+        mInitAppsHelper = new InitAppsHelper(this, mApexManager, mInstallPackageHelper,
+                mInjector.getSystemPartitions());
         mDeletePackageHelper = new DeletePackageHelper(this, mRemovePackageHelper,
                 mAppDataHelper);
         mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper);
@@ -1885,9 +1878,10 @@
                 final int dependencyCount = entry.dependencies.length;
                 for (int j = 0; j < dependencyCount; j++) {
                     final SharedLibraryInfo dependency =
-                        getSharedLibraryInfo(entry.dependencies[j], undefinedVersion);
+                        computer.getSharedLibraryInfo(entry.dependencies[j], undefinedVersion);
                     if (dependency != null) {
-                        getSharedLibraryInfo(name, undefinedVersion).addDependency(dependency);
+                        computer.getSharedLibraryInfo(name, undefinedVersion)
+                                .addDependency(dependency);
                     }
                 }
             }
@@ -1899,13 +1893,23 @@
             t.traceEnd();
 
             t.traceBegin("read user settings");
-            mFirstBoot = !mSettings.readLPw(mLiveComputer,
+            mFirstBoot = !mSettings.readLPw(computer,
                     mInjector.getUserManagerInternal().getUsers(
                     /* excludePartial= */ true,
                     /* excludeDying= */ false,
                     /* excludePreCreated= */ false));
             t.traceEnd();
 
+            if (mFirstBoot) {
+                t.traceBegin("setFirstBoot: ");
+                try {
+                    mInstaller.setFirstBoot();
+                } catch (InstallerException e) {
+                    Slog.w(TAG, "Could not set First Boot: ", e);
+                }
+                t.traceEnd();
+            }
+
             mPermissionManager.readLegacyPermissionsTEMP(mSettings.mPermissions);
             mPermissionManager.readLegacyPermissionStateTEMP();
 
@@ -1971,8 +1975,11 @@
                     mIsEngBuild, mIsUserDebugBuild, mIncrementalVersion);
 
             final int[] userIds = mUserManager.getUserIds();
-            mOverlayConfig = mInitAndSystemPackageHelper.initPackages(packageSettings,
-                    userIds, startTime);
+            PackageParser2 packageParser = mInjector.getScanningCachingPackageParser();
+            mOverlayConfig = mInitAppsHelper.initSystemApps(packageParser, packageSettings, userIds,
+                    startTime);
+            mInitAppsHelper.initNonSystemApps(packageParser, userIds, startTime);
+            packageParser.close();
 
             // Resolve the storage manager.
             mStorageManagerPackage = getStorageManagerPackageName(computer);
@@ -1980,19 +1987,26 @@
             // Resolve protected action filters. Only the setup wizard is allowed to
             // have a high priority filter for these actions.
             mSetupWizardPackage = getSetupWizardPackageNameImpl(computer);
-            mComponentResolver.fixProtectedFilterPriorities(mPmInternal.getSetupWizardPackageName());
+            mComponentResolver.fixProtectedFilterPriorities(mSetupWizardPackage);
 
-            mDefaultTextClassifierPackage = mIPackageManager.getDefaultTextClassifierPackageName();
-            mSystemTextClassifierPackageName =
-                    mIPackageManager.getSystemTextClassifierPackageName();
-            mConfiguratorPackage = getDeviceConfiguratorPackageName();
-            mAppPredictionServicePackage = mIPackageManager.getAppPredictionServicePackageName();
-            mIncidentReportApproverPackage =
-                    mIPackageManager.getIncidentReportApproverPackageName();
+            mDefaultTextClassifierPackage = ensureSystemPackageName(computer,
+                    mContext.getString(R.string.config_servicesExtensionPackage));
+            mSystemTextClassifierPackageName = ensureSystemPackageName(computer,
+                    mContext.getString(R.string.config_defaultTextClassifierPackage));
+            mConfiguratorPackage = ensureSystemPackageName(computer,
+                    mContext.getString(R.string.config_deviceConfiguratorPackageName));
+            mAppPredictionServicePackage = ensureSystemPackageName(computer,
+                    getPackageFromComponentString(R.string.config_defaultAppPredictionService));
+            mIncidentReportApproverPackage = ensureSystemPackageName(computer,
+                    mContext.getString(R.string.config_incidentReportApproverPackage));
             mRetailDemoPackage = getRetailDemoPackageName();
-            mOverlayConfigSignaturePackage = getOverlayConfigSignaturePackageName();
-            mRecentsPackage = getRecentsPackageName();
-            mAmbientContextDetectionPackage = getAmbientContextDetectionPackageName();
+            mOverlayConfigSignaturePackage = ensureSystemPackageName(computer,
+                    mInjector.getSystemConfig().getOverlayConfigSignaturePackage());
+            mRecentsPackage = ensureSystemPackageName(computer,
+                    getPackageFromComponentString(R.string.config_recentsComponentName));
+            mAmbientContextDetectionPackage = ensureSystemPackageName(computer,
+                    getPackageFromComponentString(
+                            R.string.config_defaultAmbientContextDetectionService));
 
             // Now that we know all of the shared libraries, update all clients to have
             // the correct library paths.
@@ -2126,8 +2140,8 @@
 
                 mDomainVerificationManager.setProxy(domainVerificationProxy);
 
-                mServicesExtensionPackageName = getRequiredServicesExtensionPackageLPr();
-                mSharedSystemSharedLibraryPackageName = getRequiredSharedLibrary(
+                mServicesExtensionPackageName = getRequiredServicesExtensionPackageLPr(computer);
+                mSharedSystemSharedLibraryPackageName = getRequiredSharedLibrary(computer,
                         PackageManager.SYSTEM_SHARED_LIBRARY_SHARED,
                         SharedLibraryInfo.VERSION_UNDEFINED);
             } else {
@@ -2143,11 +2157,11 @@
             mRequiredPermissionControllerPackage = getRequiredPermissionControllerLPr(computer);
 
             mSettings.setPermissionControllerVersion(
-                    mIPackageManager.getPackageInfo(mRequiredPermissionControllerPackage, 0,
+                    computer.getPackageInfo(mRequiredPermissionControllerPackage, 0,
                             UserHandle.USER_SYSTEM).getLongVersionCode());
 
             // Resolve the sdk sandbox package
-            mRequiredSdkSandboxPackage = getRequiredSdkSandboxPackageName();
+            mRequiredSdkSandboxPackage = getRequiredSdkSandboxPackageName(computer);
 
             // Initialize InstantAppRegistry's Instant App list for all users.
             for (AndroidPackage pkg : mPackages.values()) {
@@ -2155,7 +2169,8 @@
                     continue;
                 }
                 for (int userId : userIds) {
-                    final PackageStateInternal ps = getPackageStateInternal(pkg.getPackageName());
+                    final PackageStateInternal ps =
+                            computer.getPackageStateInternal(pkg.getPackageName());
                     if (ps == null || !ps.getUserStateOrDefault(userId).isInstantApp()
                             || !ps.getUserStateOrDefault(userId).isInstalled()) {
                         continue;
@@ -2165,7 +2180,7 @@
             }
 
             mInstallerService = mInjector.getPackageInstallerService();
-            final ComponentName instantAppResolverComponent = getInstantAppResolver();
+            final ComponentName instantAppResolverComponent = getInstantAppResolver(computer);
             if (instantAppResolverComponent != null) {
                 if (DEBUG_INSTANT) {
                     Slog.d(TAG, "Set ephemeral resolver: " + instantAppResolverComponent);
@@ -2191,7 +2206,7 @@
             // scanning).
             final Map<Integer, List<PackageInfo>> userPackages = new HashMap<>();
             for (int userId : userIds) {
-                userPackages.put(userId, mIPackageManager.getInstalledPackages(/*flags*/ 0, userId)
+                userPackages.put(userId, computer.getInstalledPackages(/*flags*/ 0, userId)
                         .getList());
             }
             mDexManager.load(userPackages);
@@ -2202,7 +2217,7 @@
                         SystemClock.uptimeMillis() - startTime);
             }
 
-            // Rebild the live computer since some attributes have been rebuilt.
+            // Rebuild the live computer since some attributes have been rebuilt.
             mLiveComputer = createLiveComputer();
 
         } // synchronized (mLock)
@@ -2210,6 +2225,7 @@
         // CHECKSTYLE:ON IndentationCheck
 
         mModuleInfoProvider = mInjector.getModuleInfoProvider();
+
         mInjector.getSystemWrapper().enablePackageCaches();
 
         // Now after opening every single application zip, make sure they
@@ -2281,8 +2297,9 @@
     }
 
     @NonNull
-    private String getRequiredSharedLibrary(@NonNull String name, int version) {
-        SharedLibraryInfo libraryInfo = getSharedLibraryInfo(name, version);
+    private String getRequiredSharedLibrary(@NonNull Computer snapshot, @NonNull String name,
+            int version) {
+        SharedLibraryInfo libraryInfo = snapshot.getSharedLibraryInfo(name, version);
         if (libraryInfo == null) {
             throw new IllegalStateException("Missing required shared library:" + name);
         }
@@ -2294,9 +2311,9 @@
     }
 
     @NonNull
-    private String getRequiredServicesExtensionPackageLPr() {
+    private String getRequiredServicesExtensionPackageLPr(@NonNull Computer computer) {
         String servicesExtensionPackage =
-                ensureSystemPackageName(
+                ensureSystemPackageName(computer,
                         mContext.getString(R.string.config_servicesExtensionPackage));
         if (TextUtils.isEmpty(servicesExtensionPackage)) {
             throw new RuntimeException(
@@ -2375,7 +2392,7 @@
         for (int i = 0; i < N; i++) {
             final ResolveInfo cur = matches.get(i);
             final String packageName = cur.getComponentInfo().packageName;
-            if (mIPackageManager.checkPermission(
+            if (checkPermission(
                     android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT, packageName,
                     UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) {
                 continue;
@@ -2405,7 +2422,7 @@
         for (int i = 0; i < N; i++) {
             final ResolveInfo cur = matches.get(i);
             final String packageName = cur.getComponentInfo().packageName;
-            if (mIPackageManager.checkPermission(
+            if (checkPermission(
                     android.Manifest.permission.DOMAIN_VERIFICATION_AGENT, packageName,
                     UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) {
                 Slog.w(TAG, "Domain verification agent found but does not hold permission: "
@@ -2414,7 +2431,7 @@
             }
 
             if (best == null || cur.priority > best.priority) {
-                if (mComputer.isComponentEffectivelyEnabled(cur.getComponentInfo(),
+                if (computer.isComponentEffectivelyEnabled(cur.getComponentInfo(),
                         UserHandle.USER_SYSTEM)) {
                     best = cur;
                 } else {
@@ -2430,7 +2447,7 @@
         return null;
     }
 
-    private @Nullable ComponentName getInstantAppResolver() {
+    @Nullable ComponentName getInstantAppResolver(@NonNull Computer snapshot) {
         final String[] packageArray =
                 mContext.getResources().getStringArray(R.array.config_ephemeralResolverPackage);
         if (packageArray.length == 0 && !Build.IS_DEBUGGABLE) {
@@ -2446,7 +2463,7 @@
                 | MATCH_DIRECT_BOOT_UNAWARE
                 | (!Build.IS_DEBUGGABLE ? MATCH_SYSTEM_ONLY : 0);
         final Intent resolverIntent = new Intent(Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE);
-        List<ResolveInfo> resolvers = queryIntentServicesInternal(resolverIntent, null,
+        List<ResolveInfo> resolvers = snapshot.queryIntentServicesInternal(resolverIntent, null,
                 resolveFlags, UserHandle.USER_SYSTEM, callingUid, false /*includeInstantApps*/);
         final int N = resolvers.size();
         if (N == 0) {
@@ -2519,7 +2536,7 @@
         Iterator<ResolveInfo> iter = matches.iterator();
         while (iter.hasNext()) {
             final ResolveInfo rInfo = iter.next();
-            if (mIPackageManager.checkPermission(
+            if (checkPermission(
                     Manifest.permission.INSTALL_PACKAGES,
                     rInfo.activityInfo.packageName, 0) == PERMISSION_GRANTED || mIsEngBuild) {
                 continue;
@@ -2550,48 +2567,6 @@
         return matches.get(0).getComponentInfo().getComponentName();
     }
 
-    /**
-     * @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int)
-     */
-    boolean shouldFilterApplication(
-            @Nullable PackageStateInternal ps, int callingUid, int userId) {
-        return mComputer.shouldFilterApplication(
-            ps, callingUid, userId);
-    }
-
-    private @PackageStartability int getPackageStartability(String packageName,
-            int callingUid, int userId) {
-        return mComputer.getPackageStartability(mSafeMode, packageName, callingUid, userId);
-    }
-
-    /**
-     * Returns whether or not a full application can see an instant application.
-     * <p>
-     * Currently, there are four cases in which this can occur:
-     * <ol>
-     * <li>The calling application is a "special" process. Special processes
-     *     are those with a UID < {@link Process#FIRST_APPLICATION_UID}.</li>
-     * <li>The calling application has the permission
-     *     {@link android.Manifest.permission#ACCESS_INSTANT_APPS}.</li>
-     * <li>The calling application is the default launcher on the
-     *     system partition.</li>
-     * <li>The calling application is the default app prediction service.</li>
-     * </ol>
-     */
-    boolean canViewInstantApps(int callingUid, int userId) {
-        return mComputer.canViewInstantApps(callingUid, userId);
-    }
-
-    private PackageInfo generatePackageInfo(@NonNull PackageStateInternal ps,
-            @PackageManager.PackageInfoFlagsBits long flags, int userId) {
-        return mComputer.generatePackageInfo(ps, flags, userId);
-    }
-
-    int getPackageUidInternal(String packageName,
-            @PackageManager.PackageInfoFlagsBits long flags, int userId, int callingUid) {
-        return mComputer.getPackageUidInternal(packageName, flags, userId, callingUid);
-    }
-
     public PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags) {
         // Because this is accessed via the package manager service AIDL,
         // go through the permission manager service AIDL
@@ -2600,19 +2575,6 @@
     }
 
     /**
-     * Important: The provided filterCallingUid is used exclusively to filter out applications
-     * that can be seen based on user state. It's typically the original caller uid prior
-     * to clearing. Because it can only be provided by trusted code, its value can be
-     * trusted and will be used as-is; unlike userId which will be validated by this method.
-     */
-    private ApplicationInfo getApplicationInfoInternal(String packageName,
-            @PackageManager.ApplicationInfoFlagsBits long flags,
-            int filterCallingUid, int userId) {
-        return mComputer.getApplicationInfoInternal(packageName, flags,
-                filterCallingUid, userId);
-    }
-
-    /**
      * Blocking call to clear all cached app data above quota.
      */
     public void freeAllAppCacheAboveQuota(String volumeUuid) throws IOException {
@@ -2648,7 +2610,7 @@
             // 2. Consider preloaded data (after 1w honeymoon, unless aggressive)
             if (internalVolume && (aggressive || SystemProperties
                     .getBoolean("persist.sys.preloads.file_cache_expired", false))) {
-                mIPackageManager.deletePreloadsFileCache();
+                deletePreloadsFileCache();
                 if (file.getUsableSpace() >= bytes) return;
             }
 
@@ -2769,43 +2731,6 @@
         return recommendedInstallLocation;
     }
 
-    /**
-     * Update given flags when being used to request {@link ResolveInfo}.
-     * <p>Instant apps are resolved specially, depending upon context. Minimally,
-     * {@code}flags{@code} must have the {@link PackageManager#MATCH_INSTANT}
-     * flag set. However, this flag is only honoured in three circumstances:
-     * <ul>
-     * <li>when called from a system process</li>
-     * <li>when the caller holds the permission {@code android.permission.ACCESS_INSTANT_APPS}</li>
-     * <li>when resolution occurs to start an activity with a {@code android.intent.action.VIEW}
-     * action and a {@code android.intent.category.BROWSABLE} category</li>
-     * </ul>
-     */
-    long updateFlagsForResolve(long flags, int userId, int callingUid,
-            boolean wantInstantApps, boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
-        return mComputer.updateFlagsForResolve(flags, userId, callingUid,
-                wantInstantApps, isImplicitImageCaptureIntentAndNotSetByDpc);
-    }
-
-    /**
-     * Important: The provided filterCallingUid is used exclusively to filter out activities
-     * that can be seen based on user state. It's typically the original caller uid prior
-     * to clearing. Because it can only be provided by trusted code, its value can be
-     * trusted and will be used as-is; unlike userId which will be validated by this method.
-     */
-    private ActivityInfo getActivityInfoInternal(ComponentName component,
-            @PackageManager.ComponentInfoFlagsBits long flags, int filterCallingUid, int userId) {
-        return mComputer.getActivityInfoInternal(component, flags,
-                filterCallingUid, userId);
-    }
-
-    @Nullable
-    List<VersionedPackage> getPackagesUsingSharedLibrary(
-            SharedLibraryInfo libInfo, @PackageManager.PackageInfoFlagsBits long flags,
-            int callingUid, int userId) {
-        return mComputer.getPackagesUsingSharedLibrary(libInfo, flags, callingUid, userId);
-    }
-
     public ModuleInfo getModuleInfo(String packageName, @PackageManager.ModuleInfoFlags int flags) {
         return mModuleInfoProvider.getModuleInfo(packageName, flags);
     }
@@ -2840,7 +2765,7 @@
         return mRequiredInstallerPackage;
     }
 
-    private void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
+    void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
             Intent origIntent, String resolvedType, String callingPackage,
             @Nullable String callingFeatureId, boolean isRequesterInstantApp,
             Bundle verificationBundle, int userId) {
@@ -2852,31 +2777,6 @@
         mHandler.sendMessage(msg);
     }
 
-    /**
-     * From Android R, camera intents have to match system apps. The only exception to this is if
-     * the DPC has set the camera persistent preferred activity. This case was introduced
-     * because it is important that the DPC has the ability to set both system and non-system
-     * camera persistent preferred activities.
-     *
-     * @return {@code true} if the intent is a camera intent and the persistent preferred
-     * activity was not set by the DPC.
-     */
-    @GuardedBy("mLock")
-    boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, int userId,
-            String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags) {
-        return mComputer.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId,
-                resolvedType, flags);
-    }
-
-    @GuardedBy("mLock")
-    ResolveInfo findPersistentPreferredActivityLP(Intent intent,
-            String resolvedType,
-            @PackageManager.ResolveInfoFlagsBits long flags, List<ResolveInfo> query, boolean debug,
-            int userId) {
-        return mComputer.findPersistentPreferredActivityLP(intent,
-                resolvedType, flags, query, debug, userId);
-    }
-
     // findPreferredActivityBody returns two items: a "things changed" flag and a
     // ResolveInfo, which is the preferred activity itself.
     static class FindPreferredActivityBodyResult {
@@ -2884,24 +2784,6 @@
         ResolveInfo mPreferredResolveInfo;
     }
 
-    FindPreferredActivityBodyResult findPreferredActivityInternal(
-            Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
-            List<ResolveInfo> query, boolean always,
-            boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
-        return mComputer.findPreferredActivityInternal(
-            intent, resolvedType, flags,
-            query, always,
-            removeMatches, debug, userId, queryMayBeFiltered);
-    }
-
-    /**
-     * Returns the package name of the calling Uid if it's an instant app. If it isn't
-     * instant, returns {@code null}.
-     */
-    String getInstantAppPackageName(int callingUid) {
-        return mComputer.getInstantAppPackageName(callingUid);
-    }
-
     public @NonNull ParceledListSlice<ResolveInfo> queryIntentReceivers(@NonNull Computer snapshot,
             Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
             @UserIdInt int userId) {
@@ -2909,24 +2791,6 @@
                 snapshot, intent, resolvedType, flags, userId, Binder.getCallingUid()));
     }
 
-    @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
-            String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId,
-            int callingUid, boolean includeInstantApps) {
-        return mComputer.queryIntentServicesInternal(intent,
-                resolvedType, flags, userId, callingUid,
-                includeInstantApps);
-    }
-
-    private boolean isInstantAppInternal(String packageName, @UserIdInt int userId,
-            int callingUid) {
-        return mComputer.isInstantAppInternal(packageName, userId,
-                callingUid);
-    }
-
-    boolean isCallerSameApp(String packageName, int uid) {
-        return mComputer.isCallerSameApp(packageName, uid);
-    }
-
     public static void reportSettingsProblem(int priority, String msg) {
         logCriticalInfo(priority, msg);
     }
@@ -2943,39 +2807,6 @@
         return packageName + STATIC_SHARED_LIB_DELIMITER + libraryVersion;
     }
 
-    /**
-     * Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS
-     * or INTERACT_ACROSS_USERS_FULL permissions, if the {@code userId} is not for the caller.
-     *
-     * @param checkShell whether to prevent shell from access if there's a debugging restriction
-     * @param message the message to log on security exception
-     */
-    void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
-            boolean requireFullPermission, boolean checkShell, String message) {
-        mComputer.enforceCrossUserPermission(callingUid, userId,
-                requireFullPermission, checkShell, message);
-    }
-
-    /**
-     * Checks if the request is from the system or an app that has the appropriate cross-user
-     * permissions defined as follows:
-     * <ul>
-     * <li>INTERACT_ACROSS_USERS_FULL if {@code requireFullPermission} is true.</li>
-     * <li>INTERACT_ACROSS_USERS if the given {@code userId} is in a different profile group
-     * to the caller.</li>
-     * <li>Otherwise, INTERACT_ACROSS_PROFILES if the given {@code userId} is in the same profile
-     * group as the caller.</li>
-     * </ul>
-     *
-     * @param checkShell whether to prevent shell from access if there's a debugging restriction
-     * @param message the message to log on security exception
-     */
-    private void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
-            boolean requireFullPermission, boolean checkShell, String message) {
-        mComputer.enforceCrossUserOrProfilePermission(callingUid, userId,
-                requireFullPermission, checkShell, message);
-    }
-
     public void performFstrimIfNeeded() {
         PackageManagerServiceUtils.enforceSystemOrRoot("Only the system can request fstrim");
 
@@ -3033,17 +2864,6 @@
         return mDexManager;
     }
 
-    @NonNull
-    List<PackageStateInternal> findSharedNonSystemLibraries(
-            @NonNull PackageStateInternal pkgSetting) {
-        return mComputer.findSharedNonSystemLibraries(pkgSetting);
-    }
-
-    @Nullable
-    SharedLibraryInfo getSharedLibraryInfo(String name, long version) {
-        return mComputer.getSharedLibraryInfo(name, version);
-    }
-
     public void shutdown() {
         mCompilerStats.writeNow();
         mDexManager.writePackageDexUsageNow();
@@ -3141,14 +2961,14 @@
         mPackageObserverHelper.notifyRemoved(packageName, uid);
     }
 
-    void sendPackageAddedForUser(String packageName, @NonNull PackageStateInternal packageState,
-            int userId, int dataLoaderType) {
+    void sendPackageAddedForUser(@NonNull Computer snapshot, String packageName,
+            @NonNull PackageStateInternal packageState, int userId, int dataLoaderType) {
         final PackageUserStateInternal userState = packageState.getUserStateOrDefault(userId);
         final boolean isSystem = packageState.isSystem();
         final boolean isInstantApp = userState.isInstantApp();
         final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId };
         final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY;
-        sendPackageAddedForNewUsers(packageName, isSystem /*sendBootCompleted*/,
+        sendPackageAddedForNewUsers(snapshot, packageName, isSystem /*sendBootCompleted*/,
                 false /*startReceiver*/, packageState.getAppId(), userIds, instantUserIds,
                 dataLoaderType);
 
@@ -3160,15 +2980,15 @@
     }
 
     @Override
-    public void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
-            boolean includeStopped, @AppIdInt int appId, int[] userIds, int[] instantUserIds,
-            int dataLoaderType) {
+    public void sendPackageAddedForNewUsers(@NonNull Computer snapshot, String packageName,
+            boolean sendBootCompleted, boolean includeStopped, @AppIdInt int appId, int[] userIds,
+            int[] instantUserIds, int dataLoaderType) {
         if (ArrayUtils.isEmpty(userIds) && ArrayUtils.isEmpty(instantUserIds)) {
             return;
         }
         SparseArray<int[]> broadcastAllowList = mAppsFilter.getVisibilityAllowList(
-                getPackageStateInternal(packageName, Process.SYSTEM_UID),
-                userIds, getPackageStates());
+                snapshot.getPackageStateInternal(packageName, Process.SYSTEM_UID),
+                userIds, snapshot.getPackageStates());
         mHandler.post(() -> mBroadcastHelper.sendPackageAddedForNewUsers(
                 packageName, appId, userIds, instantUserIds, dataLoaderType, broadcastAllowList));
         if (sendBootCompleted && !ArrayUtils.isEmpty(userIds)) {
@@ -3202,8 +3022,8 @@
         return false;
     }
 
-    private void enforceCanSetPackagesSuspendedAsUser(String callingPackage, int callingUid,
-            int userId, String callingMethod) {
+    private void enforceCanSetPackagesSuspendedAsUser(@NonNull Computer snapshot,
+            String callingPackage, int callingUid, int userId, String callingMethod) {
         if (callingUid == Process.ROOT_UID
                 // Need to compare app-id to allow system dialogs access on secondary users
                 || UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
@@ -3212,7 +3032,7 @@
 
         final String ownerPackage = mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(userId);
         if (ownerPackage != null) {
-            final int ownerUid = mIPackageManager.getPackageUid(ownerPackage, 0, userId);
+            final int ownerUid = snapshot.getPackageUid(ownerPackage, 0, userId);
             if (ownerUid == callingUid) {
                 return;
             }
@@ -3221,7 +3041,7 @@
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SUSPEND_APPS,
                 callingMethod);
 
-        final int packageUid = mIPackageManager.getPackageUid(callingPackage, 0, userId);
+        final int packageUid = snapshot.getPackageUid(callingPackage, 0, userId);
         final boolean allowedPackageUid = packageUid == callingUid;
         // TODO(b/139383163): remove special casing for shell and enforce INTERACT_ACROSS_USERS_FULL
         final boolean allowedShell = callingUid == SHELL_UID
@@ -3242,13 +3062,9 @@
                 allPackages, suspendingPackage::equals, userId);
     }
 
-    private boolean isSuspendingAnyPackages(String suspendingPackage, int userId) {
-        return mComputer.isSuspendingAnyPackages(suspendingPackage, userId);
-    }
-
-    void removeAllDistractingPackageRestrictions(int userId) {
-        final String[] allPackages = mComputer.getAllAvailablePackageNames();
-        removeDistractingPackageRestrictions(allPackages, userId);
+    void removeAllDistractingPackageRestrictions(@NonNull Computer snapshot, int userId) {
+        final String[] allPackages = snapshot.getAllAvailablePackageNames();
+        removeDistractingPackageRestrictions(snapshot, allPackages, userId);
     }
 
     /**
@@ -3260,11 +3076,12 @@
      * @param packagesToChange The packages on which restrictions are to be removed.
      * @param userId the user for which changes are taking place.
      */
-    private void removeDistractingPackageRestrictions(String[] packagesToChange, int userId) {
+    void removeDistractingPackageRestrictions(@NonNull Computer snapshot,
+            String[] packagesToChange, int userId) {
         final List<String> changedPackages = new ArrayList<>();
         final IntArray changedUids = new IntArray();
         for (String packageName : packagesToChange) {
-            final PackageStateInternal ps = getPackageStateInternal(packageName);
+            final PackageStateInternal ps = snapshot.getPackageStateInternal(packageName);
             if (ps != null && ps.getUserStateOrDefault(userId).getDistractionFlags() != 0) {
                 changedPackages.add(ps.getPackageName());
                 changedUids.add(UserHandle.getUid(userId, ps.getAppId()));
@@ -3287,7 +3104,7 @@
         }
     }
 
-    private void setEnableRollbackCode(int token, int enableRollbackCode) {
+    void setEnableRollbackCode(int token, int enableRollbackCode) {
         final Message msg = mHandler.obtainMessage(ENABLE_ROLLBACK_STATUS);
         msg.arg1 = token;
         msg.arg2 = enableRollbackCode;
@@ -3334,7 +3151,7 @@
             if (DEBUG_BACKUP) {
                 Slog.i(TAG, "Package " + packageName + " sending normal FIRST_LAUNCH");
             }
-            final boolean isInstantApp = isInstantAppInternal(
+            final boolean isInstantApp = snapshotComputer().isInstantAppInternal(
                     packageName, userId, Process.SYSTEM_UID);
             final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId };
             final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY;
@@ -3384,30 +3201,22 @@
                 versionedPackage, observer, userId, deleteFlags, false);
     }
 
-    private String resolveExternalPackageName(AndroidPackage pkg) {
-        return mComputer.resolveExternalPackageName(pkg);
-    }
-
-    String resolveInternalPackageName(String packageName, long versionCode) {
-        return mComputer.resolveInternalPackageName(packageName, versionCode);
-    }
-
-    boolean isCallerVerifier(int callingUid) {
+    boolean isCallerVerifier(@NonNull Computer snapshot, int callingUid) {
         final int callingUserId = UserHandle.getUserId(callingUid);
-        return mRequiredVerifierPackage != null && callingUid == mIPackageManager.getPackageUid(
+        return mRequiredVerifierPackage != null && callingUid == snapshot.getPackageUid(
                 mRequiredVerifierPackage, 0, callingUserId);
     }
 
-    public boolean isPackageDeviceAdminOnAnyUser(String packageName) {
+    public boolean isPackageDeviceAdminOnAnyUser(@NonNull Computer snapshot, String packageName) {
         final int callingUid = Binder.getCallingUid();
-        if (mIPackageManager.checkUidPermission(android.Manifest.permission.MANAGE_USERS,
-                callingUid) != PERMISSION_GRANTED) {
+        if (snapshot.checkUidPermission(android.Manifest.permission.MANAGE_USERS, callingUid)
+                != PERMISSION_GRANTED) {
             EventLog.writeEvent(0x534e4554, "128599183", -1, "");
             throw new SecurityException(android.Manifest.permission.MANAGE_USERS
                     + " permission is required to call this API");
         }
-        if (getInstantAppPackageName(callingUid) != null
-                && !isCallerSameApp(packageName, callingUid)) {
+        if (snapshot.getInstantAppPackageName(callingUid) != null
+                && !snapshot.isCallerSameApp(packageName, callingUid)) {
             return false;
         }
         return isPackageDeviceAdmin(packageName, UserHandle.USER_ALL);
@@ -3456,14 +3265,15 @@
         return mDevicePolicyManager;
     }
 
-    private boolean clearApplicationUserDataLIF(String packageName, int userId) {
+    private boolean clearApplicationUserDataLIF(@NonNull Computer snapshot, String packageName,
+            int userId) {
         if (packageName == null) {
             Slog.w(TAG, "Attempt to delete null packageName.");
             return false;
         }
 
         // Try finding details about the requested package
-        AndroidPackage pkg = getPackage(packageName);
+        AndroidPackage pkg = snapshot.getPackage(packageName);
         if (pkg == null) {
             Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
             return false;
@@ -3486,8 +3296,8 @@
         } else {
             flags = 0;
         }
-        mAppDataHelper.prepareAppDataContentsLIF(pkg, getPackageStateInternal(packageName), userId,
-                flags);
+        mAppDataHelper.prepareAppDataContentsLIF(pkg, snapshot.getPackageStateInternal(packageName),
+                userId, flags);
 
         return true;
     }
@@ -3538,10 +3348,6 @@
         }
     }
 
-    int getUidTargetSdkVersion(int uid) {
-        return mComputer.getUidTargetSdkVersion(uid);
-    }
-
     void postPreferredActivityChangedBroadcast(int userId) {
         mHandler.post(() -> mBroadcastHelper.sendPreferredActivityChangedBroadcast(userId));
     }
@@ -3562,18 +3368,19 @@
 
         // Persistent preferred activity might have came into effect due to this
         // install.
-        mPreferredActivityHelper.updateDefaultHomeNotLocked(userId);
+        mPreferredActivityHelper.updateDefaultHomeNotLocked(snapshotComputer(), userId);
     }
 
     /**
      * Variant that takes a {@link WatchedIntentFilter}
      */
-    public void addCrossProfileIntentFilter(WatchedIntentFilter intentFilter, String ownerPackage,
-            int sourceUserId, int targetUserId, int flags) {
+    public void addCrossProfileIntentFilter(@NonNull Computer snapshot,
+            WatchedIntentFilter intentFilter, String ownerPackage, int sourceUserId,
+            int targetUserId, int flags) {
         mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
         int callingUid = Binder.getCallingUid();
-        enforceOwnerRights(ownerPackage, callingUid);
+        enforceOwnerRights(snapshot, ownerPackage, callingUid);
         PackageManagerServiceUtils.enforceShellRestriction(mInjector.getUserManagerInternal(),
                 UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId);
         if (intentFilter.countActions() == 0) {
@@ -3601,18 +3408,18 @@
     }
 
     // Enforcing that callingUid is owning pkg on userId
-    private void enforceOwnerRights(String pkg, int callingUid) {
+    private void enforceOwnerRights(@NonNull Computer snapshot, String pkg, int callingUid) {
         // The system owns everything.
         if (UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
             return;
         }
-        final String[] callerPackageNames = mIPackageManager.getPackagesForUid(callingUid);
+        final String[] callerPackageNames = snapshot.getPackagesForUid(callingUid);
         if (!ArrayUtils.contains(callerPackageNames, pkg)) {
             throw new SecurityException("Calling uid " + callingUid
                     + " does not own package " + pkg);
         }
         final int callingUserId = UserHandle.getUserId(callingUid);
-        PackageInfo pi = mIPackageManager.getPackageInfo(pkg, 0, callingUserId);
+        PackageInfo pi = snapshot.getPackageInfo(pkg, 0, callingUserId);
         if (pi == null) {
             throw new IllegalArgumentException("Unknown package " + pkg + " on user "
                     + callingUserId);
@@ -3626,29 +3433,13 @@
         }
         final UserInfo parent = ums.getProfileParent(userId);
         final int launcherUid = (parent != null) ? parent.id : userId;
-        final ComponentName launcherComponent = getDefaultHomeActivity(launcherUid);
+        // TODO: Should this snapshot be moved further up?
+        final ComponentName launcherComponent = snapshotComputer()
+                .getDefaultHomeActivity(launcherUid);
         mBroadcastHelper.sendSessionCommitBroadcast(sessionInfo, userId, launcherUid,
                 launcherComponent, mAppPredictionServicePackage);
     }
 
-    /**
-     * Report the 'Home' activity which is currently set as "always use this one". If non is set
-     * then reports the most likely home activity or null if there are more than one.
-     */
-    private ComponentName getDefaultHomeActivity(int userId) {
-        return mComputer.getDefaultHomeActivity(userId);
-    }
-
-    Intent getHomeIntent() {
-        return mComputer.getHomeIntent();
-    }
-
-    ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
-            int userId) {
-        return mComputer.getHomeActivitiesAsUser(allHomeCandidates,
-                userId);
-    }
-
     private @Nullable String getSetupWizardPackageNameImpl(@NonNull Computer computer) {
         final Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.addCategory(Intent.CATEGORY_SETUP_WIZARD);
@@ -3682,10 +3473,11 @@
         }
     }
 
-    private @NonNull String getRequiredSdkSandboxPackageName() {
+    @NonNull
+    private static String getRequiredSdkSandboxPackageName(@NonNull Computer computer) {
         final Intent intent = new Intent(SdkSandboxManagerLocal.SERVICE_INTERFACE);
 
-        final List<ResolveInfo> matches = queryIntentServicesInternal(
+        final List<ResolveInfo> matches = computer.queryIntentServicesInternal(
                 intent,
                 /* resolvedType= */ null,
                 MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
@@ -3701,22 +3493,6 @@
     }
 
     @Nullable
-    private String getDeviceConfiguratorPackageName() {
-        return ensureSystemPackageName(mContext.getString(
-                R.string.config_deviceConfiguratorPackageName));
-    }
-
-    public @Nullable String getAmbientContextDetectionPackageName() {
-        return ensureSystemPackageName(getPackageFromComponentString(
-                        R.string.config_defaultAmbientContextDetectionService));
-    }
-
-    public String getOverlayConfigSignaturePackageName() {
-        return ensureSystemPackageName(mInjector.getSystemConfig()
-                .getOverlayConfigSignaturePackage());
-    }
-
-    @Nullable
     private String getRetailDemoPackageName() {
         final String predefinedPkgName = mContext.getString(R.string.config_retailDemoPackage);
         final String predefinedSignature = mContext.getString(
@@ -3752,14 +3528,7 @@
     }
 
     @Nullable
-    private String getRecentsPackageName() {
-        return ensureSystemPackageName(
-                getPackageFromComponentString(R.string.config_recentsComponentName));
-
-    }
-
-    @Nullable
-    private String getPackageFromComponentString(@StringRes int stringResId) {
+    String getPackageFromComponentString(@StringRes int stringResId) {
         final String componentString = mContext.getString(stringResId);
         if (TextUtils.isEmpty(componentString)) {
             return null;
@@ -3772,16 +3541,17 @@
     }
 
     @Nullable
-    private String ensureSystemPackageName(@Nullable String packageName) {
+    String ensureSystemPackageName(@NonNull Computer snapshot,
+            @Nullable String packageName) {
         if (packageName == null) {
             return null;
         }
         final long token = Binder.clearCallingIdentity();
         try {
-            if (mIPackageManager.getPackageInfo(packageName, MATCH_FACTORY_ONLY,
+            if (snapshot.getPackageInfo(packageName, MATCH_FACTORY_ONLY,
                     UserHandle.USER_SYSTEM) == null) {
                 PackageInfo packageInfo =
-                        mIPackageManager.getPackageInfo(packageName, 0, UserHandle.USER_SYSTEM);
+                        snapshot.getPackageInfo(packageName, 0, UserHandle.USER_SYSTEM);
                 if (packageInfo != null) {
                     EventLog.writeEvent(0x534e4554, "145981139", packageInfo.applicationInfo.uid,
                             "");
@@ -3863,8 +3633,10 @@
     private void setEnabledSettings(List<ComponentEnabledSetting> settings, int userId,
             String callingPackage) {
         final int callingUid = Binder.getCallingUid();
-        enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
-                true /* checkShell */, "set enabled");
+        // TODO: This method is not properly snapshotified beyond this call
+        final Computer preLockSnapshot = snapshotComputer();
+        preLockSnapshot.enforceCrossUserPermission(callingUid, userId,
+                false /* requireFullPermission */, true /* checkShell */, "set enabled");
 
         final int targetSize = settings.size();
         for (int i = 0; i < targetSize; i++) {
@@ -3920,6 +3692,7 @@
         final Map<String, PackageSetting> pkgSettings = new ArrayMap<>(targetSize);
         // reader
         synchronized (mLock) {
+            final Computer snapshot = snapshotComputer();
             // Checks for target packages
             for (int i = 0; i < targetSize; i++) {
                 final ComponentEnabledSetting setting = settings.get(i);
@@ -3929,13 +3702,13 @@
                     continue;
                 }
                 final boolean isCallerTargetApp = ArrayUtils.contains(
-                        mIPackageManager.getPackagesForUid(callingUid), packageName);
+                        snapshot.getPackagesForUid(callingUid), packageName);
                 final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName);
                 // Limit who can change which apps
                 if (!isCallerTargetApp) {
                     // Don't allow apps that don't have permission to modify other apps
                     if (!allowedByPermission
-                            || shouldFilterApplication(pkgSetting, callingUid, userId)) {
+                            || snapshot.shouldFilterApplication(pkgSetting, callingUid, userId)) {
                         throw new SecurityException("Attempt to change component state; "
                                 + "pid=" + Binder.getCallingPid()
                                 + ", uid=" + callingUid
@@ -4108,12 +3881,13 @@
 
         final long callingId = Binder.clearCallingIdentity();
         try {
+            final Computer newSnapshot = snapshotComputer();
             for (int i = 0; i < sendNowBroadcasts.size(); i++) {
                 final String packageName = sendNowBroadcasts.keyAt(i);
                 final ArrayList<String> components = sendNowBroadcasts.valueAt(i);
                 final int packageUid = UserHandle.getUid(
                         userId, pkgSettings.get(packageName).getAppId());
-                sendPackageChangedBroadcast(packageName, false /* dontKillApp */,
+                sendPackageChangedBroadcast(newSnapshot, packageName, false /* dontKillApp */,
                         components, packageUid, null /* reason */);
             }
         } finally {
@@ -4137,13 +3911,13 @@
             pkgSetting.setEnabled(newState, userId, callingPackage);
             if ((newState == COMPONENT_ENABLED_STATE_DISABLED_USER
                     || newState == COMPONENT_ENABLED_STATE_DISABLED)
-                    && mIPackageManager.checkPermission(Manifest.permission.SUSPEND_APPS,
-                    packageName, userId) == PERMISSION_GRANTED) {
+                    && checkPermission(Manifest.permission.SUSPEND_APPS, packageName, userId)
+                    == PERMISSION_GRANTED) {
                 // This app should not generally be allowed to get disabled by the UI, but
                 // if it ever does, we don't want to end up with some of the user's apps
                 // permanently suspended.
                 unsuspendForSuspendingPackage(computer, packageName, userId);
-                removeAllDistractingPackageRestrictions(userId);
+                removeAllDistractingPackageRestrictions(computer, userId);
             }
             success = true;
         } else {
@@ -4194,25 +3968,20 @@
         }
     }
 
-    void sendPackageChangedBroadcast(String packageName,
+    void sendPackageChangedBroadcast(@NonNull Computer snapshot, String packageName,
             boolean dontKillApp, ArrayList<String> componentNames, int packageUid, String reason) {
         final int userId = UserHandle.getUserId(packageUid);
-        final boolean isInstantApp = isInstantAppInternal(packageName, userId, Process.SYSTEM_UID);
+        final boolean isInstantApp =
+                snapshot.isInstantAppInternal(packageName, userId, Process.SYSTEM_UID);
         final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId };
         final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY;
-        final SparseArray<int[]> broadcastAllowList = getBroadcastAllowList(
+        final SparseArray<int[]> broadcastAllowList = snapshot.getBroadcastAllowList(
                 packageName, userIds, isInstantApp);
         mHandler.post(() -> mBroadcastHelper.sendPackageChangedBroadcast(
                 packageName, dontKillApp, componentNames, packageUid, reason, userIds,
                 instantUserIds, broadcastAllowList));
     }
 
-    @Nullable
-    private SparseArray<int[]> getBroadcastAllowList(@NonNull String packageName,
-            @UserIdInt int[] userIds, boolean isInstantApp) {
-        return mComputer.getBroadcastAllowList(packageName, userIds, isInstantApp);
-    }
-
     /**
      * Used by SystemServer
      */
@@ -4296,7 +4065,7 @@
 
         // Now that we're mostly running, clean up stale users and apps
         mUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
-        storageEventHelper.reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);
+        storageEventHelper.reconcileApps(snapshotComputer(), StorageManager.UUID_PRIVATE_INTERNAL);
 
         mPermissionManager.onSystemReady();
 
@@ -4308,7 +4077,7 @@
         final int livingUserCount = livingUsers.size();
         for (int i = 0; i < livingUserCount; i++) {
             final int userId = livingUsers.get(i).id;
-            if (mPmInternal.isPermissionUpgradeNeeded(userId)) {
+            if (mSettings.isPermissionUpgradeNeeded(userId)) {
                 grantPermissionsUserIds = ArrayUtils.appendInt(
                         grantPermissionsUserIds, userId);
             }
@@ -4350,11 +4119,12 @@
                 if (packageName == null) {
                     return;
                 }
-                AndroidPackage pkg = mPackages.get(packageName);
+                final Computer snapshot = snapshotComputer();
+                AndroidPackage pkg = snapshot.getPackage(packageName);
                 if (pkg == null) {
                     return;
                 }
-                sendPackageChangedBroadcast(pkg.getPackageName(),
+                sendPackageChangedBroadcast(snapshot, pkg.getPackageName(),
                         true /* dontKillApp */,
                         new ArrayList<>(Collections.singletonList(pkg.getPackageName())),
                         pkg.getUid(),
@@ -4407,14 +4177,6 @@
         mSnapshotStatistics.dump(pw, "  ", now, hits, -1, isBrief);
     }
 
-    /**
-     * Dump package manager states to the file according to a given dumping type of
-     * {@link DumpState}.
-     */
-    void dumpComputer(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
-        mComputer.dump(type, fd, pw, dumpState);
-    }
-
     //TODO: b/111402650
     private void disableSkuSpecificApps() {
         String[] apkList = mContext.getResources().getStringArray(
@@ -4428,10 +4190,11 @@
         if (!TextUtils.isEmpty(sku) && ArrayUtils.contains(skuArray, sku)) {
             return;
         }
+        final Computer snapshot = snapshotComputer();
         for (String packageName : apkList) {
-            mIPackageManager.setSystemAppHiddenUntilInstalled(packageName, true);
+            setSystemAppHiddenUntilInstalled(snapshot, packageName, true);
             for (UserInfo user : mInjector.getUserManagerInternal().getUsers(false)) {
-                mIPackageManager.setSystemAppInstallState(packageName, false, user.id);
+                setSystemAppInstallState(snapshot, packageName, false, user.id);
             }
         }
     }
@@ -4524,7 +4287,7 @@
             mPermissionManager.writeLegacyPermissionStateTEMP();
             mSettings.readPermissionStateForUserSyncLPr(userId);
             mPermissionManager.readLegacyPermissionStateTEMP();
-            return mPmInternal.isPermissionUpgradeNeeded(userId);
+            return mSettings.isPermissionUpgradeNeeded(userId);
         }
     }
 
@@ -4544,12 +4307,8 @@
         }
     }
 
-    boolean userNeedsBadging(int userId) {
-        return mUserNeedsBadging.get(userId);
-    }
-
-    private void deletePackageIfUnused(final String packageName) {
-        PackageStateInternal ps = getPackageStateInternal(packageName);
+    private void deletePackageIfUnused(@NonNull Computer snapshot, final String packageName) {
+        PackageStateInternal ps = snapshot.getPackageStateInternal(packageName);
         if (ps == null) {
             return;
         }
@@ -4567,41 +4326,101 @@
                 0, PackageManager.DELETE_ALL_USERS, true /*removedBySystem*/));
     }
 
-    private AndroidPackage getPackage(String packageName) {
-        return mComputer.getPackage(packageName);
+    void deletePreloadsFileCache() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CLEAR_APP_CACHE,
+                "deletePreloadsFileCache");
+        File dir = Environment.getDataPreloadsFileCacheDirectory();
+        Slog.i(PackageManagerService.TAG, "Deleting preloaded file cache " + dir);
+        FileUtils.deleteContents(dir);
     }
 
-    private AndroidPackage getPackage(int uid) {
-        return mComputer.getPackage(uid);
+    void setSystemAppHiddenUntilInstalled(@NonNull Computer snapshot, String packageName,
+            boolean hidden) {
+        final int callingUid = Binder.getCallingUid();
+        final boolean calledFromSystemOrPhone = callingUid == Process.PHONE_UID
+                || callingUid == Process.SYSTEM_UID;
+        if (!calledFromSystemOrPhone) {
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
+                    "setSystemAppHiddenUntilInstalled");
+        }
+
+        final PackageStateInternal stateRead = snapshot.getPackageStateInternal(packageName);
+        if (stateRead == null || !stateRead.isSystem() || stateRead.getPkg() == null) {
+            return;
+        }
+        if (stateRead.getPkg().isCoreApp() && !calledFromSystemOrPhone) {
+            throw new SecurityException("Only system or phone callers can modify core apps");
+        }
+
+        commitPackageStateMutation(null, mutator -> {
+            mutator.forPackage(packageName)
+                    .setHiddenUntilInstalled(hidden);
+            mutator.forDisabledSystemPackage(packageName)
+                    .setHiddenUntilInstalled(hidden);
+        });
     }
 
-    private SigningDetails getSigningDetails(@NonNull String packageName) {
-        return mComputer.getSigningDetails(packageName);
+    boolean setSystemAppInstallState(@NonNull Computer snapshot, String packageName,
+            boolean installed, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        final boolean calledFromSystemOrPhone = callingUid == Process.PHONE_UID
+                || callingUid == Process.SYSTEM_UID;
+        if (!calledFromSystemOrPhone) {
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
+                    "setSystemAppHiddenUntilInstalled");
+        }
+
+        final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
+        // The target app should always be in system
+        if (packageState == null || !packageState.isSystem() || packageState.getPkg() == null) {
+            return false;
+        }
+        if (packageState.getPkg().isCoreApp() && !calledFromSystemOrPhone) {
+            throw new SecurityException("Only system or phone callers can modify core apps");
+        }
+        // Check if the install state is the same
+        if (packageState.getUserStateOrDefault(userId).isInstalled() == installed) {
+            return false;
+        }
+
+        final long callingId = Binder.clearCallingIdentity();
+        try {
+            if (installed) {
+                // install the app from uninstalled state
+                mInstallPackageHelper.installExistingPackageAsUser(
+                        packageName,
+                        userId,
+                        PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
+                        PackageManager.INSTALL_REASON_DEVICE_SETUP,
+                        null,
+                        null);
+                return true;
+            }
+
+            // uninstall the app from installed state
+            deletePackageVersioned(
+                    new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),
+                    new PackageManager.LegacyPackageDeleteObserver(null).getBinder(),
+                    userId,
+                    PackageManager.DELETE_SYSTEM_APP);
+            return true;
+        } finally {
+            Binder.restoreCallingIdentity(callingId);
+        }
     }
 
-    private SigningDetails getSigningDetails(int uid) {
-        return mComputer.getSigningDetails(uid);
-    }
+    void finishPackageInstall(int token, boolean didLaunch) {
+        PackageManagerServiceUtils.enforceSystemOrRoot(
+                "Only the system is allowed to finish installs");
 
-    private boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
-        return mComputer.filterAppAccess(pkg, callingUid, userId);
-    }
+        if (PackageManagerService.DEBUG_INSTALL) {
+            Slog.v(PackageManagerService.TAG, "BM finishing package install for " + token);
+        }
+        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
 
-    private boolean filterAppAccess(String packageName, int callingUid, int userId) {
-        return mComputer.filterAppAccess(packageName, callingUid, userId);
-    }
-
-    private boolean filterAppAccess(int uid, int callingUid) {
-        return mComputer.filterAppAccess(uid, callingUid);
-    }
-
-    @Nullable
-    private int[] getVisibilityAllowList(@NonNull String packageName, @UserIdInt int userId) {
-        return mComputer.getVisibilityAllowList(packageName, userId);
-    }
-
-    boolean canQueryPackage(int callingUid, @Nullable String targetPackageName) {
-        return mComputer.canQueryPackage(callingUid, targetPackageName);
+        final Message msg = mHandler.obtainMessage(PackageManagerService.POST_INSTALL, token,
+                didLaunch ? 1 : 0);
+        mHandler.sendMessage(msg);
     }
 
     void checkPackageStartable(@NonNull Computer snapshot, @NonNull String packageName,
@@ -4689,71 +4508,15 @@
         }
     }
 
-    public class IPackageManagerImpl extends IPackageManager.Stub {
+    public class IPackageManagerImpl extends IPackageManagerBase {
 
-        @Override
-        public boolean activitySupportsIntent(ComponentName component, Intent intent,
-                String resolvedType) {
-            return mComputer.activitySupportsIntent(mResolveComponentName, component, intent,
-                    resolvedType);
-        }
-
-        @Override
-        public void addCrossProfileIntentFilter(IntentFilter intentFilter, String ownerPackage,
-                int sourceUserId, int targetUserId, int flags) {
-            PackageManagerService.this.addCrossProfileIntentFilter(
-                    new WatchedIntentFilter(intentFilter), ownerPackage, sourceUserId, targetUserId,
-                    flags);
-        }
-
-        // NOTE: Can't remove due to unsupported app usage
-        @Override
-        public boolean addPermission(PermissionInfo info) {
-            // Because this is accessed via the package manager service AIDL,
-            // go through the permission manager service AIDL
-            return mContext.getSystemService(PermissionManager.class).addPermission(info, false);
-        }
-
-        // NOTE: Can't remove due to unsupported app usage
-        @Override
-        public boolean addPermissionAsync(PermissionInfo info) {
-            // Because this is accessed via the package manager service AIDL,
-            // go through the permission manager service AIDL
-            return mContext.getSystemService(PermissionManager.class).addPermission(info, true);
-        }
-
-        @Override
-        public void addPersistentPreferredActivity(IntentFilter filter, ComponentName activity,
-                int userId) {
-            mPreferredActivityHelper.addPersistentPreferredActivity(new WatchedIntentFilter(filter),
-                    activity, userId);
-        }
-
-        @Override
-        public void addPreferredActivity(IntentFilter filter, int match,
-                ComponentName[] set, ComponentName activity, int userId, boolean removeExisting) {
-            mPreferredActivityHelper.addPreferredActivity(new WatchedIntentFilter(filter), match,
-                    set, activity, true, userId, "Adding preferred", removeExisting);
-        }
-
-        /*
-         * Returns if intent can be forwarded from the sourceUserId to the targetUserId
-         */
-        @Override
-        public boolean canForwardTo(@NonNull Intent intent, @Nullable String resolvedType,
-                @UserIdInt int sourceUserId, @UserIdInt int targetUserId) {
-            return mComputer.canForwardTo(intent, resolvedType, sourceUserId, targetUserId);
-        }
-
-        @Override
-        public boolean canRequestPackageInstalls(String packageName, int userId) {
-            return mComputer.canRequestPackageInstalls(packageName, Binder.getCallingUid(), userId,
-                    true /* throwIfPermNotDeclared*/);
-        }
-
-        @Override
-        public String[] canonicalToCurrentPackageNames(String[] names) {
-            return mComputer.canonicalToCurrentPackageNames(names);
+        public IPackageManagerImpl() {
+            super(PackageManagerService.this, mContext, mDexOptHelper, mModuleInfoProvider,
+                    mPreferredActivityHelper, mResolveIntentHelper, mDomainVerificationManager,
+                    mDomainVerificationConnection, mInstallerService, mPackageProperty,
+                    mResolveComponentName, mInstantAppResolverSettingsComponent,
+                    mRequiredSdkSandboxPackage, mServicesExtensionPackageName,
+                    mSharedSystemSharedLibraryPackageName);
         }
 
         @Override
@@ -4762,33 +4525,13 @@
                     .checkPackageStartable(snapshotComputer(), packageName, userId);
         }
 
-        // NOTE: Can't remove due to unsupported app usage
-        @Override
-        public int checkPermission(String permName, String pkgName, int userId) {
-            return PackageManagerService.this.checkPermission(permName, pkgName, userId);
-        }
-
-        @Override
-        public int checkSignatures(@NonNull String pkg1, @NonNull String pkg2) {
-            return mComputer.checkSignatures(pkg1, pkg2);
-        }
-
-        @Override
-        public int checkUidPermission(String permName, int uid) {
-            return mComputer.checkUidPermission(permName, uid);
-        }
-
-        @Override
-        public int checkUidSignatures(int uid1, int uid2) {
-            return mComputer.checkUidSignatures(uid1, uid2);
-        }
-
         @Override
         public void clearApplicationProfileData(String packageName) {
             PackageManagerServiceUtils.enforceSystemOrRoot(
                     "Only the system can clear all profile data");
 
-            final AndroidPackage pkg = getPackage(packageName);
+            final Computer snapshot = snapshotComputer();
+            final AndroidPackage pkg = snapshot.getPackage(packageName);
             try (PackageFreezer ignored = freezePackage(packageName, "clearApplicationProfileData")) {
                 synchronized (mInstallLock) {
                     mAppDataHelper.clearAppProfilesLIF(pkg);
@@ -4803,10 +4546,11 @@
                     android.Manifest.permission.CLEAR_APP_USER_DATA, null);
 
             final int callingUid = Binder.getCallingUid();
-            enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
+            final Computer snapshot = snapshotComputer();
+            snapshot.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
                     false /* checkShell */, "clear application data");
 
-            if (mComputer.getPackageStateFiltered(packageName, callingUid, userId) == null) {
+            if (snapshot.getPackageStateFiltered(packageName, callingUid, userId) == null) {
                 if (observer != null) {
                     mHandler.post(() -> {
                         try {
@@ -4831,7 +4575,8 @@
                     try (PackageFreezer freezer = freezePackage(packageName,
                             "clearApplicationUserData")) {
                         synchronized (mInstallLock) {
-                            succeeded = clearApplicationUserDataLIF(packageName, userId);
+                            succeeded = clearApplicationUserDataLIF(snapshotComputer(), packageName,
+                                    userId);
                         }
                         mInstantAppRegistry.deleteInstantApplicationMetadata(packageName, userId);
                         synchronized (mLock) {
@@ -4849,8 +4594,9 @@
                         }
                         if (checkPermission(Manifest.permission.SUSPEND_APPS, packageName, userId)
                                 == PERMISSION_GRANTED) {
-                            unsuspendForSuspendingPackage(snapshotComputer(), packageName, userId);
-                            removeAllDistractingPackageRestrictions(userId);
+                            final Computer snapshot = snapshotComputer();
+                            unsuspendForSuspendingPackage(snapshot, packageName, userId);
+                            removeAllDistractingPackageRestrictions(snapshot, userId);
                             flushPackageRestrictionsAsUserInternalLocked(userId);
                         }
                     }
@@ -4870,7 +4616,8 @@
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
             final int callingUid = Binder.getCallingUid();
-            enforceOwnerRights(ownerPackage, callingUid);
+            final Computer snapshot = snapshotComputer();
+            enforceOwnerRights(snapshot, ownerPackage, callingUid);
             PackageManagerServiceUtils.enforceShellRestriction(mInjector.getUserManagerInternal(),
                     UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId);
             synchronized (mLock) {
@@ -4888,22 +4635,7 @@
         }
 
         @Override
-        public void clearPackagePersistentPreferredActivities(String packageName, int userId) {
-            mPreferredActivityHelper.clearPackagePersistentPreferredActivities(packageName, userId);
-        }
-
-        @Override
-        public void clearPackagePreferredActivities(String packageName) {
-            mPreferredActivityHelper.clearPackagePreferredActivities(packageName);
-        }
-
-        @Override
-        public String[] currentToCanonicalPackageNames(String[] names) {
-            return mComputer.currentToCanonicalPackageNames(names);
-        }
-
-        @Override
-        public void deleteApplicationCacheFiles(final String packageName,
+        public final void deleteApplicationCacheFiles(final String packageName,
                 final IPackageDataObserver observer) {
             final int userId = UserHandle.getCallingUserId();
             deleteApplicationCacheFilesAsUser(packageName, userId, observer);
@@ -4928,17 +4660,18 @@
                 mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.INTERNAL_DELETE_CACHE_FILES, null);
             }
-            enforceCrossUserPermission(callingUid, userId, /* requireFullPermission= */ true,
+            final Computer snapshot = snapshotComputer();
+            snapshot.enforceCrossUserPermission(callingUid, userId, /* requireFullPermission= */ true,
                     /* checkShell= */ false, "delete application cache files");
             final int hasAccessInstantApps = mContext.checkCallingOrSelfPermission(
                     android.Manifest.permission.ACCESS_INSTANT_APPS);
 
-            final AndroidPackage pkg = getPackage(packageName);
-
             // Queue up an async operation since the package deletion may take a little while.
             mHandler.post(() -> {
-                final PackageStateInternal ps =
-                        pkg == null ? null : getPackageStateInternal(pkg.getPackageName());
+                // Snapshot in the Handler Runnable since this may be deferred quite a bit
+                // TODO: Is this and the later mInstallLock re-snapshot necessary?
+                final Computer newSnapshot = snapshotComputer();
+                final PackageStateInternal ps = newSnapshot.getPackageStateInternal(packageName);
                 boolean doClearData = true;
                 if (ps != null) {
                     final boolean targetIsInstantApp =
@@ -4949,6 +4682,8 @@
                 if (doClearData) {
                     synchronized (mInstallLock) {
                         final int flags = FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL;
+                        // Snapshot again after mInstallLock?
+                        final AndroidPackage pkg = snapshotComputer().getPackage(packageName);
                         // We're only clearing cache files, so we don't care if the
                         // app is unfrozen and still able to run
                         mAppDataHelper.clearAppDataLIF(pkg, userId,
@@ -4968,47 +4703,18 @@
         }
 
         @Override
-        public void deleteExistingPackageAsUser(VersionedPackage versionedPackage,
-                final IPackageDeleteObserver2 observer, final int userId) {
-            PackageManagerService.this.deleteExistingPackageAsUser(versionedPackage, observer,
-                    userId);
-        }
-
-        @Override
-        public void deletePackageAsUser(String packageName, int versionCode,
-                IPackageDeleteObserver observer, int userId, int flags) {
-            deletePackageVersioned(new VersionedPackage(packageName, versionCode),
-                    new PackageManager.LegacyPackageDeleteObserver(observer).getBinder(), userId, flags);
-        }
-
-        @Override
-        public void deletePackageVersioned(VersionedPackage versionedPackage,
-                final IPackageDeleteObserver2 observer, final int userId, final int deleteFlags) {
-            PackageManagerService.this.deletePackageVersioned(versionedPackage, observer,
-                    userId, deleteFlags);
-        }
-
-        @Override
-        public void deletePreloadsFileCache() {
-            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CLEAR_APP_CACHE,
-                    "deletePreloadsFileCache");
-            File dir = Environment.getDataPreloadsFileCacheDirectory();
-            Slog.i(PackageManagerService.TAG, "Deleting preloaded file cache " + dir);
-            FileUtils.deleteContents(dir);
-        }
-
-        @Override
         public void dumpProfiles(String packageName) {
             /* Only the shell, root, or the app user should be able to dump profiles. */
             final int callingUid = Binder.getCallingUid();
-            final String[] callerPackageNames = getPackagesForUid(callingUid);
+            final Computer snapshot = snapshotComputer();
+            final String[] callerPackageNames = snapshot.getPackagesForUid(callingUid);
             if (callingUid != Process.SHELL_UID
                     && callingUid != Process.ROOT_UID
                     && !ArrayUtils.contains(callerPackageNames, packageName)) {
                 throw new SecurityException("dumpProfiles");
             }
 
-            AndroidPackage pkg = mComputer.getPackage(packageName);
+            AndroidPackage pkg = snapshot.getPackage(packageName);
             if (pkg == null) {
                 throw new IllegalArgumentException("Unknown package: " + packageName);
             }
@@ -5062,46 +4768,25 @@
             });
         }
 
-        @Override
-        public ResolveInfo findPersistentPreferredActivity(Intent intent, int userId) {
-            return mPreferredActivityHelper.findPersistentPreferredActivity(intent, userId);
-        }
-
-        @Override
-        public void finishPackageInstall(int token, boolean didLaunch) {
-            PackageManagerServiceUtils.enforceSystemOrRoot(
-                    "Only the system is allowed to finish installs");
-
-            if (PackageManagerService.DEBUG_INSTALL) {
-                Slog.v(PackageManagerService.TAG, "BM finishing package install for " + token);
-            }
-            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
-
-            final Message msg = mHandler.obtainMessage(PackageManagerService.POST_INSTALL, token, didLaunch ? 1 : 0);
-            mHandler.sendMessage(msg);
-        }
-
         @WorkerThread
         @Override
         public void flushPackageRestrictionsAsUser(int userId) {
-            if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
+            final Computer snapshot = snapshotComputer();
+            final int callingUid = Binder.getCallingUid();
+            if (snapshot.getInstantAppPackageName(callingUid) != null) {
                 return;
             }
             if (!mUserManager.exists(userId)) {
                 return;
             }
-            enforceCrossUserPermission(Binder.getCallingUid(), userId, false /* requireFullPermission*/,
-                    false /* checkShell */, "flushPackageRestrictions");
+            snapshot.enforceCrossUserPermission(callingUid, userId,
+                    false /* requireFullPermission*/, false /* checkShell */,
+                    "flushPackageRestrictions");
             synchronized (mLock) {
                 flushPackageRestrictionsAsUserInternalLocked(userId);
             }
         }
 
-        @Override
-        public void forceDexOpt(String packageName) {
-            mDexOptHelper.forceDexOpt(packageName);
-        }
-
 
         @Override
         public void freeStorage(final String volumeUuid, final long freeStorageSize,
@@ -5150,83 +4835,17 @@
         }
 
         @Override
-        public ActivityInfo getActivityInfo(ComponentName component,
-                @PackageManager.ComponentInfoFlagsBits long flags, int userId) {
-            return mComputer.getActivityInfo(component, flags, userId);
-        }
-
-        @NonNull
-        @Override
-        public ParceledListSlice<IntentFilter> getAllIntentFilters(@NonNull String packageName) {
-            return mComputer.getAllIntentFilters(packageName);
-        }
-
-        @Override
-        public List<String> getAllPackages() {
-            return mComputer.getAllPackages();
-        }
-
-        // NOTE: Can't remove due to unsupported app usage
-        @NonNull
-        @Override
-        public String[] getAppOpPermissionPackages(@NonNull String permissionName) {
-            return mComputer.getAppOpPermissionPackages(permissionName);
-        }
-
-        @Override
-        public String getAppPredictionServicePackageName() {
-            return ensureSystemPackageName(
-                    getPackageFromComponentString(R.string.config_defaultAppPredictionService));
-        }
-
-        @PackageManager.EnabledState
-        @Override
-        public int getApplicationEnabledSetting(@NonNull String packageName, @UserIdInt int userId) {
-            return mComputer.getApplicationEnabledSetting(packageName, userId);
-        }
-
-        /**
-         * Returns true if application is not found or there was an error. Otherwise it returns
-         * the hidden state of the package for the given user.
-         */
-        @Override
-        public boolean getApplicationHiddenSettingAsUser(@NonNull String packageName,
-                @UserIdInt int userId) {
-            return mComputer.getApplicationHiddenSettingAsUser(packageName, userId);
-        }
-
-        @Override
-        public ApplicationInfo getApplicationInfo(String packageName,
-                @PackageManager.ApplicationInfoFlagsBits long flags, int userId) {
-            return mComputer.getApplicationInfo(packageName, flags, userId);
-        }
-
-        @Override
-        public IArtManager getArtManager() {
-            return mArtManagerService;
-        }
-
-        @Override
-        public @Nullable String getAttentionServicePackageName() {
-            return ensureSystemPackageName(
-                    getPackageFromComponentString(R.string.config_defaultAttentionService));
-        }
-
-        @Override
-        public boolean getBlockUninstallForUser(@NonNull String packageName, @UserIdInt int userId) {
-            return mComputer.getBlockUninstallForUser(packageName, userId);
-        }
-
-        @Override
         public ChangedPackages getChangedPackages(int sequenceNumber, int userId) {
             final int callingUid = Binder.getCallingUid();
-            if (getInstantAppPackageName(callingUid) != null) {
+            final Computer snapshot = snapshotComputer();
+            if (snapshot.getInstantAppPackageName(callingUid) != null) {
                 return null;
             }
             if (!mUserManager.exists(userId)) {
                 return null;
             }
-            enforceCrossUserPermission(callingUid, userId, false, false, "getChangedPackages");
+            snapshot.enforceCrossUserPermission(callingUid, userId, false, false,
+                    "getChangedPackages");
             final ChangedPackages changedPackages = mChangedPackagesTracker.getChangedPackages(
                     sequenceNumber, userId);
 
@@ -5234,8 +4853,9 @@
                 final List<String> packageNames = changedPackages.getPackageNames();
                 for (int index = packageNames.size() - 1; index >= 0; index--) {
                     // Filter out the changes if the calling package should not be able to see it.
-                    final PackageSetting ps = mSettings.getPackageLPr(packageNames.get(index));
-                    if (shouldFilterApplication(ps, callingUid, userId)) {
+                    final PackageStateInternal packageState =
+                            snapshot.getPackageStateInternal(packageNames.get(index));
+                    if (snapshot.shouldFilterApplication(packageState, callingUid, userId)) {
                         packageNames.remove(index);
                     }
                 }
@@ -5245,41 +4865,6 @@
         }
 
         @Override
-        public int getComponentEnabledSetting(@NonNull ComponentName component, int userId) {
-            return mComputer.getComponentEnabledSetting(component, Binder.getCallingUid(), userId);
-        }
-
-        @Override
-        public String getContentCaptureServicePackageName() {
-            return ensureSystemPackageName(
-                    getPackageFromComponentString(R.string.config_defaultContentCaptureService));
-        }
-
-        @Nullable
-        @Override
-        public ParceledListSlice<SharedLibraryInfo> getDeclaredSharedLibraries(
-                @NonNull String packageName, @PackageManager.PackageInfoFlagsBits long flags,
-                @NonNull int userId) {
-            return mComputer.getDeclaredSharedLibraries(packageName, flags, userId);
-        }
-
-        /**
-         * Non-Binder method, support for the backup/restore mechanism: write the
-         * default browser (etc) settings in its canonical XML format.  Returns the default
-         * browser XML representation as a byte array, or null if there is none.
-         */
-        @Override
-        public byte[] getDefaultAppsBackup(int userId) {
-            return mPreferredActivityHelper.getDefaultAppsBackup(userId);
-        }
-
-        @Override
-        public String getDefaultTextClassifierPackageName() {
-            return ensureSystemPackageName(
-                    mContext.getString(R.string.config_servicesExtensionPackage));
-        }
-
-        @Override
         public byte[] getDomainVerificationBackup(int userId) {
             if (Binder.getCallingUid() != Process.SYSTEM_UID) {
                 throw new SecurityException("Only the system may call getDomainVerificationBackup()");
@@ -5301,17 +4886,6 @@
         }
 
         @Override
-        public int getFlagsForUid(int uid) {
-            return mComputer.getFlagsForUid(uid);
-        }
-
-        @Nullable
-        @Override
-        public CharSequence getHarmfulAppWarning(@NonNull String packageName, @UserIdInt int userId) {
-            return mComputer.getHarmfulAppWarning(packageName, userId);
-        }
-
-        @Override
         public IBinder getHoldLockToken() {
             if (!Build.IS_DEBUGGABLE) {
                 throw new SecurityException("getHoldLockToken requires a debuggable build");
@@ -5327,72 +4901,15 @@
         }
 
         @Override
-        public ComponentName getHomeActivities(List<ResolveInfo> allHomeCandidates) {
-            if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
-                return null;
-            }
-            return getHomeActivitiesAsUser(allHomeCandidates, UserHandle.getCallingUserId());
-        }
-
-        public String getIncidentReportApproverPackageName() {
-            return ensureSystemPackageName(mContext.getString(
-                    R.string.config_incidentReportApproverPackage));
-        }
-
-        @Override
-        public int getInstallLocation() {
-            // allow instant app access
-            return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
-                    android.provider.Settings.Global.DEFAULT_INSTALL_LOCATION,
-                    InstallLocationUtils.APP_INSTALL_AUTO);
-        }
-
-        @PackageManager.InstallReason
-        @Override
-        public int getInstallReason(@NonNull String packageName, @UserIdInt int userId) {
-            return mComputer.getInstallReason(packageName, userId);
-        }
-
-        @Override
-        @Nullable
-        public InstallSourceInfo getInstallSourceInfo(@NonNull String packageName) {
-            return mComputer.getInstallSourceInfo(packageName);
-        }
-
-        @Override
-        public ParceledListSlice<ApplicationInfo> getInstalledApplications(
-                @PackageManager.ApplicationInfoFlagsBits long flags, int userId) {
-            final int callingUid = Binder.getCallingUid();
-            return new ParceledListSlice<>(
-                    mComputer.getInstalledApplications(flags, userId, callingUid));
-        }
-
-        @Override
-        public List<ModuleInfo> getInstalledModules(int flags) {
-            return mModuleInfoProvider.getInstalledModules(flags);
-        }
-
-        @Override
-        public ParceledListSlice<PackageInfo> getInstalledPackages(
-                @PackageManager.PackageInfoFlagsBits long flags, int userId) {
-            return mComputer.getInstalledPackages(flags, userId);
-        }
-
-        @Nullable
-        @Override
-        public String getInstallerPackageName(@NonNull String packageName) {
-            return mComputer.getInstallerPackageName(packageName);
-        }
-
-        @Override
         public String getInstantAppAndroidId(String packageName, int userId) {
-            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_INSTANT_APPS,
-                    "getInstantAppAndroidId");
-            enforceCrossUserPermission(Binder.getCallingUid(), userId,
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.ACCESS_INSTANT_APPS, "getInstantAppAndroidId");
+            final Computer snapshot = snapshotComputer();
+            snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId,
                     true /* requireFullPermission */, false /* checkShell */,
                     "getInstantAppAndroidId");
             // Make sure the target is an Instant App.
-            if (!isInstantApp(packageName, userId)) {
+            if (!snapshot.isInstantApp(packageName, userId)) {
                 return null;
             }
             return mInstantAppRegistry.getInstantAppAndroidId(packageName, userId);
@@ -5404,13 +4921,14 @@
                 return null;
             }
 
-            enforceCrossUserPermission(Binder.getCallingUid(), userId,
+            final Computer snapshot = snapshotComputer();
+            snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId,
                     true /* requireFullPermission */, false /* checkShell */,
                     "getInstantAppCookie");
-            if (!isCallerSameApp(packageName, Binder.getCallingUid())) {
+            if (!snapshot.isCallerSameApp(packageName, Binder.getCallingUid())) {
                 return null;
             }
-            PackageStateInternal packageState = getPackageStateInternal(packageName);
+            PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
             if (packageState == null || packageState.getPkg() == null) {
                 return null;
             }
@@ -5423,11 +4941,12 @@
                 return null;
             }
 
-            if (!canViewInstantApps(Binder.getCallingUid(), userId)) {
+            final Computer snapshot = snapshotComputer();
+            if (!snapshot.canViewInstantApps(Binder.getCallingUid(), userId)) {
                 mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_INSTANT_APPS,
                         "getInstantAppIcon");
             }
-            enforceCrossUserPermission(Binder.getCallingUid(), userId,
+            snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId,
                     true /* requireFullPermission */, false /* checkShell */,
                     "getInstantAppIcon");
 
@@ -5435,76 +4954,31 @@
         }
 
         @Override
-        public ComponentName getInstantAppInstallerComponent() {
-            if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
-                return null;
-            }
-            return mInstantAppInstallerActivity == null
-                    ? null : mInstantAppInstallerActivity.getComponentName();
-        }
-
-        @Override
-        public @Nullable ComponentName getInstantAppResolverComponent() {
-            if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
-                return null;
-            }
-            return getInstantAppResolver();
-        }
-
-        @Override
-        public ComponentName getInstantAppResolverSettingsComponent() {
-            return mInstantAppResolverSettingsComponent;
-        }
-
-        @Override
         public ParceledListSlice<InstantAppInfo> getInstantApps(int userId) {
-            if (PackageManagerService.HIDE_EPHEMERAL_APIS) {
+            if (HIDE_EPHEMERAL_APIS) {
                 return null;
             }
-            if (!canViewInstantApps(Binder.getCallingUid(), userId)) {
+
+            final Computer snapshot = snapshotComputer();
+            if (!snapshot.canViewInstantApps(Binder.getCallingUid(), userId)) {
                 mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_INSTANT_APPS,
                         "getEphemeralApplications");
             }
-            enforceCrossUserPermission(Binder.getCallingUid(), userId,
+            snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId,
                     true /* requireFullPermission */, false /* checkShell */,
                     "getEphemeralApplications");
 
-            Computer computer = snapshotComputer();
-            List<InstantAppInfo> instantApps = mInstantAppRegistry.getInstantApps(computer, userId);
+            List<InstantAppInfo> instantApps = mInstantAppRegistry.getInstantApps(snapshot, userId);
             if (instantApps != null) {
                 return new ParceledListSlice<>(instantApps);
             }
             return null;
         }
 
-        @Nullable
-        @Override
-        public InstrumentationInfo getInstrumentationInfo(@NonNull ComponentName component, int flags) {
-            return mComputer.getInstrumentationInfo(component, flags);
-        }
-
-        @Deprecated
-        @Override
-        public @NonNull ParceledListSlice<IntentFilterVerificationInfo> getIntentFilterVerifications(
-                String packageName) {
-            return ParceledListSlice.emptyList();
-        }
-
-        @Deprecated
-        @Override
-        public int getIntentVerificationStatus(String packageName, int userId) {
-            return mDomainVerificationManager.getLegacyState(packageName, userId);
-        }
-
-        @Nullable
-        @Override
-        public KeySet getKeySetByAlias(@NonNull String packageName, @NonNull String alias) {
-            return mComputer.getKeySetByAlias(packageName, alias);
-        }
-
         @Override
         public ResolveInfo getLastChosenActivity(Intent intent, String resolvedType, int flags) {
-            return mPreferredActivityHelper.getLastChosenActivity(intent, resolvedType, flags);
+            return mPreferredActivityHelper.getLastChosenActivity(snapshotComputer(), intent,
+                    resolvedType, flags);
         }
 
         @Override
@@ -5516,13 +4990,9 @@
 
         @Override
         public List<String> getMimeGroup(String packageName, String mimeGroup) {
-            enforceOwnerRights(packageName, Binder.getCallingUid());
-            return getMimeGroupInternal(packageName, mimeGroup);
-        }
-
-        @Override
-        public ModuleInfo getModuleInfo(String packageName, @PackageManager.ModuleInfoFlags int flags) {
-            return PackageManagerService.this.getModuleInfo(packageName, flags);
+            final Computer snapshot = snapshotComputer();
+            enforceOwnerRights(snapshot, packageName, Binder.getCallingUid());
+            return getMimeGroupInternal(snapshot, packageName, mimeGroup);
         }
 
         @Override
@@ -5532,99 +5002,11 @@
             return mMoveCallbacks.mLastStatus.get(moveId);
         }
 
-        @Nullable
-        @Override
-        public String getNameForUid(int uid) {
-            return mComputer.getNameForUid(uid);
-        }
-
-        @Nullable
-        @Override
-        public String[] getNamesForUids(@NonNull int[] uids) {
-            return mComputer.getNamesForUids(uids);
-        }
-
-        @Override
-        public int[] getPackageGids(String packageName, @PackageManager.PackageInfoFlagsBits long flags,
-                int userId) {
-            return mComputer.getPackageGids(packageName, flags, userId);
-        }
-
-        @Override
-        public PackageInfo getPackageInfo(String packageName,
-                @PackageManager.PackageInfoFlagsBits long flags, int userId) {
-            return mComputer.getPackageInfo(packageName, flags, userId);
-        }
-
-        @Override
-        public PackageInfo getPackageInfoVersioned(VersionedPackage versionedPackage,
-                @PackageManager.PackageInfoFlagsBits long flags, int userId) {
-            return mComputer.getPackageInfoInternal(versionedPackage.getPackageName(),
-                    versionedPackage.getLongVersionCode(), flags, Binder.getCallingUid(), userId);
-        }
-
-        @Override
-        public IPackageInstaller getPackageInstaller() {
-            // Return installer service for internal calls.
-            if (PackageManagerServiceUtils.isSystemOrRoot()) {
-                return mInstallerService;
-            }
-            // Return null for InstantApps.
-            if (snapshotComputer().getInstantAppPackageName(Binder.getCallingUid()) != null) {
-                return null;
-            }
-            return mInstallerService;
-        }
-
-        @Override
-        public void getPackageSizeInfo(final String packageName, int userId,
-                final IPackageStatsObserver observer) {
-            throw new UnsupportedOperationException(
-                    "Shame on you for calling the hidden API getPackageSizeInfo(). Shame!");
-        }
-
-        @Override
-        public int getPackageUid(@NonNull String packageName,
-                @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId) {
-            return mComputer.getPackageUid(packageName, flags, userId);
-        }
-
-        /**
-         * <em>IMPORTANT:</em> Not all packages returned by this method may be known
-         * to the system. There are two conditions in which this may occur:
-         * <ol>
-         *   <li>The package is on adoptable storage and the device has been removed</li>
-         *   <li>The package is being removed and the internal structures are partially updated</li>
-         * </ol>
-         * The second is an artifact of the current data structures and should be fixed. See
-         * b/111075456 for one such instance.
-         * This binder API is cached.  If the algorithm in this method changes,
-         * or if the underlying objecs (as returned by getSettingLPr()) change
-         * then the logic that invalidates the cache must be revisited.  See
-         * calls to invalidateGetPackagesForUidCache() to locate the points at
-         * which the cache is invalidated.
-         */
-        @Override
-        public String[] getPackagesForUid(int uid) {
-            final int callingUid = Binder.getCallingUid();
-            final int userId = UserHandle.getUserId(uid);
-            mComputer.enforceCrossUserOrProfilePermission(callingUid, userId,
-                    /* requireFullPermission */ false,
-                    /* checkShell */ false, "getPackagesForUid");
-            return mComputer.getPackagesForUid(uid);
-        }
-
-        @Override
-        public ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
-                @NonNull String[] permissions, @PackageManager.PackageInfoFlagsBits long flags,
-                @UserIdInt int userId) {
-            return mComputer.getPackagesHoldingPermissions(permissions, flags, userId);
-        }
-
         @Override
         public String getPermissionControllerPackageName() {
             final int callingUid = Binder.getCallingUid();
-            if (mComputer.getPackageStateFiltered(mRequiredPermissionControllerPackage,
+            final Computer snapshot = snapshotComputer();
+            if (snapshot.getPackageStateFiltered(mRequiredPermissionControllerPackage,
                     callingUid, UserHandle.getUserId(callingUid)) != null) {
                 return mRequiredPermissionControllerPackage;
             }
@@ -5632,73 +5014,6 @@
             throw new IllegalStateException("PermissionController is not found");
         }
 
-        // NOTE: Can't remove due to unsupported app usage
-        @Override
-        public PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags) {
-            return PackageManagerService.this.getPermissionGroupInfo(groupName, flags);
-        }
-
-        @Override
-        public @NonNull ParceledListSlice<ApplicationInfo> getPersistentApplications(int flags) {
-            if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
-                return ParceledListSlice.emptyList();
-            }
-            return new ParceledListSlice<>(mComputer.getPersistentApplications(mSafeMode, flags));
-        }
-
-        @Override
-        public int getPreferredActivities(List<IntentFilter> outFilters,
-                List<ComponentName> outActivities, String packageName) {
-            return mPreferredActivityHelper.getPreferredActivities(outFilters, outActivities,
-                    packageName, snapshotComputer());
-        }
-
-        /**
-         * Non-Binder method, support for the backup/restore mechanism: write the
-         * full set of preferred activities in its canonical XML format.  Returns the
-         * XML output as a byte array, or null if there is none.
-         */
-        @Override
-        public byte[] getPreferredActivityBackup(int userId) {
-            return mPreferredActivityHelper.getPreferredActivityBackup(userId);
-        }
-
-        @Override
-        public int getPrivateFlagsForUid(int uid) {
-            return mComputer.getPrivateFlagsForUid(uid);
-        }
-
-        @Override
-        public PackageManager.Property getProperty(String propertyName, String packageName, String className) {
-            Objects.requireNonNull(propertyName);
-            Objects.requireNonNull(packageName);
-            PackageStateInternal packageState = mComputer.getPackageStateFiltered(packageName,
-                    Binder.getCallingUid(), UserHandle.getCallingUserId());
-            if (packageState == null) {
-                return null;
-            }
-            return mPackageProperty.getProperty(propertyName, packageName, className);
-        }
-
-        @Nullable
-        @Override
-        public ProviderInfo getProviderInfo(@NonNull ComponentName component,
-                @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId) {
-            return mComputer.getProviderInfo(component, flags, userId);
-        }
-
-        @Override
-        public ActivityInfo getReceiverInfo(ComponentName component,
-                @PackageManager.ComponentInfoFlagsBits long flags, int userId) {
-            return mComputer.getReceiverInfo(component, flags, userId);
-        }
-
-        @Override
-        public @Nullable String getRotationResolverPackageName() {
-            return ensureSystemPackageName(
-                    getPackageFromComponentString(R.string.config_defaultRotationResolverService));
-        }
-
         @Override
         public int getRuntimePermissionsVersion(@UserIdInt int userId) {
             Preconditions.checkArgumentNonnegative(userId);
@@ -5707,65 +5022,25 @@
             return mSettings.getDefaultRuntimePermissionsVersion(userId);
         }
 
-        @Nullable
-        @Override
-        public ServiceInfo getServiceInfo(@NonNull ComponentName component,
-                @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId) {
-            return mComputer.getServiceInfo(component, flags, userId);
-        }
-
-        @Override
-        public @NonNull String getServicesSystemSharedLibraryPackageName() {
-            return mServicesExtensionPackageName;
-        }
-
-        @Override
-        public String getSetupWizardPackageName() {
-            if (Binder.getCallingUid() != Process.SYSTEM_UID) {
-                throw new SecurityException("Non-system caller");
-            }
-            return mPmInternal.getSetupWizardPackageName();
-        }
-
-        @Override
-        public ParceledListSlice<SharedLibraryInfo> getSharedLibraries(String packageName,
-                @PackageManager.PackageInfoFlagsBits long flags, int userId) {
-            return mComputer.getSharedLibraries(packageName, flags, userId);
-        }
-
-        @Override
-        public @NonNull String getSharedSystemSharedLibraryPackageName() {
-            return mSharedSystemSharedLibraryPackageName;
-        }
-
-        @Nullable
-        @Override
-        public KeySet getSigningKeySet(@NonNull String packageName) {
-            return mComputer.getSigningKeySet(packageName);
-        }
-
         @Override
         public String getSplashScreenTheme(@NonNull String packageName, int userId) {
-            PackageStateInternal packageState =
-                    getPackageStateInstalledFiltered(packageName, Binder.getCallingUid(), userId);
+            final Computer snapshot = snapshotComputer();
+            PackageStateInternal packageState = filterPackageStateForInstalledAndFiltered(snapshot,
+                    packageName, Binder.getCallingUid(), userId);
             return packageState == null ? null
                     : packageState.getUserStateOrDefault(userId).getSplashScreenTheme();
         }
 
         @Override
-        public String getSdkSandboxPackageName() {
-            return mRequiredSdkSandboxPackage;
-        }
-
-        @Override
         public Bundle getSuspendedPackageAppExtras(String packageName, int userId) {
             final int callingUid = Binder.getCallingUid();
-            if (getPackageUid(packageName, 0, userId) != callingUid) {
+            final Computer snapshot = snapshot();
+            if (snapshot.getPackageUid(packageName, 0, userId) != callingUid) {
                 throw new SecurityException("Calling package " + packageName
                         + " does not belong to calling uid " + callingUid);
             }
-            return mSuspendPackageHelper.getSuspendedPackageAppExtras(
-                    packageName, userId, callingUid);
+            return mSuspendPackageHelper
+                    .getSuspendedPackageAppExtras(snapshot, packageName, userId, callingUid);
         }
 
         @Override
@@ -5785,34 +5060,6 @@
         }
 
         @Override
-        public String getSystemCaptionsServicePackageName() {
-            return ensureSystemPackageName(
-                    getPackageFromComponentString(R.string.config_defaultSystemCaptionsService));
-        }
-
-        @Nullable
-        @Override
-        public String[] getSystemSharedLibraryNames() {
-            return mComputer.getSystemSharedLibraryNames();
-        }
-
-        @Override
-        public String getSystemTextClassifierPackageName() {
-            return ensureSystemPackageName(
-                    mContext.getString(R.string.config_defaultTextClassifierPackage));
-        }
-
-        @Override
-        public int getTargetSdkVersion(@NonNull String packageName)  {
-            return mComputer.getTargetSdkVersion(packageName);
-        }
-
-        @Override
-        public int getUidForSharedUser(@NonNull String sharedUserName) {
-            return mComputer.getUidForSharedUser(sharedUserName);
-        }
-
-        @Override
         public String[] getUnsuspendablePackagesForUser(String[] packageNames, int userId) {
             Objects.requireNonNull(packageNames, "packageNames cannot be null");
             mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
@@ -5838,19 +5085,7 @@
         }
 
         @Override
-        public String getWellbeingPackageName() {
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                return CollectionUtils.firstOrNull(
-                        mContext.getSystemService(RoleManager.class).getRoleHolders(
-                                RoleManager.ROLE_SYSTEM_WELLBEING));
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-
-        @Override
-        public void grantImplicitAccess(int recipientUid, @NonNull String visibleAuthority) {
+        public void makeProviderVisible(int recipientUid, @NonNull String visibleAuthority) {
             final Computer snapshot = snapshotComputer();
             final int recipientUserId = UserHandle.getUserId(recipientUid);
             final ProviderInfo providerInfo =
@@ -5864,36 +5099,24 @@
                     false /*direct*/, false /* retainOnUpdate */);
         }
 
-        // NOTE: Can't remove due to unsupported app usage
         @Override
-        public void grantRuntimePermission(String packageName, String permName, final int userId) {
-            // Because this is accessed via the package manager service AIDL,
-            // go through the permission manager service AIDL
-            mContext.getSystemService(PermissionManager.class)
-                    .grantRuntimePermission(packageName, permName, UserHandle.of(userId));
-        }
+        public void makeUidVisible(int recipientUid, int visibleUid) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.MAKE_UID_VISIBLE, "makeUidVisible");
+            final int callingUid = Binder.getCallingUid();
+            final int recipientUserId = UserHandle.getUserId(recipientUid);
+            final int visibleUserId = UserHandle.getUserId(visibleUid);
+            final Computer snapshot = snapshotComputer();
+            snapshot.enforceCrossUserPermission(callingUid, recipientUserId,
+                    false /* requireFullPermission */, false /* checkShell */, "makeUidVisible");
+            snapshot.enforceCrossUserPermission(callingUid, visibleUserId,
+                    false /* requireFullPermission */, false /* checkShell */, "makeUidVisible");
+            snapshot.enforceCrossUserPermission(recipientUid, visibleUserId,
+                    false /* requireFullPermission */, false /* checkShell */, "makeUidVisible");
 
-        @Override
-        public boolean hasSigningCertificate(@NonNull String packageName, @NonNull byte[] certificate,
-                @PackageManager.CertificateInputType int type) {
-            return mComputer.hasSigningCertificate(packageName, certificate, type);
-        }
-
-        @Override
-        public boolean hasSystemFeature(String name, int version) {
-            return PackageManagerService.this.hasSystemFeature(name, version);
-        }
-
-        @Override
-        public boolean hasSystemUidErrors() {
-            // allow instant applications
-            return false;
-        }
-
-        @Override
-        public boolean hasUidSigningCertificate(int uid, @NonNull byte[] certificate,
-                @PackageManager.CertificateInputType int type) {
-            return mComputer.hasUidSigningCertificate(uid, certificate, type);
+            PackageManagerService.this.grantImplicitAccess(snapshot, recipientUserId,
+                    null /*Intent*/, UserHandle.getAppId(recipientUid), visibleUid,
+                    false /*direct*/, false /* retainOnUpdate */);
         }
 
         @Override
@@ -5924,55 +5147,17 @@
         }
 
         @Override
-        public boolean isDeviceUpgrading() {
-            return PackageManagerService.this.isDeviceUpgrading();
-        }
-
-        @Override
-        public boolean isFirstBoot() {
-            return PackageManagerService.this.isFirstBoot();
-        }
-
-        @Override
-        public boolean isInstantApp(String packageName, int userId) {
-            return mComputer.isInstantApp(packageName, userId);
-        }
-
-        @Override
-        public boolean isOnlyCoreApps() {
-            return PackageManagerService.this.isOnlyCoreApps();
-        }
-
-        @Override
-        public boolean isPackageAvailable(String packageName, int userId) {
-            return mComputer.isPackageAvailable(packageName, userId);
-        }
-
-        @Override
-        public boolean isPackageDeviceAdminOnAnyUser(String packageName) {
-            return PackageManagerService.this.isPackageDeviceAdminOnAnyUser(packageName);
-        }
-
-        @Override
-        public boolean isPackageSignedByKeySet(@NonNull String packageName, @NonNull KeySet ks) {
-            return mComputer.isPackageSignedByKeySet(packageName, ks);
-        }
-
-        @Override
-        public boolean isPackageSignedByKeySetExactly(@NonNull String packageName, @NonNull KeySet ks) {
-            return mComputer.isPackageSignedByKeySetExactly(packageName, ks);
-        }
-
-        @Override
         public boolean isPackageStateProtected(@NonNull String packageName, @UserIdInt int userId) {
             final int callingUid = Binder.getCallingUid();
             final int callingAppId = UserHandle.getAppId(callingUid);
 
-            enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/,
+            final Computer snapshot = snapshotComputer();
+            snapshot.enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/,
                     true /*checkShell*/, "isPackageStateProtected");
 
             if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.ROOT_UID
-                    && checkUidPermission(MANAGE_DEVICE_ADMINS, callingUid) != PERMISSION_GRANTED) {
+                    && snapshot.checkUidPermission(MANAGE_DEVICE_ADMINS, callingUid)
+                    != PERMISSION_GRANTED) {
                 throw new SecurityException("Caller must have the "
                         + MANAGE_DEVICE_ADMINS + " permission.");
             }
@@ -5981,11 +5166,6 @@
         }
 
         @Override
-        public boolean isPackageSuspendedForUser(@NonNull String packageName, @UserIdInt int userId) {
-            return mComputer.isPackageSuspendedForUser(packageName, userId);
-        }
-
-        @Override
         public boolean isProtectedBroadcast(String actionName) {
             if (actionName != null) {
                 // TODO: remove these terrible hacks
@@ -6002,22 +5182,6 @@
             }
         }
 
-        @Override
-        public boolean isSafeMode() {
-            // allow instant applications
-            return mSafeMode;
-        }
-
-        @Override
-        public boolean isStorageLow() {
-            return PackageManagerService.this.isStorageLow();
-        }
-
-        @Override
-        public boolean isUidPrivileged(int uid) {
-            return mComputer.isUidPrivileged(uid);
-        }
-
         /**
          * Logs process start information (including base APK hash) to the security log.
          * @hide
@@ -6025,13 +5189,15 @@
         @Override
         public void logAppProcessStartIfNeeded(String packageName, String processName, int uid,
                 String seinfo, String apkFile, int pid) {
-            if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
+            final Computer snapshot = snapshotComputer();
+            if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
                 return;
             }
             if (!SecurityLog.isLoggingEnabled()) {
                 return;
             }
-            mProcessLoggingHandler.logAppProcessStart(mContext, mPmInternal, apkFile, packageName,
+            mProcessLoggingHandler.logAppProcessStart(mContext,
+                    LocalServices.getService(PackageManagerInternal.class), apkFile, packageName,
                     processName, uid, seinfo, pid);
         }
 
@@ -6083,25 +5249,29 @@
         }
 
         @Override
-        public void notifyDexLoad(String loadingPackageName, Map<String, String> classLoaderContextMap,
+        public void notifyDexLoad(String loadingPackageName,
+                Map<String, String> classLoaderContextMap,
                 String loaderIsa) {
             int callingUid = Binder.getCallingUid();
-            if (PackageManagerService.PLATFORM_PACKAGE_NAME.equals(loadingPackageName) && callingUid != Process.SYSTEM_UID) {
-                Slog.w(PackageManagerService.TAG, "Non System Server process reporting dex loads as system server. uid="
-                        + callingUid);
+            if (PackageManagerService.PLATFORM_PACKAGE_NAME.equals(loadingPackageName)
+                    && callingUid != Process.SYSTEM_UID) {
+                Slog.w(PackageManagerService.TAG,
+                        "Non System Server process reporting dex loads as system server. uid="
+                                + callingUid);
                 // Do not record dex loads from processes pretending to be system server.
                 // Only the system server should be assigned the package "android", so reject calls
                 // that don't satisfy the constraint.
                 //
                 // notifyDexLoad is a PM API callable from the app process. So in theory, apps could
-                // craft calls to this API and pretend to be system server. Doing so poses no particular
-                // danger for dex load reporting or later dexopt, however it is a sensible check to do
-                // in order to verify the expectations.
+                // craft calls to this API and pretend to be system server. Doing so poses no
+                // particular danger for dex load reporting or later dexopt, however it is a
+                // sensible check to do in order to verify the expectations.
                 return;
             }
 
             int userId = UserHandle.getCallingUserId();
-            ApplicationInfo ai = getApplicationInfo(loadingPackageName, /*flags*/ 0, userId);
+            ApplicationInfo ai = snapshot().getApplicationInfo(loadingPackageName, /*flags*/ 0,
+                    userId);
             if (ai == null) {
                 Slog.w(PackageManagerService.TAG, "Loading a package that does not exist for the calling user. package="
                         + loadingPackageName + ", user=" + userId);
@@ -6115,11 +5285,13 @@
         public void notifyPackageUse(String packageName, int reason) {
             final int callingUid = Binder.getCallingUid();
             final int callingUserId = UserHandle.getUserId(callingUid);
+            Computer snapshot = snapshotComputer();
             final boolean notify;
-            if (getInstantAppPackageName(callingUid) != null) {
-                notify = isCallerSameApp(packageName, callingUid);
+            if (snapshot.getInstantAppPackageName(callingUid) != null) {
+                notify = snapshot.isCallerSameApp(packageName, callingUid);
             } else {
-                notify = !isInstantAppInternal(packageName, callingUserId, Process.SYSTEM_UID);
+                notify = !snapshot.isInstantAppInternal(packageName, callingUserId,
+                        Process.SYSTEM_UID);
             }
             if (!notify) {
                 return;
@@ -6137,102 +5309,18 @@
             updateComponentLabelIcon(componentName, nonLocalizedLabel, icon, userId);
         }
 
-        /**
-         * Ask the package manager to perform a dex-opt with the given compiler filter.
-         *
-         * Note: exposed only for the shell command to allow moving packages explicitly to a
-         *       definite state.
-         */
-        @Override
-        public boolean performDexOptMode(String packageName,
-                boolean checkProfiles, String targetCompilerFilter, boolean force,
-                boolean bootComplete, String splitName) {
-            return mDexOptHelper.performDexOptMode(packageName, checkProfiles, targetCompilerFilter,
-                    force, bootComplete, splitName);
-        }
-
-        /**
-         * Ask the package manager to perform a dex-opt with the given compiler filter on the
-         * secondary dex files belonging to the given package.
-         *
-         * Note: exposed only for the shell command to allow moving packages explicitly to a
-         *       definite state.
-         */
-        @Override
-        public boolean performDexOptSecondary(String packageName, String compilerFilter,
-                boolean force) {
-            return mDexOptHelper.performDexOptSecondary(packageName, compilerFilter, force);
-        }
-
-        @NonNull
-        @Override
-        public ParceledListSlice<ProviderInfo> queryContentProviders(@Nullable  String processName,
-                int uid, @PackageManager.ComponentInfoFlagsBits long flags,
-                @Nullable String metaDataKey) {
-            return mComputer.queryContentProviders(processName, uid, flags, metaDataKey);
-        }
-
-        @NonNull
-        @Override
-        public ParceledListSlice<InstrumentationInfo> queryInstrumentation(
-                @NonNull String targetPackage, int flags) {
-            return mComputer.queryInstrumentation(targetPackage, flags);
-        }
-
-        @Override
-        public @NonNull ParceledListSlice<ResolveInfo> queryIntentActivities(Intent intent,
-                String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
-            try {
-                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities");
-
-                return new ParceledListSlice<>(snapshotComputer().queryIntentActivitiesInternal(intent,
-                        resolvedType, flags, userId));
-            } finally {
-                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-            }
-        }
-
-        @Override
-        public @NonNull ParceledListSlice<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
-                Intent[] specifics, String[] specificTypes, Intent intent,
-                String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
-            return new ParceledListSlice<>(mResolveIntentHelper.queryIntentActivityOptionsInternal(
-                    snapshotComputer(), caller, specifics, specificTypes, intent, resolvedType, flags,
-                    userId));
-        }
-
-        @Override
-        public @NonNull ParceledListSlice<ResolveInfo> queryIntentContentProviders(Intent intent,
-                String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
-            return new ParceledListSlice<>(mResolveIntentHelper.queryIntentContentProvidersInternal(
-                    snapshotComputer(), intent, resolvedType, flags, userId));
-        }
-
-        @Override
-        public @NonNull ParceledListSlice<ResolveInfo> queryIntentReceivers(Intent intent,
-                String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
-            return new ParceledListSlice<>(mResolveIntentHelper.queryIntentReceiversInternal(
-                    snapshotComputer(), intent, resolvedType, flags, userId, Binder.getCallingUid()));
-        }
-
-        @Override
-        public @NonNull ParceledListSlice<ResolveInfo> queryIntentServices(Intent intent,
-                String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
-            final int callingUid = Binder.getCallingUid();
-            return new ParceledListSlice<>(snapshotComputer().queryIntentServicesInternal(
-                    intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/));
-        }
-
         @Override
         public ParceledListSlice<PackageManager.Property> queryProperty(
                 String propertyName, @PackageManager.PropertyLocation int componentType) {
             Objects.requireNonNull(propertyName);
             final int callingUid = Binder.getCallingUid();
             final int callingUserId = UserHandle.getCallingUserId();
+            final Computer snapshot = snapshotComputer();
             final List<PackageManager.Property> result =
                     mPackageProperty.queryProperty(propertyName, componentType, packageName -> {
-                        final PackageStateInternal ps = getPackageStateInternal(packageName);
-                        return shouldFilterApplication(ps, callingUid, callingUserId);
+                        final PackageStateInternal ps =
+                                snapshot.getPackageStateInternal(packageName);
+                        return snapshot.shouldFilterApplication(ps, callingUid, callingUserId);
                     });
             if (result == null) {
                 return ParceledListSlice.emptyList();
@@ -6240,11 +5328,6 @@
             return new ParceledListSlice<>(result);
         }
 
-        @Deprecated
-        public void querySyncProviders(List<String> outNames, List<ProviderInfo> outInfo) {
-            mComputer.querySyncProviders(mSafeMode, outNames, outInfo);
-        }
-
         /**
          * Reconcile the information we have about the secondary dex files belonging to
          * {@code packageName} and the actual dex files. For all dex files that were
@@ -6252,9 +5335,10 @@
          */
         @Override
         public void reconcileSecondaryDexFiles(String packageName) {
-            if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
+            final Computer snapshot = snapshotComputer();
+            if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
                 return;
-            } else if (isInstantAppInternal(
+            } else if (snapshot.isInstantAppInternal(
                     packageName, UserHandle.getCallingUserId(), Process.SYSTEM_UID)) {
                 return;
             }
@@ -6262,14 +5346,16 @@
         }
 
         @Override
-        public void registerDexModule(String packageName, String dexModulePath, boolean isSharedModule,
+        public void registerDexModule(String packageName, String dexModulePath,
+                boolean isSharedModule,
                 IDexModuleRegisterCallback callback) {
             int userId = UserHandle.getCallingUserId();
-            ApplicationInfo ai = getApplicationInfo(packageName, /*flags*/ 0, userId);
+            ApplicationInfo ai = snapshot().getApplicationInfo(packageName, /*flags*/ 0, userId);
             DexManager.RegisterDexModuleResult result;
             if (ai == null) {
-                Slog.w(PackageManagerService.TAG, "Registering a dex module for a package that does not exist for the" +
-                        " calling user. package=" + packageName + ", user=" + userId);
+                Slog.w(PackageManagerService.TAG,
+                        "Registering a dex module for a package that does not exist for the" +
+                                " calling user. package=" + packageName + ", user=" + userId);
                 result = new DexManager.RegisterDexModuleResult(false, "Package not installed");
             } else {
                 result = mDexManager.registerDexModule(ai, dexModulePath, isSharedModule, userId);
@@ -6278,9 +5364,11 @@
             if (callback != null) {
                 mHandler.post(() -> {
                     try {
-                        callback.onDexModuleRegistered(dexModulePath, result.success, result.message);
+                        callback.onDexModuleRegistered(dexModulePath, result.success,
+                                result.message);
                     } catch (RemoteException e) {
-                        Slog.w(PackageManagerService.TAG, "Failed to callback after module registration " + dexModulePath, e);
+                        Slog.w(PackageManagerService.TAG,
+                                "Failed to callback after module registration " + dexModulePath, e);
                     }
                 });
             }
@@ -6293,52 +5381,6 @@
             mMoveCallbacks.register(callback);
         }
 
-        // NOTE: Can't remove due to unsupported app usage
-        @Override
-        public void removePermission(String permName) {
-            // Because this is accessed via the package manager service AIDL,
-            // go through the permission manager service AIDL
-            mContext.getSystemService(PermissionManager.class).removePermission(permName);
-        }
-
-        @Override
-        public void replacePreferredActivity(IntentFilter filter, int match,
-                ComponentName[] set, ComponentName activity, int userId) {
-            mPreferredActivityHelper.replacePreferredActivity(new WatchedIntentFilter(filter),
-                    match, set, activity, userId);
-        }
-
-        @Override
-        public void resetApplicationPreferences(int userId) {
-            mPreferredActivityHelper.resetApplicationPreferences(userId);
-        }
-
-        @Override
-        public ProviderInfo resolveContentProvider(String name,
-                @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
-            return mComputer.resolveContentProvider(name, flags, userId, Binder.getCallingUid());
-        }
-
-        @Override
-        public ResolveInfo resolveIntent(Intent intent, String resolvedType,
-                @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
-            return mResolveIntentHelper.resolveIntentInternal(snapshotComputer(), intent, resolvedType,
-                    flags, 0 /*privateResolveFlags*/, userId, false, Binder.getCallingUid());
-        }
-
-        @Override
-        public ResolveInfo resolveService(Intent intent, String resolvedType,
-                @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
-            final int callingUid = Binder.getCallingUid();
-            return mResolveIntentHelper.resolveServiceInternal(snapshotComputer(), intent, resolvedType,
-                    flags, userId, callingUid);
-        }
-
-        @Override
-        public void restoreDefaultApps(byte[] backup, int userId) {
-            mPreferredActivityHelper.restoreDefaultApps(backup, userId);
-        }
-
         @Override
         public void restoreDomainVerification(byte[] backup, int userId) {
             if (Binder.getCallingUid() != Process.SYSTEM_UID) {
@@ -6366,11 +5408,6 @@
         }
 
         @Override
-        public void restorePreferredActivities(byte[] backup, int userId) {
-            mPreferredActivityHelper.restorePreferredActivities(backup, userId);
-        }
-
-        @Override
         public void sendDeviceCustomizationReadyBroadcast() {
             mContext.enforceCallingPermission(Manifest.permission.SEND_DEVICE_CUSTOMIZATION_READY,
                     "sendDeviceCustomizationReadyBroadcast");
@@ -6386,16 +5423,17 @@
         @Override
         public void setApplicationCategoryHint(String packageName, int categoryHint,
                 String callerPackageName) {
-            if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
-                throw new SecurityException("Instant applications don't have access to this method");
-            }
-            mInjector.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(),
-                    callerPackageName);
-
             final PackageStateMutator.InitialState initialState = recordInitialState();
 
             final FunctionalUtils.ThrowingFunction<Computer, PackageStateMutator.Result>
                     implementation = computer -> {
+                if (computer.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+                    throw new SecurityException(
+                            "Instant applications don't have access to this method");
+                }
+                mInjector.getSystemService(AppOpsManager.class)
+                        .checkPackage(Binder.getCallingUid(), callerPackageName);
+
                 PackageStateInternal packageState = computer.getPackageStateFiltered(packageName,
                         Binder.getCallingUid(), UserHandle.getCallingUserId());
                 if (packageState == null) {
@@ -6447,7 +5485,8 @@
                 int userId) {
             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
             final int callingUid = Binder.getCallingUid();
-            enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
+            final Computer snapshot = snapshotComputer();
+            snapshot.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
                     true /* checkShell */, "setApplicationHiddenSetting for user " + userId);
 
             if (hidden && isPackageDeviceAdmin(packageName, userId)) {
@@ -6464,7 +5503,7 @@
             final long callingId = Binder.clearCallingIdentity();
             try {
                 final PackageStateInternal packageState =
-                        mComputer.getPackageStateFiltered(packageName, callingUid, userId);
+                        snapshot.getPackageStateFiltered(packageName, callingUid, userId);
                 if (packageState == null) {
                     return false;
                 }
@@ -6505,13 +5544,16 @@
                 commitPackageStateMutation(null, packageName, packageState1 ->
                         packageState1.userState(userId).setHidden(hidden));
 
-                final PackageStateInternal newPackageState = getPackageStateInternal(packageName);
+                final Computer newSnapshot = snapshotComputer();
+                final PackageStateInternal newPackageState =
+                        newSnapshot.getPackageStateInternal(packageName);
 
                 if (hidden) {
                     killApplication(packageName, newPackageState.getAppId(), userId, "hiding pkg");
                     sendApplicationHiddenForUser(packageName, newPackageState, userId);
                 } else {
-                    sendPackageAddedForUser(packageName, newPackageState, userId, DataLoaderType.NONE);
+                    sendPackageAddedForUser(newSnapshot, packageName, newPackageState, userId,
+                            DataLoaderType.NONE);
                 }
 
                 scheduleWritePackageRestrictions(userId);
@@ -6526,7 +5568,8 @@
                 int userId) {
             mContext.enforceCallingOrSelfPermission(
                     Manifest.permission.DELETE_PACKAGES, null);
-            PackageStateInternal packageState = getPackageStateInternal(packageName);
+            final Computer snapshot = snapshotComputer();
+            PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
             if (packageState != null && packageState.getPkg() != null) {
                 AndroidPackage pkg = packageState.getPkg();
                 // Cannot block uninstall SDK libs as they are controlled by SDK manager.
@@ -6584,8 +5627,10 @@
                         + userId);
             }
             Objects.requireNonNull(packageNames, "packageNames cannot be null");
+            final Computer snapshot = snapshotComputer();
             if (restrictionFlags != 0
-                    && !mSuspendPackageHelper.isSuspendAllowedForUser(userId, callingUid)) {
+                    && !mSuspendPackageHelper.isSuspendAllowedForUser(snapshot, userId,
+                    callingUid)) {
                 Slog.w(PackageManagerService.TAG, "Cannot restrict packages due to restrictions on user " + userId);
                 return packageNames;
             }
@@ -6595,16 +5640,15 @@
             final List<String> unactionedPackages = new ArrayList<>(packageNames.length);
 
             ArraySet<String> changesToCommit = new ArraySet<>();
-            Computer computer = snapshotComputer();
             final boolean[] canRestrict = (restrictionFlags != 0)
-                    ? mSuspendPackageHelper.canSuspendPackageForUser(computer, packageNames, userId,
+                    ? mSuspendPackageHelper.canSuspendPackageForUser(snapshot, packageNames, userId,
                     callingUid) : null;
             for (int i = 0; i < packageNames.length; i++) {
                 final String packageName = packageNames[i];
                 final PackageStateInternal packageState =
-                        computer.getPackageStateInternal(packageName);
+                        snapshot.getPackageStateInternal(packageName);
                 if (packageState == null
-                        || computer.shouldFilterApplication(packageState, callingUid, userId)) {
+                        || snapshot.shouldFilterApplication(packageState, callingUid, userId)) {
                     Slog.w(PackageManagerService.TAG, "Could not find package setting for package: " + packageName
                             + ". Skipping...");
                     unactionedPackages.add(packageName);
@@ -6648,11 +5692,13 @@
             final int callingUid = Binder.getCallingUid();
             final int callingAppId = UserHandle.getAppId(callingUid);
 
-            enforceCrossUserPermission(callingUid, userId, true /*requireFullPermission*/,
+            final Computer snapshot = snapshotComputer();
+            snapshot.enforceCrossUserPermission(callingUid, userId, true /*requireFullPermission*/,
                     true /*checkShell*/, "setHarmfulAppInfo");
 
             if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.ROOT_UID &&
-                    checkUidPermission(SET_HARMFUL_APP_WARNINGS, callingUid) != PERMISSION_GRANTED) {
+                    snapshot.checkUidPermission(SET_HARMFUL_APP_WARNINGS, callingUid)
+                            != PERMISSION_GRANTED) {
                 throw new SecurityException("Caller must have the "
                         + SET_HARMFUL_APP_WARNINGS + " permission.");
             }
@@ -6667,11 +5713,6 @@
         }
 
         @Override
-        public void setHomeActivity(ComponentName comp, int userId) {
-            mPreferredActivityHelper.setHomeActivity(comp, userId);
-        }
-
-        @Override
         public boolean setInstallLocation(int loc) {
             mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS,
                     null);
@@ -6693,24 +5734,24 @@
             final int callingUid = Binder.getCallingUid();
             final int callingUserId = UserHandle.getUserId(callingUid);
             final FunctionalUtils.ThrowingCheckedFunction<Computer, Boolean, RuntimeException>
-                    implementation = computer -> {
-                if (computer.getInstantAppPackageName(callingUid) != null) {
+                    implementation = snapshot -> {
+                if (snapshot.getInstantAppPackageName(callingUid) != null) {
                     return false;
                 }
 
                 PackageStateInternal targetPackageState =
-                        computer.getPackageStateInternal(targetPackage);
+                        snapshot.getPackageStateInternal(targetPackage);
                 if (targetPackageState == null
-                        || computer.shouldFilterApplication(targetPackageState, callingUid,
+                        || snapshot.shouldFilterApplication(targetPackageState, callingUid,
                         callingUserId)) {
                     throw new IllegalArgumentException("Unknown target package: " + targetPackage);
                 }
 
                 PackageStateInternal installerPackageState = null;
                 if (installerPackageName != null) {
-                    installerPackageState = computer.getPackageStateInternal(installerPackageName);
+                    installerPackageState = snapshot.getPackageStateInternal(installerPackageName);
                     if (installerPackageState == null
-                            || shouldFilterApplication(
+                            || snapshot.shouldFilterApplication(
                             installerPackageState, callingUid, callingUserId)) {
                         throw new IllegalArgumentException("Unknown installer package: "
                                 + installerPackageName);
@@ -6720,7 +5761,7 @@
                 Signature[] callerSignature;
                 final int appId = UserHandle.getAppId(callingUid);
                 Pair<PackageStateInternal, SharedUserApi> either =
-                        computer.getPackageOrSharedUser(appId);
+                        snapshot.getPackageOrSharedUser(appId);
                 if (either != null) {
                     if (either.first != null) {
                         callerSignature = either.first.getSigningDetails().getSignatures();
@@ -6748,7 +5789,7 @@
                 String targetInstallerPackageName =
                         targetPackageState.getInstallSource().installerPackageName;
                 PackageStateInternal targetInstallerPkgSetting = targetInstallerPackageName == null
-                        ? null : computer.getPackageStateInternal(targetInstallerPackageName);
+                        ? null : snapshot.getPackageStateInternal(targetInstallerPackageName);
 
                 if (targetInstallerPkgSetting != null) {
                     if (compareSignatures(callerSignature,
@@ -6804,7 +5845,7 @@
                             }
                         }
                     }
-                    targetPackageState = getPackageStateInternal(targetPackage);
+                    targetPackageState = snapshotComputer().getPackageStateInternal(targetPackage);
                     mSettings.addInstallerPackageNames(targetPackageState.getInstallSource());
                 }
                 mAppsFilter.addPackage(targetPackageState);
@@ -6818,14 +5859,15 @@
                 return true;
             }
 
-            enforceCrossUserPermission(Binder.getCallingUid(), userId,
+            final Computer snapshot = snapshotComputer();
+            snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId,
                     true /* requireFullPermission */, true /* checkShell */,
                     "setInstantAppCookie");
-            if (!isCallerSameApp(packageName, Binder.getCallingUid())) {
+            if (!snapshot.isCallerSameApp(packageName, Binder.getCallingUid())) {
                 return false;
             }
 
-            PackageStateInternal packageState = getPackageStateInternal(packageName);
+            PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
             if (packageState == null || packageState.getPkg() == null) {
                 return false;
             }
@@ -6840,21 +5882,15 @@
                     "setKeepUninstalledPackages requires KEEP_UNINSTALLED_PACKAGES permission");
             Objects.requireNonNull(packageList);
 
-            setKeepUninstalledPackagesInternal(packageList);
-        }
-
-        @Override
-        public void setLastChosenActivity(Intent intent, String resolvedType, int flags,
-                IntentFilter filter, int match, ComponentName activity) {
-            mPreferredActivityHelper.setLastChosenActivity(intent, resolvedType, flags,
-                    new WatchedIntentFilter(filter), match, activity);
+            setKeepUninstalledPackagesInternal(snapshot(), packageList);
         }
 
         @Override
         public void setMimeGroup(String packageName, String mimeGroup, List<String> mimeTypes) {
-            enforceOwnerRights(packageName, Binder.getCallingUid());
+            final Computer snapshot = snapshotComputer();
+            enforceOwnerRights(snapshot, packageName, Binder.getCallingUid());
             mimeTypes = CollectionUtils.emptyIfNull(mimeTypes);
-            final PackageStateInternal packageState = getPackageStateInternal(packageName);
+            final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
             Set<String> existingMimeTypes = packageState.getMimeGroups().get(mimeGroup);
             if (existingMimeTypes == null) {
                 throw new IllegalArgumentException("Unknown MIME group " + mimeGroup
@@ -6889,11 +5925,11 @@
                 PersistableBundle appExtras, PersistableBundle launcherExtras,
                 SuspendDialogInfo dialogInfo, String callingPackage, int userId) {
             final int callingUid = Binder.getCallingUid();
-            enforceCanSetPackagesSuspendedAsUser(callingPackage, callingUid, userId,
+            final Computer snapshot = snapshotComputer();
+            enforceCanSetPackagesSuspendedAsUser(snapshot, callingPackage, callingUid, userId,
                     "setPackagesSuspendedAsUser");
-            return mSuspendPackageHelper.setPackagesSuspended(snapshotComputer(), packageNames,
-                    suspended, appExtras, launcherExtras, dialogInfo, callingPackage, userId,
-                    callingUid);
+            return mSuspendPackageHelper.setPackagesSuspended(snapshot, packageNames, suspended,
+                    appExtras, launcherExtras, dialogInfo, callingPackage, userId, callingUid);
         }
 
         @Override
@@ -6924,12 +5960,13 @@
         public void setSplashScreenTheme(@NonNull String packageName, @Nullable String themeId,
                 int userId) {
             final int callingUid = Binder.getCallingUid();
-            enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
+            final Computer snapshot = snapshotComputer();
+            snapshot.enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
                     false /* checkShell */, "setSplashScreenTheme");
-            enforceOwnerRights(packageName, callingUid);
+            enforceOwnerRights(snapshot, packageName, callingUid);
 
-            PackageStateInternal packageState = getPackageStateInstalledFiltered(packageName,
-                    callingUid, userId);
+            PackageStateInternal packageState = filterPackageStateForInstalledAndFiltered(snapshot,
+                    packageName, callingUid, userId);
             if (packageState == null) {
                 return;
             }
@@ -6939,80 +5976,6 @@
         }
 
         @Override
-        public void setSystemAppHiddenUntilInstalled(String packageName, boolean hidden) {
-            final int callingUid = Binder.getCallingUid();
-            final boolean calledFromSystemOrPhone = callingUid == Process.PHONE_UID
-                    || callingUid == Process.SYSTEM_UID;
-            if (!calledFromSystemOrPhone) {
-                mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
-                        "setSystemAppHiddenUntilInstalled");
-            }
-
-            final PackageStateInternal stateRead = getPackageStateInternal(packageName);
-            if (stateRead == null || !stateRead.isSystem() || stateRead.getPkg() == null) {
-                return;
-            }
-            if (stateRead.getPkg().isCoreApp() && !calledFromSystemOrPhone) {
-                throw new SecurityException("Only system or phone callers can modify core apps");
-            }
-
-            commitPackageStateMutation(null, mutator -> {
-                mutator.forPackage(packageName)
-                        .setHiddenUntilInstalled(hidden);
-                mutator.forDisabledSystemPackage(packageName)
-                        .setHiddenUntilInstalled(hidden);
-            });
-        }
-
-        @Override
-        public boolean setSystemAppInstallState(String packageName, boolean installed, int userId) {
-            final int callingUid = Binder.getCallingUid();
-            final boolean calledFromSystemOrPhone = callingUid == Process.PHONE_UID
-                    || callingUid == Process.SYSTEM_UID;
-            if (!calledFromSystemOrPhone) {
-                mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
-                        "setSystemAppHiddenUntilInstalled");
-            }
-
-            final PackageStateInternal packageState = getPackageStateInternal(packageName);
-            // The target app should always be in system
-            if (packageState == null || !packageState.isSystem() || packageState.getPkg() == null) {
-                return false;
-            }
-            if (packageState.getPkg().isCoreApp() && !calledFromSystemOrPhone) {
-                throw new SecurityException("Only system or phone callers can modify core apps");
-            }
-            // Check if the install state is the same
-            if (packageState.getUserStateOrDefault(userId).isInstalled() == installed) {
-                return false;
-            }
-
-            final long callingId = Binder.clearCallingIdentity();
-            try {
-                if (installed) {
-                    // install the app from uninstalled state
-                    installExistingPackageAsUser(
-                            packageName,
-                            userId,
-                            PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
-                            PackageManager.INSTALL_REASON_DEVICE_SETUP,
-                            null);
-                    return true;
-                }
-
-                // uninstall the app from installed state
-                deletePackageVersioned(
-                        new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),
-                        new PackageManager.LegacyPackageDeleteObserver(null).getBinder(),
-                        userId,
-                        PackageManager.DELETE_SYSTEM_APP);
-                return true;
-            } finally {
-                Binder.restoreCallingIdentity(callingId);
-            }
-        }
-
-        @Override
         public void setUpdateAvailable(String packageName, boolean updateAvailable) {
             mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, null);
             commitPackageStateMutation(null, packageName, state ->
@@ -7026,19 +5989,6 @@
             mMoveCallbacks.unregister(callback);
         }
 
-        @Deprecated
-        @Override
-        public boolean updateIntentVerificationStatus(String packageName, int status, int userId) {
-            return mDomainVerificationManager.setLegacyUserState(packageName, userId, status);
-        }
-
-        @Deprecated
-        @Override
-        public void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains) {
-            DomainVerificationProxyV1.queueLegacyVerifyResult(mContext, mDomainVerificationConnection,
-                    id, verificationCode, failedDomains, Binder.getCallingUid());
-        }
-
         @Override
         public void verifyPendingInstall(int id, int verificationCode) throws RemoteException {
             mContext.enforceCallingOrSelfPermission(
@@ -7059,9 +6009,9 @@
                 @Checksum.TypeMask int optional, @Checksum.TypeMask int required,
                 @Nullable List trustedInstallers,
                 @NonNull IOnChecksumsReadyListener onChecksumsReadyListener, int userId) {
-            requestChecksumsInternal(packageName, includeSplits, optional, required, trustedInstallers,
-                    onChecksumsReadyListener, userId, mInjector.getBackgroundExecutor(),
-                    mInjector.getBackgroundHandler());
+            requestChecksumsInternal(snapshotComputer(), packageName, includeSplits, optional,
+                    required, trustedInstallers, onChecksumsReadyListener, userId,
+                    mInjector.getBackgroundExecutor(), mInjector.getBackgroundHandler());
         }
 
         @Override
@@ -7074,12 +6024,6 @@
         }
 
         @Override
-        public boolean canPackageQuery(@NonNull String sourcePackageName,
-                @NonNull String targetPackageName, @UserIdInt int userId) {
-            return mComputer.canPackageQuery(sourcePackageName, targetPackageName, userId);
-        }
-
-        @Override
         public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
                 throws RemoteException {
             try {
@@ -7097,8 +6041,8 @@
         public void onShellCommand(FileDescriptor in, FileDescriptor out,
                 FileDescriptor err, String[] args, ShellCallback callback,
                 ResultReceiver resultReceiver) {
-            (new PackageManagerShellCommand(mIPackageManager,
-                    mContext,mDomainVerificationManager.getShell()))
+            (new PackageManagerShellCommand(this, mContext,
+                    mDomainVerificationManager.getShell()))
                     .exec(this, in, out, err, args, callback, resultReceiver);
         }
 
@@ -7111,19 +6055,99 @@
     }
 
     private class PackageManagerLocalImpl implements PackageManagerLocal {
+        @Override
+        public void reconcileSdkData(@Nullable String volumeUuid, @NonNull String packageName,
+                @NonNull List<String> subDirNames, int userId, int appId, int previousAppId,
+                @NonNull String seInfo, int flags) throws IOException {
+            synchronized (mInstallLock) {
+                ReconcileSdkDataArgs args = mInstaller.buildReconcileSdkDataArgs(volumeUuid,
+                        packageName, subDirNames, userId, appId, seInfo,
+                        flags);
+                args.previousAppId = previousAppId;
+                try {
+                    mInstaller.reconcileSdkData(args);
+                } catch (InstallerException e) {
+                    throw new IOException(e.getMessage());
+                }
+            }
+        }
     }
 
-    private class PackageManagerInternalImpl extends PackageManagerInternal {
+    private class PackageManagerInternalImpl extends PackageManagerInternalBase {
+
+        public PackageManagerInternalImpl() {
+            super(PackageManagerService.this);
+        }
+
+        @NonNull
         @Override
-        public List<ApplicationInfo> getInstalledApplications(
-                @PackageManager.ApplicationInfoFlagsBits long flags, int userId, int callingUid) {
-            return PackageManagerService.this.mComputer.getInstalledApplications(flags, userId,
-                    callingUid);
+        protected Context getContext() {
+            return mContext;
+        }
+
+        @NonNull
+        @Override
+        protected PermissionManagerServiceInternal getPermissionManager() {
+            return mPermissionManager;
+        }
+
+        @NonNull
+        @Override
+        protected AppDataHelper getAppDataHelper() {
+            return mAppDataHelper;
+        }
+
+        @NonNull
+        @Override
+        protected PackageObserverHelper getPackageObserverHelper() {
+            return mPackageObserverHelper;
+        }
+
+        @NonNull
+        @Override
+        protected ResolveIntentHelper getResolveIntentHelper() {
+            return mResolveIntentHelper;
+        }
+
+        @NonNull
+        @Override
+        protected SuspendPackageHelper getSuspendPackageHelper() {
+            return mSuspendPackageHelper;
+        }
+
+        @NonNull
+        @Override
+        protected ProtectedPackages getProtectedPackages() {
+            return mProtectedPackages;
+        }
+
+        @NonNull
+        @Override
+        protected UserNeedsBadgingCache getUserNeedsBadging() {
+            return mUserNeedsBadging;
+        }
+
+        @NonNull
+        @Override
+        protected InstantAppRegistry getInstantAppRegistry() {
+            return mInstantAppRegistry;
+        }
+
+        @NonNull
+        @Override
+        protected ApexManager getApexManager() {
+            return mApexManager;
+        }
+
+        @NonNull
+        @Override
+        protected DexManager getDexManager() {
+            return mDexManager;
         }
 
         @Override
         public boolean isPlatformSigned(String packageName) {
-            PackageStateInternal packageState = getPackageStateInternal(packageName);
+            PackageStateInternal packageState = snapshot().getPackageStateInternal(packageName);
             if (packageState == null) {
                 return false;
             }
@@ -7135,7 +6159,8 @@
 
         @Override
         public boolean isDataRestoreSafe(byte[] restoringFromSigHash, String packageName) {
-            SigningDetails sd = getSigningDetails(packageName);
+            final Computer snapshot = snapshot();
+            SigningDetails sd = snapshot.getSigningDetails(packageName);
             if (sd == null) {
                 return false;
             }
@@ -7145,7 +6170,8 @@
 
         @Override
         public boolean isDataRestoreSafe(Signature restoringFromSig, String packageName) {
-            SigningDetails sd = getSigningDetails(packageName);
+            final Computer snapshot = snapshot();
+            SigningDetails sd = snapshot.getSigningDetails(packageName);
             if (sd == null) {
                 return false;
             }
@@ -7156,100 +6182,17 @@
         @Override
         public boolean hasSignatureCapability(int serverUid, int clientUid,
                 @SigningDetails.CertCapabilities int capability) {
-            SigningDetails serverSigningDetails = getSigningDetails(serverUid);
-            SigningDetails clientSigningDetails = getSigningDetails(clientUid);
+            final Computer snapshot = snapshot();
+            SigningDetails serverSigningDetails = snapshot.getSigningDetails(serverUid);
+            SigningDetails clientSigningDetails = snapshot.getSigningDetails(clientUid);
             return serverSigningDetails.checkCapability(clientSigningDetails, capability)
                     || clientSigningDetails.hasAncestorOrSelf(serverSigningDetails);
-
-        }
-
-        private SigningDetails getSigningDetails(@NonNull String packageName) {
-            return PackageManagerService.this.getSigningDetails(packageName);
-        }
-
-        private SigningDetails getSigningDetails(int uid) {
-            return PackageManagerService.this.getSigningDetails(uid);
-        }
-
-        @Override
-        public boolean isInstantApp(String packageName, int userId) {
-            return PackageManagerService.this.mIPackageManager.isInstantApp(packageName, userId);
-        }
-
-        @Override
-        public String getInstantAppPackageName(int uid) {
-            return PackageManagerService.this.getInstantAppPackageName(uid);
-        }
-
-        @Override
-        public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
-            return PackageManagerService.this.filterAppAccess(pkg, callingUid, userId);
-        }
-
-        @Override
-        public boolean filterAppAccess(String packageName, int callingUid, int userId) {
-            return PackageManagerService.this.filterAppAccess(packageName, callingUid, userId);
-        }
-
-        @Override
-        public boolean filterAppAccess(int uid, int callingUid) {
-            return PackageManagerService.this.filterAppAccess(uid, callingUid);
-        }
-
-        @Nullable
-        @Override
-        public int[] getVisibilityAllowList(@NonNull String packageName, int userId) {
-            return PackageManagerService.this.getVisibilityAllowList(packageName, userId);
-        }
-
-        @Override
-        public boolean canQueryPackage(int callingUid, @Nullable String packageName) {
-            return PackageManagerService.this.canQueryPackage(callingUid, packageName);
-        }
-
-        @Override
-        public AndroidPackage getPackage(String packageName) {
-            return PackageManagerService.this.getPackage(packageName);
-        }
-
-        @Nullable
-        @Override
-        public AndroidPackageApi getAndroidPackage(@NonNull String packageName) {
-            return PackageManagerService.this.getPackage(packageName);
-        }
-
-        @Override
-        public AndroidPackage getPackage(int uid) {
-            return PackageManagerService.this.getPackage(uid);
-        }
-
-        @Override
-        public List<AndroidPackage> getPackagesForAppId(int appId) {
-            return mComputer.getPackagesForAppId(appId);
-        }
-
-        @Nullable
-        @Override
-        public PackageStateInternal getPackageStateInternal(String packageName) {
-            return PackageManagerService.this.getPackageStateInternal(packageName);
-        }
-
-        @Nullable
-        @Override
-        public PackageState getPackageState(@NonNull String packageName) {
-            return PackageManagerService.this.getPackageState(packageName);
-        }
-
-        @NonNull
-        @Override
-        public ArrayMap<String, ? extends PackageStateInternal> getPackageStates() {
-            return PackageManagerService.this.getPackageStates();
         }
 
         @Override
         public PackageList getPackageList(@Nullable PackageListObserver observer) {
             final ArrayList<String> list = new ArrayList<>();
-            forEachPackageState(packageState -> {
+            PackageManagerService.this.forEachPackageState(snapshot(), packageState -> {
                 AndroidPackage pkg = packageState.getPkg();
                 if (pkg != null) {
                     list.add(pkg.getPackageName());
@@ -7263,19 +6206,9 @@
         }
 
         @Override
-        public void removePackageListObserver(PackageListObserver observer) {
-            mPackageObserverHelper.removeObserver(observer);
-        }
-
-        @Override
-        public PackageStateInternal getDisabledSystemPackage(@NonNull String packageName) {
-            return snapshotComputer().getDisabledSystemPackage(packageName);
-        }
-
-        @Override
         public @Nullable
         String getDisabledSystemPackageName(@NonNull String packageName) {
-            PackageStateInternal disabledPkgSetting = getDisabledSystemPackage(
+            PackageStateInternal disabledPkgSetting = snapshot().getDisabledSystemPackage(
                     packageName);
             AndroidPackage disabledPkg = disabledPkgSetting == null
                     ? null : disabledPkgSetting.getPkg();
@@ -7283,51 +6216,15 @@
         }
 
         @Override
-        public @NonNull String[] getKnownPackageNames(int knownPackage, int userId) {
-            return PackageManagerService.this.getKnownPackageNamesInternal(knownPackage, userId);
-        }
-
-        @Override
-        public boolean isSameApp(@Nullable String packageName, int callingUid, int userId) {
-            if (packageName == null) {
-                return false;
-            }
-
-            if (Process.isSdkSandboxUid(callingUid)) {
-                return packageName.equals(getSdkSandboxPackageName());
-            }
-            int uid = getPackageUid(packageName, 0, userId);
-            return UserHandle.isSameApp(uid, callingUid);
-        }
-
-        @Override
         public boolean isResolveActivityComponent(ComponentInfo component) {
             return mResolveActivity.packageName.equals(component.packageName)
                     && mResolveActivity.name.equals(component.name);
         }
 
         @Override
-        public void setKeepUninstalledPackages(final List<String> packageList) {
-            PackageManagerService.this.setKeepUninstalledPackagesInternal(packageList);
-        }
-
-        @Override
-        public boolean isPermissionsReviewRequired(String packageName, int userId) {
-            return mPermissionManager.isPermissionsReviewRequired(packageName, userId);
-        }
-
-        @Override
-        public PackageInfo getPackageInfo(
-                String packageName, @PackageManager.PackageInfoFlagsBits long flags,
-                int filterCallingUid, int userId) {
-            return PackageManagerService.this.mComputer
-                    .getPackageInfoInternal(packageName, PackageManager.VERSION_CODE_HIGHEST,
-                            flags, filterCallingUid, userId);
-        }
-
-        @Override
         public long getCeDataInode(String packageName, int userId) {
-            final PackageStateInternal packageState = getPackageStateInternal(packageName);
+            final PackageStateInternal packageState =
+                    snapshot().getPackageStateInternal(packageName);
             if (packageState == null) {
                 return 0;
             } else {
@@ -7336,18 +6233,6 @@
         }
 
         @Override
-        public Bundle getSuspendedPackageLauncherExtras(String packageName, int userId) {
-            return mSuspendPackageHelper.getSuspendedPackageLauncherExtras(
-                    packageName, userId, Binder.getCallingUid());
-        }
-
-        @Override
-        public boolean isPackageSuspended(String packageName, int userId) {
-            return mSuspendPackageHelper.isPackageSuspended(
-                    packageName, userId, Binder.getCallingUid());
-        }
-
-        @Override
         public void removeAllNonSystemPackageSuspensions(int userId) {
             final Computer computer = snapshotComputer();
             final String[] allPackages = computer.getAllAvailablePackageNames();
@@ -7357,14 +6242,6 @@
         }
 
         @Override
-        public void removeNonSystemPackageSuspensions(String packageName, int userId) {
-            mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(snapshotComputer(),
-                    new String[]{packageName},
-                    (suspendingPackage) -> !PLATFORM_PACKAGE_NAME.equals(suspendingPackage),
-                    userId);
-        }
-
-        @Override
         public void flushPackageRestrictions(int userId) {
             synchronized (mLock) {
                 PackageManagerService.this.flushPackageRestrictionsAsUserInternalLocked(userId);
@@ -7372,103 +6249,6 @@
         }
 
         @Override
-        public void removeDistractingPackageRestrictions(String packageName, int userId) {
-            PackageManagerService.this.removeDistractingPackageRestrictions(
-                    new String[]{packageName}, userId);
-        }
-
-        @Override
-        public void removeAllDistractingPackageRestrictions(int userId) {
-            PackageManagerService.this.removeAllDistractingPackageRestrictions(userId);
-        }
-
-        @Override
-        public String getSuspendingPackage(String suspendedPackage, int userId) {
-            return mSuspendPackageHelper.getSuspendingPackage(
-                    suspendedPackage, userId, Binder.getCallingUid());
-        }
-
-        @Override
-        public SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage,
-                String suspendingPackage, int userId) {
-            return mSuspendPackageHelper.getSuspendedDialogInfo(
-                    suspendedPackage, suspendingPackage, userId, Binder.getCallingUid());
-        }
-
-        @Override
-        public int getDistractingPackageRestrictions(String packageName, int userId) {
-            final PackageStateInternal packageState = getPackageStateInternal(packageName);
-            return (packageState == null) ? RESTRICTION_NONE
-                    : packageState.getUserStateOrDefault(userId).getDistractionFlags();
-        }
-
-        @Override
-        public int getPackageUid(String packageName,
-                @PackageManager.PackageInfoFlagsBits long flags, int userId) {
-            return PackageManagerService.this
-                    .getPackageUidInternal(packageName, flags, userId, Process.SYSTEM_UID);
-        }
-
-        @Override
-        public ApplicationInfo getApplicationInfo(
-                String packageName, @PackageManager.ApplicationInfoFlagsBits long flags,
-                int filterCallingUid, int userId) {
-            return PackageManagerService.this
-                    .getApplicationInfoInternal(packageName, flags, filterCallingUid, userId);
-        }
-
-        @Override
-        public ActivityInfo getActivityInfo(
-                ComponentName component, @PackageManager.ComponentInfoFlagsBits long flags,
-                int filterCallingUid, int userId) {
-            return PackageManagerService.this
-                    .getActivityInfoInternal(component, flags, filterCallingUid, userId);
-        }
-
-        @Override
-        public List<ResolveInfo> queryIntentActivities(
-                Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
-                int filterCallingUid, int userId) {
-            return snapshotComputer().queryIntentActivitiesInternal(intent, resolvedType, flags,
-                    userId);
-        }
-
-        @Override
-        public List<ResolveInfo> queryIntentReceivers(Intent intent,
-                String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
-                int filterCallingUid, int userId) {
-            return PackageManagerService.this.mResolveIntentHelper.queryIntentReceiversInternal(
-                    snapshotComputer(), intent, resolvedType, flags, userId, filterCallingUid);
-        }
-
-        @Override
-        public List<ResolveInfo> queryIntentServices(
-                Intent intent, @PackageManager.ResolveInfoFlagsBits long flags, int callingUid,
-                int userId) {
-            final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
-            return PackageManagerService.this
-                    .queryIntentServicesInternal(intent, resolvedType, flags, userId, callingUid,
-                            false);
-        }
-
-        @Override
-        public ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
-                int userId) {
-            return PackageManagerService.this.getHomeActivitiesAsUser(allHomeCandidates, userId);
-        }
-
-        @Override
-        public ComponentName getDefaultHomeActivity(int userId) {
-            return PackageManagerService.this.getDefaultHomeActivity(userId);
-        }
-
-        @Override
-        public ComponentName getSystemUiServiceComponent() {
-            return ComponentName.unflattenFromString(mContext.getResources().getString(
-                    com.android.internal.R.string.config_systemUIServiceComponent));
-        }
-
-        @Override
         public void setDeviceAndProfileOwnerPackages(
                 int deviceOwnerUserId, String deviceOwnerPackage,
                 SparseArray<String> profileOwnerPackages) {
@@ -7487,118 +6267,6 @@
         }
 
         @Override
-        public void setDeviceOwnerProtectedPackages(
-                String deviceOwnerPackageName, List<String> packageNames) {
-            mProtectedPackages.setDeviceOwnerProtectedPackages(
-                    deviceOwnerPackageName, packageNames);
-        }
-
-        @Override
-        public boolean isPackageDataProtected(int userId, String packageName) {
-            return mProtectedPackages.isPackageDataProtected(userId, packageName);
-        }
-
-        @Override
-        public boolean isPackageStateProtected(String packageName, int userId) {
-            return mProtectedPackages.isPackageStateProtected(userId, packageName);
-        }
-
-        @Override
-        public boolean isPackageEphemeral(int userId, String packageName) {
-            final PackageStateInternal packageState = getPackageStateInternal(packageName);
-            return packageState != null
-                    && packageState.getUserStateOrDefault(userId).isInstantApp();
-        }
-
-        @Override
-        public boolean wasPackageEverLaunched(String packageName, int userId) {
-            final PackageStateInternal packageState = getPackageStateInternal(packageName);
-            if (packageState == null) {
-                throw new IllegalArgumentException("Unknown package: " + packageName);
-            }
-            return !packageState.getUserStateOrDefault(userId).isNotLaunched();
-        }
-
-        @Override
-        public boolean isEnabledAndMatches(ParsedMainComponent component, long flags, int userId) {
-            return PackageStateUtils.isEnabledAndMatches(
-                    getPackageStateInternal(component.getPackageName()), component, flags, userId);
-        }
-
-        @Override
-        public boolean userNeedsBadging(int userId) {
-            synchronized (mLock) {
-                return PackageManagerService.this.userNeedsBadging(userId);
-            }
-        }
-
-        @Override
-        public String getNameForUid(int uid) {
-            return mIPackageManager.getNameForUid(uid);
-        }
-
-        @Override
-        public void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
-                Intent origIntent, String resolvedType, String callingPackage,
-                @Nullable String callingFeatureId, boolean isRequesterInstantApp,
-                Bundle verificationBundle, int userId) {
-            PackageManagerService.this.requestInstantAppResolutionPhaseTwo(responseObj, origIntent,
-                    resolvedType, callingPackage, callingFeatureId, isRequesterInstantApp,
-                    verificationBundle, userId);
-        }
-
-        @Override
-        public void grantImplicitAccess(int userId, Intent intent,
-                int recipientAppId, int visibleUid, boolean direct) {
-            grantImplicitAccess(userId, intent, recipientAppId, visibleUid, direct,
-                    false /* retainOnUpdate */);
-        }
-
-        @Override
-        public void grantImplicitAccess(int userId, Intent intent,
-                int recipientAppId, int visibleUid, boolean direct, boolean retainOnUpdate) {
-            Computer computer = snapshotComputer();
-            final AndroidPackage visiblePackage = computer.getPackage(visibleUid);
-            final int recipientUid = UserHandle.getUid(userId, recipientAppId);
-            if (visiblePackage == null || computer.getPackage(recipientUid) == null) {
-                return;
-            }
-
-            final boolean instantApp = computer.isInstantAppInternal(
-                    visiblePackage.getPackageName(), userId, visibleUid);
-            final boolean accessGranted;
-            if (instantApp) {
-                if (!direct) {
-                    // if the interaction that lead to this granting access to an instant app
-                    // was indirect (i.e.: URI permission grant), do not actually execute the
-                    // grant.
-                    return;
-                }
-                accessGranted = mInstantAppRegistry.grantInstantAccess(userId, intent,
-                        recipientAppId, UserHandle.getAppId(visibleUid) /*instantAppId*/);
-            } else {
-                accessGranted = mAppsFilter.grantImplicitAccess(recipientUid, visibleUid,
-                        retainOnUpdate);
-            }
-
-            if (accessGranted) {
-                ApplicationPackageManager.invalidateGetPackagesForUidCache();
-            }
-        }
-
-        @Override
-        public boolean isInstantAppInstallerComponent(ComponentName component) {
-            final ActivityInfo instantAppInstallerActivity = mInstantAppInstallerActivity;
-            return instantAppInstallerActivity != null
-                    && instantAppInstallerActivity.getComponentName().equals(component);
-        }
-
-        @Override
-        public void pruneInstantApps() {
-            mInstantAppRegistry.pruneInstantApps(snapshotComputer());
-        }
-
-        @Override
         public void pruneCachedApksInApex(@NonNull List<PackageInfo> apexPackages) {
             if (mCacheDir == null) {
                 return;
@@ -7606,11 +6274,12 @@
 
             final PackageCacher cacher = new PackageCacher(mCacheDir);
             synchronized (mLock) {
+                final Computer snapshot = snapshot();
                 for (int i = 0, size = apexPackages.size(); i < size; i++) {
                     final List<String> apkNames =
                             mApexManager.getApksInApex(apexPackages.get(i).packageName);
                     for (int j = 0, apksInApex = apkNames.size(); j < apksInApex; j++) {
-                        final AndroidPackage pkg = getPackage(apkNames.get(j));
+                        final AndroidPackage pkg = snapshot.getPackage(apkNames.get(j));
                         cacher.cleanCachedResult(new File(pkg.getPath()));
                     }
                 }
@@ -7618,10 +6287,6 @@
         }
 
         @Override
-        public String getSetupWizardPackageName() {
-            return mSetupWizardPackage;
-        }
-
         public void setExternalSourcesPolicy(ExternalSourcesPolicy policy) {
             if (policy != null) {
                 mExternalSourcesPolicy = policy;
@@ -7630,7 +6295,8 @@
 
         @Override
         public boolean isPackagePersistent(String packageName) {
-            final PackageStateInternal packageState = getPackageStateInternal(packageName);
+            final PackageStateInternal packageState =
+                    snapshot().getPackageStateInternal(packageName);
             if (packageState == null) {
                 return false;
             }
@@ -7641,16 +6307,20 @@
 
         @Override
         public List<PackageInfo> getOverlayPackages(int userId) {
+            final Computer snapshot = snapshotComputer();
             final ArrayList<PackageInfo> overlayPackages = new ArrayList<>();
-            forEachPackageState(packageState -> {
+            final ArrayMap<String, ? extends PackageStateInternal> packageStates =
+                    snapshot.getPackageStates();
+            for (int index = 0; index < packageStates.size(); index++) {
+                final PackageStateInternal packageState = packageStates.valueAt(index);
                 final AndroidPackage pkg = packageState.getPkg();
                 if (pkg != null && pkg.getOverlayTarget() != null) {
-                    PackageInfo pkgInfo = generatePackageInfo(packageState, 0, userId);
+                    PackageInfo pkgInfo = snapshot.generatePackageInfo(packageState, 0, userId);
                     if (pkgInfo != null) {
                         overlayPackages.add(pkgInfo);
                     }
                 }
-            });
+            }
 
             return overlayPackages;
         }
@@ -7658,7 +6328,7 @@
         @Override
         public List<String> getTargetPackageNames(int userId) {
             List<String> targetPackages = new ArrayList<>();
-            forEachPackageState(packageState -> {
+            PackageManagerService.this.forEachPackageState(snapshot(), packageState -> {
                 final AndroidPackage pkg = packageState.getPkg();
                 if (pkg != null && !pkg.isOverlay()) {
                     targetPackages.add(pkg.getPackageName());
@@ -7676,30 +6346,6 @@
         }
 
         @Override
-        public ResolveInfo resolveIntent(Intent intent, String resolvedType,
-                @PackageManager.ResolveInfoFlagsBits long flags,
-                @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId,
-                boolean resolveForStart, int filterCallingUid) {
-            return mResolveIntentHelper.resolveIntentInternal(snapshotComputer(),
-                    intent, resolvedType, flags, privateResolveFlags, userId, resolveForStart,
-                    filterCallingUid);
-        }
-
-        @Override
-        public ResolveInfo resolveService(Intent intent, String resolvedType,
-                @PackageManager.ResolveInfoFlagsBits long flags, int userId, int callingUid) {
-            return mResolveIntentHelper.resolveServiceInternal(snapshotComputer(), intent,
-                    resolvedType, flags, userId, callingUid);
-        }
-
-        @Override
-        public ProviderInfo resolveContentProvider(String name,
-                @PackageManager.ResolveInfoFlagsBits long flags, int userId, int callingUid) {
-            return PackageManagerService.this.mComputer
-                    .resolveContentProvider(name, flags, userId,callingUid);
-        }
-
-        @Override
         public void addIsolatedUid(int isolatedUid, int ownerUid) {
             synchronized (mLock) {
                 mIsolatedOwners.put(isolatedUid, ownerUid);
@@ -7714,146 +6360,12 @@
         }
 
         @Override
-        public int getUidTargetSdkVersion(int uid) {
-            return PackageManagerService.this.getUidTargetSdkVersion(uid);
-        }
-
-        @Override
-        public int getPackageTargetSdkVersion(String packageName) {
-            final PackageStateInternal packageState = getPackageStateInternal(packageName);
-            if (packageState != null && packageState.getPkg() != null) {
-                return packageState.getPkg().getTargetSdkVersion();
-            }
-            return Build.VERSION_CODES.CUR_DEVELOPMENT;
-        }
-
-        @Override
-        public boolean canAccessInstantApps(int callingUid, int userId) {
-            return PackageManagerService.this.canViewInstantApps(callingUid, userId);
-        }
-
-        @Override
-        public boolean canAccessComponent(int callingUid, @NonNull ComponentName component,
-                @UserIdInt int userId) {
-            return mComputer.canAccessComponent(callingUid, component, userId);
-        }
-
-        @Override
-        public boolean hasInstantApplicationMetadata(String packageName, int userId) {
-            return mInstantAppRegistry.hasInstantApplicationMetadata(packageName, userId);
-        }
-
-        @Override
         public void notifyPackageUse(String packageName, int reason) {
             synchronized (mLock) {
                 PackageManagerService.this.notifyPackageUseInternal(packageName, reason);
             }
         }
 
-        @Override
-        public void onPackageProcessKilledForUninstall(String packageName) {
-            mHandler.post(() -> PackageManagerService.this.notifyInstallObserver(packageName,
-                    true /* killApp */));
-        }
-
-        @Override
-        public SparseArray<String> getAppsWithSharedUserIds() {
-            return mComputer.getAppsWithSharedUserIds();
-        }
-
-        @Override
-        @NonNull
-        public String[] getSharedUserPackagesForPackage(String packageName, int userId) {
-            return mComputer.getSharedUserPackagesForPackage(packageName, userId);
-        }
-
-        @Override
-        public ArrayMap<String, ProcessInfo> getProcessesForUid(int uid) {
-            return mComputer.getProcessesForUid(uid);
-        }
-
-        @Override
-        public int[] getPermissionGids(String permissionName, int userId) {
-            return mPermissionManager.getPermissionGids(permissionName, userId);
-        }
-
-        @Override
-        public boolean isOnlyCoreApps() {
-            return mIPackageManager.isOnlyCoreApps();
-        }
-
-        @Override
-        public void freeStorage(String volumeUuid, long bytes,
-                @StorageManager.AllocateFlags int flags) throws IOException {
-            PackageManagerService.this.freeStorage(volumeUuid, bytes, flags);
-        }
-
-        @Override
-        public void freeAllAppCacheAboveQuota(@NonNull String volumeUuid) throws IOException {
-            PackageManagerService.this.freeAllAppCacheAboveQuota(volumeUuid);
-        }
-
-        @Override
-        public void forEachPackageSetting(Consumer<PackageSetting> actionLocked) {
-            PackageManagerService.this.forEachPackageSetting(actionLocked);
-        }
-
-        @Override
-        public void forEachPackageState(Consumer<PackageStateInternal> action) {
-            PackageManagerService.this.forEachPackageState(action);
-        }
-
-        @Override
-        public void forEachPackage(Consumer<AndroidPackage> action) {
-            PackageManagerService.this.forEachPackage(action);
-        }
-
-        @Override
-        public void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> action,
-                @UserIdInt int userId) {
-            PackageManagerService.this.forEachInstalledPackage(action, userId);
-        }
-
-        @Override
-        public ArraySet<String> getEnabledComponents(String packageName, int userId) {
-            final PackageStateInternal packageState = getPackageStateInternal(packageName);
-            if (packageState == null) {
-                return new ArraySet<>();
-            }
-            return packageState.getUserStateOrDefault(userId).getEnabledComponents();
-        }
-
-        @Override
-        public ArraySet<String> getDisabledComponents(String packageName, int userId) {
-            final PackageStateInternal packageState = getPackageStateInternal(packageName);
-            if (packageState == null) {
-                return new ArraySet<>();
-            }
-            return packageState.getUserStateOrDefault(userId).getDisabledComponents();
-        }
-
-        @Override
-        public @PackageManager.EnabledState int getApplicationEnabledState(
-                String packageName, int userId) {
-            final PackageStateInternal packageState = getPackageStateInternal(packageName);
-            if (packageState == null) {
-                return COMPONENT_ENABLED_STATE_DEFAULT;
-            }
-            return packageState.getUserStateOrDefault(userId).getEnabledState();
-        }
-
-        @Override
-        public @PackageManager.EnabledState int getComponentEnabledSetting(
-                @NonNull ComponentName componentName, int callingUid, int userId) {
-            return PackageManagerService.this.mComputer.getComponentEnabledSettingInternal(
-                    componentName, callingUid, userId);
-        }
-
-        @Override
-        public void setEnableRollbackCode(int token, int enableRollbackCode) {
-            PackageManagerService.this.setEnableRollbackCode(token, enableRollbackCode);
-        }
-
         /**
          * Ask the package manager to compile layouts in the given package.
          */
@@ -7869,11 +6381,6 @@
             return mArtManagerService.compileLayouts(pkg);
         }
 
-        @Override
-        public void finishPackageInstall(int token, boolean didLaunch) {
-            mIPackageManager.finishPackageInstall(token, didLaunch);
-        }
-
         @Nullable
         @Override
         public String removeLegacyDefaultBrowserPackageName(int userId) {
@@ -7883,16 +6390,6 @@
         }
 
         @Override
-        public boolean isApexPackage(String packageName) {
-            return PackageManagerService.this.mApexManager.isApexPackage(packageName);
-        }
-
-        @Override
-        public List<String> getApksInApex(String apexPackageName) {
-            return PackageManagerService.this.mApexManager.getApksInApex(apexPackageName);
-        }
-
-        @Override
         public void uninstallApex(String packageName, long versionCode, int userId,
                 IntentSender intentSender, int flags) {
             final int callerUid = Binder.getCallingUid();
@@ -7967,11 +6464,6 @@
         }
 
         @Override
-        public boolean isCallerInstallerOfRecord(@NonNull AndroidPackage pkg, int callingUid) {
-            return mComputer.isCallerInstallerOfRecord(pkg, callingUid);
-        }
-
-        @Override
         public boolean isPermissionUpgradeNeeded(int userId) {
             return mSettings.isPermissionUpgradeNeeded(userId);
         }
@@ -7985,13 +6477,9 @@
         }
 
         @Override
-        public List<String> getMimeGroup(String packageName, String mimeGroup) {
-            return PackageManagerService.this.getMimeGroupInternal(packageName, mimeGroup);
-        }
-
-        @Override
         public void setVisibilityLogging(String packageName, boolean enable) {
-            final PackageStateInternal packageState = getPackageStateInternal(packageName);
+            final PackageStateInternal packageState =
+                    snapshot().getPackageStateInternal(packageName);
             if (packageState == null) {
                 throw new IllegalStateException("No package found for " + packageName);
             }
@@ -7999,12 +6487,6 @@
         }
 
         @Override
-        public boolean isSystemPackage(@NonNull String packageName) {
-            return packageName.equals(
-                    PackageManagerService.this.ensureSystemPackageName(packageName));
-        }
-
-        @Override
         public void clearBlockUninstallForUser(@UserIdInt int userId) {
             synchronized (mLock) {
                 mSettings.clearBlockUninstallLPw(userId);
@@ -8013,21 +6495,11 @@
         }
 
         @Override
-        public void unsuspendForSuspendingPackage(final String packageName, int affectedUser) {
-            PackageManagerService.this.unsuspendForSuspendingPackage(snapshotComputer(),
-                    packageName, affectedUser);
-        }
-
-        @Override
-        public boolean isSuspendingAnyPackages(String suspendingPackage, int userId) {
-            return PackageManagerService.this.isSuspendingAnyPackages(suspendingPackage, userId);
-        }
-
-        @Override
         public boolean registerInstalledLoadingProgressCallback(String packageName,
                 PackageManagerInternal.InstalledLoadingProgressCallback callback, int userId) {
-            final PackageStateInternal ps =
-                    getPackageStateInstalledFiltered(packageName, Binder.getCallingUid(), userId);
+            final Computer snapshot = snapshotComputer();
+            final PackageStateInternal ps = filterPackageStateForInstalledAndFiltered(snapshot,
+                    packageName, Binder.getCallingUid(), userId);
             if (ps == null) {
                 return false;
             }
@@ -8048,8 +6520,9 @@
         @Override
         public IncrementalStatesInfo getIncrementalStatesInfo(
                 @NonNull String packageName, int filterCallingUid, int userId) {
-            final PackageStateInternal ps =
-                    getPackageStateInstalledFiltered(packageName, filterCallingUid, userId);
+            final Computer snapshot = snapshotComputer();
+            final PackageStateInternal ps = filterPackageStateForInstalledAndFiltered(snapshot,
+                    packageName, filterCallingUid, userId);
             if (ps == null) {
                 return null;
             }
@@ -8057,74 +6530,23 @@
         }
 
         @Override
-        public void requestChecksums(@NonNull String packageName, boolean includeSplits,
-                @Checksum.TypeMask int optional, @Checksum.TypeMask int required,
-                @Nullable List trustedInstallers,
-                @NonNull IOnChecksumsReadyListener onChecksumsReadyListener, int userId,
-                @NonNull Executor executor, @NonNull Handler handler) {
-            requestChecksumsInternal(packageName, includeSplits, optional, required,
-                    trustedInstallers, onChecksumsReadyListener, userId, executor, handler);
+        public boolean isSameApp(@Nullable String packageName, int callingUid, int userId) {
+            if (packageName == null) {
+                return false;
+            }
+
+            if (Process.isSdkSandboxUid(callingUid)) {
+                return packageName.equals(mRequiredSdkSandboxPackage);
+            }
+            Computer snapshot = snapshot();
+            int uid = snapshot.getPackageUid(packageName, 0, userId);
+            return UserHandle.isSameApp(uid, callingUid);
         }
 
         @Override
-        public boolean isPackageFrozen(@NonNull String packageName,
-                int callingUid, int userId) {
-            return PackageManagerService.this.getPackageStartability(
-                    packageName, callingUid, userId) == PACKAGE_STARTABILITY_FROZEN;
-        }
-
-        @Override
-        public long deleteOatArtifactsOfPackage(String packageName) {
-            return PackageManagerService.this.deleteOatArtifactsOfPackage(packageName);
-        }
-
-        @Override
-        public void reconcileAppsData(int userId, @StorageManager.StorageFlags int flags,
-                boolean migrateAppsData) {
-            PackageManagerService.this.mAppDataHelper.reconcileAppsData(userId, flags,
-                    migrateAppsData);
-        }
-
-        @Override
-        @NonNull
-        public ArraySet<PackageStateInternal> getSharedUserPackages(int sharedUserAppId) {
-            return PackageManagerService.this.mComputer.getSharedUserPackages(sharedUserAppId);
-        }
-
-        @Override
-        @Nullable
-        public SharedUserApi getSharedUserApi(int sharedUserAppId) {
-            return mComputer.getSharedUser(sharedUserAppId);
-        }
-
-        @NonNull
-        @Override
-        public PackageStateMutator.InitialState recordInitialState() {
-            return PackageManagerService.this.recordInitialState();
-        }
-
-        @Nullable
-        @Override
-        public PackageStateMutator.Result commitPackageStateMutation(
-                @Nullable PackageStateMutator.InitialState state,
-                @NonNull Consumer<PackageStateMutator> consumer) {
-            return PackageManagerService.this.commitPackageStateMutation(state, consumer);
-        }
-
-        @NonNull
-        @Override
-        public Computer snapshot() {
-            return snapshotComputer();
-        }
-
-        @Override
-        public void shutdown() {
-            PackageManagerService.this.shutdown();
-        }
-
-        @Override
-        public DynamicCodeLogger getDynamicCodeLogger() {
-            return PackageManagerService.this.getDexManager().getDynamicCodeLogger();
+        public void onPackageProcessKilledForUninstall(String packageName) {
+            mHandler.post(() -> PackageManagerService.this.notifyInstallObserver(packageName,
+                    true /* killApp */));
         }
     }
 
@@ -8239,24 +6661,6 @@
         return mSettings.getDisabledSystemPkgLPr(packageName);
     }
 
-    @VisibleForTesting(visibility = Visibility.PRIVATE)
-    @Nullable
-    PackageStateInternal getPackageStateInternal(String packageName) {
-        return mComputer.getPackageStateInternal(packageName);
-    }
-
-    @Nullable
-    PackageStateInternal getPackageStateInternal(String packageName, int callingUid) {
-        return mComputer.getPackageStateInternal(packageName, callingUid);
-    }
-
-    @Nullable
-    PackageStateInternal getPackageStateInstalledFiltered(@NonNull String packageName,
-            int callingUid, @UserIdInt int userId) {
-        return filterPackageStateForInstalledAndFiltered(mComputer, packageName, callingUid,
-                userId);
-    }
-
     @Nullable
     private PackageStateInternal filterPackageStateForInstalledAndFiltered(
             @NonNull Computer computer, @NonNull String packageName, int callingUid,
@@ -8272,22 +6676,8 @@
         }
     }
 
-    @Nullable
-    private PackageState getPackageState(String packageName) {
-        return mComputer.getPackageStateCopied(packageName);
-    }
-
-    @NonNull
-    ArrayMap<String, ? extends PackageStateInternal> getPackageStates() {
-        Computer computer = snapshotComputer();
-        if (computer == mLiveComputer) {
-            return new ArrayMap<>(computer.getPackageStates());
-        } else {
-            return computer.getPackageStates();
-        }
-    }
-
-    private void forEachPackageSetting(Consumer<PackageSetting> actionLocked) {
+    @Deprecated
+    void forEachPackageSetting(Consumer<PackageSetting> actionLocked) {
         synchronized (mLock) {
             int size = mSettings.getPackagesLocked().size();
             for (int index = 0; index < size; index++) {
@@ -8296,13 +6686,13 @@
         }
     }
 
-    void forEachPackageState(Consumer<PackageStateInternal> consumer) {
-        forEachPackageState(mComputer.getPackageStates(), consumer);
+    void forEachPackageState(@NonNull Computer snapshot, Consumer<PackageStateInternal> consumer) {
+        forEachPackageState(snapshot.getPackageStates(), consumer);
     }
 
-    void forEachPackage(Consumer<AndroidPackage> consumer) {
+    void forEachPackage(@NonNull Computer snapshot, Consumer<AndroidPackage> consumer) {
         final ArrayMap<String, ? extends PackageStateInternal> packageStates =
-                mComputer.getPackageStates();
+                snapshot.getPackageStates();
         int size = packageStates.size();
         for (int index = 0; index < size; index++) {
             PackageStateInternal packageState = packageStates.valueAt(index);
@@ -8322,7 +6712,7 @@
         }
     }
 
-    void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> action,
+    void forEachInstalledPackage(@NonNull Computer snapshot, @NonNull Consumer<AndroidPackage> action,
             @UserIdInt int userId) {
         Consumer<PackageStateInternal> actionWrapped = packageState -> {
             if (packageState.getPkg() != null
@@ -8330,7 +6720,7 @@
                 action.accept(packageState.getPkg());
             }
         };
-        forEachPackageState(mComputer.getPackageStates(), actionWrapped);
+        forEachPackageState(snapshot.getPackageStates(), actionWrapped);
     }
 
     boolean isHistoricalPackageUsageAvailable() {
@@ -8345,15 +6735,7 @@
         return mCompilerStats.getOrCreatePackageStats(pkgName);
     }
 
-    /**
-     * Returns true if the system or user is explicitly preventing an otherwise valid installer to
-     * complete an install. This includes checks like unknown sources and user restrictions.
-     */
-    public boolean isInstallDisabledForPackage(String packageName, int uid, int userId) {
-        return mComputer.isInstallDisabledForPackage(packageName, uid, userId);
-    }
-
-    private void grantImplicitAccess(@NonNull Computer snapshot, @UserIdInt int userId,
+    void grantImplicitAccess(@NonNull Computer snapshot, @UserIdInt int userId,
             Intent intent, @AppIdInt int recipientAppId, int visibleUid, boolean direct,
             boolean retainOnUpdate) {
         final AndroidPackage visiblePackage = snapshot.getPackage(visibleUid);
@@ -8384,8 +6766,8 @@
         }
     }
 
-    boolean canHaveOatDir(String packageName) {
-        final PackageStateInternal packageState = getPackageStateInternal(packageName);
+    boolean canHaveOatDir(@NonNull Computer snapshot, String packageName) {
+        final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
         if (packageState == null || packageState.getPkg() == null) {
             return false;
         }
@@ -8393,8 +6775,8 @@
                 packageState.getTransientState().isUpdatedSystemApp());
     }
 
-    long deleteOatArtifactsOfPackage(String packageName) {
-        PackageStateInternal packageState = getPackageStateInternal(packageName);
+    long deleteOatArtifactsOfPackage(@NonNull Computer snapshot, String packageName) {
+        PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
         if (packageState == null || packageState.getPkg() == null) {
             return -1; // error code of deleteOptimizedFiles
         }
@@ -8402,13 +6784,9 @@
                 ArtUtils.createArtPackageInfo(packageState.getPkg(), packageState));
     }
 
-    @NonNull
-    Set<String> getUnusedPackages(long downgradeTimeThresholdMillis) {
-        return mComputer.getUnusedPackages(downgradeTimeThresholdMillis);
-    }
-
-    private List<String> getMimeGroupInternal(String packageName, String mimeGroup) {
-        final PackageStateInternal packageState = getPackageStateInternal(packageName);
+    List<String> getMimeGroupInternal(@NonNull Computer snapshot, String packageName,
+            String mimeGroup) {
+        final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
         if (packageState == null) {
             return Collections.emptyList();
         }
@@ -8473,16 +6851,16 @@
      * Returns the array containing per-uid timeout configuration.
      * This is derived from DeviceConfig flags.
      */
-    public @NonNull PerUidReadTimeouts[] getPerUidReadTimeouts() {
+    public @NonNull PerUidReadTimeouts[] getPerUidReadTimeouts(@NonNull Computer snapshot) {
         PerUidReadTimeouts[] result = mPerUidReadTimeoutsCache;
         if (result == null) {
-            result = parsePerUidReadTimeouts();
+            result = parsePerUidReadTimeouts(snapshot);
             mPerUidReadTimeoutsCache = result;
         }
         return result;
     }
 
-    private @NonNull PerUidReadTimeouts[] parsePerUidReadTimeouts() {
+    private @NonNull PerUidReadTimeouts[] parsePerUidReadTimeouts(@NonNull Computer snapshot) {
         final String defaultTimeouts = getDefaultTimeouts();
         final String knownDigestersList = getKnownDigestersList();
         final List<PerPackageReadTimeouts> perPackageReadTimeouts =
@@ -8496,7 +6874,8 @@
         final List<PerUidReadTimeouts> result = new ArrayList<>(perPackageReadTimeouts.size());
         for (int i = 0, size = perPackageReadTimeouts.size(); i < size; ++i) {
             final PerPackageReadTimeouts perPackage = perPackageReadTimeouts.get(i);
-            final PackageStateInternal ps = getPackageStateInternal(perPackage.packageName);
+            final PackageStateInternal ps =
+                    snapshot.getPackageStateInternal(perPackage.packageName);
             if (ps == null) {
                 if (DEBUG_PER_UID_READ_TIMEOUTS) {
                     Slog.i(TAG, "PerUidReadTimeouts: package not found = "
@@ -8546,7 +6925,7 @@
         return result.toArray(new PerUidReadTimeouts[result.size()]);
     }
 
-    private void setKeepUninstalledPackagesInternal(List<String> packageList) {
+    void setKeepUninstalledPackagesInternal(@NonNull Computer snapshot, List<String> packageList) {
         Preconditions.checkNotNull(packageList);
         synchronized (mKeepUninstalledPackages) {
             List<String> toRemove = new ArrayList<>(mKeepUninstalledPackages);
@@ -8556,7 +6935,7 @@
             mKeepUninstalledPackages.addAll(packageList);
 
             for (int i = 0; i < toRemove.size(); i++) {
-                deletePackageIfUnused(toRemove.get(i));
+                deletePackageIfUnused(snapshot, toRemove.get(i));
             }
         }
     }
@@ -8603,43 +6982,44 @@
         mInstrumentation.put(name, instrumentation);
     }
 
-    String[] getKnownPackageNamesInternal(int knownPackage, int userId) {
+    String[] getKnownPackageNamesInternal(@NonNull Computer snapshot, int knownPackage,
+            int userId) {
         switch (knownPackage) {
             case PackageManagerInternal.PACKAGE_BROWSER:
                 return new String[] { mDefaultAppProvider.getDefaultBrowser(userId) };
             case PackageManagerInternal.PACKAGE_INSTALLER:
-                return mComputer.filterOnlySystemPackages(mRequiredInstallerPackage);
+                return snapshot.filterOnlySystemPackages(mRequiredInstallerPackage);
             case PackageManagerInternal.PACKAGE_UNINSTALLER:
-                return mComputer.filterOnlySystemPackages(mRequiredUninstallerPackage);
+                return snapshot.filterOnlySystemPackages(mRequiredUninstallerPackage);
             case PackageManagerInternal.PACKAGE_SETUP_WIZARD:
-                return mComputer.filterOnlySystemPackages(mSetupWizardPackage);
+                return snapshot.filterOnlySystemPackages(mSetupWizardPackage);
             case PackageManagerInternal.PACKAGE_SYSTEM:
                 return new String[]{"android"};
             case PackageManagerInternal.PACKAGE_VERIFIER:
-                return mComputer.filterOnlySystemPackages(mRequiredVerifierPackage);
+                return snapshot.filterOnlySystemPackages(mRequiredVerifierPackage);
             case PackageManagerInternal.PACKAGE_SYSTEM_TEXT_CLASSIFIER:
-                return mComputer.filterOnlySystemPackages(
+                return snapshot.filterOnlySystemPackages(
                         mDefaultTextClassifierPackage, mSystemTextClassifierPackageName);
             case PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER:
-                return mComputer.filterOnlySystemPackages(mRequiredPermissionControllerPackage);
+                return snapshot.filterOnlySystemPackages(mRequiredPermissionControllerPackage);
             case PackageManagerInternal.PACKAGE_CONFIGURATOR:
-                return mComputer.filterOnlySystemPackages(mConfiguratorPackage);
+                return snapshot.filterOnlySystemPackages(mConfiguratorPackage);
             case PackageManagerInternal.PACKAGE_INCIDENT_REPORT_APPROVER:
-                return mComputer.filterOnlySystemPackages(mIncidentReportApproverPackage);
+                return snapshot.filterOnlySystemPackages(mIncidentReportApproverPackage);
             case PackageManagerInternal.PACKAGE_AMBIENT_CONTEXT_DETECTION:
-                return mComputer.filterOnlySystemPackages(mAmbientContextDetectionPackage);
+                return snapshot.filterOnlySystemPackages(mAmbientContextDetectionPackage);
             case PackageManagerInternal.PACKAGE_APP_PREDICTOR:
-                return mComputer.filterOnlySystemPackages(mAppPredictionServicePackage);
+                return snapshot.filterOnlySystemPackages(mAppPredictionServicePackage);
             case PackageManagerInternal.PACKAGE_COMPANION:
-                return mComputer.filterOnlySystemPackages(COMPANION_PACKAGE_NAME);
+                return snapshot.filterOnlySystemPackages(COMPANION_PACKAGE_NAME);
             case PackageManagerInternal.PACKAGE_RETAIL_DEMO:
                 return TextUtils.isEmpty(mRetailDemoPackage)
                         ? ArrayUtils.emptyArray(String.class)
                         : new String[] {mRetailDemoPackage};
             case PackageManagerInternal.PACKAGE_OVERLAY_CONFIG_SIGNATURE:
-                return mComputer.filterOnlySystemPackages(getOverlayConfigSignaturePackageName());
+                return snapshot.filterOnlySystemPackages(mOverlayConfigSignaturePackage);
             case PackageManagerInternal.PACKAGE_RECENTS:
-                return mComputer.filterOnlySystemPackages(mRecentsPackage);
+                return snapshot.filterOnlySystemPackages(mRecentsPackage);
             default:
                 return ArrayUtils.emptyArray(String.class);
         }
@@ -8659,10 +7039,6 @@
         mDefaultAppProvider.setDefaultBrowser(packageName, async, userId);
     }
 
-    ResolveInfo getInstantAppInstallerInfo() {
-        return mInstantAppInstallerInfo;
-    }
-
     PackageUsage getPackageUsage() {
         return mPackageUsage;
     }
@@ -8676,7 +7052,7 @@
     }
 
     boolean isExpectingBetter(String packageName) {
-        return mInitAndSystemPackageHelper.isExpectingBetter(packageName);
+        return mInitAppsHelper.isExpectingBetter(packageName);
     }
 
     int getDefParseFlags() {
@@ -8754,10 +7130,6 @@
         }
     }
 
-    ResolveInfo getResolveInfo() {
-        return mResolveInfo;
-    }
-
     ApplicationInfo getCoreAndroidApplication() {
         return mAndroidApplication;
     }
@@ -8779,13 +7151,12 @@
     }
 
     boolean isOverlayMutable(String packageName) {
-        return (mOverlayConfig != null ? mOverlayConfig
-                : OverlayConfig.getSystemInstance()).isMutable(packageName);
+        return mOverlayConfig.isMutable(packageName);
     }
 
     @ScanFlags int getSystemPackageScanFlags(File codePath) {
         List<ScanPartition> dirsToScanAsSystem =
-                mInitAndSystemPackageHelper.getDirsToScanAsSystem();
+                mInitAppsHelper.getDirsToScanAsSystem();
         @PackageManagerService.ScanFlags int scanFlags = SCAN_AS_SYSTEM;
         for (int i = dirsToScanAsSystem.size() - 1; i >= 0; i--) {
             ScanPartition partition = dirsToScanAsSystem.get(i);
@@ -8803,7 +7174,7 @@
     Pair<Integer, Integer> getSystemPackageRescanFlagsAndReparseFlags(File scanFile,
             int systemScanFlags, int systemParseFlags) {
         List<ScanPartition> dirsToScanAsSystem =
-                mInitAndSystemPackageHelper.getDirsToScanAsSystem();
+                mInitAppsHelper.getDirsToScanAsSystem();
         @ParsingPackageUtils.ParseFlags int reparseFlags = 0;
         @PackageManagerService.ScanFlags int rescanFlags = 0;
         for (int i1 = dirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
index 5bdda0b..e466fe2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
@@ -109,7 +109,7 @@
     public AppDataHelper appDataHelper;
     public InstallPackageHelper installPackageHelper;
     public RemovePackageHelper removePackageHelper;
-    public InitAndSystemPackageHelper initAndSystemPackageHelper;
+    public InitAppsHelper initAndSystemPackageHelper;
     public DeletePackageHelper deletePackageHelper;
     public PreferredActivityHelper preferredActivityHelper;
     public ResolveIntentHelper resolveIntentHelper;
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 62e9d37..581e4e2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -188,6 +188,8 @@
                     return runDump();
                 case "list":
                     return runList();
+                case "gc":
+                    return runGc();
                 case "resolve-activity":
                     return runResolveActivity();
                 case "query-activities":
@@ -687,6 +689,13 @@
         return -1;
     }
 
+    private int runGc() throws RemoteException {
+        Runtime.getRuntime().gc();
+        final PrintWriter pw = getOutPrintWriter();
+        pw.println("Ok");
+        return 0;
+    }
+
     private int runListFeatures() throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
         final List<FeatureInfo> list = mInterface.getSystemAvailableFeatures().getList();
@@ -2540,8 +2549,10 @@
             privAppPermissions = SystemConfig.getInstance()
                     .getSystemExtPrivAppPermissions(pkg);
         } else if (isApexApp(pkg)) {
+            final String apexName = ApexManager.getInstance().getApexModuleNameForPackageName(
+                    getApexPackageNameContainingPackage(pkg));
             privAppPermissions = SystemConfig.getInstance()
-                    .getApexPrivAppPermissions(getApexPackageNameContainingPackage(pkg), pkg);
+                    .getApexPrivAppPermissions(apexName, pkg);
         } else {
             privAppPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg);
         }
@@ -2567,8 +2578,10 @@
             privAppPermissions = SystemConfig.getInstance()
                     .getSystemExtPrivAppDenyPermissions(pkg);
         } else if (isApexApp(pkg)) {
+            final String apexName = ApexManager.getInstance().getApexModuleNameForPackageName(
+                    getApexPackageNameContainingPackage(pkg));
             privAppPermissions = SystemConfig.getInstance()
-                    .getApexPrivAppDenyPermissions(getApexPackageNameContainingPackage(pkg), pkg);
+                    .getApexPrivAppDenyPermissions(apexName, pkg);
         } else {
             privAppPermissions = SystemConfig.getInstance().getPrivAppDenyPermissions(pkg);
         }
diff --git a/services/core/java/com/android/server/pm/PackageSender.java b/services/core/java/com/android/server/pm/PackageSender.java
index d380098..656d596 100644
--- a/services/core/java/com/android/server/pm/PackageSender.java
+++ b/services/core/java/com/android/server/pm/PackageSender.java
@@ -16,6 +16,7 @@
 
 package com.android.server.pm;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.IIntentReceiver;
 import android.os.Bundle;
@@ -30,9 +31,9 @@
             Bundle extras, int flags, String targetPkg,
             IIntentReceiver finishedReceiver, int[] userIds, int[] instantUserIds,
             @Nullable SparseArray<int[]> broadcastAllowList, @Nullable Bundle bOptions);
-    void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
-            boolean includeStopped, int appId, int[] userIds, int[] instantUserIds,
-            int dataLoaderType);
+    void sendPackageAddedForNewUsers(@NonNull Computer snapshot, String packageName,
+            boolean sendBootCompleted, boolean includeStopped, int appId, int[] userIds,
+            int[] instantUserIds, int dataLoaderType);
     void notifyPackageAdded(String packageName, int uid);
     void notifyPackageChanged(String packageName, int uid);
     void notifyPackageRemoved(String packageName, int uid);
diff --git a/services/core/java/com/android/server/pm/PreferredActivityHelper.java b/services/core/java/com/android/server/pm/PreferredActivityHelper.java
index 7253ae4..9befd6e 100644
--- a/services/core/java/com/android/server/pm/PreferredActivityHelper.java
+++ b/services/core/java/com/android/server/pm/PreferredActivityHelper.java
@@ -25,6 +25,7 @@
 import static com.android.server.pm.PackageManagerService.TAG;
 
 import android.annotation.NonNull;
+import android.annotation.UserIdInt;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -74,17 +75,18 @@
         mPm = pm;
     }
 
-    private ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType,
-            @PackageManager.ResolveInfoFlagsBits long flags, List<ResolveInfo> query,
-            boolean always, boolean removeMatches, boolean debug, int userId) {
-        return findPreferredActivityNotLocked(
-                intent, resolvedType, flags, query, always, removeMatches, debug, userId,
+    private ResolveInfo findPreferredActivityNotLocked(@NonNull Computer snapshot, Intent intent,
+            String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
+            List<ResolveInfo> query, boolean always, boolean removeMatches, boolean debug,
+            @UserIdInt int userId) {
+        return findPreferredActivityNotLocked(snapshot, intent, resolvedType, flags, query, always,
+                removeMatches, debug, userId,
                 UserHandle.getAppId(Binder.getCallingUid()) >= Process.FIRST_APPLICATION_UID);
     }
 
     // TODO: handle preferred activities missing while user has amnesia
     /** <b>must not hold {@link PackageManagerService.mLock}</b> */
-    public ResolveInfo findPreferredActivityNotLocked(
+    public ResolveInfo findPreferredActivityNotLocked(@NonNull Computer snapshot,
             Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
             List<ResolveInfo> query, boolean always, boolean removeMatches, boolean debug,
             int userId, boolean queryMayBeFiltered) {
@@ -95,7 +97,7 @@
         if (!mPm.mUserManager.exists(userId)) return null;
 
         PackageManagerService.FindPreferredActivityBodyResult body =
-                mPm.findPreferredActivityInternal(
+                snapshot.findPreferredActivityInternal(
                 intent, resolvedType, flags, query, always,
                 removeMatches, debug, userId, queryMayBeFiltered);
         if (body.mChanged) {
@@ -117,7 +119,7 @@
             mPm.clearPackagePreferredActivitiesLPw(packageName, changedUsers, userId);
         }
         if (changedUsers.size() > 0) {
-            updateDefaultHomeNotLocked(changedUsers);
+            updateDefaultHomeNotLocked(mPm.snapshotComputer(), changedUsers);
             mPm.postPreferredActivityChangedBroadcast(userId);
             mPm.scheduleWritePackageRestrictions(userId);
         }
@@ -128,7 +130,7 @@
      *
      * @return Whether the ACTION_PREFERRED_ACTIVITY_CHANGED broadcast has been scheduled.
      */
-    public boolean updateDefaultHomeNotLocked(int userId) {
+    public boolean updateDefaultHomeNotLocked(@NonNull Computer snapshot, @UserIdInt int userId) {
         if (Thread.holdsLock(mPm.mLock)) {
             Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
                     + " is holding mLock", new Throwable());
@@ -139,10 +141,10 @@
             // before that.
             return false;
         }
-        final Intent intent = mPm.getHomeIntent();
-        final List<ResolveInfo> resolveInfos = mPm.snapshotComputer().queryIntentActivitiesInternal(
+        final Intent intent = snapshot.getHomeIntent();
+        final List<ResolveInfo> resolveInfos = snapshot.queryIntentActivitiesInternal(
                 intent, null, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId);
-        final ResolveInfo preferredResolveInfo = findPreferredActivityNotLocked(
+        final ResolveInfo preferredResolveInfo = findPreferredActivityNotLocked(snapshot,
                 intent, null, 0, resolveInfos, true, false, false, userId);
         final String packageName = preferredResolveInfo != null
                 && preferredResolveInfo.activityInfo != null
@@ -151,8 +153,7 @@
         if (TextUtils.equals(currentPackageName, packageName)) {
             return false;
         }
-        final String[] callingPackages = mPm.mIPackageManager
-                .getPackagesForUid(Binder.getCallingUid());
+        final String[] callingPackages = snapshot.getPackagesForUid(Binder.getCallingUid());
         if (callingPackages != null && ArrayUtils.contains(callingPackages,
                 mPm.mRequiredPermissionControllerPackage)) {
             // PermissionController manages default home directly.
@@ -174,23 +175,21 @@
     /**
      * Variant that takes a {@link WatchedIntentFilter}
      */
-    public void addPreferredActivity(WatchedIntentFilter filter, int match,
-            ComponentName[] set, ComponentName activity, boolean always, int userId,
+    public void addPreferredActivity(@NonNull Computer snapshot, WatchedIntentFilter filter,
+            int match, ComponentName[] set, ComponentName activity, boolean always, int userId,
             String opname, boolean removeExisting) {
         // writer
         int callingUid = Binder.getCallingUid();
-        mPm.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
+        snapshot.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
                 false /* checkShell */, "add preferred activity");
         if (mPm.mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
                 != PackageManager.PERMISSION_GRANTED) {
-            synchronized (mPm.mLock) {
-                if (mPm.getUidTargetSdkVersion(callingUid)
-                        < Build.VERSION_CODES.FROYO) {
-                    Slog.w(TAG, "Ignoring addPreferredActivity() from uid "
-                            + callingUid);
-                    return;
-                }
+            if (snapshot.getUidTargetSdkVersion(callingUid)
+                    < Build.VERSION_CODES.FROYO) {
+                Slog.w(TAG, "Ignoring addPreferredActivity() from uid "
+                        + callingUid);
+                return;
             }
             mPm.mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
@@ -214,7 +213,8 @@
                     new PreferredActivity(filter, match, set, activity, always));
             mPm.scheduleWritePackageRestrictions(userId);
         }
-        if (!(isHomeFilter(filter) && updateDefaultHomeNotLocked(userId))) {
+        // Re-snapshot after mLock
+        if (!(isHomeFilter(filter) && updateDefaultHomeNotLocked(mPm.snapshotComputer(), userId))) {
             mPm.postPreferredActivityChangedBroadcast(userId);
         }
     }
@@ -222,8 +222,8 @@
     /**
      * Variant that takes a {@link WatchedIntentFilter}
      */
-    public void replacePreferredActivity(WatchedIntentFilter filter, int match,
-            ComponentName[] set, ComponentName activity, int userId) {
+    public void replacePreferredActivity(@NonNull Computer snapshot, WatchedIntentFilter filter,
+            int match, ComponentName[] set, ComponentName activity, int userId) {
         if (filter.countActions() != 1) {
             throw new IllegalArgumentException(
                     "replacePreferredActivity expects filter to have only 1 action.");
@@ -238,13 +238,14 @@
         }
 
         final int callingUid = Binder.getCallingUid();
-        mPm.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
+        snapshot.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
                 false /* checkShell */, "replace preferred activity");
         if (mPm.mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
                 != PackageManager.PERMISSION_GRANTED) {
             synchronized (mPm.mLock) {
-                if (mPm.getUidTargetSdkVersion(callingUid)
+                // TODO: Remove lock?
+                if (mPm.snapshotComputer().getUidTargetSdkVersion(callingUid)
                         < Build.VERSION_CODES.FROYO) {
                     Slog.w(TAG, "Ignoring replacePreferredActivity() from uid "
                             + Binder.getCallingUid());
@@ -296,21 +297,23 @@
                 }
             }
         }
-        addPreferredActivity(filter, match, set, activity, true, userId,
+
+        // Retake a snapshot after editing with lock held
+        addPreferredActivity(mPm.snapshotComputer(), filter, match, set, activity, true, userId,
                 "Replacing preferred", false);
     }
 
-    public void clearPackagePreferredActivities(String packageName) {
+    public void clearPackagePreferredActivities(@NonNull Computer snapshot, String packageName) {
         final int callingUid = Binder.getCallingUid();
-        if (mPm.getInstantAppPackageName(callingUid) != null) {
+        if (snapshot.getInstantAppPackageName(callingUid) != null) {
             return;
         }
-        final PackageStateInternal packageState = mPm.getPackageStateInternal(packageName);
-        if (packageState == null || !mPm.isCallerSameApp(packageName, callingUid)) {
+        final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
+        if (packageState == null || !snapshot.isCallerSameApp(packageName, callingUid)) {
             if (mPm.mContext.checkCallingOrSelfPermission(
                     android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
                     != PackageManager.PERMISSION_GRANTED) {
-                if (mPm.getUidTargetSdkVersion(callingUid)
+                if (snapshot.getUidTargetSdkVersion(callingUid)
                         < Build.VERSION_CODES.FROYO) {
                     Slog.w(TAG, "Ignoring clearPackagePreferredActivities() from uid "
                             + callingUid);
@@ -320,7 +323,7 @@
                         android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
             }
         }
-        if (packageState != null && mPm.shouldFilterApplication(packageState, callingUid,
+        if (packageState != null && snapshot.shouldFilterApplication(packageState, callingUid,
                 UserHandle.getUserId(callingUid))) {
             return;
         }
@@ -329,23 +332,23 @@
     }
 
     /** <b>must not hold {@link #PackageManagerService.mLock}</b> */
-    void updateDefaultHomeNotLocked(SparseBooleanArray userIds) {
+    void updateDefaultHomeNotLocked(@NonNull Computer snapshot, SparseBooleanArray userIds) {
         if (Thread.holdsLock(mPm.mLock)) {
             Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
                     + " is holding mLock", new Throwable());
         }
         for (int i = userIds.size() - 1; i >= 0; --i) {
             final int userId = userIds.keyAt(i);
-            updateDefaultHomeNotLocked(userId);
+            updateDefaultHomeNotLocked(snapshot, userId);
         }
     }
 
-    public void setHomeActivity(ComponentName comp, int userId) {
-        if (mPm.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+    public void setHomeActivity(@NonNull Computer snapshot, ComponentName comp, int userId) {
+        if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
             return;
         }
         ArrayList<ResolveInfo> homeActivities = new ArrayList<>();
-        mPm.getHomeActivitiesAsUser(homeActivities, userId);
+        snapshot.getHomeActivitiesAsUser(homeActivities, userId);
 
         boolean found = false;
 
@@ -364,7 +367,7 @@
             throw new IllegalArgumentException("Component " + comp + " cannot be home on user "
                     + userId);
         }
-        replacePreferredActivity(getHomeFilter(), IntentFilter.MATCH_CATEGORY_EMPTY,
+        replacePreferredActivity(snapshot, getHomeFilter(), IntentFilter.MATCH_CATEGORY_EMPTY,
                 set, comp, userId);
     }
 
@@ -401,7 +404,7 @@
             mPm.scheduleWritePackageRestrictions(userId);
         }
         if (isHomeFilter(filter)) {
-            updateDefaultHomeNotLocked(userId);
+            updateDefaultHomeNotLocked(mPm.snapshotComputer(), userId);
         }
         mPm.postPreferredActivityChangedBroadcast(userId);
     }
@@ -417,7 +420,7 @@
             changed = mPm.mSettings.clearPackagePersistentPreferredActivities(packageName, userId);
         }
         if (changed) {
-            updateDefaultHomeNotLocked(userId);
+            updateDefaultHomeNotLocked(mPm.snapshotComputer(), userId);
             mPm.postPreferredActivityChangedBroadcast(userId);
             mPm.scheduleWritePackageRestrictions(userId);
         }
@@ -506,7 +509,7 @@
                         synchronized (mPm.mLock) {
                             mPm.mSettings.readPreferredActivitiesLPw(readParser, readUserId);
                         }
-                        updateDefaultHomeNotLocked(readUserId);
+                        updateDefaultHomeNotLocked(mPm.snapshotComputer(), readUserId);
                     });
         } catch (Exception e) {
             if (DEBUG_BACKUP) {
@@ -598,7 +601,7 @@
                     mPm.mPermissionManager.resetRuntimePermissions(pkg, userId);
                 }
             }
-            updateDefaultHomeNotLocked(userId);
+            updateDefaultHomeNotLocked(mPm.snapshotComputer(), userId);
             resetNetworkPolicies(userId);
             mPm.scheduleWritePackageRestrictions(userId);
         } finally {
@@ -610,12 +613,11 @@
         mPm.mInjector.getLocalService(NetworkPolicyManagerInternal.class).resetUserState(userId);
     }
 
-    // TODO: This method should not touch the Computer directly
-    public int getPreferredActivities(List<IntentFilter> outFilters,
-            List<ComponentName> outActivities, String packageName, Computer computer) {
+    public int getPreferredActivities(@NonNull Computer snapshot, List<IntentFilter> outFilters,
+            List<ComponentName> outActivities, String packageName) {
         List<WatchedIntentFilter> temp =
                 WatchedIntentFilter.toWatchedIntentFilterList(outFilters);
-        int result = getPreferredActivitiesInternal(temp, outActivities, packageName, computer);
+        int result = getPreferredActivitiesInternal(snapshot, temp, outActivities, packageName);
         outFilters.clear();
         for (int i = 0; i < temp.size(); i++) {
             outFilters.add(temp.get(i).getIntentFilter());
@@ -626,16 +628,17 @@
     /**
      * Variant that takes a {@link WatchedIntentFilter}
      */
-    private int getPreferredActivitiesInternal(List<WatchedIntentFilter> outFilters,
-            List<ComponentName> outActivities, String packageName, Computer computer) {
+    private int getPreferredActivitiesInternal(@NonNull Computer snapshot,
+            List<WatchedIntentFilter> outFilters, List<ComponentName> outActivities,
+            String packageName) {
         final int callingUid = Binder.getCallingUid();
-        if (mPm.getInstantAppPackageName(callingUid) != null) {
+        if (snapshot.getInstantAppPackageName(callingUid) != null) {
             return 0;
         }
         int num = 0;
         final int userId = UserHandle.getCallingUserId();
 
-        PreferredIntentResolver pir = computer.getPreferredActivities(userId);
+        PreferredIntentResolver pir = snapshot.getPreferredActivities(userId);
         if (pir != null) {
             final Iterator<PreferredActivity> it = pir.filterIterator();
             while (it.hasNext()) {
@@ -643,8 +646,9 @@
                 final String prefPackageName = pa.mPref.mComponent.getPackageName();
                 if (packageName == null
                         || (prefPackageName.equals(packageName) && pa.mPref.mAlways)) {
-                    if (mPm.shouldFilterApplication(
-                            mPm.getPackageStateInternal(prefPackageName), callingUid, userId)) {
+                    if (snapshot.shouldFilterApplication(
+                            snapshot.getPackageStateInternal(prefPackageName), callingUid,
+                            userId)) {
                         continue;
                     }
                     if (outFilters != null) {
@@ -660,7 +664,8 @@
         return num;
     }
 
-    public ResolveInfo findPersistentPreferredActivity(Intent intent, int userId) {
+    public ResolveInfo findPersistentPreferredActivity(@NonNull Computer snapshot, Intent intent,
+            int userId) {
         if (!UserHandle.isSameApp(Binder.getCallingUid(), Process.SYSTEM_UID)) {
             throw new SecurityException(
                     "findPersistentPreferredActivity can only be run by the system");
@@ -671,24 +676,23 @@
         final int callingUid = Binder.getCallingUid();
         intent = PackageManagerServiceUtils.updateIntentForResolve(intent);
         final String resolvedType = intent.resolveTypeIfNeeded(mPm.mContext.getContentResolver());
-        final long flags = mPm.updateFlagsForResolve(
+        final long flags = snapshot.updateFlagsForResolve(
                 0, userId, callingUid, false /*includeInstantApps*/,
-                mPm.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+                snapshot.isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId, resolvedType,
                         0));
-        final List<ResolveInfo> query = mPm.snapshotComputer().queryIntentActivitiesInternal(intent,
+        final List<ResolveInfo> query = snapshot.queryIntentActivitiesInternal(intent,
                 resolvedType, flags, userId);
-        synchronized (mPm.mLock) {
-            return mPm.findPersistentPreferredActivityLP(intent, resolvedType, flags, query, false,
-                    userId);
-        }
+        return snapshot.findPersistentPreferredActivity(intent, resolvedType, flags, query, false,
+                userId);
     }
 
     /**
      * Variant that takes a {@link WatchedIntentFilter}
      */
-    public void setLastChosenActivity(Intent intent, String resolvedType, int flags,
-            WatchedIntentFilter filter, int match, ComponentName activity) {
-        if (mPm.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+    public void setLastChosenActivity(@NonNull Computer snapshot, Intent intent,
+            String resolvedType, int flags, WatchedIntentFilter filter, int match,
+            ComponentName activity) {
+        if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
             return;
         }
         final int userId = UserHandle.getCallingUserId();
@@ -702,25 +706,26 @@
             filter.dump(new PrintStreamPrinter(System.out), "    ");
         }
         intent.setComponent(null);
-        final List<ResolveInfo> query = mPm.snapshotComputer().queryIntentActivitiesInternal(intent,
+        final List<ResolveInfo> query = snapshot.queryIntentActivitiesInternal(intent,
                 resolvedType, flags, userId);
         // Find any earlier preferred or last chosen entries and nuke them
-        findPreferredActivityNotLocked(
-                intent, resolvedType, flags, query, false, true, false, userId);
+        findPreferredActivityNotLocked(snapshot, intent, resolvedType, flags, query, false, true,
+                false, userId);
         // Add the new activity as the last chosen for this filter
-        addPreferredActivity(filter, match, null, activity, false, userId,
+        addPreferredActivity(snapshot, filter, match, null, activity, false, userId,
                 "Setting last chosen", false);
     }
 
-    public ResolveInfo getLastChosenActivity(Intent intent, String resolvedType, int flags) {
-        if (mPm.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+    public ResolveInfo getLastChosenActivity(@NonNull Computer snapshot, Intent intent,
+            String resolvedType, int flags) {
+        if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
             return null;
         }
         final int userId = UserHandle.getCallingUserId();
         if (DEBUG_PREFERRED) Log.v(TAG, "Querying last chosen activity for " + intent);
-        final List<ResolveInfo> query = mPm.snapshotComputer().queryIntentActivitiesInternal(intent,
+        final List<ResolveInfo> query = snapshot.queryIntentActivitiesInternal(intent,
                 resolvedType, flags, userId);
-        return findPreferredActivityNotLocked(
-                intent, resolvedType, flags, query, false, false, false, userId);
+        return findPreferredActivityNotLocked(snapshot, intent, resolvedType, flags, query, false,
+                false, false, userId);
     }
 }
diff --git a/services/core/java/com/android/server/pm/PreferredComponent.java b/services/core/java/com/android/server/pm/PreferredComponent.java
index 4ec042f..2a1ca2c 100644
--- a/services/core/java/com/android/server/pm/PreferredComponent.java
+++ b/services/core/java/com/android/server/pm/PreferredComponent.java
@@ -57,7 +57,6 @@
     private String mParseError;
 
     private final Callbacks mCallbacks;
-    private final String mSetupWizardPackageName;
 
     public interface Callbacks {
         public boolean onReadTag(String tagName, TypedXmlPullParser parser)
@@ -72,7 +71,6 @@
         mAlways = always;
         mShortComponent = component.flattenToShortString();
         mParseError = null;
-        mSetupWizardPackageName = null;
         if (set != null) {
             final int N = set.length;
             String[] myPackages = new String[N];
@@ -174,8 +172,6 @@
         mSetPackages = myPackages;
         mSetClasses = myClasses;
         mSetComponents = myComponents;
-        final PackageManagerInternal packageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
-        mSetupWizardPackageName = packageManagerInternal.getSetupWizardPackageName();
     }
 
     public String getParseError() {
@@ -209,6 +205,7 @@
         final int NQ = query.size();
         final int NS = mSetPackages.length;
         final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+        String setupWizardPackageName = pmi.getSetupWizardPackageName();
         int numMatch = 0;
         for (int i=0; i<NQ; i++) {
             ResolveInfo ri = query.get(i);
@@ -217,7 +214,7 @@
 
             // ignore SetupWizard package's launcher capability because it is only existed
             // during SetupWizard is running
-            if (excludeSetupWizardPackage && ai.packageName.equals(mSetupWizardPackageName)) {
+            if (excludeSetupWizardPackage && ai.packageName.equals(setupWizardPackageName)) {
                 continue;
             }
 
@@ -307,6 +304,8 @@
         if (!excludeSetupWizardPackage && NS < NQ) {
             return false;
         }
+        final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+        String setupWizardPackageName = pmi.getSetupWizardPackageName();
         for (int i=0; i<NQ; i++) {
             ResolveInfo ri = query.get(i);
             ActivityInfo ai = ri.activityInfo;
@@ -314,7 +313,7 @@
 
             // ignore SetupWizard package's launcher capability because it is only existed
             // during SetupWizard is running
-            if (excludeSetupWizardPackage && ai.packageName.equals(mSetupWizardPackageName)) {
+            if (excludeSetupWizardPackage && ai.packageName.equals(setupWizardPackageName)) {
                 continue;
             }
 
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index 88df843..b181cdd 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -118,7 +118,8 @@
 
     public void removePackageLI(AndroidPackage pkg, boolean chatty) {
         // Remove the parent package setting
-        PackageStateInternal ps = mPm.getPackageStateInternal(pkg.getPackageName());
+        PackageStateInternal ps = mPm.snapshotComputer()
+                .getPackageStateInternal(pkg.getPackageName());
         if (ps != null) {
             removePackageLI(ps.getPackageName(), chatty);
         } else if (DEBUG_REMOVE && chatty) {
@@ -271,8 +272,8 @@
             synchronized (mPm.mLock) {
                 mPm.mDomainVerificationManager.clearPackage(deletedPs.getPackageName());
                 mPm.mSettings.getKeySetManagerService().removeAppKeySetDataLPw(packageName);
-                mPm.mAppsFilter.removePackage(mPm.getPackageStateInternal(packageName),
-                        false /* isReplace */);
+                mPm.mAppsFilter.removePackage(mPm.snapshotComputer()
+                                .getPackageStateInternal(packageName), false /* isReplace */);
                 removedAppId = mPm.mSettings.removePackageLPw(packageName);
                 if (outInfo != null) {
                     outInfo.mRemovedAppId = removedAppId;
@@ -298,7 +299,8 @@
             if (changedUsers.size() > 0) {
                 final PreferredActivityHelper preferredActivityHelper =
                         new PreferredActivityHelper(mPm);
-                preferredActivityHelper.updateDefaultHomeNotLocked(changedUsers);
+                preferredActivityHelper.updateDefaultHomeNotLocked(mPm.snapshotComputer(),
+                        changedUsers);
                 mPm.postPreferredActivityChangedBroadcast(UserHandle.USER_ALL);
             }
         }
diff --git a/services/core/java/com/android/server/pm/ResolveIntentHelper.java b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
index 25356a4..b74670b 100644
--- a/services/core/java/com/android/server/pm/ResolveIntentHelper.java
+++ b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
@@ -115,7 +115,7 @@
             if (!mUserManager.exists(userId)) return null;
             final int callingUid = Binder.getCallingUid();
             flags = computer.updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart,
-                    computer.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId,
+                    computer.isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId,
                             resolvedType, flags));
             computer.enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/,
                     false /*checkShell*/, "resolve intent");
@@ -170,9 +170,9 @@
                 }
                 // If we have saved a preference for a preferred activity for
                 // this Intent, use that.
-                ResolveInfo ri = mPreferredActivityHelper.findPreferredActivityNotLocked(intent,
-                        resolvedType, flags, query, true, false, debug, userId,
-                        queryMayBeFiltered);
+                ResolveInfo ri = mPreferredActivityHelper.findPreferredActivityNotLocked(computer,
+                        intent, resolvedType, flags, query, true, false, debug,
+                        userId, queryMayBeFiltered);
                 if (ri != null) {
                     return ri;
                 }
@@ -317,7 +317,7 @@
         final String instantAppPkgName = computer.getInstantAppPackageName(filterCallingUid);
         flags = computer.updateFlagsForResolve(flags, userId, filterCallingUid,
                 false /*includeInstantApps*/,
-                computer.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId,
+                computer.isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId,
                         resolvedType, flags));
         Intent originalIntent = null;
         ComponentName comp = intent.getComponent();
@@ -562,7 +562,7 @@
         final int callingUid = Binder.getCallingUid();
         flags = computer.updateFlagsForResolve(flags, userId, callingUid,
                 false /*includeInstantApps*/,
-                computer.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId,
+                computer.isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId,
                         resolvedType, flags));
         computer.enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/,
                 false /*checkShell*/, "query intent activity options");
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 6ccaae1..698dbe9 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -62,7 +62,6 @@
 import android.os.Message;
 import android.os.PatternMatcher;
 import android.os.PersistableBundle;
-import android.os.Process;
 import android.os.SELinux;
 import android.os.SystemClock;
 import android.os.Trace;
@@ -408,8 +407,6 @@
         int[] excludedUserIds;
     }
 
-    private static int mFirstAvailableUid = Process.FIRST_APPLICATION_UID;
-
     /** Map from volume UUID to {@link VersionInfo} */
     @Watched
     private final WatchedArrayMap<String, VersionInfo> mVersion = new WatchedArrayMap<>();
@@ -472,10 +469,8 @@
 
     @Watched
     final WatchedArrayMap<String, SharedUserSetting> mSharedUsers = new WatchedArrayMap<>();
-    @Watched
+    @Watched(manual = true)
     private final AppIdSettingMap mAppIds;
-    @Watched
-    private final AppIdSettingMap mOtherAppIds;
 
     // For reading/writing settings file.
     @Watched
@@ -565,7 +560,6 @@
         mCrossProfileIntentResolvers.registerObserver(mObserver);
         mSharedUsers.registerObserver(mObserver);
         mAppIds.registerObserver(mObserver);
-        mOtherAppIds.registerObserver(mObserver);
         mRenamedPackages.registerObserver(mObserver);
         mNextAppLinkGeneration.registerObserver(mObserver);
         mDefaultBrowserApp.registerObserver(mObserver);
@@ -592,7 +586,6 @@
         mLock = new PackageManagerTracedLock();
         mPackages.putAll(pkgSettings);
         mAppIds = new AppIdSettingMap();
-        mOtherAppIds = new AppIdSettingMap();
         mSystemDir = null;
         mPermissions = null;
         mRuntimePermissionsPersistence = null;
@@ -629,7 +622,6 @@
 
         mLock = lock;
         mAppIds = new AppIdSettingMap();
-        mOtherAppIds = new AppIdSettingMap();
         mPermissions = new LegacyPermissionSettings(lock);
         mRuntimePermissionsPersistence = new RuntimePermissionPersistence(
                 runtimePermissionsPersistence, new Consumer<Integer>() {
@@ -710,7 +702,6 @@
                 mCrossProfileIntentResolvers, r.mCrossProfileIntentResolvers);
         mSharedUsers.snapshot(r.mSharedUsers);
         mAppIds = r.mAppIds.snapshot();
-        mOtherAppIds = r.mOtherAppIds.snapshot();
         WatchedArrayList.snapshot(
                 mPastSignatures, r.mPastSignatures);
         WatchedArrayMap.snapshot(
@@ -782,7 +773,7 @@
         SharedUserSetting s = mSharedUsers.get(name);
         if (s == null && create) {
             s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
-            s.mAppId = acquireAndRegisterNewAppIdLPw(s);
+            s.mAppId = mAppIds.acquireAndRegisterNewAppId(s);
             if (s.mAppId < 0) {
                 // < 0 means we couldn't assign a userid; throw exception
                 throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
@@ -890,7 +881,7 @@
                 pkgPrivateFlags, 0 /*userId*/, usesSdkLibraries, usesSdkLibrariesVersions,
                 usesStaticLibraries, usesStaticLibrariesVersions, mimeGroups, domainSetId);
         p.setAppId(uid);
-        if (registerExistingAppIdLPw(uid, p, name)) {
+        if (mAppIds.registerExistingAppId(uid, p, name)) {
             mPackages.put(name, p);
             return p;
         }
@@ -909,7 +900,7 @@
         }
         s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
         s.mAppId = uid;
-        if (registerExistingAppIdLPw(uid, s, name)) {
+        if (mAppIds.registerExistingAppId(uid, s, name)) {
             mSharedUsers.put(name, s);
             return s;
         }
@@ -1210,11 +1201,11 @@
         final boolean createdNew;
         if (p.getAppId() == 0 || forceNew) {
             // Assign new user ID
-            p.setAppId(acquireAndRegisterNewAppIdLPw(p));
+            p.setAppId(mAppIds.acquireAndRegisterNewAppId(p));
             createdNew = true;
         } else {
             // Add new setting to list of user IDs
-            createdNew = registerExistingAppIdLPw(p.getAppId(), p, p.getPackageName());
+            createdNew = mAppIds.registerExistingAppId(p.getAppId(), p, p.getPackageName());
         }
         if (p.getAppId() < 0) {
             PackageManagerService.reportSettingsProblem(Log.WARN,
@@ -1304,11 +1295,11 @@
         Object userIdPs = getSettingLPr(p.getAppId());
         if (sharedUser == null) {
             if (userIdPs != null && userIdPs != p) {
-                replaceAppIdLPw(p.getAppId(), p);
+                mAppIds.replaceSetting(p.getAppId(), p);
             }
         } else {
             if (userIdPs != null && userIdPs != sharedUser) {
-                replaceAppIdLPw(p.getAppId(), sharedUser);
+                mAppIds.replaceSetting(p.getAppId(), sharedUser);
             }
         }
     }
@@ -1357,73 +1348,22 @@
         mInstallerPackages.remove(packageName);
     }
 
-    /** Returns true if the requested AppID was valid and not already registered. */
-    private boolean registerExistingAppIdLPw(int appId, SettingBase obj, Object name) {
-        if (appId > Process.LAST_APPLICATION_UID) {
-            return false;
-        }
-
-        if (appId >= Process.FIRST_APPLICATION_UID) {
-            if (mAppIds.get(appId) != null) {
-                PackageManagerService.reportSettingsProblem(Log.WARN,
-                        "Adding duplicate app id: " + appId
-                        + " name=" + name);
-                return false;
-            }
-            mAppIds.put(appId, obj);
-        } else {
-            if (mOtherAppIds.get(appId) != null) {
-                PackageManagerService.reportSettingsProblem(Log.WARN,
-                        "Adding duplicate shared id: " + appId
-                                + " name=" + name);
-                return false;
-            }
-            mOtherAppIds.put(appId, obj);
-        }
-        return true;
-    }
-
     /** Gets the setting associated with the provided App ID */
     public SettingBase getSettingLPr(int appId) {
-        if (appId >= Process.FIRST_APPLICATION_UID) {
-            return mAppIds.get(appId);
-        } else {
-            return mOtherAppIds.get(appId);
-        }
+        return mAppIds.getSetting(appId);
     }
 
     /** Unregisters the provided app ID. */
     void removeAppIdLPw(int appId) {
-        if (appId >= Process.FIRST_APPLICATION_UID) {
-            mAppIds.remove(appId);
-        } else {
-            mOtherAppIds.remove(appId);
-        }
-        setFirstAvailableUid(appId + 1);
+        mAppIds.removeSetting(appId);
     }
-
-    private void replaceAppIdLPw(int appId, SettingBase obj) {
-        if (appId >= Process.FIRST_APPLICATION_UID) {
-            if (appId <= mAppIds.getCurrentMaxAppId()) {
-                mAppIds.put(appId, obj);
-            } else {
-                PackageManagerService.reportSettingsProblem(Log.WARN,
-                        "Error in package manager settings: calling replaceAppIdLpw to"
-                                + " replace SettingBase at appId=" + appId
-                                + " but nothing is replaced.");
-            }
-        } else {
-            mOtherAppIds.put(appId, obj);
-        }
-    }
-
     /**
      * Transparently convert a SharedUserSetting into PackageSettings without changing appId.
      * The sharedUser passed to this method has to be {@link SharedUserSetting#isSingleUser()}.
      */
     void convertSharedUserSettingsLPw(SharedUserSetting sharedUser) {
         final PackageSetting ps = sharedUser.getPackageSettings().valueAt(0);
-        replaceAppIdLPw(sharedUser.getAppId(), ps);
+        mAppIds.replaceSetting(sharedUser.getAppId(), ps);
 
         // Unlink the SharedUserSetting
         ps.setSharedUserAppId(INVALID_UID);
@@ -4287,32 +4227,6 @@
         }
     }
 
-    // This should be called (at least) whenever an application is removed
-    private void setFirstAvailableUid(int uid) {
-        if (uid > mFirstAvailableUid) {
-            mFirstAvailableUid = uid;
-        }
-    }
-
-    /** Returns a new AppID or -1 if we could not find an available AppID to assign */
-    private int acquireAndRegisterNewAppIdLPw(SettingBase obj) {
-        final int nextAvailableAppId = mAppIds.getNextAvailableAppId();
-        for (int uid = mFirstAvailableUid; uid < nextAvailableAppId; uid++) {
-            if (mAppIds.get(uid) == null) {
-                mAppIds.put(uid, obj);
-                return uid;
-            }
-        }
-
-        // None left?
-        if (nextAvailableAppId > Process.LAST_APPLICATION_UID) {
-            return -1;
-        }
-
-        mAppIds.put(nextAvailableAppId, obj);
-        return nextAvailableAppId;
-    }
-
     public VerifierDeviceIdentity getVerifierDeviceIdentityLPw(@NonNull Computer computer) {
         if (mVerifierDeviceIdentity == null) {
             mVerifierDeviceIdentity = VerifierDeviceIdentity.generate();
diff --git a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
index 3fe0790..479a404 100644
--- a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
+++ b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
@@ -741,9 +741,11 @@
         }
         SharedLibraryInfo libraryInfo = versionedLib.valueAt(libIdx);
 
+        final Computer snapshot = mPm.snapshotComputer();
+
         // Remove the shared library overlays from its dependent packages.
         for (int currentUserId : mPm.mUserManager.getUserIds()) {
-            final List<VersionedPackage> dependents = mPm.getPackagesUsingSharedLibrary(
+            final List<VersionedPackage> dependents = snapshot.getPackagesUsingSharedLibrary(
                     libraryInfo, 0, Process.SYSTEM_UID, currentUserId);
             if (dependents == null) {
                 continue;
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 8921fee..9ce4cdf 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -19,11 +19,13 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.Person;
+import android.app.appsearch.AppSearchBatchResult;
 import android.app.appsearch.AppSearchManager;
 import android.app.appsearch.AppSearchResult;
 import android.app.appsearch.AppSearchSession;
+import android.app.appsearch.BatchResultCallback;
+import android.app.appsearch.GenericDocument;
 import android.app.appsearch.GetByDocumentIdRequest;
-import android.app.appsearch.PackageIdentifier;
 import android.app.appsearch.PutDocumentsRequest;
 import android.app.appsearch.RemoveByDocumentIdRequest;
 import android.app.appsearch.ReportUsageRequest;
@@ -181,11 +183,6 @@
     private final ArrayList<ShareTargetInfo> mShareTargets = new ArrayList<>(0);
 
     /**
-     * All external packages that have gained access to the shortcuts from this package
-     */
-    private final Map<String, PackageIdentifier> mPackageIdentifiers = new ArrayMap<>(0);
-
-    /**
      * # of times the package has called rate-limited APIs.
      */
     private int mApiCallCount;
@@ -341,7 +338,7 @@
 
     public void ensureAllShortcutsVisibleToLauncher(@NonNull List<ShortcutInfo> shortcuts) {
         for (ShortcutInfo shortcut : shortcuts) {
-            if (!shortcut.isIncludedIn(ShortcutInfo.SURFACE_LAUNCHER)) {
+            if (shortcut.isExcludedFromSurfaces(ShortcutInfo.SURFACE_LAUNCHER)) {
                 throw new IllegalArgumentException("Shortcut ID=" + shortcut.getId()
                         + " is hidden from launcher and may not be manipulated via APIs");
             }
@@ -402,7 +399,7 @@
                     & (ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_CACHED_ALL));
         }
 
-        if (!newShortcut.isIncludedIn(ShortcutInfo.SURFACE_LAUNCHER)) {
+        if (newShortcut.isExcludedFromSurfaces(ShortcutInfo.SURFACE_LAUNCHER)) {
             if (isAppSearchEnabled()) {
                 synchronized (mLock) {
                     mTransientShortcuts.put(newShortcut.getId(), newShortcut);
@@ -480,7 +477,7 @@
                     & (ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_CACHED_ALL));
         }
 
-        if (!newShortcut.isIncludedIn(ShortcutInfo.SURFACE_LAUNCHER)) {
+        if (newShortcut.isExcludedFromSurfaces(ShortcutInfo.SURFACE_LAUNCHER)) {
             if (isAppSearchEnabled()) {
                 synchronized (mLock) {
                     mTransientShortcuts.put(newShortcut.getId(), newShortcut);
@@ -1827,9 +1824,9 @@
             ShortcutService.writeTagExtra(out, TAG_EXTRAS, si.getExtras());
 
             final Map<String, Map<String, List<String>>> capabilityBindings =
-                    si.getCapabilityBindings();
+                    si.getCapabilityBindingsInternal();
             if (capabilityBindings != null && !capabilityBindings.isEmpty()) {
-                XmlUtils.writeMapXml(si.getCapabilityBindings(), NAME_CAPABILITY, out);
+                XmlUtils.writeMapXml(capabilityBindings, NAME_CAPABILITY, out);
             }
         }
 
@@ -2313,14 +2310,15 @@
         }
         SetSchemaRequest.Builder schemaBuilder = new SetSchemaRequest.Builder()
                 .addSchemas(AppSearchShortcutPerson.SCHEMA, AppSearchShortcutInfo.SCHEMA)
-                .setForceOverride(true);
-        for (PackageIdentifier pi : mPackageIdentifiers.values()) {
-            schemaBuilder = schemaBuilder
-                    .setSchemaTypeVisibilityForPackage(
-                            AppSearchShortcutPerson.SCHEMA_TYPE, true, pi)
-                    .setSchemaTypeVisibilityForPackage(
-                            AppSearchShortcutInfo.SCHEMA_TYPE, true, pi);
-        }
+                .setForceOverride(true)
+                .addRequiredPermissionsForSchemaTypeVisibility(AppSearchShortcutInfo.SCHEMA_TYPE,
+                        Collections.singleton(SetSchemaRequest.READ_HOME_APP_SEARCH_DATA))
+                .addRequiredPermissionsForSchemaTypeVisibility(AppSearchShortcutInfo.SCHEMA_TYPE,
+                        Collections.singleton(SetSchemaRequest.READ_ASSISTANT_APP_SEARCH_DATA))
+                .addRequiredPermissionsForSchemaTypeVisibility(AppSearchShortcutPerson.SCHEMA_TYPE,
+                        Collections.singleton(SetSchemaRequest.READ_HOME_APP_SEARCH_DATA))
+                .addRequiredPermissionsForSchemaTypeVisibility(AppSearchShortcutPerson.SCHEMA_TYPE,
+                        Collections.singleton(SetSchemaRequest.READ_ASSISTANT_APP_SEARCH_DATA));
         final AndroidFuture<AppSearchSession> future = new AndroidFuture<>();
         session.setSchema(
                 schemaBuilder.build(), mExecutor, mShortcutUser.mExecutor, result -> {
@@ -2384,14 +2382,24 @@
         }
         runAsSystem(() -> fromAppSearch().thenAccept(session -> {
             session.getByDocumentId(new GetByDocumentIdRequest.Builder(getPackageName())
-                    .addIds(ids).build(), mShortcutUser.mExecutor, result -> {
-                    final List<ShortcutInfo> ret = result.getSuccesses().values()
-                            .stream().map(doc ->
-                                    ShortcutInfo.createFromGenericDocument(
-                                            mShortcutUser.getUserId(), doc))
-                            .collect(Collectors.toList());
-                    cb.accept(ret);
-                });
+                            .addIds(ids).build(), mShortcutUser.mExecutor,
+                    new BatchResultCallback<String, GenericDocument>() {
+                        @Override
+                        public void onResult(
+                                @NonNull AppSearchBatchResult<String, GenericDocument> result) {
+                            final List<ShortcutInfo> ret = result.getSuccesses().values()
+                                    .stream().map(doc ->
+                                            ShortcutInfo.createFromGenericDocument(
+                                                    mShortcutUser.getUserId(), doc))
+                                    .collect(Collectors.toList());
+                            cb.accept(ret);
+                        }
+                        @Override
+                        public void onSystemError(
+                                @Nullable Throwable throwable) {
+                            Slog.d(TAG, "Error retrieving shortcuts", throwable);
+                        }
+                    });
         }));
     }
 
@@ -2407,15 +2415,24 @@
         runAsSystem(() -> fromAppSearch().thenAccept(session ->
                 session.remove(
                         new RemoveByDocumentIdRequest.Builder(getPackageName()).addIds(ids).build(),
-                        mShortcutUser.mExecutor, result -> {
-                            if (!result.isSuccess()) {
-                                final Map<String, AppSearchResult<Void>> failures =
-                                        result.getFailures();
-                                for (String key : failures.keySet()) {
-                                    Slog.e(TAG, "Failed deleting " + key + ", error message:"
-                                            + failures.get(key).getErrorMessage());
+                        mShortcutUser.mExecutor,
+                        new BatchResultCallback<String, Void>() {
+                            @Override
+                            public void onResult(
+                                    @NonNull AppSearchBatchResult<String, Void> result) {
+                                if (!result.isSuccess()) {
+                                    final Map<String, AppSearchResult<Void>> failures =
+                                            result.getFailures();
+                                    for (String key : failures.keySet()) {
+                                        Slog.e(TAG, "Failed deleting " + key + ", error message:"
+                                                + failures.get(key).getErrorMessage());
+                                    }
                                 }
                             }
+                            @Override
+                            public void onSystemError(@Nullable Throwable throwable) {
+                                Slog.e(TAG, "Error removing shortcuts", throwable);
+                            }
                         })));
     }
 
@@ -2452,12 +2469,20 @@
                                     AppSearchShortcutInfo.toGenericDocuments(shortcuts))
                             .build(),
                     mShortcutUser.mExecutor,
-                    result -> {
-                        if (!result.isSuccess()) {
-                            for (AppSearchResult<Void> k : result.getFailures().values()) {
-                                Slog.e(TAG, k.getErrorMessage());
+                    new BatchResultCallback<String, Void>() {
+                        @Override
+                        public void onResult(
+                                @NonNull AppSearchBatchResult<String, Void> result) {
+                            if (!result.isSuccess()) {
+                                for (AppSearchResult<Void> k : result.getFailures().values()) {
+                                    Slog.e(TAG, k.getErrorMessage());
+                                }
                             }
                         }
+                        @Override
+                        public void onSystemError(@Nullable Throwable throwable) {
+                            Slog.d(TAG, "Error persisting shortcuts", throwable);
+                        }
                     });
         }));
     }
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 1cf2dc5..9ca4f24 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -488,7 +488,8 @@
         mShortcutBitmapSaver = new ShortcutBitmapSaver(this);
         mShortcutDumpFiles = new ShortcutDumpFiles(this);
         mIsAppSearchEnabled = DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.SHORTCUT_APPSEARCH_INTEGRATION, true);
+                SystemUiDeviceConfigFlags.SHORTCUT_APPSEARCH_INTEGRATION, true)
+                && !injectIsLowRamDevice();
 
         if (onlyForPackageManagerApis) {
             return; // Don't do anything further.  For unit tests only.
@@ -2227,7 +2228,7 @@
         Objects.requireNonNull(shortcut);
         Preconditions.checkArgument(shortcut.isEnabled(), "Shortcut must be enabled");
         Preconditions.checkArgument(
-                shortcut.isIncludedIn(ShortcutInfo.SURFACE_LAUNCHER),
+                !shortcut.isExcludedFromSurfaces(ShortcutInfo.SURFACE_LAUNCHER),
                 "Shortcut excluded from launcher cannot be pinned");
         ret.complete(String.valueOf(requestPinItem(
                 packageName, userId, shortcut, null, null, resultIntent)));
diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java
index bb7e55a..a991ed3 100644
--- a/services/core/java/com/android/server/pm/StorageEventHelper.java
+++ b/services/core/java/com/android/server/pm/StorageEventHelper.java
@@ -26,13 +26,13 @@
 import static com.android.server.pm.PackageManagerService.TAG;
 import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
 
+import android.annotation.NonNull;
 import android.app.ResourcesManager;
 import android.content.IIntentReceiver;
 import android.content.pm.PackageManager;
 import android.content.pm.PackagePartitions;
 import android.content.pm.UserInfo;
 import android.content.pm.VersionedPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.UserHandle;
@@ -48,6 +48,7 @@
 import com.android.internal.policy.AttributeCache;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -78,7 +79,7 @@
                 // Clean up any users or apps that were removed or recreated
                 // while this volume was missing
                 mPm.mUserManager.reconcileUsers(volumeUuid);
-                reconcileApps(volumeUuid);
+                reconcileApps(mPm.snapshotComputer(), volumeUuid);
 
                 // Clean up any install sessions that expired or were
                 // cancelled while this volume was missing
@@ -150,7 +151,7 @@
                 final AndroidPackage pkg;
                 try {
                     pkg = installPackageHelper.scanSystemPackageTracedLI(
-                            ps.getPath(), parseFlags, SCAN_INITIAL, 0, null);
+                            ps.getPath(), parseFlags, SCAN_INITIAL, null);
                     loaded.add(pkg);
 
                 } catch (PackageManagerException e) {
@@ -299,8 +300,8 @@
      * aren't expected, either due to uninstallation or reinstallation on
      * another volume.
      */
-    public void reconcileApps(String volumeUuid) {
-        List<String> absoluteCodePaths = collectAbsoluteCodePaths();
+    public void reconcileApps(@NonNull Computer snapshot, String volumeUuid) {
+        List<String> absoluteCodePaths = collectAbsoluteCodePaths(snapshot);
         List<File> filesToDelete = null;
 
         final File[] files = FileUtils.listFilesOrEmpty(
@@ -345,10 +346,10 @@
         }
     }
 
-    private List<String> collectAbsoluteCodePaths() {
+    private List<String> collectAbsoluteCodePaths(@NonNull Computer snapshot) {
         List<String> codePaths = new ArrayList<>();
         final ArrayMap<String, ? extends PackageStateInternal> packageStates =
-                mPm.getPackageStates();
+                snapshot.getPackageStates();
         final int packageCount = packageStates.size();
         for (int i = 0; i < packageCount; i++) {
             final PackageStateInternal ps = packageStates.valueAt(i);
diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
index 3ef5599..588dfaf 100644
--- a/services/core/java/com/android/server/pm/SuspendPackageHelper.java
+++ b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
@@ -100,14 +100,14 @@
      * @return The names of failed packages.
      */
     @Nullable
-    String[] setPackagesSuspended(@NonNull Computer computer, @Nullable String[] packageNames,
+    String[] setPackagesSuspended(@NonNull Computer snapshot, @Nullable String[] packageNames,
             boolean suspended, @Nullable PersistableBundle appExtras,
             @Nullable PersistableBundle launcherExtras, @Nullable SuspendDialogInfo dialogInfo,
             @NonNull String callingPackage, @UserIdInt int userId, int callingUid) {
         if (ArrayUtils.isEmpty(packageNames)) {
             return packageNames;
         }
-        if (suspended && !isSuspendAllowedForUser(userId, callingUid)) {
+        if (suspended && !isSuspendAllowedForUser(snapshot, userId, callingUid)) {
             Slog.w(TAG, "Cannot suspend due to restrictions on user " + userId);
             return packageNames;
         }
@@ -123,7 +123,7 @@
         ArraySet<String> modifiedPackages = new ArraySet<>();
 
         final boolean[] canSuspend = suspended
-                ? canSuspendPackageForUser(computer, packageNames, userId, callingUid) : null;
+                ? canSuspendPackageForUser(snapshot, packageNames, userId, callingUid) : null;
         for (int i = 0; i < packageNames.length; i++) {
             final String packageName = packageNames[i];
             if (callingPackage.equals(packageName)) {
@@ -133,9 +133,9 @@
                 continue;
             }
             final PackageStateInternal packageState =
-                    computer.getPackageStateInternal(packageName);
+                    snapshot.getPackageStateInternal(packageName);
             if (packageState == null
-                    || computer.shouldFilterApplication(packageState, callingUid, userId)) {
+                    || snapshot.shouldFilterApplication(packageState, callingUid, userId)) {
                 Slog.w(TAG, "Could not find package setting for package: " + packageName
                         + ". Skipping suspending/un-suspending.");
                 unmodifiablePackages.add(packageName);
@@ -191,9 +191,11 @@
             }
         });
 
+        final Computer newSnapshot = mPm.snapshotComputer();
+
         if (!changedPackagesList.isEmpty()) {
             final String[] changedPackages = changedPackagesList.toArray(new String[0]);
-            sendPackagesSuspendedForUser(
+            sendPackagesSuspendedForUser(newSnapshot,
                     suspended ? Intent.ACTION_PACKAGES_SUSPENDED
                             : Intent.ACTION_PACKAGES_UNSUSPENDED,
                     changedPackages, changedUids.toArray(), userId);
@@ -202,7 +204,7 @@
         }
         // Send the suspension changed broadcast to ensure suspension state is not stale.
         if (!modifiedPackages.isEmpty()) {
-            sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED,
+            sendPackagesSuspendedForUser(newSnapshot, Intent.ACTION_PACKAGES_SUSPENSION_CHANGED,
                     modifiedPackages.toArray(new String[0]), modifiedUids.toArray(), userId);
         }
         return unmodifiablePackages.toArray(new String[0]);
@@ -217,14 +219,14 @@
      * @return The names of packages which are Unsuspendable.
      */
     @NonNull
-    String[] getUnsuspendablePackagesForUser(@NonNull Computer computer,
+    String[] getUnsuspendablePackagesForUser(@NonNull Computer snapshot,
             @NonNull String[] packageNames, @UserIdInt int userId, int callingUid) {
-        if (!isSuspendAllowedForUser(userId, callingUid)) {
+        if (!isSuspendAllowedForUser(snapshot, userId, callingUid)) {
             Slog.w(TAG, "Cannot suspend due to restrictions on user " + userId);
             return packageNames;
         }
         final ArraySet<String> unactionablePackages = new ArraySet<>();
-        final boolean[] canSuspend = canSuspendPackageForUser(computer, packageNames, userId,
+        final boolean[] canSuspend = canSuspendPackageForUser(snapshot, packageNames, userId,
                 callingUid);
         for (int i = 0; i < packageNames.length; i++) {
             if (!canSuspend[i]) {
@@ -232,7 +234,7 @@
                 continue;
             }
             final PackageStateInternal packageState =
-                    computer.getPackageStateFiltered(packageNames[i], callingUid, userId);
+                    snapshot.getPackageStateFiltered(packageNames[i], callingUid, userId);
             if (packageState == null) {
                 Slog.w(TAG, "Could not find package setting for package: " + packageNames[i]);
                 unactionablePackages.add(packageNames[i]);
@@ -250,8 +252,9 @@
      * @return The app extras of the suspended package.
      */
     @Nullable
-    Bundle getSuspendedPackageAppExtras(@NonNull String packageName, int userId, int callingUid) {
-        final PackageStateInternal ps = mPm.getPackageStateInternal(packageName, callingUid);
+    Bundle getSuspendedPackageAppExtras(@NonNull Computer snapshot, @NonNull String packageName,
+            int userId, int callingUid) {
+        final PackageStateInternal ps = snapshot.getPackageStateInternal(packageName, callingUid);
         if (ps == null) {
             return null;
         }
@@ -329,12 +332,14 @@
             }
         });
 
+        final Computer newSnapshot = mPm.snapshotComputer();
+
         mPm.scheduleWritePackageRestrictions(userId);
         if (!unsuspendedPackages.isEmpty()) {
             final String[] packageArray = unsuspendedPackages.toArray(
                     new String[unsuspendedPackages.size()]);
             sendMyPackageSuspendedOrUnsuspended(packageArray, false, userId);
-            sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_UNSUSPENDED,
+            sendPackagesSuspendedForUser(newSnapshot, Intent.ACTION_PACKAGES_UNSUSPENDED,
                     packageArray, unsuspendedUids.toArray(), userId);
         }
     }
@@ -348,10 +353,10 @@
      * @return The launcher extras.
      */
     @Nullable
-    Bundle getSuspendedPackageLauncherExtras(@NonNull String packageName, int userId,
-            int callingUid) {
-        final PackageStateInternal packageState = mPm.getPackageStateInternal(
-                packageName, callingUid);
+    Bundle getSuspendedPackageLauncherExtras(@NonNull Computer snapshot,
+            @NonNull String packageName, int userId, int callingUid) {
+        final PackageStateInternal packageState =
+                snapshot.getPackageStateInternal(packageName, callingUid);
         if (packageState == null) {
             return null;
         }
@@ -376,9 +381,10 @@
      * @param callingUid The caller's uid.
      * @return {@code true}, if the given package is suspended.
      */
-    boolean isPackageSuspended(@NonNull String packageName, int userId, int callingUid) {
-        final PackageStateInternal packageState = mPm.getPackageStateInternal(
-                packageName, callingUid);
+    boolean isPackageSuspended(@NonNull Computer snapshot, @NonNull String packageName, int userId,
+            int callingUid) {
+        final PackageStateInternal packageState =
+                snapshot.getPackageStateInternal(packageName, callingUid);
         return packageState != null && packageState.getUserStateOrDefault(userId)
                 .isSuspended();
     }
@@ -392,8 +398,9 @@
      * @return The name of suspending package.
      */
     @Nullable
-    String getSuspendingPackage(@NonNull String suspendedPackage, int userId, int callingUid) {
-        final PackageStateInternal packageState = mPm.getPackageStateInternal(
+    String getSuspendingPackage(@NonNull Computer snapshot, @NonNull String suspendedPackage,
+            int userId, int callingUid) {
+        final PackageStateInternal packageState = snapshot.getPackageStateInternal(
                 suspendedPackage, callingUid);
         if (packageState == null) {
             return  null;
@@ -424,9 +431,10 @@
      * @return The dialog info.
      */
     @Nullable
-    SuspendDialogInfo getSuspendedDialogInfo(@NonNull String suspendedPackage,
-            @NonNull String suspendingPackage, int userId, int callingUid) {
-        final PackageStateInternal packageState = mPm.getPackageStateInternal(
+    SuspendDialogInfo getSuspendedDialogInfo(@NonNull Computer snapshot,
+            @NonNull String suspendedPackage, @NonNull String suspendingPackage, int userId,
+            int callingUid) {
+        final PackageStateInternal packageState = snapshot.getPackageStateInternal(
                 suspendedPackage, callingUid);
         if (packageState == null) {
             return  null;
@@ -454,9 +462,9 @@
      * @param callingUid The caller's uid.
      * @return {@code true} if the user is allowed to suspend packages by the caller.
      */
-    boolean isSuspendAllowedForUser(int userId, int callingUid) {
+    boolean isSuspendAllowedForUser(@NonNull Computer snapshot, int userId, int callingUid) {
         final UserManagerService userManager = mInjector.getUserManagerService();
-        return isCallerDeviceOrProfileOwner(userId, callingUid)
+        return isCallerDeviceOrProfileOwner(snapshot, userId, callingUid)
                 || (!userManager.hasUserRestriction(UserManager.DISALLOW_APPS_CONTROL, userId)
                 && !userManager.hasUserRestriction(UserManager.DISALLOW_UNINSTALL_APPS, userId));
     }
@@ -471,21 +479,23 @@
      * @return An array containing results of the checks
      */
     @NonNull
-    boolean[] canSuspendPackageForUser(@NonNull Computer computer, @NonNull String[] packageNames,
+    boolean[] canSuspendPackageForUser(@NonNull Computer snapshot, @NonNull String[] packageNames,
             int userId, int callingUid) {
         final boolean[] canSuspend = new boolean[packageNames.length];
-        final boolean isCallerOwner = isCallerDeviceOrProfileOwner(userId, callingUid);
+        final boolean isCallerOwner = isCallerDeviceOrProfileOwner(snapshot, userId, callingUid);
         final long token = Binder.clearCallingIdentity();
         try {
             final DefaultAppProvider defaultAppProvider = mInjector.getDefaultAppProvider();
             final String activeLauncherPackageName = defaultAppProvider.getDefaultHome(userId);
             final String dialerPackageName = defaultAppProvider.getDefaultDialer(userId);
-            final String requiredInstallerPackage = getKnownPackageName(PACKAGE_INSTALLER, userId);
+            final String requiredInstallerPackage =
+                    getKnownPackageName(snapshot, PACKAGE_INSTALLER, userId);
             final String requiredUninstallerPackage =
-                    getKnownPackageName(PACKAGE_UNINSTALLER, userId);
-            final String requiredVerifierPackage = getKnownPackageName(PACKAGE_VERIFIER, userId);
+                    getKnownPackageName(snapshot, PACKAGE_UNINSTALLER, userId);
+            final String requiredVerifierPackage =
+                    getKnownPackageName(snapshot, PACKAGE_VERIFIER, userId);
             final String requiredPermissionControllerPackage =
-                    getKnownPackageName(PACKAGE_PERMISSION_CONTROLLER, userId);
+                    getKnownPackageName(snapshot, PACKAGE_PERMISSION_CONTROLLER, userId);
             for (int i = 0; i < packageNames.length; i++) {
                 canSuspend[i] = false;
                 final String packageName = packageNames[i];
@@ -530,7 +540,7 @@
                             + "\": protected package");
                     continue;
                 }
-                if (!isCallerOwner && computer.getBlockUninstall(userId, packageName)) {
+                if (!isCallerOwner && snapshot.getBlockUninstall(userId, packageName)) {
                     Slog.w(TAG, "Cannot suspend package \"" + packageName
                             + "\": blocked by admin");
                     continue;
@@ -539,7 +549,7 @@
                 // Cannot suspend static shared libs as they are considered
                 // a part of the using app (emulating static linking). Also
                 // static libs are installed always on internal storage.
-                PackageStateInternal packageState = computer.getPackageStateInternal(packageName);
+                PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
                 AndroidPackage pkg = packageState == null ? null : packageState.getPkg();
                 if (pkg != null) {
                     // Cannot suspend SDK libs as they are controlled by SDK manager.
@@ -580,8 +590,8 @@
      * @param userId The user where packages reside.
      */
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
-    void sendPackagesSuspendedForUser(@NonNull String intent, @NonNull String[] pkgList,
-            @NonNull int[] uidList, int userId) {
+    void sendPackagesSuspendedForUser(@NonNull Computer snapshot, @NonNull String intent,
+            @NonNull String[] pkgList, @NonNull int[] uidList, int userId) {
         final List<List<String>> pkgsToSend = new ArrayList(pkgList.length);
         final List<IntArray> uidsToSend = new ArrayList(pkgList.length);
         final List<SparseArray<int[]>> allowListsToSend = new ArrayList(pkgList.length);
@@ -592,8 +602,8 @@
             final String pkgName = pkgList[i];
             final int uid = uidList[i];
             SparseArray<int[]> allowList = mInjector.getAppsFilter().getVisibilityAllowList(
-                    mPm.getPackageStateInternal(pkgName, SYSTEM_UID),
-                    userIds, mPm.getPackageStates());
+                    snapshot.getPackageStateInternal(pkgName, SYSTEM_UID),
+                    userIds, snapshot.getPackageStates());
             if (allowList == null) {
                 allowList = new SparseArray<>(0);
             }
@@ -628,19 +638,22 @@
         }
     }
 
-    private String getKnownPackageName(@KnownPackage int knownPackage, int userId) {
-        final String[] knownPackages = mPm.getKnownPackageNamesInternal(knownPackage, userId);
+    private String getKnownPackageName(@NonNull Computer snapshot, @KnownPackage int knownPackage,
+            int userId) {
+        final String[] knownPackages =
+                mPm.getKnownPackageNamesInternal(snapshot, knownPackage, userId);
         return knownPackages.length > 0 ? knownPackages[0] : null;
     }
 
-    private boolean isCallerDeviceOrProfileOwner(int userId, int callingUid) {
+    private boolean isCallerDeviceOrProfileOwner(@NonNull Computer snapshot, int userId,
+            int callingUid) {
         if (callingUid == SYSTEM_UID) {
             return true;
         }
         final String ownerPackage = mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(userId);
         if (ownerPackage != null) {
-            return callingUid == mPm.getPackageUidInternal(
-                    ownerPackage, 0, userId, callingUid);
+            return callingUid == snapshot.getPackageUidInternal(ownerPackage, 0, userId,
+                    callingUid);
         }
         return false;
     }
@@ -659,9 +672,10 @@
                 return;
             }
             final int[] targetUserIds = new int[] {userId};
+            final Computer snapshot = mPm.snapshotComputer();
             for (String packageName : affectedPackages) {
                 final Bundle appExtras = suspended
-                        ? getSuspendedPackageAppExtras(packageName, userId, SYSTEM_UID)
+                        ? getSuspendedPackageAppExtras(snapshot, packageName, userId, SYSTEM_UID)
                         : null;
                 final Bundle intentExtras;
                 if (appExtras != null) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index a8d24fa..d340561 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1387,7 +1387,7 @@
      */
     @Override
     public boolean isUserOfType(@UserIdInt int userId, String userType) {
-        checkManageUsersPermission("check user type");
+        checkQueryOrCreateUsersPermission("check user type");
         return userType != null && userType.equals(getUserTypeNoChecks(userId));
     }
 
@@ -1593,13 +1593,13 @@
     }
 
     @Override
-    public boolean isCredentialSharedWithParent(@UserIdInt int userId) {
+    public boolean isCredentialSharableWithParent(@UserIdInt int userId) {
         checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId,
-                "isCredentialSharedWithParent");
+                "isCredentialSharableWithParent");
         synchronized (mUsersLock) {
             UserTypeDetails userTypeDetails = getUserTypeDetailsNoChecks(userId);
             return userTypeDetails != null && userTypeDetails.isProfile()
-                    && userTypeDetails.isCredentialSharedWithParent();
+                    && userTypeDetails.isCredentialSharableWithParent();
         }
     }
 
@@ -1643,7 +1643,7 @@
         if (!hasQueryOrCreateUsersPermission()
                 && !hasPermissionGranted(
                         android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED, callingUid)) {
-            throw new SecurityException("You need MANAGE_USERS or CREATE_USERS or "
+            throw new SecurityException("You need MANAGE_USERS, CREATE_USERS, QUERY_USERS, or "
                     + "GET_ACCOUNTS_PRIVILEGED permissions to: get user name");
         }
         final int userId = UserHandle.getUserId(callingUid);
@@ -4148,11 +4148,11 @@
                 continue;
             }
             if (filter.direction == DefaultCrossProfileIntentFilter.Direction.TO_PARENT) {
-                mPm.addCrossProfileIntentFilter(
+                mPm.addCrossProfileIntentFilter(mPm.snapshotComputer(),
                         filter.filter, mContext.getOpPackageName(), profileUserId, parentUserId,
                         filter.flags);
             } else {
-                mPm.addCrossProfileIntentFilter(
+                mPm.addCrossProfileIntentFilter(mPm.snapshotComputer(),
                         filter.filter, mContext.getOpPackageName(), parentUserId, profileUserId,
                         filter.flags);
             }
@@ -4638,12 +4638,12 @@
             final String restriction = getUserRemovalRestriction(userId);
             if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(restriction, false)) {
                 Slog.w(LOG_TAG, "Cannot remove user. " + restriction + " is enabled.");
-                return UserManager.REMOVE_RESULT_ERROR;
+                return UserManager.REMOVE_RESULT_ERROR_USER_RESTRICTION;
             }
         }
         if (userId == UserHandle.USER_SYSTEM) {
             Slog.e(LOG_TAG, "System user cannot be removed.");
-            return UserManager.REMOVE_RESULT_ERROR;
+            return UserManager.REMOVE_RESULT_ERROR_SYSTEM_USER;
         }
 
         final long ident = Binder.clearCallingIdentity();
@@ -4655,7 +4655,7 @@
                     if (userData == null) {
                         Slog.e(LOG_TAG,
                                 "Cannot remove user " + userId + ", invalid user id provided.");
-                        return UserManager.REMOVE_RESULT_ERROR;
+                        return UserManager.REMOVE_RESULT_ERROR_USER_NOT_FOUND;
                     }
 
                     if (mRemovingUserIds.get(userId)) {
@@ -5064,9 +5064,13 @@
 
     @Override
     public boolean isUserNameSet(@UserIdInt int userId) {
-        if (!hasManageUsersOrPermission(android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED)) {
-            throw new SecurityException("You need MANAGE_USERS or GET_ACCOUNTS_PRIVILEGED "
-                    + "permissions to: get whether user name is set");
+        final int callingUid = Binder.getCallingUid();
+        final int callingUserId = UserHandle.getUserId(callingUid);
+        if (!hasQueryOrCreateUsersPermission()
+                && !(callingUserId == userId && hasPermissionGranted(
+                android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED, callingUid))) {
+            throw new SecurityException("You need MANAGE_USERS, CREATE_USERS, QUERY_USERS, or "
+                    + "GET_ACCOUNTS_PRIVILEGED permissions to: get whether user name is set");
         }
         synchronized (mUsersLock) {
             final UserInfo userInfo = getUserInfoLU(userId);
@@ -5409,37 +5413,82 @@
         (new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
     }
 
-    private int onShellCommand(Shell shell, String cmd) {
+    private static final String PREFIX_HELP_COMMAND = "  ";
+    private static final String PREFIX_HELP_DESCRIPTION = "    ";
+    private static final String PREFIX_HELP_DESCRIPTION_EXTRA_LINES = "      ";
+
+    private static final String CMD_HELP = "help";
+    private static final String CMD_LIST = "list";
+    private static final String CMD_REPORT_SYSTEM_USER_PACKAGE_ALLOWLIST_PROBLEMS =
+            "report-system-user-package-whitelist-problems";
+
+    private static final String ARG_V = "-v";
+    private static final String ARG_VERBOSE = "--verbose";
+    private static final String ARG_ALL = "--all";
+    private static final String ARG_CRITICAL_ONLY = "--critical-only";
+    private static final String ARG_MODE = "--mode";
+
+    private final class Shell extends ShellCommand {
+
+    @Override
+    public void onHelp() {
+        final PrintWriter pw = getOutPrintWriter();
+        pw.printf("User manager (user) commands:\n");
+
+        pw.printf("%s%s\n", PREFIX_HELP_COMMAND, CMD_HELP);
+        pw.printf("%sPrints this help text.\n\n", PREFIX_HELP_DESCRIPTION);
+
+        pw.printf("%s%s [%s] [%s]\n", PREFIX_HELP_COMMAND, CMD_LIST, ARG_V, ARG_ALL);
+        pw.printf("%sPrints all users on the system.\n\n", PREFIX_HELP_DESCRIPTION);
+
+        pw.printf("%s%s [%s | %s] [%s] [%s MODE]\n", PREFIX_HELP_COMMAND,
+                CMD_REPORT_SYSTEM_USER_PACKAGE_ALLOWLIST_PROBLEMS,
+                ARG_V, ARG_VERBOSE, ARG_CRITICAL_ONLY, ARG_MODE);
+
+        pw.printf("%sReports all issues on user-type package allowlist XML files. Options:\n",
+                PREFIX_HELP_DESCRIPTION);
+        pw.printf("%s%s | %s: shows extra info, like number of issues\n",
+                PREFIX_HELP_DESCRIPTION, ARG_V, ARG_VERBOSE);
+        pw.printf("%s%s: show only critical issues, excluding warnings\n",
+                PREFIX_HELP_DESCRIPTION, ARG_CRITICAL_ONLY);
+        pw.printf("%s%s MODE: shows what errors would be if device used mode MODE\n"
+                + "%s(where MODE is the allowlist mode integer as defined by "
+                + "config_userTypePackageWhitelistMode)\n\n",
+                PREFIX_HELP_DESCRIPTION, ARG_MODE, PREFIX_HELP_DESCRIPTION_EXTRA_LINES);
+    }
+
+    @Override
+    public int onCommand(String cmd) {
         if (cmd == null) {
-            return shell.handleDefaultCommands(cmd);
+            return handleDefaultCommands(cmd);
         }
 
-        final PrintWriter pw = shell.getOutPrintWriter();
         try {
             switch(cmd) {
-                case "list":
-                    return runList(pw, shell);
-                case "report-system-user-package-whitelist-problems":
-                    return runReportPackageWhitelistProblems(pw, shell);
+                case CMD_LIST:
+                    return runList();
+                case CMD_REPORT_SYSTEM_USER_PACKAGE_ALLOWLIST_PROBLEMS:
+                    return runReportPackageAllowlistProblems();
                 default:
-                    return shell.handleDefaultCommands(cmd);
+                    return handleDefaultCommands(cmd);
             }
         } catch (RemoteException e) {
-            pw.println("Remote exception: " + e);
+            getOutPrintWriter().println("Remote exception: " + e);
         }
         return -1;
     }
 
-    private int runList(PrintWriter pw, Shell shell) throws RemoteException {
+    private int runList() throws RemoteException {
+        final PrintWriter pw = getOutPrintWriter();
         boolean all = false;
         boolean verbose = false;
         String opt;
-        while ((opt = shell.getNextOption()) != null) {
+        while ((opt = getNextOption()) != null) {
             switch (opt) {
-                case "-v":
+                case ARG_V:
                     verbose = true;
                     break;
-                case "--all":
+                case ARG_ALL:
                     all = true;
                     break;
                 default:
@@ -5513,22 +5562,23 @@
         }
     }
 
-    private int runReportPackageWhitelistProblems(PrintWriter pw, Shell shell) {
+    private int runReportPackageAllowlistProblems() {
+        final PrintWriter pw = getOutPrintWriter();
         boolean verbose = false;
         boolean criticalOnly = false;
         int mode = UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_NONE;
         String opt;
-        while ((opt = shell.getNextOption()) != null) {
+        while ((opt = getNextOption()) != null) {
             switch (opt) {
-                case "-v":
-                case "--verbose":
+                case ARG_V:
+                case ARG_VERBOSE:
                     verbose = true;
                     break;
-                case "--critical-only":
+                case ARG_CRITICAL_ONLY:
                     criticalOnly = true;
                     break;
-                case "--mode":
-                    mode = Integer.parseInt(shell.getNextArgRequired());
+                case ARG_MODE:
+                    mode = Integer.parseInt(getNextArgRequired());
                     break;
                 default:
                     pw.println("Invalid option: " + opt);
@@ -5536,15 +5586,17 @@
             }
         }
 
-        Slog.d(LOG_TAG, "runReportPackageWhitelistProblems(): verbose=" + verbose
+        Slog.d(LOG_TAG, "runReportPackageAllowlistProblems(): verbose=" + verbose
                 + ", criticalOnly=" + criticalOnly
                 + ", mode=" + UserSystemPackageInstaller.modeToString(mode));
 
         try (IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ")) {
-            mSystemPackageInstaller.dumpPackageWhitelistProblems(ipw, mode, verbose, criticalOnly);
+            mSystemPackageInstaller.dumpPackageWhitelistProblems(ipw, mode, verbose,
+                    criticalOnly);
         }
         return 0;
     }
+    }
 
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -6239,32 +6291,6 @@
         }
     }
 
-    private class Shell extends ShellCommand {
-        @Override
-        public int onCommand(String cmd) {
-            return onShellCommand(this, cmd);
-        }
-
-        @Override
-        public void onHelp() {
-            final PrintWriter pw = getOutPrintWriter();
-            pw.println("User manager (user) commands:");
-            pw.println("  help");
-            pw.println("    Prints this help text.");
-            pw.println("");
-            pw.println("  list [-v] [-all]");
-            pw.println("    Prints all users on the system.");
-            pw.println("  report-system-user-package-whitelist-problems [-v | --verbose] "
-                    + "[--critical-only] [--mode MODE]");
-            pw.println("    Reports all issues on user-type package whitelist XML files. Options:");
-            pw.println("    -v | --verbose : shows extra info, like number of issues");
-            pw.println("    --critical-only: show only critical issues, excluding warnings");
-            pw.println("    --mode MODE: shows what errors would be if device used mode MODE (where"
-                    + " MODE is the whitelist mode integer as defined by "
-                    + "config_userTypePackageWhitelistMode)");
-        }
-    }
-
     private static void debug(String message) {
         Slog.d(LOG_TAG, message
                 + (DBG_WITH_STACKTRACE ? " called at\n" + Debug.getCallers(10, "  ") : ""));
diff --git a/services/core/java/com/android/server/pm/UserTypeDetails.java b/services/core/java/com/android/server/pm/UserTypeDetails.java
index 2f5e238..4aad1a7 100644
--- a/services/core/java/com/android/server/pm/UserTypeDetails.java
+++ b/services/core/java/com/android/server/pm/UserTypeDetails.java
@@ -161,7 +161,7 @@
      *
      * <p> Default value is false
      */
-    private final boolean mIsCredentialSharedWithParent;
+    private final boolean mIsCredentialSharableWithParent;
 
     private UserTypeDetails(@NonNull String name, boolean enabled, int maxAllowed,
             @UserInfoFlag int baseType, @UserInfoFlag int defaultUserInfoPropertyFlags, int label,
@@ -174,7 +174,7 @@
             @Nullable Bundle defaultSecureSettings,
             @Nullable List<DefaultCrossProfileIntentFilter> defaultCrossProfileIntentFilters,
             boolean isMediaSharedWithParent,
-            boolean isCredentialSharedWithParent) {
+            boolean isCredentialSharableWithParent) {
         this.mName = name;
         this.mEnabled = enabled;
         this.mMaxAllowed = maxAllowed;
@@ -194,7 +194,7 @@
         this.mBadgeColors = badgeColors;
         this.mDarkThemeBadgeColors = darkThemeBadgeColors;
         this.mIsMediaSharedWithParent = isMediaSharedWithParent;
-        this.mIsCredentialSharedWithParent = isCredentialSharedWithParent;
+        this.mIsCredentialSharableWithParent = isCredentialSharableWithParent;
     }
 
     /**
@@ -323,8 +323,8 @@
      * Returns true if the user has shared encryption credential with parent user or
      * false otherwise.
      */
-    public boolean isCredentialSharedWithParent() {
-        return mIsCredentialSharedWithParent;
+    public boolean isCredentialSharableWithParent() {
+        return mIsCredentialSharableWithParent;
     }
 
     /** Returns a {@link Bundle} representing the default user restrictions. */
@@ -419,7 +419,7 @@
         private @DrawableRes int mBadgePlain = Resources.ID_NULL;
         private @DrawableRes int mBadgeNoBackground = Resources.ID_NULL;
         private boolean mIsMediaSharedWithParent = false;
-        private boolean mIsCredentialSharedWithParent = false;
+        private boolean mIsCredentialSharableWithParent = false;
 
         public Builder setName(String name) {
             mName = name;
@@ -521,10 +521,10 @@
 
         /**
          * Sets shared media property for the user.
-         * @param isCredentialSharedWithParent  the value to be set, true or false
+         * @param isCredentialSharableWithParent  the value to be set, true or false
          */
-        public Builder setIsCredentialSharedWithParent(boolean isCredentialSharedWithParent) {
-            mIsCredentialSharedWithParent = isCredentialSharedWithParent;
+        public Builder setIsCredentialSharableWithParent(boolean isCredentialSharableWithParent) {
+            mIsCredentialSharableWithParent = isCredentialSharableWithParent;
             return this;
         }
 
@@ -571,7 +571,7 @@
                     mDefaultSecureSettings,
                     mDefaultCrossProfileIntentFilters,
                     mIsMediaSharedWithParent,
-                    mIsCredentialSharedWithParent);
+                    mIsCredentialSharableWithParent);
         }
 
         private boolean hasBadge() {
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index 1e3b67c..cb18c6d 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -122,7 +122,7 @@
                 .setLabel(0)
                 .setDefaultRestrictions(null)
                 .setIsMediaSharedWithParent(true)
-                .setIsCredentialSharedWithParent(true);
+                .setIsCredentialSharableWithParent(true);
     }
 
     /**
@@ -154,7 +154,7 @@
                 .setDefaultRestrictions(getDefaultManagedProfileRestrictions())
                 .setDefaultSecureSettings(getDefaultManagedProfileSecureSettings())
                 .setDefaultCrossProfileIntentFilters(getDefaultManagedCrossProfileIntentFilter())
-                .setIsCredentialSharedWithParent(true);
+                .setIsCredentialSharableWithParent(true);
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/WatchedIntentFilter.java b/services/core/java/com/android/server/pm/WatchedIntentFilter.java
index 30f276e..5d7a2a3 100644
--- a/services/core/java/com/android/server/pm/WatchedIntentFilter.java
+++ b/services/core/java/com/android/server/pm/WatchedIntentFilter.java
@@ -84,7 +84,7 @@
     }
 
     // Convert an {@link IntentFilter} to a {@link WatchedIntentFilter}
-    protected WatchedIntentFilter(IntentFilter f) {
+    public WatchedIntentFilter(IntentFilter f) {
         mFilter = new IntentFilter(f);
     }
 
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index e28a6ea..7e4da94 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -31,13 +31,13 @@
 import android.content.pm.dex.DexMetadataHelper;
 import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
 import android.content.pm.dex.PackageOptimizationInfo;
-import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Handler;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.system.Os;
@@ -55,6 +55,7 @@
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.PackageManagerServiceCompilerMapping;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
 
 import dalvik.system.DexFile;
 import dalvik.system.VMRuntime;
@@ -92,7 +93,7 @@
     private static final String BOOT_IMAGE_PROFILE_NAME = "android.prof";
 
     private final Context mContext;
-    private final IPackageManager mPackageManager;
+    private IPackageManager mPackageManager;
     private final Object mInstallLock;
     @GuardedBy("mInstallLock")
     private final Installer mInstaller;
@@ -103,10 +104,9 @@
         verifyTronLoggingConstants();
     }
 
-    public ArtManagerService(Context context, IPackageManager pm, Installer installer,
+    public ArtManagerService(Context context, Installer installer,
             Object installLock) {
         mContext = context;
-        mPackageManager = pm;
         mInstaller = installer;
         mInstallLock = installLock;
         mHandler = new Handler(BackgroundThread.getHandler().getLooper());
@@ -114,6 +114,15 @@
         LocalServices.addService(ArtManagerInternal.class, new ArtManagerInternalImpl());
     }
 
+    @NonNull
+    private IPackageManager getPackageManager() {
+        if (mPackageManager == null) {
+            mPackageManager = IPackageManager.Stub.asInterface(
+                    ServiceManager.getService("package"));
+        }
+        return mPackageManager;
+    }
+
     private boolean checkAndroidPermissions(int callingUid, String callingPackage) {
         // Callers always need this permission
         mContext.enforceCallingOrSelfPermission(
@@ -157,7 +166,7 @@
         }
         PackageInfo info = null;
         try {
-            info = mPackageManager.getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0);
+            info =  getPackageManager().getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0);
         } catch (RemoteException ignored) {
             // Should not happen.
         }
@@ -221,7 +230,7 @@
 
             // TODO(calin): consider adding an API to PMS which can retrieve the
             // PackageParser.Package.
-            info = mPackageManager.getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0);
+            info =  getPackageManager().getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0);
         } catch (RemoteException ignored) {
             // Should not happen.
         }
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 5371454..17109e9 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -23,6 +23,8 @@
 
 import static java.util.function.Function.identity;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
@@ -33,6 +35,7 @@
 import android.os.FileUtils;
 import android.os.PowerManager;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
@@ -109,7 +112,7 @@
     // record class loaders or ISAs.)
     private final DynamicCodeLogger mDynamicCodeLogger;
 
-    private final IPackageManager mPackageManager;
+    private IPackageManager mPackageManager;
     private final PackageDexOptimizer mPackageDexOptimizer;
     private final Object mInstallLock;
     @GuardedBy("mInstallLock")
@@ -128,16 +131,22 @@
     private static int DEX_SEARCH_FOUND_SPLIT = 2;  // dex file is a split apk
     private static int DEX_SEARCH_FOUND_SECONDARY = 3;  // dex file is a secondary dex
 
-    public DexManager(Context context, IPackageManager pms, PackageDexOptimizer pdo,
-            Installer installer, Object installLock) {
+    public DexManager(Context context, PackageDexOptimizer pdo, Installer installer,
+            Object installLock) {
+        this(context, pdo, installer, installLock, null);
+    }
+
+    @VisibleForTesting
+    public DexManager(Context context, PackageDexOptimizer pdo, Installer installer,
+            Object installLock, @Nullable IPackageManager packageManager) {
         mContext = context;
         mPackageCodeLocationsCache = new HashMap<>();
         mPackageDexUsage = new PackageDexUsage();
-        mPackageManager = pms;
         mPackageDexOptimizer = pdo;
         mInstaller = installer;
         mInstallLock = installLock;
-        mDynamicCodeLogger = new DynamicCodeLogger(pms, installer);
+        mDynamicCodeLogger = new DynamicCodeLogger(installer);
+        mPackageManager = packageManager;
 
         // This is currently checked to handle tests that pass in a null context.
         // TODO(b/174783329): Modify the tests to pass in a mocked Context, PowerManager,
@@ -157,6 +166,15 @@
         }
     }
 
+    @NonNull
+    private IPackageManager getPackageManager() {
+        if (mPackageManager == null) {
+            mPackageManager = IPackageManager.Stub.asInterface(
+                    ServiceManager.getService("package"));
+        }
+        return mPackageManager;
+    }
+
     public DynamicCodeLogger getDynamicCodeLogger() {
         return mDynamicCodeLogger;
     }
@@ -529,7 +547,7 @@
 
             PackageInfo pkg;
             try {
-                pkg = mPackageManager.getPackageInfo(packageName, /*flags*/0,
+                pkg = getPackageManager().getPackageInfo(packageName, /*flags*/0,
                     dexUseInfo.getOwnerUserId());
             } catch (RemoteException e) {
                 throw new AssertionError(e);
@@ -673,7 +691,7 @@
                 // to get back the real app uid and its storage kind. These are only used
                 // to perform extra validation in installd.
                 // TODO(calin): maybe a bit overkill.
-                pkg = mPackageManager.getPackageInfo(packageName, /*flags*/0,
+                pkg = getPackageManager().getPackageInfo(packageName, /*flags*/0,
                     dexUseInfo.getOwnerUserId());
             } catch (RemoteException ignore) {
                 // Can't happen, DexManager is local.
diff --git a/services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java b/services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java
index 75b4e38..9b94e99 100644
--- a/services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java
+++ b/services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java
@@ -19,11 +19,13 @@
 import static com.android.server.pm.dex.PackageDynamicCodeLoading.FILE_TYPE_DEX;
 import static com.android.server.pm.dex.PackageDynamicCodeLoading.FILE_TYPE_NATIVE;
 
+import android.annotation.NonNull;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.os.FileUtils;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
 import android.util.EventLog;
@@ -58,20 +60,30 @@
     private static final String DCL_DEX_SUBTAG = "dcl";
     private static final String DCL_NATIVE_SUBTAG = "dcln";
 
-    private final IPackageManager mPackageManager;
+    private IPackageManager mPackageManager;
     private final PackageDynamicCodeLoading mPackageDynamicCodeLoading;
     private final Installer mInstaller;
 
-    DynamicCodeLogger(IPackageManager pms, Installer installer) {
-        this(pms, installer, new PackageDynamicCodeLoading());
+    DynamicCodeLogger(Installer installer) {
+        mInstaller = installer;
+        mPackageDynamicCodeLoading = new PackageDynamicCodeLoading();
     }
 
     @VisibleForTesting
-    DynamicCodeLogger(IPackageManager pms, Installer installer,
-            PackageDynamicCodeLoading packageDynamicCodeLoading) {
-        mPackageManager = pms;
-        mPackageDynamicCodeLoading = packageDynamicCodeLoading;
+    DynamicCodeLogger(@NonNull IPackageManager packageManager, @NonNull Installer installer,
+            @NonNull PackageDynamicCodeLoading packageDynamicCodeLoading) {
+        mPackageManager = packageManager;
         mInstaller = installer;
+        mPackageDynamicCodeLoading = packageDynamicCodeLoading;
+    }
+
+    @NonNull
+    private IPackageManager getPackageManager() {
+        if (mPackageManager == null) {
+            mPackageManager = IPackageManager.Stub.asInterface(
+                    ServiceManager.getService("package"));
+        }
+        return mPackageManager;
     }
 
     public Set<String> getAllPackagesWithDynamicCodeLoading() {
@@ -104,7 +116,7 @@
 
                 try {
                     PackageInfo ownerInfo =
-                            mPackageManager.getPackageInfo(packageName, /*flags*/ 0, userId);
+                            getPackageManager().getPackageInfo(packageName, /*flags*/ 0, userId);
                     appInfo = ownerInfo == null ? null : ownerInfo.applicationInfo;
                 } catch (RemoteException ignored) {
                     // Can't happen, we're local.
@@ -167,7 +179,7 @@
                     loadingUid = appInfo.uid;
                 } else {
                     try {
-                        loadingUid = mPackageManager.getPackageUid(loadingPackageName, /*flags*/ 0,
+                        loadingUid =  getPackageManager().getPackageUid(loadingPackageName, /*flags*/ 0,
                                 userId);
                     } catch (RemoteException ignored) {
                         // Can't happen, we're local.
@@ -223,7 +235,7 @@
     public void recordNative(int loadingUid, String path) {
         String[] packages;
         try {
-            packages = mPackageManager.getPackagesForUid(loadingUid);
+            packages =  getPackageManager().getPackagesForUid(loadingUid);
             if (packages == null || packages.length == 0) {
                 return;
             }
diff --git a/services/core/java/com/android/server/pm/dex/OWNERS b/services/core/java/com/android/server/pm/dex/OWNERS
index 052a4ca..5ca8ddd 100644
--- a/services/core/java/com/android/server/pm/dex/OWNERS
+++ b/services/core/java/com/android/server/pm/dex/OWNERS
@@ -1,3 +1,4 @@
 alanstokes@google.com
 jiakaiz@google.com
 ngeoffray@google.com
+mast@google.com
diff --git a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
index 46fde4b..881f870 100644
--- a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
+++ b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
@@ -272,6 +272,10 @@
                 mHandler.removeCallbacksAndMessages(mToken);
 
                 if (importance > IMPORTANCE_CACHED) {
+                    if (mRevokeAfterKilledDelay == 0) {
+                        onPackageInactiveLocked();
+                        return;
+                    }
                     // Delay revocation in case app is restarting
                     mHandler.postDelayed(() -> {
                         int imp = mActivityManager.getUidImportance(mUid);
@@ -313,9 +317,21 @@
             synchronized (mInnerLock) {
                 mIsFinished = true;
                 cancelAlarmLocked();
-                mActivityManager.removeOnUidImportanceListener(mStartTimerListener);
-                mActivityManager.removeOnUidImportanceListener(mSessionKillableListener);
-                mActivityManager.removeOnUidImportanceListener(mGoneListener);
+                try {
+                    mActivityManager.removeOnUidImportanceListener(mStartTimerListener);
+                } catch (IllegalArgumentException e) {
+                    Log.e(LOG_TAG, "Could not remove start timer listener", e);
+                }
+                try {
+                    mActivityManager.removeOnUidImportanceListener(mSessionKillableListener);
+                } catch (IllegalArgumentException e) {
+                    Log.e(LOG_TAG, "Could not remove session killable listener", e);
+                }
+                try {
+                    mActivityManager.removeOnUidImportanceListener(mGoneListener);
+                } catch (IllegalArgumentException e) {
+                    Log.e(LOG_TAG, "Could not remove gone listener", e);
+                }
             }
         }
 
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 71554ee..5a05134b 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -562,12 +562,6 @@
     }
 
     @Override
-    public void revokeOwnPermissionsOnKill(@NonNull String packageName,
-            @NonNull List<String> permissions) {
-        mPermissionManagerServiceImpl.revokeOwnPermissionsOnKill(packageName, permissions);
-    }
-
-    @Override
     public boolean shouldShowRequestPermissionRationale(String packageName, String permissionName,
             int userId) {
         return mPermissionManagerServiceImpl.shouldShowRequestPermissionRationale(packageName,
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 9084261..009d155 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -1597,25 +1597,6 @@
         }
     }
 
-    @Override
-    public void revokeOwnPermissionsOnKill(String packageName, List<String> permissions) {
-        final int callingUid = Binder.getCallingUid();
-        int callingUserId = UserHandle.getUserId(callingUid);
-        int targetPackageUid = mPackageManagerInt.getPackageUid(packageName, 0, callingUserId);
-        if (targetPackageUid != callingUid) {
-            throw new SecurityException("uid " + callingUid
-                    + " cannot revoke permissions for package " + packageName + " with uid "
-                    + targetPackageUid);
-        }
-        for (String permName : permissions) {
-            if (!checkCallingOrSelfPermission(permName)) {
-                throw new SecurityException("uid " + callingUid + " cannot revoke permission "
-                        + permName + " because it does not hold that permission");
-            }
-        }
-        mPermissionControllerManager.revokeOwnPermissionsOnKill(packageName, permissions);
-    }
-
     private boolean mayManageRolePermission(int uid) {
         final PackageManager packageManager = mContext.getPackageManager();
         final String[] packageNames = packageManager.getPackagesForUid(uid);
@@ -3291,10 +3272,13 @@
         } else if (pkg.isSystemExt()) {
             permissions = systemConfig.getSystemExtPrivAppPermissions(pkg.getPackageName());
         } else if (containingApexPackageName != null) {
+            final ApexManager apexManager = ApexManager.getInstance();
+            final String apexName = apexManager.getApexModuleNameForPackageName(
+                    containingApexPackageName);
             final Set<String> privAppPermissions = systemConfig.getPrivAppPermissions(
                     pkg.getPackageName());
             final Set<String> apexPermissions = systemConfig.getApexPrivAppPermissions(
-                    containingApexPackageName, pkg.getPackageName());
+                    apexName, pkg.getPackageName());
             if (privAppPermissions != null) {
                 // TODO(andreionea): Remove check as soon as all apk-in-apex
                 // permission allowlists are migrated.
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
index 3e28320..3771f03 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
@@ -327,28 +327,6 @@
     void revokePostNotificationPermissionWithoutKillForTest(String packageName, int userId);
 
     /**
-     * Triggers the revocation of one or more permissions for a package, under the following
-     * conditions:
-     * <ul>
-     * <li>The package {@code packageName} must be under the same UID as the calling process
-     *   (typically, the target package is the calling package).
-     * <li>Each permission in {@code permissions} must be granted to the package
-     * {@code packageName}.
-     * <li>Each permission in {@code permissions} must be a runtime permission.
-     * </ul>
-     * <p>
-     * Background permissions which have no corresponding foreground permission still granted once
-     * the revocation is effective will also be revoked.
-     * <p>
-     * This revocation happens asynchronously and kills all processes running in the same UID as
-     * {@code packageName}. It will be triggered once it is safe to do so.
-     *
-     * @param packageName The name of the package for which the permissions will be revoked.
-     * @param permissions List of permissions to be revoked.
-     */
-    void revokeOwnPermissionsOnKill(String packageName, List<String> permissions);
-
-    /**
      * Get whether you should show UI with rationale for requesting a permission. You should do this
      * only if you do not have the permission and the context in which the permission is requested
      * does not clearly communicate to the user what would be the benefit from grating this
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
index cbba346..40f859c 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
@@ -302,6 +302,8 @@
 
     ParsingPackage setMinSdkVersion(int minSdkVersion);
 
+    ParsingPackage setMaxSdkVersion(int maxSdkVersion);
+
     ParsingPackage setNetworkSecurityConfigRes(int networkSecurityConfigRes);
 
     ParsingPackage setNonLocalizedLabel(CharSequence nonLocalizedLabel);
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
index 1484df8..67d9aec 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
@@ -383,6 +383,7 @@
     @Nullable
     private SparseIntArray minExtensionVersions;
     private int minSdkVersion = ParsingUtils.DEFAULT_MIN_SDK_VERSION;
+    private int maxSdkVersion = ParsingUtils.DEFAULT_MAX_SDK_VERSION;
     private int networkSecurityConfigRes;
     @Nullable
     private CharSequence nonLocalizedLabel;
@@ -1306,6 +1307,7 @@
         dest.writeFloat(this.maxAspectRatio);
         dest.writeFloat(this.minAspectRatio);
         dest.writeInt(this.minSdkVersion);
+        dest.writeInt(this.maxSdkVersion);
         dest.writeInt(this.networkSecurityConfigRes);
         dest.writeCharSequence(this.nonLocalizedLabel);
         dest.writeString(this.permission);
@@ -1454,6 +1456,7 @@
         this.maxAspectRatio = in.readFloat();
         this.minAspectRatio = in.readFloat();
         this.minSdkVersion = in.readInt();
+        this.maxSdkVersion = in.readInt();
         this.networkSecurityConfigRes = in.readInt();
         this.nonLocalizedLabel = in.readCharSequence();
         this.permission = in.readString();
@@ -2068,6 +2071,11 @@
     }
 
     @Override
+    public int getMaxSdkVersion() {
+        return maxSdkVersion;
+    }
+
+    @Override
     public int getNetworkSecurityConfigRes() {
         return networkSecurityConfigRes;
     }
@@ -2592,6 +2600,12 @@
     }
 
     @Override
+    public ParsingPackageImpl setMaxSdkVersion(int value) {
+        maxSdkVersion = value;
+        return this;
+    }
+
+    @Override
     public ParsingPackageImpl setNetworkSecurityConfigRes(int value) {
         networkSecurityConfigRes = value;
         return this;
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index 112b9e0..f255db4 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -209,6 +209,8 @@
 
     public static final int SDK_VERSION = Build.VERSION.SDK_INT;
     public static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES;
+    public static final String[] PREVIOUS_CODENAMES =
+            Build.VERSION.KNOWN_CODENAMES.toArray(new String[]{});
 
     public static boolean sCompatibilityModeEnabled = true;
     public static boolean sUseRoundIcon = false;
@@ -236,9 +238,15 @@
      */
     public static final int PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY = 1 << 7;
     public static final int PARSE_FRAMEWORK_RES_SPLITS = 1 << 8;
+    public static final int PARSE_CHECK_MAX_SDK_VERSION = 1 << 9;
 
     public static final int PARSE_CHATTY = 1 << 31;
 
+    /** The total maximum number of activities, services, providers and activity-aliases */
+    private static final int MAX_NUM_COMPONENTS = 30000;
+    private static final String MAX_NUM_COMPONENTS_ERR_MSG =
+            "Total number of components has exceeded the maximum number: " + MAX_NUM_COMPONENTS;
+
     @IntDef(flag = true, prefix = { "PARSE_" }, value = {
             PARSE_CHATTY,
             PARSE_COLLECT_CERTIFICATES,
@@ -834,11 +842,20 @@
             if (result.isError()) {
                 return input.error(result);
             }
+
+            if (hasTooManyComponents(pkg)) {
+                return input.error(MAX_NUM_COMPONENTS_ERR_MSG);
+            }
         }
 
         return input.success(pkg);
     }
 
+    private static boolean hasTooManyComponents(ParsingPackage pkg) {
+        return pkg.getActivities().size() + pkg.getServices().size() + pkg.getProviders().size()
+                > MAX_NUM_COMPONENTS;
+    }
+
     /**
      * For parsing non-MainComponents. Main ones have an order and some special handling which is
      * done directly in {@link #parseSplitApplication(ParseInput, ParsingPackage, Resources,
@@ -1002,7 +1019,7 @@
             case TAG_FEATURE_GROUP:
                 return parseFeatureGroup(input, pkg, res, parser);
             case TAG_USES_SDK:
-                return parseUsesSdk(input, pkg, res, parser);
+                return parseUsesSdk(input, pkg, res, parser, flags);
             case TAG_SUPPORT_SCREENS:
                 return parseSupportScreens(input, pkg, res, parser);
             case TAG_PROTECTED_BROADCAST:
@@ -1514,15 +1531,17 @@
     }
 
     private static ParseResult<ParsingPackage> parseUsesSdk(ParseInput input,
-            ParsingPackage pkg, Resources res, XmlResourceParser parser)
+            ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)
             throws IOException, XmlPullParserException {
         if (SDK_VERSION > 0) {
+            final boolean checkMaxSdkVersion = (flags & PARSE_CHECK_MAX_SDK_VERSION) != 0;
             TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesSdk);
             try {
                 int minVers = ParsingUtils.DEFAULT_MIN_SDK_VERSION;
                 String minCode = null;
                 int targetVers = ParsingUtils.DEFAULT_TARGET_SDK_VERSION;
                 String targetCode = null;
+                int maxVers = Integer.MAX_VALUE;
 
                 TypedValue val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_minSdkVersion);
                 if (val != null) {
@@ -1550,6 +1569,14 @@
                     targetCode = minCode;
                 }
 
+                if (checkMaxSdkVersion) {
+                    val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_maxSdkVersion);
+                    if (val != null) {
+                        // maxSdkVersion only supports integer
+                        maxVers = val.data;
+                    }
+                }
+
                 ParseResult<Integer> targetSdkVersionResult = FrameworkParsingPackageUtils
                         .computeTargetSdkVersion(targetVers, targetCode, SDK_CODENAMES, input);
                 if (targetSdkVersionResult.isError()) {
@@ -1574,6 +1601,15 @@
 
                 pkg.setMinSdkVersion(minSdkVersion)
                         .setTargetSdkVersion(targetSdkVersion);
+                if (checkMaxSdkVersion) {
+                    ParseResult<Integer> maxSdkVersionResult = FrameworkParsingPackageUtils
+                            .computeMaxSdkVersion(maxVers, SDK_VERSION, input);
+                    if (maxSdkVersionResult.isError()) {
+                        return input.error(maxSdkVersionResult);
+                    }
+                    int maxSdkVersion = maxSdkVersionResult.getResult();
+                    pkg.setMaxSdkVersion(maxSdkVersion);
+                }
 
                 int type;
                 final int innerDepth = parser.getDepth();
@@ -2123,6 +2159,9 @@
             if (result.isError()) {
                 return input.error(result);
             }
+            if (hasTooManyComponents(pkg)) {
+                return input.error(MAX_NUM_COMPONENTS_ERR_MSG);
+            }
         }
 
         if (TextUtils.isEmpty(pkg.getStaticSharedLibName()) && TextUtils.isEmpty(
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java
index cb474df..0751285 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java
@@ -50,6 +50,7 @@
     public static final String ANDROID_RES_NAMESPACE = "http://schemas.android.com/apk/res/android";
 
     public static final int DEFAULT_MIN_SDK_VERSION = 1;
+    public static final int DEFAULT_MAX_SDK_VERSION = Integer.MAX_VALUE;
     public static final int DEFAULT_TARGET_SDK_VERSION = 0;
 
     public static final int NOT_SET = -1;
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/PkgWithoutStateAppInfo.java b/services/core/java/com/android/server/pm/pkg/parsing/PkgWithoutStateAppInfo.java
index 3205b76..99bcdb96 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/PkgWithoutStateAppInfo.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/PkgWithoutStateAppInfo.java
@@ -250,6 +250,11 @@
     int getMinSdkVersion();
 
     /**
+     * @see R.styleable#AndroidManifestUsesSdk_maxSdkVersion
+     */
+    int getMaxSdkVersion();
+
+    /**
      * @see ApplicationInfo#getNativeHeapZeroInitialized()
      * @see R.styleable#AndroidManifestApplication_nativeHeapZeroInitialized
      */
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 70ef3d3..bd9e892 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -153,9 +153,10 @@
 
     private List<String> mAppOpPermissions;
 
-    private Context mContext;
-    private Handler mHandler;
+    private final Context mContext;
+    private final Handler mHandler;
     private PackageManagerInternal mPackageManagerInternal;
+    private PermissionManagerServiceInternal mPermissionManagerInternal;
     private NotificationManagerInternal mNotificationManager;
     private final KeyguardManager mKeyguardManager;
     private final PackageManager mPackageManager;
@@ -174,7 +175,7 @@
     public void onStart() {
         mPackageManagerInternal = LocalServices.getService(
                 PackageManagerInternal.class);
-        PermissionManagerServiceInternal permissionManagerInternal = LocalServices.getService(
+        mPermissionManagerInternal = LocalServices.getService(
                 PermissionManagerServiceInternal.class);
         final IAppOpsService appOpsService = IAppOpsService.Stub.asInterface(
                 ServiceManager.getService(Context.APP_OPS_SERVICE));
@@ -206,7 +207,7 @@
             }
         });
 
-        permissionManagerInternal.addOnRuntimePermissionStateChangedListener(
+        mPermissionManagerInternal.addOnRuntimePermissionStateChangedListener(
                 this::synchronizePackagePermissionsAndAppOpsAsyncForUser);
 
         mAppOpsCallback = new IAppOpsCallback.Stub() {
@@ -218,7 +219,7 @@
         };
 
         final ArrayList<PermissionInfo> dangerousPerms =
-                permissionManagerInternal.getAllPermissionsWithProtection(
+                mPermissionManagerInternal.getAllPermissionsWithProtection(
                         PermissionInfo.PROTECTION_DANGEROUS);
         try {
             int numDangerousPerms = dangerousPerms.size();
@@ -243,7 +244,7 @@
         }
 
         final List<PermissionInfo> appOpPermissionInfos =
-                permissionManagerInternal.getAllPermissionsWithProtectionFlags(
+                mPermissionManagerInternal.getAllPermissionsWithProtectionFlags(
                         PermissionInfo.PROTECTION_FLAG_APPOP);
         mAppOpPermissions = new ArrayList<>();
         final int appOpPermissionInfosSize = appOpPermissionInfos.size();
@@ -1283,10 +1284,12 @@
             }
             boolean hasCreatedNotificationChannels = mNotificationManager
                     .getNumNotificationChannelsForPackage(pkgName, uid, true) > 0;
+            boolean granted = mPermissionManagerInternal.checkUidPermission(uid, POST_NOTIFICATIONS)
+                    == PackageManager.PERMISSION_GRANTED;
             int flags = mPackageManager.getPermissionFlags(POST_NOTIFICATIONS, pkgName, user);
             boolean explicitlySet = (flags & PermissionManager.EXPLICIT_SET_FLAGS) != 0;
             boolean needsReview = (flags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0;
-            return hasCreatedNotificationChannels && (needsReview || !explicitlySet);
+            return !granted && hasCreatedNotificationChannels && (needsReview || !explicitlySet);
         }
     }
 }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index e79148d..999428a 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -792,7 +792,7 @@
         public void onWakeUp() {
             synchronized (mLock) {
                 if (shouldEnableWakeGestureLp()
-                        && mBatteryManagerInternal.getPlugType() != BATTERY_PLUGGED_WIRELESS) {
+                        && getBatteryManagerInternal().getPlugType() != BATTERY_PLUGGED_WIRELESS) {
                     performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, false,
                             "Wake Up");
                     wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromWakeGesture,
@@ -1023,7 +1023,8 @@
                     break;
                 }
                 case SHORT_PRESS_POWER_LOCK_OR_SLEEP: {
-                    if (keyguardOn()) {
+                    if (mKeyguardDelegate == null || !mKeyguardDelegate.hasKeyguard()
+                            || !mKeyguardDelegate.isSecure(mCurrentUserId) || keyguardOn()) {
                         sleepDefaultDisplayFromPowerButton(eventTime, 0);
                     } else {
                         lockNow(null /*options*/);
@@ -1490,11 +1491,19 @@
     }
 
     private long getAccessibilityShortcutTimeout() {
-        ViewConfiguration config = ViewConfiguration.get(mContext);
-        return Settings.Secure.getIntForUser(mContext.getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0, mCurrentUserId) == 0
-                ? config.getAccessibilityShortcutKeyTimeout()
-                : config.getAccessibilityShortcutKeyTimeoutAfterConfirmation();
+        final ViewConfiguration config = ViewConfiguration.get(mContext);
+        final boolean hasDialogShown = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0, mCurrentUserId) != 0;
+        final boolean skipTimeoutRestriction =
+                Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                        Settings.Secure.SKIP_ACCESSIBILITY_SHORTCUT_DIALOG_TIMEOUT_RESTRICTION, 0,
+                        mCurrentUserId) != 0;
+
+        // If users manually set the volume key shortcut for any accessibility service, the
+        // system would bypass the timeout restriction of the shortcut dialog.
+        return hasDialogShown || skipTimeoutRestriction
+                ? config.getAccessibilityShortcutKeyTimeoutAfterConfirmation()
+                : config.getAccessibilityShortcutKeyTimeout();
     }
 
     private long getScreenshotChordLongPressDelay() {
@@ -5445,8 +5454,7 @@
         VibrationAttributes attrs = getVibrationAttributes(effectId);
         if (always) {
             attrs = new VibrationAttributes.Builder(attrs)
-                    .setFlags(VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF,
-                            VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF)
+                    .setFlags(VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF)
                     .build();
         }
         mVibrator.vibrate(uid, packageName, effect, reason, attrs);
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 048f8d6..c04d608 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -40,12 +40,14 @@
 import android.annotation.RequiresPermission;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
+import android.app.AppOpsManager;
 import android.app.SynchronousUserSwitchObserver;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.database.ContentObserver;
@@ -1454,6 +1456,15 @@
     private void acquireWakeLockInternal(IBinder lock, int displayId, int flags, String tag,
             String packageName, WorkSource ws, String historyTag, int uid, int pid,
             @Nullable IWakeLockCallback callback) {
+
+        boolean isCallerPrivileged = false;
+        try {
+            ApplicationInfo appInfo = mContext.getPackageManager().getApplicationInfo(packageName,
+                    PackageManager.ApplicationInfoFlags.of(0));
+            isCallerPrivileged = appInfo.uid == uid && appInfo.isPrivilegedApp();
+        } catch (PackageManager.NameNotFoundException e) {
+            // assume app is not privileged
+        }
         synchronized (mLock) {
             if (displayId != Display.INVALID_DISPLAY) {
                 final DisplayInfo displayInfo =
@@ -1500,7 +1511,7 @@
                 notifyAcquire = true;
             }
 
-            applyWakeLockFlagsOnAcquireLocked(wakeLock, uid);
+            applyWakeLockFlagsOnAcquireLocked(wakeLock, isCallerPrivileged);
             mDirty |= DIRTY_WAKE_LOCKS;
             updatePowerStateLocked();
             if (notifyAcquire) {
@@ -1539,8 +1550,34 @@
         return null;
     }
 
+    private boolean isAcquireCausesWakeupFlagAllowed(String opPackageName, int opUid,
+            boolean isCallerPrivileged) {
+        if (opPackageName == null) {
+            return false;
+        }
+        if (isCallerPrivileged) {
+            if (DEBUG_SPEW) {
+                Slog.d(TAG, "Allowing device wake-up for privileged app, call attributed to "
+                        + opPackageName);
+            }
+            return true;
+        }
+        if (mContext.getSystemService(AppOpsManager.class).checkOpNoThrow(
+                AppOpsManager.OP_TURN_SCREEN_ON, opUid, opPackageName)
+                == AppOpsManager.MODE_ALLOWED) {
+            if (DEBUG_SPEW) {
+                Slog.d(TAG, "Allowing device wake-up for app with special access " + opPackageName);
+            }
+            return true;
+        }
+        if (DEBUG_SPEW) {
+            Slog.d(TAG, "Not allowing device wake-up for " + opPackageName);
+        }
+        return false;
+    }
+
     @GuardedBy("mLock")
-    private void applyWakeLockFlagsOnAcquireLocked(WakeLock wakeLock, int uid) {
+    private void applyWakeLockFlagsOnAcquireLocked(WakeLock wakeLock, boolean isCallerPrivileged) {
         if ((wakeLock.mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0
                 && isScreenLock(wakeLock)) {
             String opPackageName;
@@ -1560,10 +1597,30 @@
                 opPackageName = wakeLock.mPackageName;
                 opUid = wakeLock.mOwnerUid;
             }
-            for (int idx = 0; idx < mPowerGroups.size(); idx++) {
-                wakePowerGroupLocked(mPowerGroups.valueAt(idx), mClock.uptimeMillis(),
-                        PowerManager.WAKE_REASON_APPLICATION, wakeLock.mTag, opUid, opPackageName,
-                        opUid);
+            Integer powerGroupId = wakeLock.getPowerGroupId();
+            // powerGroupId is null if the wakelock associated display is no longer available
+            if (powerGroupId != null && isAcquireCausesWakeupFlagAllowed(opPackageName, opUid,
+                    isCallerPrivileged)) {
+                if (powerGroupId == Display.INVALID_DISPLAY_GROUP) {
+                    // wake up all display groups
+                    if (DEBUG_SPEW) {
+                        Slog.d(TAG, "Waking up all power groups");
+                    }
+                    for (int idx = 0; idx < mPowerGroups.size(); idx++) {
+                        wakePowerGroupLocked(mPowerGroups.valueAt(idx), mClock.uptimeMillis(),
+                                PowerManager.WAKE_REASON_APPLICATION, wakeLock.mTag, opUid,
+                                opPackageName, opUid);
+                    }
+                    return;
+                }
+                if (mPowerGroups.contains(powerGroupId)) {
+                    if (DEBUG_SPEW) {
+                        Slog.d(TAG, "Waking up power group " + powerGroupId);
+                    }
+                    wakePowerGroupLocked(mPowerGroups.get(powerGroupId), mClock.uptimeMillis(),
+                            PowerManager.WAKE_REASON_APPLICATION, wakeLock.mTag, opUid,
+                            opPackageName, opUid);
+                }
             }
         }
     }
@@ -1972,7 +2029,7 @@
     private boolean dozePowerGroupLocked(final PowerGroup powerGroup, long eventTime,
             int reason, int uid) {
         if (DEBUG_SPEW) {
-            Slog.d(TAG, "sleepDisplayGroupNoUpdateLocked: eventTime=" + eventTime
+            Slog.d(TAG, "dozePowerGroup: eventTime=" + eventTime
                     + ", groupId=" + powerGroup.getGroupId() + ", reason=" + reason
                     + ", uid=" + uid);
         }
@@ -2661,8 +2718,8 @@
     @GuardedBy("mLock")
     private void updateUserActivitySummaryLocked(long now, int dirty) {
         // Update the status of the user activity timeout timer.
-        if ((dirty & (DIRTY_DISPLAY_GROUP_WAKEFULNESS | DIRTY_WAKE_LOCKS
-                | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) == 0) {
+        if ((dirty & (DIRTY_DISPLAY_GROUP_WAKEFULNESS | DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY
+                | DIRTY_WAKEFULNESS | DIRTY_SETTINGS | DIRTY_ATTENTIVE)) == 0) {
             return;
         }
         mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);
@@ -2746,6 +2803,11 @@
                             screenDimDuration);
                 }
 
+                if (isAttentiveTimeoutExpired(powerGroup, now)) {
+                    groupUserActivitySummary = 0;
+                    groupNextTimeout = -1;
+                }
+
                 hasUserActivitySummary |= groupUserActivitySummary != 0;
 
                 if (nextTimeout == -1) {
@@ -3101,7 +3163,7 @@
                     Message msg = mHandler.obtainMessage(MSG_SANDMAN);
                     msg.arg1 = powerGroup.getGroupId();
                     msg.setAsynchronous(true);
-                    mHandler.sendMessage(msg);
+                    mHandler.sendMessageAtTime(msg, mClock.uptimeMillis());
                 }
             }
         }
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/AidlUtil.java b/services/core/java/com/android/server/soundtrigger_middleware/AidlUtil.java
new file mode 100644
index 0000000..f3457f5
--- /dev/null
+++ b/services/core/java/com/android/server/soundtrigger_middleware/AidlUtil.java
@@ -0,0 +1,71 @@
+/*
+ * 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.server.soundtrigger_middleware;
+
+import android.media.soundtrigger.PhraseRecognitionEvent;
+import android.media.soundtrigger.PhraseRecognitionExtra;
+import android.media.soundtrigger.RecognitionEvent;
+import android.media.soundtrigger.RecognitionStatus;
+import android.media.soundtrigger.SoundModelType;
+
+/**
+ * Utilities for working with sound trigger related AIDL generated types.
+ */
+public class AidlUtil {
+    /**
+     * Initialize a new recognition event.
+     * @return The new event.
+     */
+    static RecognitionEvent newEmptyRecognitionEvent() {
+        RecognitionEvent result = new RecognitionEvent();
+        result.data = new byte[0];
+        return result;
+    }
+
+    /**
+     * Initialize a new phrase recognition event.
+     * @return The new event.
+     */
+    static PhraseRecognitionEvent newEmptyPhraseRecognitionEvent() {
+        PhraseRecognitionEvent result = new PhraseRecognitionEvent();
+        result.common = newEmptyRecognitionEvent();
+        result.phraseExtras = new PhraseRecognitionExtra[0];
+        return result;
+    }
+
+    /**
+     * Creates a new generic abort event.
+     * @return The new event.
+     */
+    static RecognitionEvent newAbortEvent() {
+        RecognitionEvent event = newEmptyRecognitionEvent();
+        event.type = SoundModelType.GENERIC;
+        event.status = RecognitionStatus.ABORTED;
+        return event;
+    }
+
+    /**
+     * Creates a new generic phrase event.
+     * @return The new event.
+     */
+    static PhraseRecognitionEvent newAbortPhraseEvent() {
+        PhraseRecognitionEvent event = newEmptyPhraseRecognitionEvent();
+        event.common.type = SoundModelType.KEYPHRASE;
+        event.common.status = RecognitionStatus.ABORTED;
+        return event;
+    }
+}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
index 990b21c..c0ab65a 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
@@ -24,7 +24,6 @@
 import android.media.soundtrigger.Properties;
 import android.media.soundtrigger.RecognitionConfig;
 import android.media.soundtrigger.RecognitionEvent;
-import android.media.soundtrigger.RecognitionStatus;
 import android.media.soundtrigger.SoundModel;
 import android.media.soundtrigger.SoundModelType;
 import android.media.soundtrigger.Status;
@@ -391,21 +390,14 @@
     /** Notify the client that recognition has been aborted. */
     private static void notifyAbort(int modelHandle, LoadedModel model) {
         switch (model.type) {
-            case SoundModelType.GENERIC: {
-                RecognitionEvent event = new RecognitionEvent();
-                event.status = RecognitionStatus.ABORTED;
-                event.type = SoundModelType.GENERIC;
-                model.callback.recognitionCallback(modelHandle, event);
-            }
-            break;
+            case SoundModelType.GENERIC:
+                model.callback.recognitionCallback(modelHandle, AidlUtil.newAbortEvent());
+                break;
 
-            case SoundModelType.KEYPHRASE: {
-                PhraseRecognitionEvent event = new PhraseRecognitionEvent();
-                event.common.status = RecognitionStatus.ABORTED;
-                event.common.type = SoundModelType.KEYPHRASE;
-                model.callback.phraseRecognitionCallback(modelHandle, event);
-            }
-            break;
+            case SoundModelType.KEYPHRASE:
+                model.callback.phraseRecognitionCallback(modelHandle,
+                        AidlUtil.newAbortPhraseEvent());
+                break;
         }
     }
 
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
index 934b0e4..fd8dee8 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
@@ -25,6 +25,7 @@
 import android.media.soundtrigger.RecognitionConfig;
 import android.media.soundtrigger.RecognitionEvent;
 import android.media.soundtrigger.SoundModel;
+import android.media.soundtrigger.SoundModelType;
 import android.media.soundtrigger.Status;
 import android.media.soundtrigger_middleware.ISoundTriggerCallback;
 import android.media.soundtrigger_middleware.ISoundTriggerModule;
@@ -305,9 +306,12 @@
 
         @Override
         public void stopRecognition(int modelHandle) {
+            Model model;
             synchronized (SoundTriggerModule.this) {
-                mLoadedModels.get(modelHandle).stopRecognition();
+                checkValid();
+                model = mLoadedModels.get(modelHandle);
             }
+            model.stopRecognition();
         }
 
         @Override
@@ -374,6 +378,7 @@
         private class Model implements ISoundTriggerHal.ModelCallback {
             public int mHandle;
             private ModelState mState = ModelState.INIT;
+            private int mType = SoundModelType.INVALID;
             private SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession mSession;
 
             private @NonNull
@@ -390,6 +395,7 @@
                     SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession audioSession) {
                 mSession = audioSession;
                 mHandle = mHalService.loadSoundModel(model, this);
+                mType = SoundModelType.GENERIC;
                 setState(ModelState.LOADED);
                 mLoadedModels.put(mHandle, this);
                 return mHandle;
@@ -399,7 +405,7 @@
                     SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession audioSession) {
                 mSession = audioSession;
                 mHandle = mHalService.loadPhraseSoundModel(model, this);
-
+                mType = SoundModelType.KEYPHRASE;
                 setState(ModelState.LOADED);
                 mLoadedModels.put(mHandle, this);
                 return mHandle;
@@ -422,12 +428,41 @@
             }
 
             private void stopRecognition() {
-                if (getState() == ModelState.LOADED) {
-                    // This call is idempotent in order to avoid races.
-                    return;
+                synchronized (SoundTriggerModule.this) {
+                    if (getState() == ModelState.LOADED) {
+                        // This call is idempotent in order to avoid races.
+                        return;
+                    }
                 }
+                // This must be invoked outside the lock.
                 mHalService.stopRecognition(mHandle);
-                setState(ModelState.LOADED);
+
+                // No more callbacks for this model after this point.
+                synchronized (SoundTriggerModule.this) {
+                    // Generate an abortion callback to the client if the model is still active.
+                    if (getState() == ModelState.ACTIVE) {
+                        if (mCallback != null) {
+                            try {
+                                switch (mType) {
+                                    case SoundModelType.GENERIC:
+                                        mCallback.onRecognition(mHandle, AidlUtil.newAbortEvent(),
+                                                mSession.mSessionHandle);
+                                        break;
+                                    case SoundModelType.KEYPHRASE:
+                                        mCallback.onPhraseRecognition(mHandle,
+                                                AidlUtil.newAbortPhraseEvent(),
+                                                mSession.mSessionHandle);
+                                        break;
+                                    default:
+                                        throw new RuntimeException(
+                                                "Unexpected model type: " + mType);
+                                }
+                            } catch (RemoteException e) {
+                            }
+                        }
+                        setState(ModelState.LOADED);
+                    }
+                }
             }
 
             /** Request a forced recognition event. Will do nothing if recognition is inactive. */
@@ -518,4 +553,5 @@
             }
         }
     }
+
 }
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 2e60f13..526dccb 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -1633,7 +1633,14 @@
         if (adapter != null) {
             SynchronousResultReceiver bluetoothReceiver =
                     new SynchronousResultReceiver("bluetooth");
-            adapter.requestControllerActivityEnergyInfo(bluetoothReceiver);
+            adapter.requestControllerActivityEnergyInfo(
+                    Runnable::run,
+                    info -> {
+                        Bundle bundle = new Bundle();
+                        bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, info);
+                        bluetoothReceiver.send(0, bundle);
+                    }
+            );
             return awaitControllerInfo(bluetoothReceiver);
         } else {
             Slog.e(TAG, "Failed to get bluetooth adapter!");
@@ -2338,51 +2345,25 @@
     }
 
     int pullProcessDmabufMemory(int atomTag, List<StatsEvent> pulledData) {
-        List<ProcessMemoryState> managedProcessList =
-                LocalServices.getService(ActivityManagerInternal.class)
-                        .getMemoryStateForProcesses();
-        for (ProcessMemoryState process : managedProcessList) {
-            KernelAllocationStats.ProcessDmabuf proc =
-                    KernelAllocationStats.getDmabufAllocations(process.pid);
-            if (proc == null || (proc.retainedBuffersCount <= 0 && proc.mappedBuffersCount <= 0)) {
-                continue;
-            }
-            pulledData.add(
-                    FrameworkStatsLog.buildStatsEvent(
-                            atomTag,
-                            process.uid,
-                            process.processName,
-                            process.oomScore,
-                            proc.retainedSizeKb,
-                            proc.retainedBuffersCount,
-                            proc.mappedSizeKb,
-                            proc.mappedBuffersCount));
+        KernelAllocationStats.ProcessDmabuf[] procBufs =
+                KernelAllocationStats.getDmabufAllocations();
+
+        if (procBufs == null) {
+            return StatsManager.PULL_SKIP;
         }
-        SparseArray<String> processCmdlines = getProcessCmdlines();
-        managedProcessList.forEach(managedProcess -> processCmdlines.delete(managedProcess.pid));
-        int size = processCmdlines.size();
-        for (int i = 0; i < size; ++i) {
-            int pid = processCmdlines.keyAt(i);
-            int uid = getUidForPid(pid);
-            // ignore root processes (unlikely to be interesting)
-            if (uid <= 0) {
-                continue;
-            }
-            KernelAllocationStats.ProcessDmabuf proc =
-                    KernelAllocationStats.getDmabufAllocations(pid);
-            if (proc == null || (proc.retainedBuffersCount <= 0 && proc.mappedBuffersCount <= 0)) {
-                continue;
-            }
-            pulledData.add(
-                    FrameworkStatsLog.buildStatsEvent(
-                            atomTag,
-                            uid,
-                            processCmdlines.valueAt(i),
-                            -1001 /*Placeholder for native processes, OOM_SCORE_ADJ_MIN - 1.*/,
-                            proc.retainedSizeKb,
-                            proc.retainedBuffersCount,
-                            proc.mappedSizeKb,
-                            proc.mappedBuffersCount));
+        for (KernelAllocationStats.ProcessDmabuf procBuf : procBufs) {
+            pulledData.add(FrameworkStatsLog.buildStatsEvent(
+                    atomTag,
+                    procBuf.uid,
+                    procBuf.processName,
+                    procBuf.oomScore,
+                    procBuf.retainedSizeKb,
+                    procBuf.retainedBuffersCount,
+                    0, /* mapped_dmabuf_kb - deprecated */
+                    0, /* mapped_dmabuf_count - deprecated */
+                    procBuf.surfaceFlingerSizeKb,
+                    procBuf.surfaceFlingerCount
+            ));
         }
         return StatsManager.PULL_SUCCESS;
     }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 59b9daf..8087738 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -36,6 +36,7 @@
 import android.app.StatusBarManager;
 import android.app.compat.CompatChanges;
 import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
 import android.compat.annotation.EnabledSince;
 import android.content.ComponentName;
 import android.content.Context;
@@ -135,6 +136,17 @@
     @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
     private static final long LOCK_DOWN_COLLAPSE_STATUS_BAR = 173031413L;
 
+    /**
+     * In apps targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or higher, calling
+     * {@link android.service.quicksettings.TileService#requestListeningState} will check that the 
+     * calling package (uid) and the package of the target {@link android.content.ComponentName} 
+     * match. It'll also make sure that the context used can take actions on behalf of the current 
+     * user.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
+    static final long REQUEST_LISTENING_MUST_MATCH_PACKAGE = 172251878L;
+
     private final Context mContext;
 
     private final Handler mHandler = new Handler();
@@ -1652,6 +1664,7 @@
 
     @Override
     public void hideCurrentInputMethodForBubbles() {
+        enforceStatusBarService();
         final long token = Binder.clearCallingIdentity();
         try {
             InputMethodManagerInternal.get().hideCurrentInputMethod(
@@ -1776,6 +1789,42 @@
     }
 
     @Override
+    public void requestTileServiceListeningState(
+            @NonNull ComponentName componentName,
+            int userId
+    ) {
+        int callingUid = Binder.getCallingUid();
+        String packageName = componentName.getPackageName();
+
+        boolean mustPerformChecks = CompatChanges.isChangeEnabled(
+                REQUEST_LISTENING_MUST_MATCH_PACKAGE, callingUid);
+
+        if (mustPerformChecks) {
+            // Check calling user can act on behalf of current user
+            userId = mActivityManagerInternal.handleIncomingUser(Binder.getCallingPid(), callingUid,
+                    userId, false, ActivityManagerInternal.ALLOW_NON_FULL,
+                    "requestTileServiceListeningState", packageName);
+
+            // Check calling uid matches package
+            checkCallingUidPackage(packageName, callingUid, userId);
+
+            int currentUser = mActivityManagerInternal.getCurrentUserId();
+
+            // Check current user
+            if (userId != currentUser) {
+                throw new IllegalArgumentException("User " + userId + " is not the current user.");
+            }
+        }
+        if (mBar != null) {
+            try {
+                mBar.requestTileServiceListeningState(componentName);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "requestTileServiceListeningState", e);
+            }
+        }
+    }
+
+    @Override
     public void requestAddTile(
             @NonNull ComponentName componentName,
             @NonNull CharSequence label,
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index 20cd8f5..d374814 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -40,12 +40,16 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.service.trust.GrantTrustResult;
 import android.service.trust.ITrustAgentService;
 import android.service.trust.ITrustAgentServiceCallback;
 import android.service.trust.TrustAgentService;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
 
+import com.android.internal.infra.AndroidFuture;
+
 import java.util.Collections;
 import java.util.List;
 
@@ -156,7 +160,9 @@
                     }
                     mTrusted = true;
                     mTrustable = false;
-                    mMessage = (CharSequence) msg.obj;
+                    Pair<CharSequence, AndroidFuture<GrantTrustResult>> pair = (Pair) msg.obj;
+                    mMessage = pair.first;
+                    AndroidFuture<GrantTrustResult> resultCallback = pair.second;
                     int flags = msg.arg1;
                     mDisplayTrustGrantedMessage = (flags & FLAG_GRANT_TRUST_DISPLAY_MESSAGE) != 0;
                     if ((flags & FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) != 0) {
@@ -189,7 +195,7 @@
                     mTrustManagerService.mArchive.logGrantTrust(mUserId, mName,
                             (mMessage != null ? mMessage.toString() : null),
                             durationMs, flags);
-                    mTrustManagerService.updateTrust(mUserId, flags);
+                    mTrustManagerService.updateTrust(mUserId, flags, resultCallback);
                     break;
                 case MSG_TRUST_TIMEOUT:
                     if (DEBUG) Slog.d(TAG, "Trust timed out : " + mName.flattenToShortString());
@@ -198,6 +204,8 @@
                     // Fall through.
                 case MSG_REVOKE_TRUST:
                     mTrusted = false;
+                    mTrustable = false;
+                    mWaitingForTrustableDowngrade = false;
                     mDisplayTrustGrantedMessage = false;
                     mMessage = null;
                     mHandler.removeMessages(MSG_TRUST_TIMEOUT);
@@ -312,13 +320,18 @@
     private ITrustAgentServiceCallback mCallback = new ITrustAgentServiceCallback.Stub() {
 
         @Override
-        public void grantTrust(CharSequence message, long durationMs, int flags) {
+        public void grantTrust(
+                CharSequence message,
+                long durationMs,
+                int flags,
+                AndroidFuture resultCallback) {
             if (DEBUG) {
                 Slog.d(TAG, "enableTrust(" + message + ", durationMs = " + durationMs
                         + ", flags = " + flags + ")");
             }
 
-            Message msg = mHandler.obtainMessage(MSG_GRANT_TRUST, flags, 0, message);
+            Message msg = mHandler.obtainMessage(
+                    MSG_GRANT_TRUST, flags, 0, Pair.create(message, resultCallback));
             msg.getData().putLong(DATA_DURATION, durationMs);
             msg.sendToTarget();
         }
@@ -512,12 +525,23 @@
     }
 
     /**
-     * @see android.service.trust.TrustAgentService#onUserRequestedUnlock()
+     * @see android.service.trust.TrustAgentService#onUserRequestedUnlock(boolean)
      */
-    public void onUserRequestedUnlock() {
+    public void onUserRequestedUnlock(boolean dismissKeyguard) {
         try {
             if (mTrustAgentService != null) {
-                mTrustAgentService.onUserRequestedUnlock();
+                mTrustAgentService.onUserRequestedUnlock(dismissKeyguard);
+            }
+        } catch (RemoteException e) {
+            onError(e);
+        }
+    }
+
+    /** @see android.service.trust.TrustAgentService#onUserMayRequestUnlock() */
+    public void onUserMayRequestUnlock() {
+        try {
+            if (mTrustAgentService != null) {
+                mTrustAgentService.onUserMayRequestUnlock();
             }
         } catch (RemoteException e) {
             onError(e);
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index bd4b8d1..8f4ddea 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.trust;
 
+import static android.service.trust.GrantTrustResult.STATUS_UNLOCKED_BY_GRANT;
 import static android.service.trust.TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE;
 
 import android.Manifest;
@@ -61,6 +62,7 @@
 import android.os.UserManager;
 import android.provider.Settings;
 import android.security.Authorization;
+import android.service.trust.GrantTrustResult;
 import android.service.trust.TrustAgentService;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -77,6 +79,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.PackageMonitor;
+import com.android.internal.infra.AndroidFuture;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.LocalServices;
@@ -131,6 +134,7 @@
     private static final int MSG_SCHEDULE_TRUST_TIMEOUT = 15;
     private static final int MSG_USER_REQUESTED_UNLOCK = 16;
     private static final int MSG_REFRESH_TRUSTABLE_TIMERS_AFTER_AUTH = 17;
+    private static final int MSG_USER_MAY_REQUEST_UNLOCK = 18;
 
     private static final String REFRESH_DEVICE_LOCKED_EXCEPT_USER = "except";
 
@@ -495,13 +499,28 @@
         }
     }
 
-    public void updateTrust(int userId, int flags) {
-        updateTrust(userId, flags, false /* isFromUnlock */);
+    /** Triggers a trust update. */
+    public void updateTrust(
+            int userId,
+            int flags) {
+        updateTrust(userId, flags, null);
     }
 
-    private void updateTrust(int userId, int flags, boolean isFromUnlock) {
+    /** Triggers a trust update. */
+    public void updateTrust(
+            int userId,
+            int flags,
+            @Nullable AndroidFuture<GrantTrustResult> resultCallback) {
+        updateTrust(userId, flags, false /* isFromUnlock */, resultCallback);
+    }
+
+    private void updateTrust(
+            int userId,
+            int flags,
+            boolean isFromUnlock,
+            @Nullable AndroidFuture<GrantTrustResult> resultCallback) {
         if (ENABLE_ACTIVE_UNLOCK_FLAG) {
-            updateTrustWithRenewableUnlock(userId, flags, isFromUnlock);
+            updateTrustWithRenewableUnlock(userId, flags, isFromUnlock, resultCallback);
         } else {
             updateTrustWithNonrenewableTrust(userId, flags, isFromUnlock);
         }
@@ -553,7 +572,11 @@
         }
     }
 
-    private void updateTrustWithRenewableUnlock(int userId, int flags, boolean isFromUnlock) {
+    private void updateTrustWithRenewableUnlock(
+            int userId,
+            int flags,
+            boolean isFromUnlock,
+            @Nullable AndroidFuture<GrantTrustResult> resultCallback) {
         boolean managed = aggregateIsTrustManaged(userId);
         dispatchOnTrustManagedChanged(managed, userId);
         if (mStrongAuthTracker.isTrustAllowedForUser(userId)
@@ -614,8 +637,16 @@
                         isTrustableTimeout /* isTrustableTimeout */);
             }
         }
-    }
 
+        boolean wasLocked = !alreadyUnlocked;
+        boolean shouldSendCallback = wasLocked && pendingTrustState == TrustState.TRUSTED;
+        if (shouldSendCallback) {
+            if (resultCallback != null) {
+                if (DEBUG) Slog.d(TAG, "calling back with UNLOCKED_BY_GRANT");
+                resultCallback.complete(new GrantTrustResult(STATUS_UNLOCKED_BY_GRANT));
+            }
+        }
+    }
 
     private void updateTrustUsuallyManaged(int userId, boolean managed) {
         synchronized (mTrustUsuallyManagedForUser) {
@@ -715,7 +746,7 @@
                     (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0;
 
             List<ComponentName> enabledAgents = lockPatternUtils.getEnabledTrustAgents(userInfo.id);
-            if (enabledAgents == null) {
+            if (enabledAgents.isEmpty()) {
                 if (DEBUG) Slog.d(TAG, "refreshAgentList: skipping user " + userInfo.id
                         + ": no agents enabled by user");
                 continue;
@@ -1080,9 +1111,7 @@
         }
 
         List<ComponentName> previouslyEnabledAgents = utils.getEnabledTrustAgents(userId);
-        if (previouslyEnabledAgents != null) {
-            discoveredAgents.addAll(previouslyEnabledAgents);
-        }
+        discoveredAgents.addAll(previouslyEnabledAgents);
         utils.setEnabledTrustAgents(discoveredAgents, userId);
         Settings.Secure.putIntForUser(mContext.getContentResolver(),
                 Settings.Secure.TRUST_AGENTS_INITIALIZED, 1, userId);
@@ -1192,7 +1221,7 @@
         if (successful) {
             mStrongAuthTracker.allowTrustFromUnlock(userId);
             // Allow the presence of trust on a successful unlock attempt to extend unlock
-            updateTrust(userId, 0 /* flags */, true);
+            updateTrust(userId, 0 /* flags */, true, null);
             mHandler.obtainMessage(MSG_REFRESH_TRUSTABLE_TIMERS_AFTER_AUTH, userId).sendToTarget();
         }
 
@@ -1204,11 +1233,27 @@
         }
     }
 
-    private void dispatchUserRequestedUnlock(int userId) {
+    private void dispatchUserRequestedUnlock(int userId, boolean dismissKeyguard) {
+        if (DEBUG) {
+            Slog.d(TAG, "dispatchUserRequestedUnlock(user=" + userId + ", dismissKeyguard="
+                    + dismissKeyguard + ")");
+        }
         for (int i = 0; i < mActiveAgents.size(); i++) {
             AgentInfo info = mActiveAgents.valueAt(i);
             if (info.userId == userId) {
-                info.agent.onUserRequestedUnlock();
+                info.agent.onUserRequestedUnlock(dismissKeyguard);
+            }
+        }
+    }
+
+    private void dispatchUserMayRequestUnlock(int userId) {
+        if (DEBUG) {
+            Slog.d(TAG, "dispatchUserMayRequestUnlock(user=" + userId + ")");
+        }
+        for (int i = 0; i < mActiveAgents.size(); i++) {
+            AgentInfo info = mActiveAgents.valueAt(i);
+            if (info.userId == userId) {
+                info.agent.onUserMayRequestUnlock();
             }
         }
     }
@@ -1343,9 +1388,17 @@
         }
 
         @Override
-        public void reportUserRequestedUnlock(int userId) throws RemoteException {
+        public void reportUserRequestedUnlock(int userId, boolean dismissKeyguard)
+                throws RemoteException {
             enforceReportPermission();
-            mHandler.obtainMessage(MSG_USER_REQUESTED_UNLOCK, userId).sendToTarget();
+            mHandler.obtainMessage(MSG_USER_REQUESTED_UNLOCK, userId, dismissKeyguard ? 1 : 0)
+                    .sendToTarget();
+        }
+
+        @Override
+        public void reportUserMayRequestUnlock(int userId) throws RemoteException {
+            enforceReportPermission();
+            mHandler.obtainMessage(MSG_USER_MAY_REQUEST_UNLOCK, userId).sendToTarget();
         }
 
         @Override
@@ -1685,7 +1738,10 @@
                     dispatchUnlockAttempt(msg.arg1 != 0, msg.arg2);
                     break;
                 case MSG_USER_REQUESTED_UNLOCK:
-                    dispatchUserRequestedUnlock(msg.arg1);
+                    dispatchUserRequestedUnlock(msg.arg1, msg.arg2 != 0);
+                    break;
+                case MSG_USER_MAY_REQUEST_UNLOCK:
+                    dispatchUserMayRequestUnlock(msg.arg1);
                     break;
                 case MSG_DISPATCH_UNLOCK_LOCKOUT:
                     dispatchUnlockLockout(msg.arg1, msg.arg2);
@@ -1727,7 +1783,7 @@
                     break;
                 case MSG_REFRESH_DEVICE_LOCKED_FOR_USER:
                     if (msg.arg2 == 1) {
-                        updateTrust(msg.arg1, 0 /* flags */, true /* isFromUnlock */);
+                        updateTrust(msg.arg1, 0 /* flags */, true /* isFromUnlock */, null);
                     }
                     final int unlockedUser = msg.getData().getInt(
                             REFRESH_DEVICE_LOCKED_EXCEPT_USER, UserHandle.USER_NULL);
diff --git a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
index 53a9244..672458b 100644
--- a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
@@ -42,8 +42,8 @@
 import android.media.tv.interactive.ITvInteractiveAppServiceCallback;
 import android.media.tv.interactive.ITvInteractiveAppSession;
 import android.media.tv.interactive.ITvInteractiveAppSessionCallback;
-import android.media.tv.interactive.TvInteractiveAppInfo;
 import android.media.tv.interactive.TvInteractiveAppService;
+import android.media.tv.interactive.TvInteractiveAppServiceInfo;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -130,7 +130,7 @@
                 new Intent(TvInteractiveAppService.SERVICE_INTERFACE),
                 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
                 userId);
-        List<TvInteractiveAppInfo> iAppList = new ArrayList<>();
+        List<TvInteractiveAppServiceInfo> iAppList = new ArrayList<>();
 
         for (ResolveInfo ri : services) {
             ServiceInfo si = ri.serviceInfo;
@@ -143,8 +143,8 @@
 
             ComponentName component = new ComponentName(si.packageName, si.name);
             try {
-                TvInteractiveAppInfo info =
-                        new TvInteractiveAppInfo(mContext, component);
+                TvInteractiveAppServiceInfo info =
+                        new TvInteractiveAppServiceInfo(mContext, component);
                 iAppList.add(info);
             } catch (Exception e) {
                 Slogf.e(TAG, "failed to load TV Interactive App service " + si.name, e);
@@ -154,10 +154,10 @@
         }
 
         // sort the iApp list by iApp service id
-        Collections.sort(iAppList, Comparator.comparing(TvInteractiveAppInfo::getId));
+        Collections.sort(iAppList, Comparator.comparing(TvInteractiveAppServiceInfo::getId));
         Map<String, TvInteractiveAppState> iAppMap = new HashMap<>();
         ArrayMap<String, Integer> tiasAppCount = new ArrayMap<>(iAppMap.size());
-        for (TvInteractiveAppInfo info : iAppList) {
+        for (TvInteractiveAppServiceInfo info : iAppList) {
             String iAppServiceId = info.getId();
             if (DEBUG) {
                 Slogf.d(TAG, "add " + iAppServiceId);
@@ -195,7 +195,7 @@
 
         for (String iAppServiceId : userState.mIAppMap.keySet()) {
             if (!iAppMap.containsKey(iAppServiceId)) {
-                TvInteractiveAppInfo info = userState.mIAppMap.get(iAppServiceId).mInfo;
+                TvInteractiveAppServiceInfo info = userState.mIAppMap.get(iAppServiceId).mInfo;
                 ServiceState serviceState = userState.mServiceStateMap.get(info.getComponent());
                 if (serviceState != null) {
                     abortPendingCreateSessionRequestsLocked(serviceState, iAppServiceId, userId);
@@ -283,7 +283,7 @@
         userState.mCallbacks.finishBroadcast();
     }
 
-    private int getInteractiveAppUid(TvInteractiveAppInfo info) {
+    private int getInteractiveAppUid(TvInteractiveAppServiceInfo info) {
         try {
             return getContext().getPackageManager().getApplicationInfo(
                     info.getServiceInfo().packageName, 0).uid;
@@ -642,7 +642,7 @@
     private final class BinderService extends ITvInteractiveAppManager.Stub {
 
         @Override
-        public List<TvInteractiveAppInfo> getTvInteractiveAppServiceList(int userId) {
+        public List<TvInteractiveAppServiceInfo> getTvInteractiveAppServiceList(int userId) {
             final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
                     Binder.getCallingUid(), userId, "getTvInteractiveAppServiceList");
             final long identity = Binder.clearCallingIdentity();
@@ -653,7 +653,7 @@
                         mGetServiceListCalled = true;
                     }
                     UserState userState = getOrCreateUserStateLocked(resolvedUserId);
-                    List<TvInteractiveAppInfo> iAppList = new ArrayList<>();
+                    List<TvInteractiveAppServiceInfo> iAppList = new ArrayList<>();
                     for (TvInteractiveAppState state : userState.mIAppMap.values()) {
                         iAppList.add(state.mInfo);
                     }
@@ -665,42 +665,6 @@
         }
 
         @Override
-        public void prepare(String tiasId, int type, int userId) {
-            // TODO: bind service
-            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
-                    Binder.getCallingUid(), userId, "prepare");
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                synchronized (mLock) {
-                    UserState userState = getOrCreateUserStateLocked(resolvedUserId);
-                    TvInteractiveAppState iAppState = userState.mIAppMap.get(tiasId);
-                    if (iAppState == null) {
-                        Slogf.e(TAG, "failed to prepare TIAS - unknown TIAS id " + tiasId);
-                        return;
-                    }
-                    ComponentName componentName = iAppState.mInfo.getComponent();
-                    ServiceState serviceState = userState.mServiceStateMap.get(componentName);
-                    if (serviceState == null) {
-                        serviceState = new ServiceState(
-                                componentName, tiasId, resolvedUserId, true, type);
-                        userState.mServiceStateMap.put(componentName, serviceState);
-                        updateServiceConnectionLocked(componentName, resolvedUserId);
-                    } else if (serviceState.mService != null) {
-                        serviceState.mService.prepare(type);
-                    } else {
-                        serviceState.mPendingPrepare = true;
-                        serviceState.mPendingPrepareType = type;
-                        updateServiceConnectionLocked(componentName, resolvedUserId);
-                    }
-                }
-            } catch (RemoteException e) {
-                Slogf.e(TAG, "error in prepare", e);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-
-        @Override
         public void registerAppLinkInfo(String tiasId, AppLinkInfo appLinkInfo, int userId) {
             final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
                     Binder.getCallingUid(), userId, "registerAppLinkInfo: " + appLinkInfo);
@@ -1360,6 +1324,32 @@
         }
 
         @Override
+        public void sendSigningResult(
+                IBinder sessionToken, String signingId, byte[] result, int userId) {
+            if (DEBUG) {
+                Slogf.d(TAG, "sendSigningResult(signingId=%s)", signingId);
+            }
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "sendSigningResult");
+            SessionState sessionState = null;
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        sessionState = getSessionStateLocked(sessionToken, callingUid,
+                                resolvedUserId);
+                        getSessionLocked(sessionState).sendSigningResult(signingId, result);
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slogf.e(TAG, "error in sendSigningResult", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public void setSurface(IBinder sessionToken, Surface surface, int userId) {
             final int callingUid = Binder.getCallingUid();
             final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
@@ -1679,7 +1669,6 @@
         }
 
         boolean shouldBind = (!serviceState.mSessionTokens.isEmpty())
-                || (serviceState.mPendingPrepare)
                 || (!serviceState.mPendingAppLinkInfo.isEmpty())
                 || (!serviceState.mPendingAppLinkCommand.isEmpty());
 
@@ -1738,7 +1727,7 @@
     private static final class TvInteractiveAppState {
         private String mIAppServiceId;
         private ComponentName mComponentName;
-        private TvInteractiveAppInfo mInfo;
+        private TvInteractiveAppServiceInfo mInfo;
         private int mUid;
         private int mIAppNumber;
     }
@@ -1831,22 +1820,13 @@
         private final List<Pair<AppLinkInfo, Boolean>> mPendingAppLinkInfo = new ArrayList<>();
         private final List<Bundle> mPendingAppLinkCommand = new ArrayList<>();
 
-        private boolean mPendingPrepare = false;
-        private Integer mPendingPrepareType = null;
         private ITvInteractiveAppService mService;
         private ServiceCallback mCallback;
         private boolean mBound;
         private boolean mReconnecting;
 
         private ServiceState(ComponentName component, String tias, int userId) {
-            this(component, tias, userId, false, null);
-        }
-
-        private ServiceState(ComponentName component, String tias, int userId,
-                boolean pendingPrepare, Integer prepareType) {
             mComponent = component;
-            mPendingPrepare = pendingPrepare;
-            mPendingPrepareType = prepareType;
             mConnection = new InteractiveAppServiceConnection(component, userId);
             mIAppServiceId = tias;
         }
@@ -1894,19 +1874,6 @@
                     }
                 }
 
-                if (serviceState.mPendingPrepare) {
-                    final long identity = Binder.clearCallingIdentity();
-                    try {
-                        serviceState.mService.prepare(serviceState.mPendingPrepareType);
-                        serviceState.mPendingPrepare = false;
-                        serviceState.mPendingPrepareType = null;
-                    } catch (RemoteException e) {
-                        Slogf.e(TAG, "error in prepare when onServiceConnected", e);
-                    } finally {
-                        Binder.restoreCallingIdentity(identity);
-                    }
-                }
-
                 if (!serviceState.mPendingAppLinkInfo.isEmpty()) {
                     for (Iterator<Pair<AppLinkInfo, Boolean>> it =
                             serviceState.mPendingAppLinkInfo.iterator();
@@ -2221,6 +2188,24 @@
         }
 
         @Override
+        public void onRequestSigning(String id, String algorithm, String alias, byte[] data) {
+            synchronized (mLock) {
+                if (DEBUG) {
+                    Slogf.d(TAG, "onRequestSigning");
+                }
+                if (mSessionState.mSession == null || mSessionState.mClient == null) {
+                    return;
+                }
+                try {
+                    mSessionState.mClient.onRequestSigning(
+                            id, algorithm, alias, data, mSessionState.mSeq);
+                } catch (RemoteException e) {
+                    Slogf.e(TAG, "error in onRequestSigning", e);
+                }
+            }
+        }
+
+        @Override
         public void onAdRequest(AdRequest request) {
             synchronized (mLock) {
                 if (DEBUG) {
diff --git a/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java b/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java
index 397acfa..b45c962 100644
--- a/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java
+++ b/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java
@@ -88,7 +88,7 @@
 
     @Override
     public void traceBegin(@NonNull String name) {
-        Slog.i(mTag, name);
+        Slog.d(mTag, name);
         super.traceBegin(name);
     }
 
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index 30e2617..092853f 100644
--- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -39,7 +39,7 @@
 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
 import android.telephony.TelephonyCallback;
 import android.telephony.TelephonyManager;
-import android.telephony.TelephonyManager.CarrierPrivilegesListener;
+import android.telephony.TelephonyManager.CarrierPrivilegesCallback;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
@@ -98,8 +98,7 @@
     @NonNull private final OnSubscriptionsChangedListener mSubscriptionChangedListener;
 
     @NonNull
-    private final List<CarrierPrivilegesListener> mCarrierPrivilegesChangedListeners =
-            new ArrayList<>();
+    private final List<CarrierPrivilegesCallback> mCarrierPrivilegesCallbacks = new ArrayList<>();
 
     @NonNull private TelephonySubscriptionSnapshot mCurrentSnapshot;
 
@@ -151,20 +150,21 @@
                 executor, mSubscriptionChangedListener);
         mTelephonyManager.registerTelephonyCallback(executor, mActiveDataSubIdListener);
 
-        registerCarrierPrivilegesListeners();
+        registerCarrierPrivilegesCallbacks();
     }
 
-    private void registerCarrierPrivilegesListeners() {
+    // TODO(b/221306368): Refactor with the new onCarrierServiceChange in the new CPCallback
+    private void registerCarrierPrivilegesCallbacks() {
         final HandlerExecutor executor = new HandlerExecutor(mHandler);
         final int modemCount = mTelephonyManager.getActiveModemCount();
         try {
             for (int i = 0; i < modemCount; i++) {
-                CarrierPrivilegesListener carrierPrivilegesListener =
-                        new CarrierPrivilegesListener() {
+                CarrierPrivilegesCallback carrierPrivilegesCallback =
+                        new CarrierPrivilegesCallback() {
                             @Override
                             public void onCarrierPrivilegesChanged(
-                                    @NonNull List<String> privilegedPackageNames,
-                                    @NonNull int[] privilegedUids) {
+                                    @NonNull Set<String> privilegedPackageNames,
+                                    @NonNull Set<Integer> privilegedUids) {
                                 // Re-trigger the synchronous check (which is also very cheap due
                                 // to caching in CarrierPrivilegesTracker). This allows consistency
                                 // with the onSubscriptionsChangedListener and broadcasts.
@@ -172,9 +172,9 @@
                             }
                         };
 
-                mTelephonyManager.addCarrierPrivilegesListener(
-                        i, executor, carrierPrivilegesListener);
-                mCarrierPrivilegesChangedListeners.add(carrierPrivilegesListener);
+                mTelephonyManager.registerCarrierPrivilegesCallback(
+                        i, executor, carrierPrivilegesCallback);
+                mCarrierPrivilegesCallbacks.add(carrierPrivilegesCallback);
             }
         } catch (IllegalArgumentException e) {
             Slog.wtf(TAG, "Encounted exception registering carrier privileges listeners", e);
@@ -191,15 +191,15 @@
         mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionChangedListener);
         mTelephonyManager.unregisterTelephonyCallback(mActiveDataSubIdListener);
 
-        unregisterCarrierPrivilegesListeners();
+        unregisterCarrierPrivilegesCallbacks();
     }
 
-    private void unregisterCarrierPrivilegesListeners() {
-        for (CarrierPrivilegesListener carrierPrivilegesListener :
-                mCarrierPrivilegesChangedListeners) {
-            mTelephonyManager.removeCarrierPrivilegesListener(carrierPrivilegesListener);
+    private void unregisterCarrierPrivilegesCallbacks() {
+        for (CarrierPrivilegesCallback carrierPrivilegesCallback :
+                mCarrierPrivilegesCallbacks) {
+            mTelephonyManager.unregisterCarrierPrivilegesCallback(carrierPrivilegesCallback);
         }
-        mCarrierPrivilegesChangedListeners.clear();
+        mCarrierPrivilegesCallbacks.clear();
     }
 
     /**
@@ -283,7 +283,7 @@
     }
 
     private void handleActionMultiSimConfigChanged(Context context, Intent intent) {
-        unregisterCarrierPrivilegesListeners();
+        unregisterCarrierPrivilegesCallbacks();
 
         // Clear invalid slotIds from the mReadySubIdsBySlotId map.
         final int modemCount = mTelephonyManager.getActiveModemCount();
@@ -296,7 +296,7 @@
             }
         }
 
-        registerCarrierPrivilegesListeners();
+        registerCarrierPrivilegesCallbacks();
         handleSubscriptionsChanged();
     }
 
diff --git a/services/core/java/com/android/server/vibrator/Vibration.java b/services/core/java/com/android/server/vibrator/Vibration.java
index f02f9f9..8ecc51b 100644
--- a/services/core/java/com/android/server/vibrator/Vibration.java
+++ b/services/core/java/com/android/server/vibrator/Vibration.java
@@ -47,12 +47,16 @@
         FINISHED,
         FINISHED_UNEXPECTED,  // Didn't terminate in the usual way.
         FORWARDED_TO_INPUT_DEVICES,
-        CANCELLED,
+        CANCELLED_BINDER_DIED,
+        CANCELLED_BY_SCREEN_OFF,
+        CANCELLED_BY_SETTINGS_UPDATE,
+        CANCELLED_BY_USER,
+        CANCELLED_BY_UNKNOWN_REASON,
+        CANCELLED_SUPERSEDED,
         IGNORED_ERROR_APP_OPS,
         IGNORED_ERROR_CANCELLING,
         IGNORED_ERROR_SCHEDULING,
         IGNORED_ERROR_TOKEN,
-        IGNORED,
         IGNORED_APP_OPS,
         IGNORED_BACKGROUND,
         IGNORED_UNKNOWN_VIBRATION,
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index 77da751..e9535e0 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -121,6 +121,11 @@
                     USAGE_PHYSICAL_EMULATION,
                     USAGE_HARDWARE_FEEDBACK));
 
+    private static final IntentFilter USER_SWITCHED_INTENT_FILTER =
+            new IntentFilter(Intent.ACTION_USER_SWITCHED);
+    private static final IntentFilter INTERNAL_RINGER_MODE_CHANGED_INTENT_FILTER =
+            new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
+
     /** Listener for changes on vibration settings. */
     interface OnVibratorSettingsChanged {
         /** Callback triggered when any of the vibrator settings change. */
@@ -130,11 +135,11 @@
     private final Object mLock = new Object();
     private final Context mContext;
     private final String mSystemUiPackage;
-    private final SettingsObserver mSettingObserver;
+    private final SettingsContentObserver mSettingObserver;
     @VisibleForTesting
     final UidObserver mUidObserver;
     @VisibleForTesting
-    final UserObserver mUserReceiver;
+    final SettingsBroadcastReceiver mSettingChangeReceiver;
 
     @GuardedBy("mLock")
     private final List<OnVibratorSettingsChanged> mListeners = new ArrayList<>();
@@ -154,6 +159,8 @@
     private boolean mBatterySaverMode;
     @GuardedBy("mLock")
     private boolean mVibrateOn;
+    @GuardedBy("mLock")
+    private int mRingerMode;
 
     VibrationSettings(Context context, Handler handler) {
         this(context, handler, new VibrationConfig(context.getResources()));
@@ -163,9 +170,9 @@
     VibrationSettings(Context context, Handler handler, VibrationConfig config) {
         mContext = context;
         mVibrationConfig = config;
-        mSettingObserver = new SettingsObserver(handler);
+        mSettingObserver = new SettingsContentObserver(handler);
         mUidObserver = new UidObserver();
-        mUserReceiver = new UserObserver();
+        mSettingChangeReceiver = new SettingsBroadcastReceiver();
 
         mSystemUiPackage = LocalServices.getService(PackageManagerInternal.class)
                 .getSystemUiServiceComponent().getPackageName();
@@ -188,12 +195,13 @@
                 VibrationEffect.get(VibrationEffect.EFFECT_TICK, false));
 
         // Update with current values from settings.
-        updateSettings();
+        update();
     }
 
     public void onSystemReady() {
         synchronized (mLock) {
             mAudioManager = mContext.getSystemService(AudioManager.class);
+            mRingerMode = mAudioManager.getRingerModeInternal();
         }
         try {
             ActivityManager.getService().registerUidObserver(mUidObserver,
@@ -224,8 +232,8 @@
                     }
                 });
 
-        IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
-        mContext.registerReceiver(mUserReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
+        registerSettingsChangeReceiver(USER_SWITCHED_INTENT_FILTER);
+        registerSettingsChangeReceiver(INTERNAL_RINGER_MODE_CHANGED_INTENT_FILTER);
 
         // Listen to all settings that might affect the result of Vibrator.getVibrationIntensity.
         registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES));
@@ -248,7 +256,7 @@
                 Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY));
 
         // Update with newly loaded services.
-        updateSettings();
+        update();
     }
 
     /**
@@ -396,16 +404,17 @@
             // Only ringtone and notification vibrations are disabled when phone is on silent mode.
             return true;
         }
-        // If audio manager was not loaded yet then assume most restrictive mode.
-        int ringerMode = (mAudioManager == null)
-                ? AudioManager.RINGER_MODE_SILENT
-                : mAudioManager.getRingerModeInternal();
-        return ringerMode != AudioManager.RINGER_MODE_SILENT;
+        return mRingerMode != AudioManager.RINGER_MODE_SILENT;
     }
 
-    /** Updates all vibration settings and triggers registered listeners. */
-    @VisibleForTesting
-    void updateSettings() {
+    /** Update all cached settings and triggers registered listeners. */
+    void update() {
+        updateSettings();
+        updateRingerMode();
+        notifyListeners();
+    }
+
+    private void updateSettings() {
         synchronized (mLock) {
             mVibrateInputDevices = loadSystemSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0) > 0;
             mVibrateOn = loadSystemSetting(Settings.System.VIBRATE_ON, 1) > 0;
@@ -435,7 +444,6 @@
                     loadSystemSetting(Settings.System.RING_VIBRATION_INTENSITY, -1),
                     getDefaultIntensity(USAGE_RINGTONE));
 
-
             mCurrentVibrationIntensities.clear();
             mCurrentVibrationIntensities.put(USAGE_ALARM, alarmIntensity);
             mCurrentVibrationIntensities.put(USAGE_NOTIFICATION, notificationIntensity);
@@ -469,7 +477,16 @@
             // A11y is not disabled by any haptic feedback setting.
             mCurrentVibrationIntensities.put(USAGE_ACCESSIBILITY, positiveHapticFeedbackIntensity);
         }
-        notifyListeners();
+    }
+
+    private void updateRingerMode() {
+        synchronized (mLock) {
+            // If audio manager was not loaded yet then assume most restrictive mode.
+            // This will be loaded again as soon as the audio manager is loaded in onSystemReady.
+            mRingerMode = (mAudioManager == null)
+                    ? AudioManager.RINGER_MODE_SILENT
+                    : mAudioManager.getRingerModeInternal();
+        }
     }
 
     @Override
@@ -586,6 +603,11 @@
                 UserHandle.USER_ALL);
     }
 
+    private void registerSettingsChangeReceiver(IntentFilter intentFilter) {
+        mContext.registerReceiver(mSettingChangeReceiver, intentFilter,
+                Context.RECEIVER_NOT_EXPORTED);
+    }
+
     @Nullable
     private VibrationEffect createEffectFromResource(int resId) {
         long[] timings = getLongIntArray(mContext.getResources(), resId);
@@ -616,24 +638,33 @@
     }
 
     /** Implementation of {@link ContentObserver} to be registered to a setting {@link Uri}. */
-    private final class SettingsObserver extends ContentObserver {
-        SettingsObserver(Handler handler) {
+    private final class SettingsContentObserver extends ContentObserver {
+        SettingsContentObserver(Handler handler) {
             super(handler);
         }
 
         @Override
         public void onChange(boolean selfChange) {
             updateSettings();
+            notifyListeners();
         }
     }
 
-    /** Implementation of {@link BroadcastReceiver} to update settings on current user change. */
+    /**
+     * Implementation of {@link BroadcastReceiver} to update settings on current user or ringer
+     * mode change.
+     */
     @VisibleForTesting
-    final class UserObserver extends BroadcastReceiver {
+    final class SettingsBroadcastReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
-                updateSettings();
+            String action = intent.getAction();
+            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+                // Reload all settings, as they are user-based.
+                update();
+            } else if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) {
+                updateRingerMode();
+                notifyListeners();
             }
         }
     }
diff --git a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
index e12426b..e3d8067 100644
--- a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
+++ b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
@@ -79,12 +79,14 @@
     private final Object mLock = new Object();
     @GuardedBy("mLock")
     private final IntArray mSignalVibratorsComplete;
+    @Nullable
     @GuardedBy("mLock")
-    private boolean mSignalCancel = false;
+    private Vibration.Status mSignalCancelStatus = null;
     @GuardedBy("mLock")
     private boolean mSignalCancelImmediate = false;
 
-    private boolean mCancelled = false;
+    @Nullable
+    private Vibration.Status mCancelStatus = null;
     private boolean mCancelledImmediately = false;  // hard stop
     private int mPendingVibrateSteps;
     private int mRemainingStartSequentialEffectSteps;
@@ -185,8 +187,8 @@
             expectIsVibrationThread(true);
         }
 
-        if (mCancelled) {
-            return Vibration.Status.CANCELLED;
+        if (mCancelStatus != null) {
+            return mCancelStatus;
         }
         if (mPendingVibrateSteps > 0
                 || mRemainingStartSequentialEffectSteps > 0) {
@@ -303,7 +305,7 @@
         if (DEBUG) {
             Slog.d(TAG, "Binder died, cancelling vibration...");
         }
-        notifyCancelled(/* immediate= */ false);
+        notifyCancelled(Vibration.Status.CANCELLED_BINDER_DIED, /* immediate= */ false);
     }
 
     /**
@@ -312,22 +314,41 @@
      *
      * @param immediate indicates whether cancellation should abort urgently and skip cleanup steps.
      */
-    public void notifyCancelled(boolean immediate) {
+    public void notifyCancelled(@NonNull Vibration.Status cancelStatus, boolean immediate) {
         if (Build.IS_DEBUGGABLE) {
             expectIsVibrationThread(false);
         }
+        if (DEBUG) {
+            Slog.d(TAG, "Vibration cancel requested with status=" + cancelStatus
+                    + ", immediate=" + immediate);
+        }
+        if ((cancelStatus == null) || !cancelStatus.name().startsWith("CANCEL")) {
+            Slog.w(TAG, "Vibration cancel requested with bad status=" + cancelStatus
+                    + ", using CANCELLED_UNKNOWN_REASON to ensure cancellation.");
+            cancelStatus = Vibration.Status.CANCELLED_BY_UNKNOWN_REASON;
+        }
         synchronized (mLock) {
-            if (immediate && mSignalCancelImmediate || mSignalCancel) {
-                // Nothing to update: already cancelled previously.
+            if (immediate && mSignalCancelImmediate || (mSignalCancelStatus != null)) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Vibration cancel request ignored as the vibration "
+                            + mVibration.id + "is already being cancelled with status="
+                            + mSignalCancelStatus + ", immediate=" + mSignalCancelImmediate);
+                }
                 return;
             }
             mSignalCancelImmediate |= immediate;
-            mSignalCancel = true;
+            if (mSignalCancelStatus == null) {
+                mSignalCancelStatus = cancelStatus;
+            } else {
+                if (DEBUG) {
+                    Slog.d(TAG, "Vibration cancel request new status=" + cancelStatus
+                            + " ignored as the vibration was already cancelled with status="
+                            + mSignalCancelStatus + ", but immediate flag was updated to "
+                            + mSignalCancelImmediate);
+                }
+            }
             mLock.notify();
         }
-        if (DEBUG) {
-            Slog.d(TAG, "Vibration cancel requested, immediate=" + immediate);
-        }
     }
 
     /**
@@ -380,7 +401,7 @@
         if (Build.IS_DEBUGGABLE) {
             expectIsVibrationThread(true);  // Reads VibrationThread variables as well as signals.
         }
-        return (mSignalCancel && !mCancelled)
+        return (mSignalCancelStatus != mCancelStatus)
             || (mSignalCancelImmediate && !mCancelledImmediately)
             || (mSignalVibratorsComplete.size() > 0);
     }
@@ -395,7 +416,7 @@
         }
 
         int[] vibratorsToProcess = null;
-        boolean doCancel = false;
+        Vibration.Status doCancelStatus = null;
         boolean doCancelImmediate = false;
         // Collect signals to process, but don't keep the lock while processing them.
         synchronized (mLock) {
@@ -405,9 +426,10 @@
                 }
                 // This should only happen once.
                 doCancelImmediate = true;
+                doCancelStatus = mSignalCancelStatus;
             }
-            if (mSignalCancel && !mCancelled) {
-                doCancel = true;
+            if (mSignalCancelStatus != mCancelStatus) {
+                doCancelStatus = mSignalCancelStatus;
             }
             if (!doCancelImmediate && mSignalVibratorsComplete.size() > 0) {
                 // Swap out the queue of completions to process.
@@ -421,11 +443,11 @@
         // completion signals that were collected in this call, but we won't process them
         // anyway as all steps are cancelled.
         if (doCancelImmediate) {
-            processCancelImmediately();
+            processCancelImmediately(doCancelStatus);
             return;
         }
-        if (doCancel) {
-            processCancel();
+        if (doCancelStatus != null) {
+            processCancel(doCancelStatus);
         }
         if (vibratorsToProcess != null) {
             processVibratorsComplete(vibratorsToProcess);
@@ -438,12 +460,12 @@
      * <p>This will remove all steps and replace them with respective results of
      * {@link Step#cancel()}.
      */
-    public void processCancel() {
+    public void processCancel(Vibration.Status cancelStatus) {
         if (Build.IS_DEBUGGABLE) {
             expectIsVibrationThread(true);
         }
 
-        mCancelled = true;
+        mCancelStatus = cancelStatus;
         // Vibrator callbacks should wait until all steps from the queue are properly cancelled
         // and clean up steps are added back to the queue, so they can handle the callback.
         List<Step> cleanUpSteps = new ArrayList<>();
@@ -461,13 +483,13 @@
      *
      * <p>This will remove and trigger {@link Step#cancelImmediately()} in all steps, in order.
      */
-    public void processCancelImmediately() {
+    public void processCancelImmediately(Vibration.Status cancelStatus) {
         if (Build.IS_DEBUGGABLE) {
             expectIsVibrationThread(true);
         }
 
         mCancelledImmediately = true;
-        mCancelled = true;
+        mCancelStatus = cancelStatus;
         Step step;
         while ((step = pollNext()) != null) {
             step.cancelImmediately();
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 1260e5d..f749773 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -162,10 +162,11 @@
                     // When the system is entering a non-interactive state, we want to cancel
                     // vibrations in case a misbehaving app has abandoned them.
                     if (shouldCancelOnScreenOffLocked(mNextVibration)) {
-                        clearNextVibrationLocked(Vibration.Status.CANCELLED);
+                        clearNextVibrationLocked(Vibration.Status.CANCELLED_BY_SCREEN_OFF);
                     }
                     if (shouldCancelOnScreenOffLocked(mCurrentVibration)) {
-                        mCurrentVibration.notifyCancelled(/* immediate= */ false);
+                        mCurrentVibration.notifyCancelled(Vibration.Status.CANCELLED_BY_SCREEN_OFF,
+                                /* immediate= */ false);
                     }
                 }
             }
@@ -401,6 +402,12 @@
                     uid, opPkg, reason);
             fillVibrationFallbacks(vib, effect);
 
+            if (attrs.isFlagSet(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) {
+                // Force update of user settings before checking if this vibration effect should
+                // be ignored or scaled.
+                mVibrationSettings.update();
+            }
+
             synchronized (mLock) {
                 if (DEBUG) {
                     Slog.d(TAG, "Starting vibrate for vibration  " + vib.id);
@@ -420,7 +427,8 @@
                 final long ident = Binder.clearCallingIdentity();
                 try {
                     if (mCurrentVibration != null) {
-                        mCurrentVibration.notifyCancelled(/* immediate= */ false);
+                        mCurrentVibration.notifyCancelled(Vibration.Status.CANCELLED_SUPERSEDED,
+                                /* immediate= */ false);
                     }
                     Vibration.Status status = startVibrationLocked(vib);
                     if (status != Vibration.Status.RUNNING) {
@@ -453,19 +461,20 @@
                     if (mNextVibration != null
                             && shouldCancelVibration(mNextVibration.getVibration(),
                             usageFilter, token)) {
-                        clearNextVibrationLocked(Vibration.Status.CANCELLED);
+                        clearNextVibrationLocked(Vibration.Status.CANCELLED_BY_USER);
                     }
                     if (mCurrentVibration != null
                             && shouldCancelVibration(mCurrentVibration.getVibration(),
                             usageFilter, token)) {
-                        mCurrentVibration.notifyCancelled(/* immediate= */false);
+                        mCurrentVibration.notifyCancelled(Vibration.Status.CANCELLED_BY_USER,
+                                /* immediate= */false);
                     }
                     if (mCurrentExternalVibration != null
                             && shouldCancelVibration(
                             mCurrentExternalVibration.externalVibration.getVibrationAttributes(),
                             usageFilter)) {
                         mCurrentExternalVibration.externalVibration.mute();
-                        endExternalVibrateLocked(Vibration.Status.CANCELLED,
+                        endExternalVibrateLocked(Vibration.Status.CANCELLED_BY_USER,
                                 /* continueExternalControl= */ false);
                     }
                 } finally {
@@ -594,7 +603,8 @@
                     Slog.d(TAG, "Canceling vibration because settings changed: "
                             + (inputDevicesChanged ? "input devices changed" : ignoreStatus));
                 }
-                mCurrentVibration.notifyCancelled(/* immediate= */ false);
+                mCurrentVibration.notifyCancelled(Vibration.Status.CANCELLED_BY_SETTINGS_UPDATE,
+                        /* immediate= */ false);
             }
         }
     }
@@ -1313,7 +1323,7 @@
                     if (DEBUG) {
                         Slog.d(TAG, "External vibration finished because binder died");
                     }
-                    endExternalVibrateLocked(Vibration.Status.CANCELLED,
+                    endExternalVibrateLocked(Vibration.Status.CANCELLED_BINDER_DIED,
                             /* continueExternalControl= */ false);
                 }
             }
@@ -1506,12 +1516,20 @@
                 return IExternalVibratorService.SCALE_MUTE;
             }
 
+            VibrationAttributes attrs = fixupVibrationAttributes(vib.getVibrationAttributes(),
+                    /* effect= */ null);
+            if (attrs.isFlagSet(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) {
+                // Force update of user settings before checking if this vibration effect should
+                // be ignored or scaled.
+                mVibrationSettings.update();
+            }
+
             boolean alreadyUnderExternalControl = false;
             boolean waitForCompletion = false;
             int scale;
             synchronized (mLock) {
                 Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked(
-                        vib.getUid(), vib.getPackage(), vib.getVibrationAttributes());
+                        vib.getUid(), vib.getPackage(), attrs);
                 if (ignoreStatus != null) {
                     ExternalVibrationHolder vibHolder = new ExternalVibrationHolder(vib);
                     vibHolder.scale = IExternalVibratorService.SCALE_MUTE;
@@ -1529,7 +1547,8 @@
                     // vibration that may be playing and ready the vibrator for external control.
                     if (mCurrentVibration != null) {
                         clearNextVibrationLocked(Vibration.Status.IGNORED_FOR_EXTERNAL);
-                        mCurrentVibration.notifyCancelled(/* immediate= */ true);
+                        mCurrentVibration.notifyCancelled(Vibration.Status.CANCELLED_SUPERSEDED,
+                                /* immediate= */ true);
                         waitForCompletion = true;
                     }
                 } else {
@@ -1543,13 +1562,13 @@
                     // would need to mute the old one still if it came from a different controller.
                     alreadyUnderExternalControl = true;
                     mCurrentExternalVibration.externalVibration.mute();
-                    endExternalVibrateLocked(Vibration.Status.CANCELLED,
+                    endExternalVibrateLocked(Vibration.Status.CANCELLED_SUPERSEDED,
                             /* continueExternalControl= */ true);
                 }
                 mCurrentExternalVibration = new ExternalVibrationHolder(vib);
                 vib.linkToDeath(mCurrentExternalVibration);
                 mCurrentExternalVibration.scale = mVibrationScaler.getExternalVibrationScale(
-                        vib.getVibrationAttributes().getUsage());
+                        attrs.getUsage());
                 scale = mCurrentExternalVibration.scale;
             }
 
@@ -1908,7 +1927,7 @@
             final int flags =
                     commonOptions.force ? VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY : 0;
             return new VibrationAttributes.Builder()
-                    .setFlags(flags, VibrationAttributes.FLAG_ALL_SUPPORTED)
+                    .setFlags(flags)
                     // Used to apply Settings.System.HAPTIC_FEEDBACK_INTENSITY to scale effects.
                     .setUsage(VibrationAttributes.USAGE_TOUCH)
                     .build();
diff --git a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
index d4648a4..799d59c 100644
--- a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
+++ b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
@@ -30,6 +30,7 @@
 import android.os.InputConfig;
 import android.os.Looper;
 import android.os.Message;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.IWindow;
@@ -94,8 +95,6 @@
         mService = service;
         mAccessibilityController = accessibilityController;
         mHandler = new MyHandler(mService.mH.getLooper());
-
-        register();
     }
 
     /**
@@ -219,8 +218,10 @@
             }
             mWindowsNotificationEnabled = register;
             if (mWindowsNotificationEnabled) {
-                populateVisibleWindowHandlesAndNotifyWindowsChangeIfNeeded();
+                Pair<InputWindowHandle[], DisplayInfo[]> info = register();
+                onWindowInfosChangedInternal(info.first, info.second);
             } else {
+                unregister();
                 releaseResources();
             }
         }
@@ -810,8 +811,8 @@
                 RectF windowFrame = TEMP_RECTF;
                 windowFrame.set(rect);
 
-                inverseMatrix.mapRect(windowFrame);
                 displayMatrix.mapRect(windowFrame);
+                inverseMatrix.mapRect(windowFrame);
                 // Union all rects.
                 outRegion.union(new Rect((int) windowFrame.left, (int) windowFrame.top,
                         (int) windowFrame.right, (int) windowFrame.bottom));
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index a4a200d..8018d56 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -746,9 +746,11 @@
                     // if it is not already expanding to fullscreen. Otherwise, the arguments will
                     // be used the next time the activity enters PiP.
                     final Task rootTask = r.getRootTask();
-                    rootTask.setPictureInPictureAspectRatio(r.pictureInPictureArgs.getAspectRatio(),
-                            r.pictureInPictureArgs.getExpandedAspectRatio());
-                    rootTask.setPictureInPictureActions(r.pictureInPictureArgs.getActions());
+                    rootTask.setPictureInPictureAspectRatio(
+                            r.pictureInPictureArgs.getAspectRatioFloat(),
+                            r.pictureInPictureArgs.getExpandedAspectRatioFloat());
+                    rootTask.setPictureInPictureActions(r.pictureInPictureArgs.getActions(),
+                            r.pictureInPictureArgs.getCloseAction());
                 }
             }
         } finally {
@@ -757,12 +759,12 @@
     }
 
     @Override
-    public void setPreferDockBigOverlays(IBinder token, boolean preferDockBigOverlays) {
+    public void setShouldDockBigOverlays(IBinder token, boolean shouldDockBigOverlays) {
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
                 final ActivityRecord r = ActivityRecord.forTokenLocked(token);
-                r.setPreferDockBigOverlays(preferDockBigOverlays);
+                r.setShouldDockBigOverlays(shouldDockBigOverlays);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -828,7 +830,7 @@
 
         if (params.hasSetAspectRatio()
                 && !mService.mWindowManager.isValidPictureInPictureAspectRatio(
-                r.mDisplayContent, params.getAspectRatio())) {
+                r.mDisplayContent, params.getAspectRatioFloat())) {
             throw new IllegalArgumentException(String.format(caller
                             + ": Aspect ratio is too extreme (must be between %f and %f).",
                     minAspectRatio, maxAspectRatio));
@@ -836,7 +838,7 @@
 
         if (mService.mSupportsExpandedPictureInPicture && params.hasSetExpandedAspectRatio()
                 && !mService.mWindowManager.isValidExpandedPictureInPictureAspectRatio(
-                r.mDisplayContent, params.getExpandedAspectRatio())) {
+                r.mDisplayContent, params.getExpandedAspectRatioFloat())) {
             throw new IllegalArgumentException(String.format(caller
                             + ": Expanded aspect ratio is not extreme enough (must not be between"
                             + " %f and %f).",
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index a8dd856..7f84f61 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -191,6 +191,35 @@
         private long mCurrentTransitionStartTimeNs;
         /** Non-null when a {@link TransitionInfo} is created for this state. */
         private TransitionInfo mAssociatedTransitionInfo;
+        /** The sequence id for trace. It is used to map the traces before resolving intent. */
+        private static int sTraceSeqId;
+        /** The trace format is "launchingActivity#$seqId:$state(:$packageName)". */
+        final String mTraceName;
+
+        LaunchingState() {
+            if (!Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+                mTraceName = null;
+                return;
+            }
+            // Use an id because the launching app is not yet known before resolving intent.
+            sTraceSeqId++;
+            mTraceName = "launchingActivity#" + sTraceSeqId;
+            Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, mTraceName, 0);
+        }
+
+        void stopTrace(boolean abort) {
+            if (mTraceName == null) return;
+            Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, mTraceName, 0);
+            final String launchResult;
+            if (mAssociatedTransitionInfo == null) {
+                launchResult = ":failed";
+            } else {
+                launchResult = (abort ? ":canceled:" : ":completed:")
+                        + mAssociatedTransitionInfo.mLastLaunchedActivity.packageName;
+            }
+            // Put a supplement trace as the description of the async trace with the same id.
+            Trace.instant(Trace.TRACE_TAG_ACTIVITY_MANAGER, mTraceName + launchResult);
+        }
 
         @VisibleForTesting
         boolean allDrawn() {
@@ -549,10 +578,10 @@
         }
 
         if (existingInfo == null) {
-            // Only notify the observer for a new launching event.
-            launchObserverNotifyIntentStarted(intent, transitionStartTimeNs);
             final LaunchingState launchingState = new LaunchingState();
             launchingState.mCurrentTransitionStartTimeNs = transitionStartTimeNs;
+            // Only notify the observer for a new launching event.
+            launchObserverNotifyIntentStarted(intent, transitionStartTimeNs);
             return launchingState;
         }
         existingInfo.mLaunchingState.mCurrentTransitionStartTimeNs = transitionStartTimeNs;
@@ -574,7 +603,7 @@
             @Nullable ActivityOptions options) {
         if (launchedActivity == null) {
             // The launch is aborted, e.g. intent not resolved, class not found.
-            abort(null /* info */, "nothing launched");
+            abort(launchingState, "nothing launched");
             return;
         }
 
@@ -601,7 +630,7 @@
 
         if (launchedActivity.isReportedDrawn() && launchedActivity.isVisible()) {
             // Launched activity is already visible. We cannot measure windows drawn delay.
-            abort(info, "launched activity already visible");
+            abort(launchingState, "launched activity already visible");
             return;
         }
 
@@ -633,7 +662,7 @@
         final TransitionInfo newInfo = TransitionInfo.create(launchedActivity, launchingState,
                 options, processRunning, processSwitch, newActivityCreated, resultCode);
         if (newInfo == null) {
-            abort(info, "unrecognized launch");
+            abort(launchingState, "unrecognized launch");
             return;
         }
 
@@ -657,7 +686,7 @@
         for (int i = mTransitionInfoList.size() - 2; i >= 0; i--) {
             final TransitionInfo prevInfo = mTransitionInfoList.get(i);
             if (prevInfo.mIsDrawn || !prevInfo.mLastLaunchedActivity.mVisibleRequested) {
-                abort(prevInfo, "nothing will be drawn");
+                scheduleCheckActivityToBeDrawn(prevInfo.mLastLaunchedActivity, 0 /* delay */);
             }
         }
     }
@@ -757,6 +786,10 @@
     /** Makes sure that the reference to the removed activity is cleared. */
     void notifyActivityRemoved(@NonNull ActivityRecord r) {
         mLastTransitionInfo.remove(r);
+        final TransitionInfo info = getActiveTransitionInfo(r);
+        if (info != null) {
+            abort(info, "removed");
+        }
 
         final int packageUid = r.info.applicationInfo.uid;
         final PackageCompatStateInfo compatStateInfo = mPackageUidToCompatStateInfo.get(packageUid);
@@ -870,23 +903,29 @@
         }
     }
 
+    private void abort(@NonNull LaunchingState state, String cause) {
+        if (state.mAssociatedTransitionInfo != null) {
+            abort(state.mAssociatedTransitionInfo, cause);
+            return;
+        }
+        if (DEBUG_METRICS) Slog.i(TAG, "abort launch cause=" + cause);
+        state.stopTrace(true /* abort */);
+        launchObserverNotifyIntentFailed();
+    }
+
     /** Aborts tracking of current launch metrics. */
-    private void abort(TransitionInfo info, String cause) {
+    private void abort(@NonNull TransitionInfo info, String cause) {
         done(true /* abort */, info, cause, 0L /* timestampNs */);
     }
 
     /** Called when the given transition (info) is no longer active. */
-    private void done(boolean abort, @Nullable TransitionInfo info, String cause,
+    private void done(boolean abort, @NonNull TransitionInfo info, String cause,
             long timestampNs) {
         if (DEBUG_METRICS) {
             Slog.i(TAG, "done abort=" + abort + " cause=" + cause + " timestamp=" + timestampNs
                     + " info=" + info);
         }
-        if (info == null) {
-            launchObserverNotifyIntentFailed();
-            return;
-        }
-
+        info.mLaunchingState.stopTrace(abort);
         stopLaunchTrace(info);
         final Boolean isHibernating =
                 mLastHibernationStates.remove(info.mLastLaunchedActivity.packageName);
@@ -1453,7 +1492,7 @@
     /** Starts trace for an activity is actually launching. */
     private void startLaunchTrace(@NonNull TransitionInfo info) {
         if (DEBUG_METRICS) Slog.i(TAG, "startLaunchTrace " + info);
-        if (!Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+        if (info.mLaunchingState.mTraceName == null) {
             return;
         }
         info.mLaunchTraceName = "launching: " + info.mLastLaunchedActivity.packageName;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 2153f5f..0b52fd6 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -116,6 +116,7 @@
 import static android.view.WindowManager.TRANSIT_OLD_UNSET;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
@@ -155,6 +156,7 @@
 import static com.android.server.wm.ActivityRecordProto.IS_ANIMATING;
 import static com.android.server.wm.ActivityRecordProto.IS_WAITING_FOR_TRANSITION_START;
 import static com.android.server.wm.ActivityRecordProto.LAST_ALL_DRAWN;
+import static com.android.server.wm.ActivityRecordProto.LAST_DROP_INPUT_MODE;
 import static com.android.server.wm.ActivityRecordProto.LAST_SURFACE_SHOWING;
 import static com.android.server.wm.ActivityRecordProto.MIN_ASPECT_RATIO;
 import static com.android.server.wm.ActivityRecordProto.NAME;
@@ -216,7 +218,6 @@
 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowContainerChildProto.ACTIVITY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
@@ -534,7 +535,7 @@
         // activity can enter picture in picture while pausing (only when switching to another task)
     PictureInPictureParams pictureInPictureArgs = new PictureInPictureParams.Builder().build();
         // The PiP params used when deferring the entering of picture-in-picture.
-    boolean preferDockBigOverlays;
+    boolean shouldDockBigOverlays;
     int launchCount;        // count of launches since last state
     long lastLaunchTime;    // time of last launch of this activity
     ComponentName requestedVrComponent; // the requested component for handling VR mode.
@@ -550,7 +551,7 @@
 
     private void updateEnterpriseThumbnailDrawable(Context context) {
         DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
-        mEnterpriseThumbnailDrawable = dpm.getDrawable(
+        mEnterpriseThumbnailDrawable = dpm.getResources().getDrawable(
                 WORK_PROFILE_ICON, OUTLINE, PROFILE_SWITCH_ANIMATION,
                 () -> context.getDrawable(R.drawable.ic_corp_badge));
     }
@@ -786,6 +787,8 @@
     /** The last set {@link DropInputMode} for this activity surface. */
     @DropInputMode
     private int mLastDropInputMode = DropInputMode.NONE;
+    /** Whether the input to this activity will be dropped during the current playing animation. */
+    private boolean mIsInputDroppedForAnimation;
 
     /**
      * If it is non-null, it requires all activities who have the same starting data to be drawn
@@ -853,6 +856,7 @@
 
     boolean mEnteringAnimation;
     boolean mOverrideTaskTransition;
+    boolean mDismissKeyguardIfInsecure;
 
     boolean mAppStopped;
     // A hint to override the window specified rotation animation, or -1 to use the window specified
@@ -1567,6 +1571,15 @@
         }
     }
 
+    /** Sets if all input will be dropped as a protection during the client-driven animation. */
+    void setDropInputForAnimation(boolean isInputDroppedForAnimation) {
+        if (mIsInputDroppedForAnimation == isInputDroppedForAnimation) {
+            return;
+        }
+        mIsInputDroppedForAnimation = isInputDroppedForAnimation;
+        updateUntrustedEmbeddingInputProtection();
+    }
+
     /**
      * Sets to drop input when obscured to activity if it is embedded in untrusted mode.
      *
@@ -1576,11 +1589,13 @@
      * all untrusted activities.
      */
     private void updateUntrustedEmbeddingInputProtection() {
-        final SurfaceControl sc = getSurfaceControl();
-        if (sc == null) {
+        if (getSurfaceControl() == null) {
             return;
         }
-        if (isEmbeddedInUntrustedMode()) {
+        if (mIsInputDroppedForAnimation) {
+            // Disable all input during the animation.
+            setDropInputMode(DropInputMode.ALL);
+        } else if (isEmbeddedInUntrustedMode()) {
             // Set drop input to OBSCURED when untrusted embedded.
             setDropInputMode(DropInputMode.OBSCURED);
         } else {
@@ -1591,7 +1606,7 @@
 
     @VisibleForTesting
     void setDropInputMode(@DropInputMode int mode) {
-        if (mLastDropInputMode != mode && getSurfaceControl() != null) {
+        if (mLastDropInputMode != mode) {
             mLastDropInputMode = mode;
             mWmService.mTransactionFactory.get()
                     .setDropInputMode(getSurfaceControl(), mode)
@@ -1939,6 +1954,7 @@
             }
 
             mOverrideTaskTransition = options.getOverrideTaskTransition();
+            mDismissKeyguardIfInsecure = options.getDismissKeyguardIfInsecure();
         }
 
         ColorDisplayService.ColorDisplayServiceInternal cds = LocalServices.getService(
@@ -2042,7 +2058,7 @@
         mLetterboxUiController = new LetterboxUiController(mWmService, this);
         mCameraCompatControlEnabled = mWmService.mContext.getResources()
                 .getBoolean(R.bool.config_isCameraCompatControlForStretchedIssuesEnabled);
-        preferDockBigOverlays = mWmService.mContext.getResources()
+        shouldDockBigOverlays = mWmService.mContext.getResources()
                 .getBoolean(R.bool.config_dockBigOverlayWindows);
 
         if (_createTime > 0) {
@@ -2476,7 +2492,8 @@
     }
 
     private boolean transferSplashScreenIfNeeded() {
-        if (!mHandleExitSplashScreen || mStartingSurface == null || mStartingWindow == null
+        if (finishing || !mHandleExitSplashScreen || mStartingSurface == null
+                || mStartingWindow == null
                 || mTransferringSplashScreenState == TRANSFER_SPLASH_SCREEN_FINISH) {
             return false;
         }
@@ -3012,6 +3029,14 @@
             return false;
         }
 
+        // Check to see if PiP is supported for the display this container is on.
+        if (mDisplayContent != null && !mDisplayContent.mDwpcHelper.isWindowingModeSupported(
+                WINDOWING_MODE_PINNED)) {
+            Slog.w(TAG, "Display " + mDisplayContent.getDisplayId()
+                    + " doesn't support enter picture-in-picture mode. caller = " + caller);
+            return false;
+        }
+
         boolean isCurrentAppLocked =
                 mAtmService.getLockTaskModeState() != LOCK_TASK_MODE_NONE;
         final TaskDisplayArea taskDisplayArea = getDisplayArea();
@@ -5600,19 +5625,8 @@
                     "makeInvisible", true /* beforeStopping */);
             // Defer telling the client it is hidden if it can enter Pip and isn't current paused,
             // stopped or stopping. This gives it a chance to enter Pip in onPause().
-            // TODO: There is still a question surrounding activities in multi-window mode that want
-            // to enter Pip after they are paused, but are still visible. I they should be okay to
-            // enter Pip in those cases, but not "auto-Pip" which is what this condition covers and
-            // the current contract for "auto-Pip" is that the app should enter it before onPause
-            // returns. Just need to confirm this reasoning makes sense.
             final boolean deferHidingClient = canEnterPictureInPicture
                     && !isState(STARTED, STOPPING, STOPPED, PAUSED);
-            if (!mTransitionController.isShellTransitionsEnabled()
-                    && deferHidingClient && pictureInPictureArgs.isAutoEnterEnabled()) {
-                // Go ahead and just put the activity in pip if it supports auto-pip.
-                mAtmService.enterPictureInPictureMode(this, pictureInPictureArgs);
-                return;
-            }
             setDeferHidingClient(deferHidingClient);
             setVisibility(false);
 
@@ -7239,11 +7253,9 @@
 
         getDisplayContent().computeImeTargetIfNeeded(this);
 
-        if (DEBUG_ANIM) Slog.v(TAG, "Animation done in " + this
-                + ": reportedVisible=" + reportedVisible
-                + " okToDisplay=" + okToDisplay()
-                + " okToAnimate=" + okToAnimate()
-                + " startingDisplayed=" + startingDisplayed);
+        ProtoLog.v(WM_DEBUG_ANIM, "Animation done in %s"
+                + ": reportedVisible=%b okToDisplay=%b okToAnimate=%b startingDisplayed=%b",
+                this, reportedVisible, okToDisplay(), okToAnimate(), startingDisplayed);
 
         // clean up thumbnail window
         if (mThumbnail != null) {
@@ -9303,6 +9315,7 @@
         // permission to access the device configs.
         proto.write(PROVIDES_MAX_BOUNDS, providesMaxBounds());
         proto.write(ENABLE_RECENTS_SCREENSHOT, mEnableRecentsScreenshot);
+        proto.write(LAST_DROP_INPUT_MODE, mLastDropInputMode);
     }
 
     @Override
@@ -9575,9 +9588,9 @@
         getTask().getRootTask().onPictureInPictureParamsChanged();
     }
 
-    void setPreferDockBigOverlays(boolean preferDockBigOverlays) {
-        this.preferDockBigOverlays = preferDockBigOverlays;
-        getTask().getRootTask().onPreferDockBigOverlaysChanged();
+    void setShouldDockBigOverlays(boolean shouldDockBigOverlays) {
+        this.shouldDockBigOverlays = shouldDockBigOverlays;
+        getTask().getRootTask().onShouldDockBigOverlaysChanged();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
index 8622bd3..ce49a86 100644
--- a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
+++ b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
@@ -18,20 +18,11 @@
 
 import android.app.compat.CompatChanges;
 import android.compat.annotation.ChangeId;
-import android.os.IBinder;
 import android.os.InputConfig;
-import android.os.InputConstants;
-import android.os.Looper;
 import android.os.Process;
-import android.util.Slog;
-import android.view.InputChannel;
-import android.view.InputEvent;
-import android.view.InputEventReceiver;
 import android.view.InputWindowHandle;
-import android.view.MotionEvent;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
-import android.widget.Toast;
 
 /**
  * Creates a InputWindowHandle that catches all touches that would otherwise pass through an
@@ -45,20 +36,12 @@
     @ChangeId
     static final long ENABLE_TOUCH_OPAQUE_ACTIVITIES = 194480991L;
 
-    private static final String TAG = "ActivityRecordInputSink";
-    private static final int NUMBER_OF_TOUCHES_TO_DISABLE = 3;
-    private static final long TOAST_COOL_DOWN_MILLIS = 3000L;
-
     private final ActivityRecord mActivityRecord;
     private final boolean mIsCompatEnabled;
     private final String mName;
 
-    // Hold on to InputEventReceiver to prevent it from getting GCd.
-    private InputEventReceiver mInputEventReceiver;
     private InputWindowHandleWrapper mInputWindowHandleWrapper;
     private SurfaceControl mSurfaceControl;
-    private int mRapidTouchCount = 0;
-    private IBinder mToken;
     private boolean mDisabled = false;
 
     ActivityRecordInputSink(ActivityRecord activityRecord) {
@@ -66,7 +49,7 @@
         mIsCompatEnabled = CompatChanges.isChangeEnabled(ENABLE_TOUCH_OPAQUE_ACTIVITIES,
                 mActivityRecord.getUid());
         mName = Integer.toHexString(System.identityHashCode(this)) + " ActivityRecordInputSink "
-                + mActivityRecord.mActivityComponent.getShortClassName();
+                + mActivityRecord.mActivityComponent.flattenToShortString();
     }
 
     public void applyChangesToSurfaceIfChanged(SurfaceControl.Transaction transaction) {
@@ -93,16 +76,13 @@
     private InputWindowHandleWrapper getInputWindowHandleWrapper() {
         if (mInputWindowHandleWrapper == null) {
             mInputWindowHandleWrapper = new InputWindowHandleWrapper(createInputWindowHandle());
-            InputChannel inputChannel =
-                    mActivityRecord.mWmService.mInputManager.createInputChannel(mName);
-            mToken = inputChannel.getToken();
-            mInputEventReceiver = createInputEventReceiver(inputChannel);
         }
         if (mDisabled || !mIsCompatEnabled || mActivityRecord.isInTransition()) {
             // TODO(b/208662670): Investigate if we can have feature active during animations.
-            mInputWindowHandleWrapper.setToken(null);
+            mInputWindowHandleWrapper.setInputConfigMasked(InputConfig.NOT_TOUCHABLE,
+                    InputConfig.NOT_TOUCHABLE);
         } else {
-            mInputWindowHandleWrapper.setToken(mToken);
+            mInputWindowHandleWrapper.setInputConfigMasked(0, InputConfig.NOT_TOUCHABLE);
         }
         return mInputWindowHandleWrapper;
     }
@@ -115,58 +95,8 @@
         inputWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
         inputWindowHandle.ownerUid = Process.myUid();
         inputWindowHandle.ownerPid = Process.myPid();
-        inputWindowHandle.dispatchingTimeoutMillis =
-                InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
-        inputWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE;
+        inputWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE | InputConfig.NO_INPUT_CHANNEL;
         return inputWindowHandle;
     }
 
-    private InputEventReceiver createInputEventReceiver(InputChannel inputChannel) {
-        return new SinkInputEventReceiver(inputChannel,
-                mActivityRecord.mAtmService.mUiHandler.getLooper());
-    }
-
-    private void showAsToastAndLog(String message) {
-        Toast.makeText(mActivityRecord.mAtmService.mUiContext, message,
-                Toast.LENGTH_LONG).show();
-        Slog.wtf(TAG, message + " " + mActivityRecord.mActivityComponent);
-    }
-
-    private class SinkInputEventReceiver extends InputEventReceiver {
-        private long mLastToast = 0;
-
-        SinkInputEventReceiver(InputChannel inputChannel, Looper looper) {
-            super(inputChannel, looper);
-        }
-
-        public void onInputEvent(InputEvent event) {
-            if (!(event instanceof MotionEvent)) {
-                Slog.wtf(TAG,
-                        "Received InputEvent that was not a MotionEvent");
-                finishInputEvent(event, true);
-                return;
-            }
-            MotionEvent motionEvent = (MotionEvent) event;
-            if (motionEvent.getAction() != MotionEvent.ACTION_DOWN) {
-                finishInputEvent(event, true);
-                return;
-            }
-
-            if (event.getEventTime() - mLastToast > TOAST_COOL_DOWN_MILLIS) {
-                String message = "go/activity-touch-opaque - "
-                        + mActivityRecord.mActivityComponent.getPackageName()
-                        + " blocked the touch!";
-                showAsToastAndLog(message);
-                mLastToast = event.getEventTime();
-                mRapidTouchCount = 1;
-            } else if (++mRapidTouchCount >= NUMBER_OF_TOUCHES_TO_DISABLE && !mDisabled) {
-                // Disable touch blocking until Activity Record is recreated.
-                String message = "Disabled go/activity-touch-opaque - "
-                        + mActivityRecord.mActivityComponent.getPackageName();
-                showAsToastAndLog(message);
-                mDisabled = true;
-            }
-            finishInputEvent(event, true);
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index c9b8501..72408b6 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -544,10 +544,8 @@
 
         if (mLastHomeActivityStartRecord != null && (!dumpPackagePresent
                 || dumpPackage.equals(mLastHomeActivityStartRecord.packageName))) {
-            if (!dumped) {
-                dumped = true;
-                dumpLastHomeActivityStartResult(pw, prefix);
-            }
+            dumped = true;
+            dumpLastHomeActivityStartResult(pw, prefix);
             pw.print(prefix);
             pw.println("mLastHomeActivityStartRecord:");
             mLastHomeActivityStartRecord.dump(pw, prefix + "  ", true /* dumpAll */);
@@ -565,6 +563,7 @@
                     dumpLastHomeActivityStartResult(pw, prefix);
                 }
                 pw.print(prefix);
+                pw.println("mLastStarter:");
                 mLastStarter.dump(pw, prefix + "  ");
 
                 if (dumpPackagePresent) {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index ac121a1..714aa5f 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -135,6 +135,7 @@
 
 import java.io.PrintWriter;
 import java.text.DateFormat;
+import java.util.ArrayList;
 import java.util.Date;
 
 /**
@@ -613,6 +614,9 @@
         mVoiceInteractor = starter.mVoiceInteractor;
 
         mIntentDelivered = starter.mIntentDelivered;
+        mLastStartActivityResult = starter.mLastStartActivityResult;
+        mLastStartActivityTimeMs = starter.mLastStartActivityTimeMs;
+        mLastStartReason = starter.mLastStartReason;
 
         mRequest.set(starter.mRequest);
     }
@@ -1598,7 +1602,6 @@
             TaskFragment inTaskFragment, boolean restrictedBgActivity,
             NeededUriGrants intentGrants) {
         int result = START_CANCELED;
-        boolean startResultSuccessful = false;
         final Task startedActivityRootTask;
 
         // Create a transition now to record the original intent of actions taken within
@@ -1614,75 +1617,18 @@
             newTransition.setRemoteTransition(remoteTransition);
         }
         transitionController.collect(r);
-        final boolean isTransient = r.getOptions() != null && r.getOptions().getTransientLaunch();
         try {
             mService.deferWindowLayout();
             Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
             result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
                     startFlags, doResume, options, inTask, inTaskFragment, restrictedBgActivity,
                     intentGrants);
-            startResultSuccessful = ActivityManager.isStartResultSuccessful(result);
-            final boolean taskAlwaysOnTop = options != null && options.getTaskAlwaysOnTop();
-            // Apply setAlwaysOnTop when starting an Activity is successful regardless of creating
-            // a new Activity or recycling the existing Activity.
-            if (taskAlwaysOnTop && startResultSuccessful) {
-                final Task targetRootTask =
-                        mTargetRootTask != null ? mTargetRootTask : mTargetTask.getRootTask();
-                targetRootTask.setAlwaysOnTop(true);
-            }
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
-            startedActivityRootTask = handleStartResult(r, result);
+            startedActivityRootTask = handleStartResult(r, options, result, newTransition,
+                    remoteTransition);
             mService.continueWindowLayout();
-            mSupervisor.mUserLeaving = false;
-
-            // Transition housekeeping
-            if (!startResultSuccessful) {
-                if (newTransition != null) {
-                    newTransition.abort();
-                }
-            } else {
-                if (!mAvoidMoveToFront && mDoResume
-                        && mRootWindowContainer.hasVisibleWindowAboveButDoesNotOwnNotificationShade(
-                            r.launchedFromUid)) {
-                    // If the UID launching the activity has a visible window on top of the
-                    // notification shade and it's launching an activity that's going to be at the
-                    // front, we should move the shade out of the way so the user can see it.
-                    // We want to avoid the case where the activity is launched on top of a
-                    // background task which is not moved to the front.
-                    StatusBarManagerInternal statusBar = mService.getStatusBarManagerInternal();
-                    if (statusBar != null) {
-                        // This results in a async call since the interface is one-way
-                        statusBar.collapsePanels();
-                    }
-                }
-                final boolean started = result == START_SUCCESS || result == START_TASK_TO_FRONT;
-                if (started) {
-                    // The activity is started new rather than just brought forward, so record
-                    // it as an existence change.
-                    transitionController.collectExistenceChange(r);
-                } else if (result == START_DELIVERED_TO_TOP && newTransition != null) {
-                    // We just delivered to top, so there isn't an actual transition here
-                    newTransition.abort();
-                    newTransition = null;
-                }
-                if (isTransient) {
-                    // `r` isn't guaranteed to be the actual relevant activity, so we must wait
-                    // until after we launched to identify the relevant activity.
-                    transitionController.setTransientLaunch(mLastStartActivityRecord,
-                            mPriorAboveTask);
-                }
-                if (newTransition != null) {
-                    transitionController.requestStartTransition(newTransition,
-                            mTargetTask == null ? r.getTask() : mTargetTask,
-                            remoteTransition, null /* displayChange */);
-                } else if (started) {
-                    // Make the collecting transition wait until this request is ready.
-                    transitionController.setReady(r, false);
-                }
-            }
         }
-
         postStartActivityProcessing(r, result, startedActivityRootTask);
 
         return result;
@@ -1694,39 +1640,89 @@
      *
      * @return the root task where the successful started activity resides.
      */
-    private @Nullable Task handleStartResult(@NonNull ActivityRecord started, int result) {
+    private @Nullable Task handleStartResult(@NonNull ActivityRecord started,
+            ActivityOptions options, int result, Transition newTransition,
+            RemoteTransition remoteTransition) {
+        mSupervisor.mUserLeaving = false;
         final Task currentRootTask = started.getRootTask();
-        Task startedActivityRootTask = currentRootTask != null ? currentRootTask : mTargetRootTask;
+        final Task startedActivityRootTask =
+                currentRootTask != null ? currentRootTask : mTargetRootTask;
 
-        if (ActivityManager.isStartResultSuccessful(result)) {
-            if (startedActivityRootTask != null) {
-                // If there is no state change (e.g. a resumed activity is reparented to top of
-                // another display) to trigger a visibility/configuration checking, we have to
-                // update the configuration for changing to different display.
-                final ActivityRecord currentTop = startedActivityRootTask.topRunningActivity();
-                if (currentTop != null && currentTop.shouldUpdateConfigForDisplayChanged()) {
-                    mRootWindowContainer.ensureVisibilityAndConfig(
-                            currentTop, currentTop.getDisplayId(),
-                            true /* markFrozenIfConfigChanged */, false /* deferResume */);
-                }
+        if (!ActivityManager.isStartResultSuccessful(result) || startedActivityRootTask == null) {
+            // If we are not able to proceed, disassociate the activity from the task. Leaving an
+            // activity in an incomplete state can lead to issues, such as performing operations
+            // without a window container.
+            if (mStartActivity.getTask() != null) {
+                mStartActivity.finishIfPossible("startActivity", true /* oomAdj */);
+            } else if (mStartActivity.getParent() != null) {
+                mStartActivity.getParent().removeChild(mStartActivity);
             }
-            return startedActivityRootTask;
+
+            // Root task should also be detached from display and be removed if it's empty.
+            if (startedActivityRootTask != null && startedActivityRootTask.isAttached()
+                    && !startedActivityRootTask.hasActivity()
+                    && !startedActivityRootTask.isActivityTypeHome()) {
+                startedActivityRootTask.removeIfPossible("handleStartResult");
+            }
+            if (newTransition != null) {
+                newTransition.abort();
+            }
+            return null;
         }
 
-        // If we are not able to proceed, disassociate the activity from the task. Leaving an
-        // activity in an incomplete state can lead to issues, such as performing operations
-        // without a window container.
-        final Task rootTask = mStartActivity.getRootTask();
-        if (rootTask != null) {
-            mStartActivity.finishIfPossible("startActivity", true /* oomAdj */);
+        // Apply setAlwaysOnTop when starting an activity is successful regardless of creating
+        // a new Activity or reusing the existing activity.
+        if (options != null && options.getTaskAlwaysOnTop()) {
+            startedActivityRootTask.setAlwaysOnTop(true);
         }
 
-        // Root task should also be detached from display and be removed if it's empty.
-        if (startedActivityRootTask != null && startedActivityRootTask.isAttached()
-                && !startedActivityRootTask.hasActivity()
-                && !startedActivityRootTask.isActivityTypeHome()) {
-            startedActivityRootTask.removeIfPossible("handleStartResult");
-            startedActivityRootTask = null;
+        // If there is no state change (e.g. a resumed activity is reparented to top of
+        // another display) to trigger a visibility/configuration checking, we have to
+        // update the configuration for changing to different display.
+        final ActivityRecord currentTop = startedActivityRootTask.topRunningActivity();
+        if (currentTop != null && currentTop.shouldUpdateConfigForDisplayChanged()) {
+            mRootWindowContainer.ensureVisibilityAndConfig(
+                    currentTop, currentTop.getDisplayId(),
+                    true /* markFrozenIfConfigChanged */, false /* deferResume */);
+        }
+
+        if (!mAvoidMoveToFront && mDoResume && mRootWindowContainer
+                .hasVisibleWindowAboveButDoesNotOwnNotificationShade(started.launchedFromUid)) {
+            // If the UID launching the activity has a visible window on top of the notification
+            // shade and it's launching an activity that's going to be at the front, we should move
+            // the shade out of the way so the user can see it. We want to avoid the case where the
+            // activity is launched on top of a background task which is not moved to the front.
+            final StatusBarManagerInternal statusBar = mService.getStatusBarManagerInternal();
+            if (statusBar != null) {
+                // This results in a async call since the interface is one-way.
+                statusBar.collapsePanels();
+            }
+        }
+
+        // Transition housekeeping.
+        final TransitionController transitionController = started.mTransitionController;
+        final boolean isStarted = result == START_SUCCESS || result == START_TASK_TO_FRONT;
+        if (isStarted) {
+            // The activity is started new rather than just brought forward, so record it as an
+            // existence change.
+            transitionController.collectExistenceChange(started);
+        } else if (result == START_DELIVERED_TO_TOP && newTransition != null) {
+            // We just delivered to top, so there isn't an actual transition here.
+            newTransition.abort();
+            newTransition = null;
+        }
+        if (options != null && options.getTransientLaunch()) {
+            // `started` isn't guaranteed to be the actual relevant activity, so we must wait
+            // until after we launched to identify the relevant activity.
+            transitionController.setTransientLaunch(mLastStartActivityRecord, mPriorAboveTask);
+        }
+        if (newTransition != null) {
+            transitionController.requestStartTransition(newTransition,
+                    mTargetTask == null ? started.getTask() : mTargetTask,
+                    remoteTransition, null /* displayChange */);
+        } else if (isStarted) {
+            // Make the collecting transition wait until this request is ready.
+            transitionController.setReady(started, false);
         }
         return startedActivityRootTask;
     }
@@ -2009,6 +2005,27 @@
             return START_PERMISSION_DENIED;
         }
 
+        // Do not start the activity if target display's DWPC does not allow it.
+        // We can't return fatal error code here because it will crash the caller of
+        // startActivity() if they don't catch the exception. We don't expect 3P apps to make
+        // changes.
+        if (mPreferredTaskDisplayArea != null) {
+            final DisplayContent displayContent = mRootWindowContainer.getDisplayContentOrCreate(
+                    mPreferredTaskDisplayArea.getDisplayId());
+            if (displayContent != null && displayContent.mDwpcHelper.hasController()) {
+                final ArrayList<ActivityInfo> activities = new ArrayList<>();
+                activities.add(r.info);
+                final int targetWindowingMode = (targetTask != null)
+                        ? targetTask.getWindowingMode() : displayContent.getWindowingMode();
+                if (!displayContent.mDwpcHelper
+                        .canContainActivities(activities, targetWindowingMode)) {
+                    Slog.w(TAG, "Abort to launch " + r.info.getComponentName()
+                            + " on display area " + mPreferredTaskDisplayArea);
+                    return START_ABORTED;
+                }
+            }
+        }
+
         return START_SUCCESS;
     }
 
@@ -2023,22 +2040,12 @@
     private boolean canEmbedActivity(@NonNull TaskFragment taskFragment,
             @NonNull ActivityRecord starting, boolean newTask, Task targetTask) {
         final Task hostTask = taskFragment.getTask();
-        if (hostTask == null) {
+        // Not allowed embedding a separate task or without host task.
+        if (hostTask == null || newTask || targetTask != hostTask) {
             return false;
         }
 
-        // Allowing the embedding if the task is owned by system.
-        final int hostUid = hostTask.effectiveUid;
-        if (UserHandle.getAppId(hostUid) == Process.SYSTEM_UID) {
-            return true;
-        }
-
-        if (!taskFragment.isAllowedToEmbedActivity(starting)) {
-            return false;
-        }
-
-        // Not allowed embedding task.
-        return !newTask && (targetTask == null || targetTask == hostTask);
+        return taskFragment.isAllowedToEmbedActivity(starting);
     }
 
     /**
@@ -2696,11 +2703,8 @@
                 // launched into the same root task.
                 mTargetRootTask = Task.fromWindowContainerToken(mSourceRecord.mLaunchRootTask);
             } else {
-                final Task rootTask =
-                        getOrCreateRootTask(mStartActivity, mLaunchFlags, intentTask, mOptions);
-                // TODO(b/184806710): #getOrCreateRootTask should never return null?
-                mTargetRootTask =
-                        rootTask != null ? rootTask : intentActivity.getRootTask();
+                mTargetRootTask = getOrCreateRootTask(mStartActivity, mLaunchFlags, intentTask,
+                        mOptions);
             }
         }
 
@@ -2740,10 +2744,11 @@
                                 false /* includingParents */);
                         intentTask = intentTask.getParent().asTaskFragment().getTask();
                     }
-                    // If the task is in multi-windowing mode, the activity may already be on
+                    // If the activity is visible in multi-windowing mode, it may already be on
                     // the top (visible to user but not the global top), then the result code
                     // should be START_DELIVERED_TO_TOP instead of START_TASK_TO_FRONT.
                     final boolean wasTopOfVisibleRootTask = intentActivity.mVisibleRequested
+                            && intentActivity.inMultiWindowMode()
                             && intentActivity == mTargetRootTask.topRunningActivity();
                     // We only want to move to the front, if we aren't going to launch on a
                     // different root task. If we launch on a different root task, we will put the
@@ -2940,7 +2945,8 @@
 
         final boolean onTop =
                 (aOptions == null || !aOptions.getAvoidMoveToFront()) && !mLaunchTaskBehind;
-        return mRootWindowContainer.getOrCreateRootTask(r, aOptions, task, mSourceRootTask, onTop,
+        final Task sourceTask = mSourceRecord != null ? mSourceRecord.getTask() : null;
+        return mRootWindowContainer.getOrCreateRootTask(r, aOptions, task, sourceTask, onTop,
                 mLaunchParams, launchFlags);
     }
 
@@ -3158,7 +3164,6 @@
     }
 
     void dump(PrintWriter pw, String prefix) {
-        prefix = prefix + "  ";
         pw.print(prefix);
         pw.print("mCurrentUser=");
         pw.println(mRootWindowContainer.mCurrentUser);
@@ -3204,7 +3209,7 @@
         pw.print(" mDoResume=");
         pw.print(mDoResume);
         pw.print(" mAddingToTask=");
-        pw.println(mAddingToTask);
+        pw.print(mAddingToTask);
         pw.print(" mInTaskFragment=");
         pw.println(mInTaskFragment);
     }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index b5312c4..eacf205 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -421,30 +421,6 @@
     // How long to wait in getAutofillAssistStructure() for the activity to respond with the result.
     private static final int PENDING_AUTOFILL_ASSIST_STRUCTURE_TIMEOUT = 2000;
 
-    // Permission tokens are used to temporarily granted a trusted app the ability to call
-    // #startActivityAsCaller.  A client is expected to dump its token after this time has elapsed,
-    // showing any appropriate error messages to the user.
-    private static final long START_AS_CALLER_TOKEN_TIMEOUT =
-            10 * MINUTE_IN_MILLIS;
-
-    // How long before the service actually expires a token.  This is slightly longer than
-    // START_AS_CALLER_TOKEN_TIMEOUT, to provide a buffer so clients will rarely encounter the
-    // expiration exception.
-    private static final long START_AS_CALLER_TOKEN_TIMEOUT_IMPL =
-            START_AS_CALLER_TOKEN_TIMEOUT + 2 * 1000;
-
-    // How long the service will remember expired tokens, for the purpose of providing error
-    // messaging when a client uses an expired token.
-    private static final long START_AS_CALLER_TOKEN_EXPIRED_TIMEOUT =
-            START_AS_CALLER_TOKEN_TIMEOUT_IMPL + 20 * MINUTE_IN_MILLIS;
-
-    // The component name of the delegated activities that are allowed to call
-    // #startActivityAsCaller with the one-time used permission token.
-    final HashMap<IBinder, ComponentName> mStartActivitySources = new HashMap<>();
-
-    // Permission tokens that have expired, but we remember for error reporting.
-    final ArrayList<IBinder> mExpiredStartAsCallerTokens = new ArrayList<>();
-
     private final ArrayList<PendingAssistExtras> mPendingAssistExtras = new ArrayList<>();
 
     // Keeps track of the active voice interaction service component, notified from
@@ -1547,41 +1523,19 @@
     }
 
     @Override
-    public IBinder requestStartActivityPermissionToken(ComponentName componentName) {
-        int callingUid = Binder.getCallingUid();
-        if (UserHandle.getAppId(callingUid) != SYSTEM_UID) {
-            throw new SecurityException("Only the system process can request a permission token, "
-                    + "received request from uid: " + callingUid);
-        }
-        IBinder permissionToken = new Binder();
-        synchronized (mGlobalLock) {
-            mStartActivitySources.put(permissionToken, componentName);
-        }
-
-        Message expireMsg = PooledLambda.obtainMessage(
-                ActivityTaskManagerService::expireStartAsCallerTokenMsg, this, permissionToken);
-        mUiHandler.sendMessageDelayed(expireMsg, START_AS_CALLER_TOKEN_TIMEOUT_IMPL);
-
-        Message forgetMsg = PooledLambda.obtainMessage(
-                ActivityTaskManagerService::forgetStartAsCallerTokenMsg, this, permissionToken);
-        mUiHandler.sendMessageDelayed(forgetMsg, START_AS_CALLER_TOKEN_EXPIRED_TIMEOUT);
-
-        return permissionToken;
-    }
-
-    @Override
     public final int startActivityAsCaller(IApplicationThread caller, String callingPackage,
             Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
-            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, IBinder permissionToken,
+            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions,
             boolean ignoreTargetSecurity, int userId) {
         // This is very dangerous -- it allows you to perform a start activity (including
         // permission grants) as any app that may launch one of your own activities.  So we only
         // allow this in two cases:
-        // 1)  The caller is an activity that is part of the core framework, and then only when it
-        //     is running as the system.
-        // 2)  The caller provides a valid permissionToken.  Permission tokens are one-time use and
-        //     can only be requested from system uid, which may then delegate this call to
-        //     another app.
+        // 1)  The calling process holds the signature permission START_ACTIVITY_AS_CALLER
+        //
+        // 2) The calling process is an activity belonging to the package "android" which is
+        //    running as UID_SYSTEM or as the target UID (the activity which started the activity
+        //    calling this method).
+
         final ActivityRecord sourceRecord;
         final int targetUid;
         final String targetPackage;
@@ -1600,26 +1554,8 @@
                 throw new SecurityException("Called without a process attached to activity");
             }
 
-            final ComponentName componentName;
-            if (permissionToken != null) {
-                // To even attempt to use a permissionToken, an app must also have this signature
-                // permission.
-                mAmInternal.enforceCallingPermission(
-                        android.Manifest.permission.START_ACTIVITY_AS_CALLER,
-                        "startActivityAsCaller");
-                // If called with a permissionToken, the caller must be the same component that
-                // was allowed to use the permissionToken.
-                componentName = mStartActivitySources.remove(permissionToken);
-                if (!sourceRecord.mActivityComponent.equals(componentName)) {
-                    if (mExpiredStartAsCallerTokens.contains(permissionToken)) {
-                        throw new SecurityException("Called with expired permission token: "
-                                + permissionToken);
-                    } else {
-                        throw new SecurityException("Called with invalid permission token: "
-                                + permissionToken);
-                    }
-                }
-            } else {
+            if (checkCallingPermission(Manifest.permission.START_ACTIVITY_AS_CALLER)
+                    != PERMISSION_GRANTED) {
                 // Whether called directly or from a delegate, the source activity must be from the
                 // android package.
                 if (!sourceRecord.info.packageName.equals("android")) {
@@ -3523,14 +3459,16 @@
                 }
                 // Only update the saved args from the args that are set
                 r.setPictureInPictureParams(params);
-                final float aspectRatio = r.pictureInPictureArgs.getAspectRatio();
-                final float expandedAspectRatio = r.pictureInPictureArgs.getExpandedAspectRatio();
+                final float aspectRatio = r.pictureInPictureArgs.getAspectRatioFloat();
+                final float expandedAspectRatio =
+                        r.pictureInPictureArgs.getExpandedAspectRatioFloat();
                 final List<RemoteAction> actions = r.pictureInPictureArgs.getActions();
+                final RemoteAction closeAction = r.pictureInPictureArgs.getCloseAction();
                 mRootWindowContainer.moveActivityToPinnedRootTask(r,
                         null /* launchIntoPipHostActivity */, "enterPictureInPictureMode");
                 final Task task = r.getTask();
                 task.setPictureInPictureAspectRatio(aspectRatio, expandedAspectRatio);
-                task.setPictureInPictureActions(actions);
+                task.setPictureInPictureActions(actions, closeAction);
 
                 // Continue the pausing process after entering pip.
                 if (task.getPausingActivity() == r) {
@@ -4451,15 +4389,6 @@
         Settings.System.putConfigurationForUser(resolver, config, userId);
     }
 
-    private void expireStartAsCallerTokenMsg(IBinder permissionToken) {
-        mStartActivitySources.remove(permissionToken);
-        mExpiredStartAsCallerTokens.add(permissionToken);
-    }
-
-    private void forgetStartAsCallerTokenMsg(IBinder permissionToken) {
-        mExpiredStartAsCallerTokens.remove(permissionToken);
-    }
-
     boolean isActivityStartsLoggingEnabled() {
         return mAmInternal.isActivityStartsLoggingEnabled();
     }
@@ -5301,14 +5230,19 @@
 
     /**
      * Returns {@code true} if the process represented by the pid passed as argument is
-     * instrumented.
+     * instrumented and the instrumentation source was granted with the permission also
+     * passed as argument.
      */
-    boolean isInstrumenting(int pid) {
+    boolean instrumentationSourceHasPermission(int pid, String permission) {
         final WindowProcessController process;
         synchronized (mGlobalLock) {
             process = mProcessMap.getProcess(pid);
         }
-        return process != null ? process.isInstrumenting() : false;
+        if (process == null || !process.isInstrumenting()) {
+            return false;
+        }
+        final int sourceUid = process.getInstrumentationSourceUid();
+        return checkPermission(permission, -1, sourceUid) == PackageManager.PERMISSION_GRANTED;
     }
 
     final class H extends Handler {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 64f4261..eb5ca9c 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -402,7 +402,8 @@
                     activities.add(r.info);
                 });
             }
-            if (!displayContent.mDwpcHelper.canContainActivities(activities)) {
+            if (!displayContent.mDwpcHelper.canContainActivities(activities,
+                    displayContent.getWindowingMode())) {
                 return false;
             }
         }
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 05efb29..5c09f09 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -81,11 +81,11 @@
 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
 import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation;
 import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
 import static com.android.server.wm.AppTransitionProto.APP_TRANSITION_STATE;
 import static com.android.server.wm.AppTransitionProto.LAST_USED_APP_TRANSITION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
@@ -130,6 +130,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.policy.TransitionAnimation;
+import com.android.internal.protolog.ProtoLogImpl;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.DumpUtils.Dump;
 import com.android.internal.util.function.pooled.PooledLambda;
@@ -237,7 +238,8 @@
         mService = service;
         mHandler = new Handler(service.mH.getLooper());
         mDisplayContent = displayContent;
-        mTransitionAnimation = new TransitionAnimation(context, DEBUG_ANIM, TAG);
+        mTransitionAnimation = new TransitionAnimation(
+                context, ProtoLogImpl.isEnabled(WM_DEBUG_ANIM), TAG);
 
         mGridLayoutRecentsEnabled = SystemProperties.getBoolean("ro.recents.grid", false);
 
@@ -1305,6 +1307,8 @@
             pw.print(Integer.toHexString(mNextAppTransitionEnter));
             pw.print(" mNextAppTransitionExit=0x");
             pw.println(Integer.toHexString(mNextAppTransitionExit));
+            pw.print(" mNextAppTransitionBackgroundColor=0x");
+            pw.println(Integer.toHexString(mNextAppTransitionBackgroundColor));
         }
         switch (mNextAppTransitionType) {
             case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE:
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 457ea13..0b4d887 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -98,6 +98,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.LinkedList;
+import java.util.function.Consumer;
 import java.util.function.Predicate;
 
 /**
@@ -541,12 +542,13 @@
     }
 
     /**
-     * Finds the common {@link android.window.TaskFragmentOrganizer} that organizes all app windows
-     * in the current transition.
-     * @return {@code null} if there is no such organizer, or if there are more than one.
+     * Finds the common parent {@link Task} that is parent of all embedded app windows in the
+     * current transition.
+     * @return {@code null} if app windows in the transition are not children of the same Task, or
+     *         if none of the app windows is embedded.
      */
     @Nullable
-    private ITaskFragmentOrganizer findTaskFragmentOrganizerForAllWindows() {
+    private Task findParentTaskForAllEmbeddedWindows() {
         mTempTransitionWindows.clear();
         mTempTransitionWindows.addAll(mDisplayContent.mClosingApps);
         mTempTransitionWindows.addAll(mDisplayContent.mOpeningApps);
@@ -600,13 +602,22 @@
             leafTask = task;
         }
         mTempTransitionWindows.clear();
-        if (leafTask == null) {
+        return leafTask;
+    }
+
+    /**
+     * Finds the common {@link android.window.TaskFragmentOrganizer} that organizes all embedded
+     * {@link TaskFragment} belong to the given {@link Task}.
+     * @return {@code null} if there is no such organizer, or if there are more than one.
+     */
+    @Nullable
+    private ITaskFragmentOrganizer findTaskFragmentOrganizer(@Nullable Task task) {
+        if (task == null) {
             return null;
         }
-
         // We don't support remote animation for Task with multiple TaskFragmentOrganizers.
         final ITaskFragmentOrganizer[] organizer = new ITaskFragmentOrganizer[1];
-        final boolean hasMultipleOrganizers = leafTask.forAllLeafTaskFragments(taskFragment -> {
+        final boolean hasMultipleOrganizers = task.forAllLeafTaskFragments(taskFragment -> {
             final ITaskFragmentOrganizer tfOrganizer = taskFragment.getTaskFragmentOrganizer();
             if (tfOrganizer == null) {
                 return false;
@@ -638,7 +649,8 @@
             return false;
         }
 
-        final ITaskFragmentOrganizer organizer = findTaskFragmentOrganizerForAllWindows();
+        final Task task = findParentTaskForAllEmbeddedWindows();
+        final ITaskFragmentOrganizer organizer = findTaskFragmentOrganizer(task);
         final RemoteAnimationDefinition definition = organizer != null
                 ? mDisplayContent.mAtmService.mTaskFragmentOrganizerController
                     .getRemoteAnimationDefinition(organizer)
@@ -653,6 +665,21 @@
         ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
                 "Override with TaskFragment remote animation for transit=%s",
                 AppTransition.appTransitionOldToString(transit));
+
+        final RemoteAnimationController remoteAnimationController =
+                mDisplayContent.mAppTransition.getRemoteAnimationController();
+        if (remoteAnimationController != null) {
+            // We are going to use client-driven animation, Disable all input on activity windows
+            // during the animation to ensure it is safe to allow client to animate the surfaces.
+            // This is needed for all activity windows in the animation Task.
+            remoteAnimationController.setOnRemoteAnimationReady(() -> {
+                final Consumer<ActivityRecord> updateActivities =
+                        activity -> activity.setDropInputForAnimation(true);
+                task.forAllActivities(updateActivities);
+            });
+            ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "Task=%d contains embedded TaskFragment."
+                    + " Disabled all input during TaskFragment remote animation.", task.mTaskId);
+        }
         return true;
     }
 
diff --git a/services/core/java/com/android/server/wm/AsyncRotationController.java b/services/core/java/com/android/server/wm/AsyncRotationController.java
index 220d9ec..e79e77c 100644
--- a/services/core/java/com/android/server/wm/AsyncRotationController.java
+++ b/services/core/java/com/android/server/wm/AsyncRotationController.java
@@ -144,7 +144,8 @@
         // Legacy animation doesn't need to wait for the start transaction.
         if (mTransitionOp == OP_LEGACY) {
             mIsStartTransactionCommitted = true;
-        } else if (displayContent.mTransitionController.useShellTransitionsRotation()) {
+        } else if (displayContent.mTransitionController.useShellTransitionsRotation()
+                || displayContent.mTransitionController.isCollecting(displayContent)) {
             keepAppearanceInPreviousRotation();
         }
     }
diff --git a/services/core/java/com/android/server/wm/BLASTSync.md b/services/core/java/com/android/server/wm/BLASTSync.md
new file mode 100644
index 0000000..2f39d6d
--- /dev/null
+++ b/services/core/java/com/android/server/wm/BLASTSync.md
@@ -0,0 +1,108 @@
+= What does it mean for BLAST Sync to work? =
+There are two BLAST sync primitives on the server side, BLASTSyncEngine and applyWithNextDraw.
+Both of them are used to solve subclasses of this category of problem:
+ 1. You have some server side changes, which will trigger both WM/SysUI initiated SurfaceControl.Transactions, 
+    and also trigger a client redraw/update
+ 2. You want to synchronize the redraw of those clients with the application of those WM/SysUI side changes.
+
+Put simply, you would like to synchronize the graphical effects of some WM changes with the graphical output of various windows
+observing those changes.
+
+To talk about exactly what the primitives guarantee, we need to clarify what we mean by server side changes. 
+In this document we will use a term syncable state to refer to any state mutated under the WindowManager lock
+which when observed by the client, produces a visible outcome in the produced frame. 
+For example the current Configuration. 
+
+The guarantee provided by Server-side BLAST Sync Primitives is thus:
+Guarantee 1:	If you make a set of changes to syncable state, at the same time that you begin a sync, 
+then the first frame drawn by the client after observing the syncable state will be sent in a transaction
+to the consumer of the sync which was begun, rather than directly sent to SurfaceFlinger.
+
+Here "at the same time" means in the same critical section (while holding the WM lock)
+For example this guarantee means that you can write code like:
+	window.performConfigurationChange(someConfiguration)
+	window.applyOnNextDraw(consumer)
+And the consumer will always be passed the first frame containing the configuration change. This can work with any 
+syncable state not just Configuration.
+
+The following is the protocol and additional requirements for BLAST sync, and an analysis of why it is correct. Due to time
+constraints we analyze it for a single window only (as this is actually the hard part).
+
+Protocol requirements:
+    Server protocol, precondition, begin a syncSeqId integer per window at 0:
+        SA: Enter the critical section
+        SB: Change syncable state, any number of times, prepare any number of syncs (and
+            increment the seqId if a sync was prepared, assosciate it with the sync)
+        SC: Leave the critical section
+        SD: Send syncable state updates to the client, always paired with the current seqId
+        SE: When the client calls finishDrawing, execute the consumer for each sync with
+            seqId <= the seqId which the client passed to finishDrawing
+    Client protocol:
+        CA: Observe state and seqid changes up until a fixed frame deadline, then execute performTraversals
+        CB: If the seqId is incremeneted at the time of the frame deadline, configure the renderer to
+            redirect the next draw in to a transaction, record the seqId at the time
+        CC: When the draw is finished, send the transaction containing the draw to WM with the
+            previously recorded seqId
+    Additional requirements/assumptions:
+        1. The server may only send changes to the syncable state paired with the seqId. The client may
+           only receive them together (e.g. not from other sources)
+        2. In between changing and sending syncable state, the lock must be released and acquired again
+        3. The client wont draw a frame reflecting syncable state changes without passing through "performTraversals"
+        4. Drawing never fails
+        5. There are no blocking calls between the client or the server
+            
+Note that the server can begin the protocol at any time, so it may be possible for the client to proceed through
+phases SA, SB, SC, and SD multiple times before the client receives any messages.
+
+To show that the guarantee can't be violated, we use a notation of sequences, where we describe interleaving
+of protocol events. For duplicate events, we attach a number, e.g. SA_1, SA_2.
+
+We proceed by contradiction, imagine there was some sequence (..., SA_N, ...) for which the guarantee was
+not upheld. This means that either
+    1. finishDrawing with the assosciate seqId was never sent to the server OR
+    2. It was sent too late (after the first frame was sent to SF instead of WM) OR
+    3. It was sent too early (not containing the state changes originating with SA_N)
+If it was sent neither too late, nor too early, and contained the assosciated seqId, then protocol step SE
+says that the frame will be passed to the consumer and we uphold our guarantee.
+
+The first case is impossible because step SD says that the server always sends the seqId if a sync was prepared.
+If we send it the client must receive it. Since we only increment the seqId, and the client only takes the
+seqId from us (requirement 1, protocol step SB), the received ID must be higher than the clients previous seqId.
+CA says that performTraversals will execute, and CB says that when it does, if the seqId is higher than before
+it will schedule the render to sync. Requirement 4 says drawing never fails, so CC must execute, and so we will always
+eventually send every seqId (or a seqId > than it) back to the server.
+
+It also can't be sent too late. By requirement 2 we must release and acquire the lock
+after after changing and before emitting syncable state changes. This means it's guaranteed
+that even in an ordering like AcquireLock, ChangeState, PrepareSync, Release lock we can't
+send the state changes before prepareSync, and so they can always include at least the seqId
+assosciated with changestate (or a later one).
+Since we only receive the SeqId with the State changes (requirement 1),
+and we wont draw state changes without passing through perform traversals (requirement 3) the first frame
+containing the state change must have been generated by a call to performTraversals which also observed
+the seqId change, and so it will appropriately configure the renderer.
+
+By the same argument it can't be sent too early! Since we only send seqIds we receive from the server, 
+and we only send seqIds after completing a drawing pass of the assosciated state.
+
+So we can see that no matter at what time the server makes syncable state changes, the first frame will
+always be delivered to the draw handler. Assuming that the client and server uphold this protocol and these
+requirements.
+
+The trickiest part of the implementation at the moment is due to assosciating seqId. Currently we send one of the most
+most important pieces of syncable state (configuration) over multiple channels. Namely ClientTransaction
+and MSG_RESIZED. The ordering of these relative to sync preparation in server code is undefined, in fact we have cases like
+this all the time:
+    acquireLock()
+    changeConfiguration()
+    // time passes, but still in critical section
+    prepareSync()
+    releaseLock()
+This is exactly the kind of case Guarantee 1 mentions as an example. In previous incarnations of the code this worked
+because relayoutWindow needed to acquire the same lock and relayoutWindow was a necessary part of completing sync.
+
+Now that we have no barrier, that could create issues, because at the time we change configuration (and send the change
+to the client via ClientTransaction), we haven't even incremented the seqId yet, and so how can the client observe it
+at the same time as the state? We solve this by pushing all client communication through a handler thread that has to
+acquire the lock. This ensures we uphold requirement 2.
+    
diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
index 5c1ddd9..6e205be 100644
--- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java
+++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
@@ -30,6 +30,8 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.common.ProtoLog;
 
+import java.util.ArrayList;
+
 /**
  * Utility class for collecting WindowContainers that will merge transactions.
  * For example to use to synchronously resize all the children of a window container
@@ -64,9 +66,17 @@
         void onTransactionReady(int mSyncId, SurfaceControl.Transaction transaction);
     }
 
-    interface SyncEngineListener {
-        /** Called when there is no more active sync set. */
-        void onSyncEngineFree();
+    /**
+     * Represents the desire to make a {@link BLASTSyncEngine.SyncGroup} while another is active.
+     *
+     * @see #queueSyncSet
+     */
+    private static class PendingSyncSet {
+        /** Called immediately when the {@link BLASTSyncEngine} is free. */
+        private Runnable mStartSync;
+
+        /** Posted to the main handler after {@link #mStartSync} is called. */
+        private Runnable mApplySync;
     }
 
     /**
@@ -142,8 +152,21 @@
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
             mActiveSyncs.remove(mSyncId);
             mWm.mH.removeCallbacks(mOnTimeout);
-            if (mSyncEngineListener != null && mActiveSyncs.size() == 0) {
-                mSyncEngineListener.onSyncEngineFree();
+
+            // Immediately start the next pending sync-transaction if there is one.
+            if (mActiveSyncs.size() == 0 && !mPendingSyncSets.isEmpty()) {
+                ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "PendingStartTransaction found");
+                final PendingSyncSet pt = mPendingSyncSets.remove(0);
+                pt.mStartSync.run();
+                if (mActiveSyncs.size() == 0) {
+                    throw new IllegalStateException("Pending Sync Set didn't start a sync.");
+                }
+                // Post this so that the now-playing transition setup isn't interrupted.
+                mWm.mH.post(() -> {
+                    synchronized (mWm.mGlobalLock) {
+                        pt.mApplySync.run();
+                    }
+                });
             }
         }
 
@@ -183,17 +206,18 @@
     private final WindowManagerService mWm;
     private int mNextSyncId = 0;
     private final SparseArray<SyncGroup> mActiveSyncs = new SparseArray<>();
-    private SyncEngineListener mSyncEngineListener;
+
+    /**
+     * A queue of pending sync-sets waiting for their turn to run.
+     *
+     * @see #queueSyncSet
+     */
+    private final ArrayList<PendingSyncSet> mPendingSyncSets = new ArrayList<>();
 
     BLASTSyncEngine(WindowManagerService wms) {
         mWm = wms;
     }
 
-    /** Sets listener listening to whether the sync engine is free. */
-    void setSyncEngineListener(SyncEngineListener listener) {
-        mSyncEngineListener = listener;
-    }
-
     /**
      * Prepares a {@link SyncGroup} that is not active yet. Caller must call {@link #startSyncSet}
      * before calling {@link #addToSyncSet(int, WindowContainer)} on any {@link WindowContainer}.
@@ -275,4 +299,31 @@
             mActiveSyncs.valueAt(i).onSurfacePlacement();
         }
     }
+
+    /**
+     * Queues a sync operation onto this engine. It will wait until any current/prior sync-sets
+     * have finished to run. This is needed right now because currently {@link BLASTSyncEngine}
+     * only supports 1 sync at a time.
+     *
+     * Code-paths should avoid using this unless absolutely necessary. Usually, we use this for
+     * difficult edge-cases that we hope to clean-up later.
+     *
+     * @param startSync will be called immediately when the {@link BLASTSyncEngine} is free to
+     *                  "reserve" the {@link BLASTSyncEngine} by calling one of the
+     *                  {@link BLASTSyncEngine#startSyncSet} variants.
+     * @param applySync will be posted to the main handler after {@code startSync} has been
+     *                  called. This is posted so that it doesn't interrupt any clean-up for the
+     *                  prior sync-set.
+     */
+    void queueSyncSet(@NonNull Runnable startSync, @NonNull Runnable applySync) {
+        final PendingSyncSet pt = new PendingSyncSet();
+        pt.mStartSync = startSync;
+        pt.mApplySync = applySync;
+        mPendingSyncSets.add(pt);
+    }
+
+    /** @return {@code true} if there are any sync-sets waiting to start. */
+    boolean hasPendingSyncSets() {
+        return !mPendingSyncSets.isEmpty();
+    }
 }
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 23f14a7..dbc0141 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -25,6 +25,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.hardware.HardwareBuffer;
+import android.os.Bundle;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.SystemProperties;
@@ -44,7 +45,11 @@
 class BackNavigationController {
 
     private static final String TAG = "BackNavigationController";
-    private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability";
+    // By default, enable new back dispatching without any animations.
+    private static final int BACK_PREDICTABILITY_PROP =
+            SystemProperties.getInt("persist.debug.back_predictability", 1);
+    private static final int ANIMATIONS_MASK = 1 << 1;
+    private static final int SCREENSHOT_MASK = 1 << 2;
 
     @Nullable
     private TaskSnapshotController mTaskSnapshotController;
@@ -53,11 +58,15 @@
      * Returns true if the back predictability feature is enabled
      */
     static boolean isEnabled() {
-        return SystemProperties.getInt(BACK_PREDICTABILITY_PROP, 0) > 0;
+        return BACK_PREDICTABILITY_PROP > 0;
     }
 
     static boolean isScreenshotEnabled() {
-        return false;
+        return (BACK_PREDICTABILITY_PROP & SCREENSHOT_MASK) != 0;
+    }
+
+    private static boolean isAnimationEnabled() {
+        return (BACK_PREDICTABILITY_PROP & ANIMATIONS_MASK) != 0;
     }
 
     /**
@@ -93,14 +102,17 @@
         ActivityRecord prev;
         WindowContainer<?> removedWindowContainer;
         ActivityRecord activityRecord;
+        ActivityRecord prevTaskTopActivity = null;
         SurfaceControl animationLeashParent;
         WindowConfiguration taskWindowConfiguration;
         HardwareBuffer screenshotBuffer = null;
+        SurfaceControl screenshotSurface;
         int prevTaskId;
         int prevUserId;
         RemoteAnimationTarget topAppTarget;
         SurfaceControl animLeash;
-        IOnBackInvokedCallback callback = null;
+        IOnBackInvokedCallback applicationCallback = null;
+        IOnBackInvokedCallback systemCallback = null;
 
         synchronized (task.mWmService.mGlobalLock) {
 
@@ -116,15 +128,14 @@
                 removedWindowContainer = activityRecord;
                 taskWindowConfiguration = window.getWindowConfiguration();
             }
-            IOnBackInvokedCallback applicationCallback = null;
-            IOnBackInvokedCallback systemCallback = null;
             if (window != null) {
                 applicationCallback = window.getApplicationOnBackInvokedCallback();
-                callback = applicationCallback;
-                if (callback == null) {
-                    systemCallback = window.getSystemOnBackInvokedCallback();
-                    callback = systemCallback;
-                }
+                systemCallback = window.getSystemOnBackInvokedCallback();
+            }
+            if (applicationCallback == null && systemCallback == null) {
+                // Return null when either there's no window, or apps have just initialized and
+                // have not finished registering callbacks.
+                return null;
             }
 
             ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "startBackNavigation task=%s, "
@@ -133,24 +144,24 @@
                     task, activityRecord, applicationCallback, systemCallback);
 
             // TODO Temp workaround for Sysui until b/221071505 is fixed
-            if (activityRecord == null && callback != null) {
+            if (activityRecord == null && applicationCallback != null) {
                 return new BackNavigationInfo(BackNavigationInfo.TYPE_CALLBACK,
                         null /* topWindowLeash */, null /* screenshotSurface */,
                         null /* screenshotBuffer */, null /* taskWindowConfiguration */,
                         null /* onBackNavigationDone */,
-                        callback /* onBackInvokedCallback */);
+                        applicationCallback /* onBackInvokedCallback */);
             }
 
             // For IME and Home, either a callback is registered, or we do nothing. In both cases,
             // we don't need to pass the leashes below.
             if (activityRecord == null || task.getDisplayContent().getImeContainer().isVisible()
                     || activityRecord.isActivityTypeHome()) {
-                if (callback != null) {
+                if (applicationCallback != null) {
                     return new BackNavigationInfo(BackNavigationInfo.TYPE_CALLBACK,
                             null /* topWindowLeash */, null /* screenshotSurface */,
                             null /* screenshotBuffer */, null /* taskWindowConfiguration */,
                             null /* onBackNavigationDone */,
-                            callback /* onBackInvokedCallback */);
+                            applicationCallback /* onBackInvokedCallback */);
                 } else {
                     return null;
                 }
@@ -159,12 +170,12 @@
             prev = task.getActivity(
                     (r) -> !r.finishing && r.getTask() == task && !r.isTopRunningActivity());
 
-            if (callback != null) {
+            if (applicationCallback != null) {
                 return new BackNavigationInfo(BackNavigationInfo.TYPE_CALLBACK,
                         null /* topWindowLeash */, null /* screenshotSurface */,
                         null /* screenshotBuffer */, null /* taskWindowConfiguration */,
                         null /* onBackNavigationDone */,
-                        callback /* onBackInvokedCallback */);
+                        applicationCallback /* onBackInvokedCallback */);
             } else if (prev != null) {
                 backType = BackNavigationInfo.TYPE_CROSS_ACTIVITY;
             } else if (task.returnsToHomeRootTask()) {
@@ -188,8 +199,8 @@
             prevTaskId = prevTask != null ? prevTask.mTaskId : 0;
             prevUserId = prevTask != null ? prevTask.mUserId : 0;
 
-            ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Previous Activity is %s",
-                    prev != null ? prev.mActivityComponent : null);
+            ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Previous Activity is %s. "
+                    + "Back type is %s", prev != null ? prev.mActivityComponent : null, backType);
 
             //TODO(207481538) Remove once the infrastructure to support per-activity screenshot is
             // implemented. For now we simply have the mBackScreenshots hash map that dumbly
@@ -204,6 +215,7 @@
                 return null;
             }
             // Prepare a leash to animate the current top window
+            // TODO(b/220934562): Use surface animator to better manage animation conflicts.
             animLeash = removedWindowContainer.makeAnimationLeash()
                     .setName("BackPreview Leash for " + removedWindowContainer)
                     .setHidden(false)
@@ -231,12 +243,30 @@
                     activityRecord.windowType);
         }
 
-        SurfaceControl.Builder builder = new SurfaceControl.Builder()
+        screenshotSurface = new SurfaceControl.Builder()
                 .setName("BackPreview Screenshot for " + prev)
                 .setParent(animationLeashParent)
                 .setHidden(false)
-                .setBLASTLayer();
-        SurfaceControl screenshotSurface = builder.build();
+                .setBLASTLayer()
+                .build();
+        if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && isAnimationEnabled()) {
+            task.mBackGestureStarted = true;
+            // Make launcher show from behind by marking its top activity as visible and
+            // launch-behind to bump its visibility for the duration of the back gesture.
+            prevTaskTopActivity = prevTask.getTopNonFinishingActivity();
+            if (prevTaskTopActivity != null) {
+                if (!prevTaskTopActivity.mVisibleRequested) {
+                    prevTaskTopActivity.setVisibility(true);
+                }
+                prevTaskTopActivity.mLaunchTaskBehind = true;
+                ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
+                        "Setting Activity.mLauncherTaskBehind to true. Activity=%s",
+                        prevTaskTopActivity);
+                prevTaskTopActivity.mRootWindowContainer.ensureActivitiesVisible(
+                        null /* starting */, 0 /* configChanges */,
+                        false /* preserveWindows */);
+            }
+        }
 
         // Find a screenshot of the previous activity
 
@@ -253,17 +283,20 @@
 
         WindowContainer<?> finalRemovedWindowContainer = removedWindowContainer;
         try {
-            activityRecord.token.linkToDeath(
-                    () -> resetSurfaces(finalRemovedWindowContainer), 0);
+            activityRecord.token.linkToDeath(() -> resetSurfaces(finalRemovedWindowContainer), 0);
         } catch (RemoteException e) {
             Slog.e(TAG, "Failed to link to death", e);
             resetSurfaces(removedWindowContainer);
             return null;
         }
 
-        RemoteCallback onBackNavigationDone = new RemoteCallback(
-                result -> resetSurfaces(finalRemovedWindowContainer
-                ));
+        int finalBackType = backType;
+        final IOnBackInvokedCallback callback =
+                applicationCallback != null ? applicationCallback : systemCallback;
+        ActivityRecord finalPrevTaskTopActivity = prevTaskTopActivity;
+        RemoteCallback onBackNavigationDone = new RemoteCallback(result -> onBackNavigationDone(
+                result, finalRemovedWindowContainer, finalBackType, task,
+                finalPrevTaskTopActivity));
         return new BackNavigationInfo(backType,
                 topAppTarget,
                 screenshotSurface,
@@ -273,6 +306,39 @@
                 callback);
     }
 
+    private void onBackNavigationDone(
+            Bundle result, WindowContainer windowContainer, int backType,
+            Task task, ActivityRecord prevTaskTopActivity) {
+        SurfaceControl surfaceControl = windowContainer.getSurfaceControl();
+        boolean triggerBack = result != null
+                ? result.getBoolean(BackNavigationInfo.KEY_TRIGGER_BACK)
+                : false;
+        ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "onBackNavigationDone backType=%s, "
+                + "task=%s, prevTaskTopActivity=%s", backType, task, prevTaskTopActivity);
+
+        if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && isAnimationEnabled()) {
+            if (triggerBack) {
+                if (surfaceControl != null && surfaceControl.isValid()) {
+                    // When going back to home, hide the task surface before it is re-parented to
+                    // avoid flicker.
+                    SurfaceControl.Transaction t = windowContainer.getSyncTransaction();
+                    t.hide(surfaceControl);
+                    t.apply();
+                }
+            }
+            if (prevTaskTopActivity != null && !triggerBack) {
+                // Restore the launch-behind state.
+                task.mTaskSupervisor.scheduleLaunchTaskBehindComplete(prevTaskTopActivity.token);
+                prevTaskTopActivity.mLaunchTaskBehind = false;
+                ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
+                        "Setting Activity.mLauncherTaskBehind to false. Activity=%s",
+                        prevTaskTopActivity);
+            }
+        } else {
+            task.mBackGestureStarted = false;
+        }
+        resetSurfaces(windowContainer);
+    }
 
     private HardwareBuffer getActivitySnapshot(@NonNull Task task,
             ComponentName activityComponent) {
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index 07a0c37..87523f4 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY;
+import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONTENT_RECORDING;
 
@@ -26,6 +27,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.IBinder;
+import android.provider.DeviceConfig;
 import android.view.ContentRecordingSession;
 import android.view.Display;
 import android.view.SurfaceControl;
@@ -39,6 +41,11 @@
 final class ContentRecorder {
 
     /**
+     * The key for accessing the device config that controls if task recording is supported.
+     */
+    @VisibleForTesting static final String KEY_RECORD_TASK_FEATURE = "record_task_content";
+
+    /**
      * The display content this class is handling recording for.
      */
     @NonNull
@@ -48,7 +55,7 @@
      * The session for content recording, or null if this DisplayContent is not being used for
      * recording.
      */
-    @VisibleForTesting private ContentRecordingSession mContentRecordingSession = null;
+    private ContentRecordingSession mContentRecordingSession = null;
 
     /**
      * The WindowContainer for the level of the hierarchy to record.
@@ -187,6 +194,8 @@
             mDisplayContent.mWmService.mTransactionFactory.get().remove(mRecordedSurface).apply();
             mRecordedSurface = null;
             clearContentRecordingSession();
+            // Do not need to force remove the VirtualDisplay; this is handled by the media
+            // projection service.
         }
     }
 
@@ -215,46 +224,12 @@
             return;
         }
 
-        final int contentToRecord = mContentRecordingSession.getContentToRecord();
-        if (contentToRecord != RECORD_CONTENT_DISPLAY) {
-            // TODO(b/216625226) handle task-based recording
-            // Not a valid region, or recording is disabled, so fall back to prior MediaProjection
-            // approach.
-            clearContentRecordingSession();
-            ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
-                    "Unable to start recording due to invalid region for display %d",
-                    mDisplayContent.getDisplayId());
+        mRecordedWindowContainer = retrieveRecordedWindowContainer();
+        if (mRecordedWindowContainer == null) {
+            // Either the token is missing, or the window associated with the token is missing.
+            // Error has already been handled, so just leave.
             return;
         }
-        // Given the WindowToken of the DisplayArea to record, retrieve the associated
-        // SurfaceControl.
-        IBinder tokenToRecord = mContentRecordingSession.getTokenToRecord();
-        if (tokenToRecord == null) {
-            // Unexpectedly missing token. Fall back to prior MediaProjection approach.
-            clearContentRecordingSession();
-            ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
-                    "Unable to start recording due to null token for display %d",
-                    mDisplayContent.getDisplayId());
-            return;
-        }
-
-        final WindowContainer wc =
-                mDisplayContent.mWmService.mWindowContextListenerController.getContainer(
-                        tokenToRecord);
-        if (wc == null) {
-            // Un-set the window token to record for this VirtualDisplay. Fall back to the
-            // original MediaProjection approach.
-            mDisplayContent.mWmService.mDisplayManagerInternal.setWindowManagerMirroring(
-                    mDisplayContent.getDisplayId(), false);
-            clearContentRecordingSession();
-            ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
-                    "Unable to retrieve window container to start recording for "
-                            + "display %d",
-                    mDisplayContent.getDisplayId());
-            return;
-        }
-        // TODO(206461622) Migrate to using the RootDisplayArea
-        mRecordedWindowContainer = wc.getDisplayContent();
 
         final Point surfaceSize = fetchSurfaceSizeIfPresent();
         if (surfaceSize == null) {
@@ -296,6 +271,107 @@
     }
 
     /**
+     * Retrieves the {@link WindowContainer} for the level of the hierarchy to start recording,
+     * indicated by the {@link #mContentRecordingSession}. Performs any error handling and state
+     * updates necessary if the {@link WindowContainer} could not be retrieved.
+     * {@link #mContentRecordingSession} must be non-null.
+     *
+     * @return a {@link WindowContainer} to record, or {@code null} if an error was encountered. The
+     * error is logged and any cleanup is handled.
+     */
+    @Nullable
+    private WindowContainer retrieveRecordedWindowContainer() {
+        final int contentToRecord = mContentRecordingSession.getContentToRecord();
+        // Given the WindowToken of the region to record, retrieve the associated
+        // SurfaceControl.
+        final IBinder tokenToRecord = mContentRecordingSession.getTokenToRecord();
+        if (tokenToRecord == null) {
+            handleStartRecordingFailed();
+            ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+                    "Unable to start recording due to null token for display %d",
+                    mDisplayContent.getDisplayId());
+            return null;
+        }
+        switch (contentToRecord) {
+            case RECORD_CONTENT_DISPLAY:
+                final WindowContainer wc =
+                        mDisplayContent.mWmService.mWindowContextListenerController.getContainer(
+                                tokenToRecord);
+                if (wc == null) {
+                    // Un-set the window token to record for this VirtualDisplay. Fall back to
+                    // Display stack capture for the entire display.
+                    mDisplayContent.mWmService.mDisplayManagerInternal.setWindowManagerMirroring(
+                            mDisplayContent.getDisplayId(), false);
+                    handleStartRecordingFailed();
+                    ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+                            "Unable to retrieve window container to start recording for "
+                                    + "display %d", mDisplayContent.getDisplayId());
+                    return null;
+                }
+                // TODO(206461622) Migrate to using the RootDisplayArea
+                return wc.getDisplayContent();
+            case RECORD_CONTENT_TASK:
+                if (!DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+                        KEY_RECORD_TASK_FEATURE, false)) {
+                    handleStartRecordingFailed();
+                    ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+                            "Unable to record task since feature is disabled %d",
+                            mDisplayContent.getDisplayId());
+                    return null;
+                }
+                Task taskToRecord = WindowContainer.fromBinder(tokenToRecord).asTask();
+                if (taskToRecord == null) {
+                    handleStartRecordingFailed();
+                    ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+                            "Unable to retrieve task to start recording for "
+                                    + "display %d", mDisplayContent.getDisplayId());
+                }
+                return taskToRecord;
+            default:
+                // Not a valid region, or recording is disabled, so fall back to Display stack
+                // capture for the entire display.
+                handleStartRecordingFailed();
+                ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+                        "Unable to start recording due to invalid region for display %d",
+                        mDisplayContent.getDisplayId());
+                return null;
+        }
+    }
+
+    /**
+     * Exit this recording session.
+     * <p>
+     * If this is a task session, tear down the recording entirely. Do not fall back
+     * to recording the entire display on the display stack; this would surprise the user
+     * given they selected task capture.
+     * </p><p>
+     * If this is a display session, just stop recording by layer mirroring. Fall back to recording
+     * from the display stack.
+     * </p>
+     */
+    private void handleStartRecordingFailed() {
+        final boolean shouldExitTaskRecording = mContentRecordingSession != null
+                && mContentRecordingSession.getContentToRecord() == RECORD_CONTENT_TASK;
+        if (shouldExitTaskRecording) {
+            // Clean up the cached session first, since tearing down the display will generate
+            // display
+            // events which will trickle back to here.
+            clearContentRecordingSession();
+            tearDownVirtualDisplay();
+        } else {
+            clearContentRecordingSession();
+        }
+    }
+
+    /**
+     * Ensure recording does not fall back to the display stack; ensure the recording is stopped
+     * and the client notified by tearing down the virtual display.
+     */
+    private void tearDownVirtualDisplay() {
+        // TODO(b/219761722) Clean up the VirtualDisplay if task mirroring fails
+    }
+
+    /**
      * Apply transformations to the mirrored surface to ensure the captured contents are scaled to
      * fit and centred in the output surface.
      *
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 0868111..dfa3b74 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -662,7 +662,7 @@
                 mDimmer.resetDimStates();
             }
 
-            if (mDimmer.updateDims(getPendingTransaction(), mTmpDimBoundsRect)) {
+            if (mDimmer.updateDims(getSyncTransaction(), mTmpDimBoundsRect)) {
                 scheduleAnimation();
             }
         }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index d1b9a78..8eb0046 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -128,9 +128,7 @@
 import static com.android.server.wm.DisplayContentProto.ROOT_DISPLAY_AREA;
 import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION;
 import static com.android.server.wm.DisplayContentProto.SLEEP_TOKENS;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
@@ -145,7 +143,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.H.REPORT_HARD_KEYBOARD_STATUS_CHANGE;
 import static com.android.server.wm.WindowManagerService.H.WINDOW_HIDE_TIMEOUT;
-import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_ASSIGN_LAYERS;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
@@ -3976,7 +3973,7 @@
             boolean nonAppImeTargetAnimatingExit = mImeLayeringTarget.mAnimatingExit
                     && mImeLayeringTarget.mAttrs.type != TYPE_BASE_APPLICATION
                     && mImeLayeringTarget.isSelfAnimating(0, ANIMATION_TYPE_WINDOW_ANIMATION);
-            if (mImeLayeringTarget.inAppOrRecentsTransition() || nonAppImeTargetAnimatingExit) {
+            if (mImeLayeringTarget.inTransitionSelfOrParent() || nonAppImeTargetAnimatingExit) {
                 showImeScreenshot();
             }
         }
@@ -4047,11 +4044,8 @@
         private SurfaceControl createImeSurface(SurfaceControl.ScreenshotHardwareBuffer b,
                 Transaction t) {
             final HardwareBuffer buffer = b.getHardwareBuffer();
-            if (DEBUG_INPUT_METHOD) {
-                Slog.d(TAG, "create IME snapshot for "
-                        + mImeTarget + ", buff width=" + buffer.getWidth()
-                        + ", height=" + buffer.getHeight());
-            }
+            ProtoLog.i(WM_DEBUG_IME, "create IME snapshot for %s, buff width=%s, height=%s",
+                    mImeTarget, buffer.getWidth(), buffer.getHeight());
             final WindowState imeWindow = mImeTarget.getDisplayContent().mInputMethodWindow;
             final ActivityRecord activity = mImeTarget.mActivityRecord;
             final SurfaceControl imeParent = mImeTarget.mAttrs.type == TYPE_BASE_APPLICATION
@@ -4077,22 +4071,24 @@
             t.setColorSpace(activity.mSurfaceControl, ColorSpace.get(ColorSpace.Named.SRGB));
             t.setLayer(imeSurface, 1);
 
-            final Point surfacePosition = new Point(
-                    imeWindow.getFrame().left - mImeTarget.getFrame().left,
-                    imeWindow.getFrame().top - mImeTarget.getFrame().top);
+            final Point surfacePosition = new Point(imeWindow.getFrame().left,
+                    imeWindow.getFrame().top);
             if (imeParent == activity.getSurfaceControl()) {
                 t.setPosition(imeSurface, surfacePosition.x, surfacePosition.y);
             } else {
+                surfacePosition.offset(-mImeTarget.getFrame().left, -mImeTarget.getFrame().top);
                 surfacePosition.offset(mImeTarget.mAttrs.surfaceInsets.left,
                         mImeTarget.mAttrs.surfaceInsets.top);
                 t.setPosition(imeSurface, surfacePosition.x, surfacePosition.y);
             }
+            ProtoLog.i(WM_DEBUG_IME, "Set IME snapshot position: (%d, %d)", surfacePosition.x,
+                    surfacePosition.y);
             return imeSurface;
         }
 
         private void removeImeSurface(Transaction t) {
             if (mImeSurface != null) {
-                if (DEBUG_INPUT_METHOD) Slog.d(TAG, "remove IME snapshot");
+                ProtoLog.i(WM_DEBUG_IME, "remove IME snapshot, caller=%s", Debug.getCallers(6));
                 t.remove(mImeSurface);
                 mImeSurface = null;
             }
@@ -4122,9 +4118,8 @@
             // to reflect the true IME insets visibility and the app task layout as possible.
             if (isValidSnapshot
                     && dc.getInsetsStateController().getImeSourceProvider().isImeShowing()) {
-                if (DEBUG_INPUT_METHOD) {
-                    Slog.d(TAG, "show IME snapshot, ime target=" + mImeTarget);
-                }
+                ProtoLog.i(WM_DEBUG_IME, "show IME snapshot, ime target=%s, callers=%s",
+                        mImeTarget, Debug.getCallers(6));
                 t.show(mImeSurface);
             } else if (!isValidSnapshot) {
                 removeImeSurface(t);
@@ -4170,7 +4165,7 @@
     void removeImeScreenshotIfPossible() {
         if (mImeLayeringTarget == null
                 || mImeLayeringTarget.mAttrs.type != TYPE_APPLICATION_STARTING
-                && !mImeLayeringTarget.inAppOrRecentsTransition()) {
+                && !mImeLayeringTarget.inTransitionSelfOrParent()) {
             removeImeSurfaceImmediately();
         }
     }
@@ -4270,17 +4265,17 @@
      */
     @VisibleForTesting
     SurfaceControl computeImeParent() {
+        if (mImeLayeringTarget != null && mImeInputTarget != null
+                && mImeLayeringTarget.mActivityRecord != mImeInputTarget.getActivityRecord()) {
+            // Do not change parent if the window hasn't requested IME.
+            return null;
+        }
         // Attach it to app if the target is part of an app and such app is covering the entire
         // screen. If it's not covering the entire screen the IME might extend beyond the apps
         // bounds.
         if (shouldImeAttachedToApp()) {
-            if (mImeLayeringTarget.mActivityRecord != mImeInputTarget.getActivityRecord()) {
-                // Do not change parent if the window hasn't requested IME.
-                return null;
-            }
             return mImeLayeringTarget.mActivityRecord.getSurfaceControl();
         }
-
         // Otherwise, we just attach it to where the display area policy put it.
         return mImeWindowsContainer.getParent() != null
                 ? mImeWindowsContainer.getParent().getSurfaceControl() : null;
@@ -4491,6 +4486,12 @@
      * hierarchy.
      */
     void onWindowAnimationFinished(@NonNull WindowContainer wc, int type) {
+        if (mImeScreenshot != null) {
+            ProtoLog.i(WM_DEBUG_IME,
+                    "onWindowAnimationFinished, wc=%s, type=%s, imeSnapshot=%s, target=%s",
+                    wc, SurfaceAnimator.animationTypeToString(type), mImeScreenshot,
+                    mImeScreenshot.getImeTarget());
+        }
         if (mImeScreenshot != null && (wc == mImeScreenshot.getImeTarget()
                 || wc.getWindow(w -> w == mImeScreenshot.getImeTarget()) != null)
                 && (type & WindowState.EXIT_ANIMATING_TYPES) != 0) {
@@ -4504,56 +4505,38 @@
 
         mTmpUpdateAllDrawn.clear();
 
-        int repeats = 0;
-        do {
-            repeats++;
-            if (repeats > 6) {
-                Slog.w(TAG, "Animation repeat aborted after too many iterations");
-                clearLayoutNeeded();
-                break;
-            }
+        if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats("On entry to LockedInner",
+                pendingLayoutChanges);
 
-            if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats("On entry to LockedInner",
-                    pendingLayoutChanges);
+        if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
+            mWallpaperController.adjustWallpaperWindows();
+        }
 
-            if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
-                mWallpaperController.adjustWallpaperWindows();
-            }
-
-            if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_CONFIG) != 0) {
-                if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
-                if (updateOrientation()) {
-                    setLayoutNeeded();
-                    sendNewConfiguration();
-                }
-            }
-
-            if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_LAYOUT) != 0) {
+        if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_CONFIG) != 0) {
+            if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
+            if (updateOrientation()) {
                 setLayoutNeeded();
+                sendNewConfiguration();
             }
+        }
 
-            // FIRST LOOP: Perform a layout, if needed.
-            if (repeats < LAYOUT_REPEAT_THRESHOLD) {
-                performLayout(repeats == 1, false /* updateInputWindows */);
-            } else {
-                Slog.w(TAG, "Layout repeat skipped after too many iterations");
-            }
+        if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_LAYOUT) != 0) {
+            setLayoutNeeded();
+        }
 
-            // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think it is animating.
-            pendingLayoutChanges = 0;
+        // Perform a layout, if needed.
+        performLayout(true /* initial */, false /* updateInputWindows */);
+        pendingLayoutChanges = 0;
 
-            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applyPostLayoutPolicy");
-            try {
-                mDisplayPolicy.beginPostLayoutPolicyLw();
-                forAllWindows(mApplyPostLayoutPolicy, true /* traverseTopToBottom */);
-                pendingLayoutChanges |= mDisplayPolicy.finishPostLayoutPolicyLw();
-            } finally {
-                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
-            }
-            if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats(
-                    "after finishPostLayoutPolicyLw", pendingLayoutChanges);
-            mInsetsStateController.onPostLayout();
-        } while (pendingLayoutChanges != 0);
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applyPostLayoutPolicy");
+        try {
+            mDisplayPolicy.beginPostLayoutPolicyLw();
+            forAllWindows(mApplyPostLayoutPolicy, true /* traverseTopToBottom */);
+            mDisplayPolicy.finishPostLayoutPolicyLw();
+        } finally {
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+        }
+        mInsetsStateController.onPostLayout();
 
         mTmpApplySurfaceChangesTransactionState.reset();
 
@@ -4896,6 +4879,23 @@
         void setOrganizer(IDisplayAreaOrganizer organizer, boolean skipDisplayAreaAppeared) {
             super.setOrganizer(organizer, skipDisplayAreaAppeared);
             mDisplayContent.updateImeParent();
+
+            // If the ImeContainer was previously unorganized then the framework might have
+            // reparented its surface control under an activity so we need to reparent it back
+            // under its parent.
+            if (organizer != null) {
+                final SurfaceControl imeParentSurfaceControl = getParentSurfaceControl();
+                if (mSurfaceControl != null && imeParentSurfaceControl != null) {
+                    ProtoLog.i(WM_DEBUG_IME, "ImeContainer just became organized. Reparenting "
+                            + "under parent. imeParentSurfaceControl=%s", imeParentSurfaceControl);
+                    getPendingTransaction().reparent(mSurfaceControl, imeParentSurfaceControl);
+                } else {
+                    ProtoLog.e(WM_DEBUG_IME, "ImeContainer just became organized but it doesn't "
+                            + "have a parent or the parent doesn't have a surface control."
+                            + " mSurfaceControl=%s imeParentSurfaceControl=%s",
+                            mSurfaceControl, imeParentSurfaceControl);
+                }
+            }
         }
     }
 
@@ -5020,10 +5020,6 @@
         // docked divider while keeping the app itself below the docked divider, so instead
         // we will put the docked divider below the IME. @see #assignRelativeLayerForImeTargetChild
         //
-        // In the case the IME target is animating, the animation Z order may be different
-        // than the WindowContainer Z order, so it's difficult to be sure we have the correct
-        // IME target. In this case we just layer the IME over its parent surface.
-        //
         // In the case where we have no IME target we let its window parent to place it.
         //
         // Keep IME window in surface parent as long as app's starting window
@@ -5035,13 +5031,7 @@
                             ? mImeControlTarget.getWindow().mToken : null;
             final boolean canImeTargetSetRelativeLayer = imeTarget.getSurfaceControl() != null
                     && imeTarget.mToken == imeControlTargetToken
-                    && !imeTarget.inMultiWindowMode()
-                    // We don't need to set relative layer if the IME target in non-multi-window
-                    // mode is the activity main window since updateImeParent will ensure the IME
-                    // surface be attached on the fullscreen activity.
-                    && imeTarget.mAttrs.type != TYPE_BASE_APPLICATION
-                    && imeTarget.mToken.getActivity(app -> app.isAnimating(TRANSITION | PARENTS,
-                            ANIMATION_TYPE_ALL & ~ANIMATION_TYPE_RECENTS)) == null;
+                    && !imeTarget.inMultiWindowMode();
             if (canImeTargetSetRelativeLayer) {
                 mImeWindowsContainer.assignRelativeLayer(t, imeTarget.getSurfaceControl(),
                         // TODO: We need to use an extra level on the app surface to ensure
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 4148d8b..4573ede 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -42,11 +42,9 @@
 import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
@@ -77,16 +75,15 @@
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
 import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
 
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SCREEN_ON;
 import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
-import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER;
 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_HIDE;
 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_SHOW;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -117,6 +114,7 @@
 import android.util.ArraySet;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
 import android.view.Gravity;
@@ -136,6 +134,7 @@
 import android.view.WindowManagerGlobal;
 import android.view.WindowManagerPolicyConstants;
 import android.view.accessibility.AccessibilityManager;
+import android.window.ClientWindowFrames;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
@@ -340,15 +339,12 @@
     private static final Rect sTmpRect2 = new Rect();
     private static final Rect sTmpLastParentFrame = new Rect();
     private static final Rect sTmpDisplayCutoutSafe = new Rect();
-    private static final Rect sTmpDisplayFrame = new Rect();
-    private static final Rect sTmpParentFrame = new Rect();
-    private static final Rect sTmpFrame = new Rect();
+    private static final ClientWindowFrames sTmpClientFrames = new ClientWindowFrames();
 
     private final WindowLayout mWindowLayout = new WindowLayout();
 
     private WindowState mTopFullscreenOpaqueWindowState;
     private boolean mTopIsFullscreen;
-    private boolean mForceStatusBar;
     private int mNavBarOpacityMode = NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED;
     private boolean mForceShowSystemBars;
 
@@ -940,6 +936,26 @@
                 break;
         }
 
+        if (LayoutParams.isSystemAlertWindowType(attrs.type)) {
+            float maxOpacity = mService.mMaximumObscuringOpacityForTouch;
+            if (attrs.alpha > maxOpacity
+                    && (attrs.flags & FLAG_NOT_TOUCHABLE) != 0
+                    && (attrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) == 0) {
+                // The app is posting a SAW with the intent of letting touches pass through, but
+                // they are going to be deemed untrusted and will be blocked. Try to honor the
+                // intent of letting touches pass through at the cost of 0.2 opacity for app
+                // compatibility reasons. More details on b/218777508.
+                Slog.w(TAG, String.format(
+                        "App %s has a system alert window (type = %d) with FLAG_NOT_TOUCHABLE and "
+                                + "LayoutParams.alpha = %.2f > %.2f, setting alpha to %.2f to "
+                                + "let touches pass through (if this is isn't desirable, remove "
+                                + "flag FLAG_NOT_TOUCHABLE).",
+                        attrs.packageName, attrs.type, attrs.alpha, maxOpacity, maxOpacity));
+                attrs.alpha = maxOpacity;
+                win.mWinAnimator.mAlpha = maxOpacity;
+            }
+        }
+
         // Check if alternate bars positions were updated.
         if (mStatusBarAlt == win) {
             mStatusBarAltPosition = getAltBarPosition(attrs);
@@ -1136,9 +1152,8 @@
                             }
                         },
 
-                        // For IME we use regular frame.
                         (displayFrames, windowContainer, inOutFrame) -> {
-                            inOutFrame.set(win.getFrame());
+                            // For IME, we don't modify the frame.
                         });
 
                 mDisplayContent.setInsetProvider(ITYPE_BOTTOM_MANDATORY_GESTURES, win,
@@ -1351,8 +1366,7 @@
      * @return Resource ID of the actual animation to use, or {@link #ANIMATION_NONE} for none.
      */
     int selectAnimation(WindowState win, int transit) {
-        if (DEBUG_ANIM) Slog.i(TAG, "selectAnimation in " + win
-                + ": transit=" + transit);
+        ProtoLog.i(WM_DEBUG_ANIM, "selectAnimation in %s: transit=%d", win, transit);
         if (win == mStatusBar) {
             if (transit == TRANSIT_EXIT
                     || transit == TRANSIT_HIDE) {
@@ -1445,7 +1459,7 @@
                     // with old content because home is easier to have different UI states.
                     return ANIMATION_NONE;
                 }
-                if (DEBUG_ANIM) Slog.i(TAG, "**** STARTING EXIT");
+                ProtoLog.i(WM_DEBUG_ANIM, "**** STARTING EXIT");
                 return R.anim.app_starting_exit;
             }
         }
@@ -1473,9 +1487,30 @@
                     displayFrames.mInsetsState, displayFrames.mDisplayCutoutSafe,
                     displayFrames.mUnrestricted, win.getWindowingMode(), UNSPECIFIED_LENGTH,
                     UNSPECIFIED_LENGTH, win.getRequestedVisibilities(),
-                    null /* attachedWindowFrame */, win.mGlobalScale,
-                    sTmpDisplayFrame, sTmpParentFrame, sTmpFrame);
-            controller.computeSimulatedState(win, displayFrames, sTmpFrame);
+                    null /* attachedWindowFrame */, win.mGlobalScale, sTmpClientFrames);
+            final SparseArray<InsetsSource> sources = win.getProvidedInsetsSources();
+            final InsetsState state = displayFrames.mInsetsState;
+            for (int index = sources.size() - 1; index >= 0; index--) {
+                final int type = sources.keyAt(index);
+                state.addSource(controller.getSourceProvider(type).createSimulatedSource(
+                        displayFrames, sTmpClientFrames.frame));
+            }
+        }
+    }
+
+    // TODO(b/161810301): No one is calling this since we haven't moved window layout to the client.
+    //                    When that happens, this should be called when the display rotation is
+    //                    changed, so that we can dispatch the correct insets to all the clients
+    //                    before the insets source windows report their frames to the server.
+    void updateInsetsSourceFramesExceptIme(DisplayFrames displayFrames) {
+        for (int i = mInsetsSourceWindowsExceptIme.size() - 1; i >= 0; i--) {
+            final WindowState win = mInsetsSourceWindowsExceptIme.valueAt(i);
+            mWindowLayout.computeFrames(win.getLayoutingAttrs(displayFrames.mRotation),
+                    displayFrames.mInsetsState, displayFrames.mDisplayCutoutSafe,
+                    displayFrames.mUnrestricted, win.getWindowingMode(), UNSPECIFIED_LENGTH,
+                    UNSPECIFIED_LENGTH, win.getRequestedVisibilities(),
+                    null /* attachedWindowFrame */, win.mGlobalScale, sTmpClientFrames);
+            win.updateSourceFrame(sTmpClientFrames.frame);
         }
     }
 
@@ -1504,10 +1539,6 @@
         displayFrames = win.getDisplayFrames(displayFrames);
 
         final WindowManager.LayoutParams attrs = win.getLayoutingAttrs(displayFrames.mRotation);
-        final WindowFrames windowFrames = win.getWindowFrames();
-        final Rect pf = windowFrames.mParentFrame;
-        final Rect df = windowFrames.mDisplayFrame;
-        final Rect f = windowFrames.mFrame;
         final Rect attachedWindowFrame = attached != null ? attached.getFrame() : null;
 
         // If this window has different LayoutParams for rotations, we cannot trust its requested
@@ -1516,27 +1547,12 @@
         final int requestedWidth = trustedSize ? win.mRequestedWidth : UNSPECIFIED_LENGTH;
         final int requestedHeight = trustedSize ? win.mRequestedHeight : UNSPECIFIED_LENGTH;
 
-        sTmpLastParentFrame.set(pf);
-
-        final boolean clippedByDisplayCutout = mWindowLayout.computeFrames(attrs,
-                win.getInsetsState(), displayFrames.mDisplayCutoutSafe,
+        mWindowLayout.computeFrames(attrs, win.getInsetsState(), displayFrames.mDisplayCutoutSafe,
                 win.getBounds(), win.getWindowingMode(), requestedWidth, requestedHeight,
                 win.getRequestedVisibilities(), attachedWindowFrame, win.mGlobalScale,
-                df, pf, f);
-        windowFrames.setParentFrameWasClippedByDisplayCutout(clippedByDisplayCutout);
+                sTmpClientFrames);
 
-        if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
-                + ": sim=#" + Integer.toHexString(attrs.softInputMode)
-                + " attach=" + attached + " type=" + attrs.type
-                + " flags=" + ViewDebug.flagsToString(LayoutParams.class, "flags", attrs.flags)
-                + " pf=" + pf.toShortString() + " df=" + df.toShortString()
-                + " f=" + f.toShortString());
-
-        if (!sTmpLastParentFrame.equals(pf)) {
-            windowFrames.setContentChanged(true);
-        }
-
-        win.setFrame();
+        win.setFrames(sTmpClientFrames);
     }
 
     WindowState getTopFullscreenOpaqueWindow() {
@@ -1558,7 +1574,6 @@
         mStatusBarBackgroundWindows.clear();
         mStatusBarColorCheckedBounds.setEmpty();
         mStatusBarBackgroundCheckedBounds.setEmpty();
-        mForceStatusBar = false;
 
         mAllowLockscreenWhenOn = false;
         mShowingDream = false;
@@ -1599,9 +1614,6 @@
                 && attrs.type < FIRST_SYSTEM_WINDOW;
         if (mTopFullscreenOpaqueWindowState == null) {
             final int fl = attrs.flags;
-            if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
-                mForceStatusBar = true;
-            }
             if (win.isDreamWindow()) {
                 // If the lockscreen was showing when the dream started then wait
                 // for the dream to draw before hiding the lockscreen.
@@ -1710,21 +1722,9 @@
     }
 
     /**
-     * Called following layout of all windows and after policy has been applied
-     * to each window. If in this function you do
-     * something that may have modified the animation state of another window,
-     * be sure to return non-zero in order to perform another pass through layout.
-     *
-     * @return Return any bit set of
-     *         {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_LAYOUT},
-     *         {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_CONFIG},
-     *         {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_WALLPAPER}, or
-     *         {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_ANIM}.
+     * Called following layout of all windows and after policy has been applied to each window.
      */
-    public int finishPostLayoutPolicyLw() {
-        int changes = 0;
-        boolean topIsFullscreen = false;
-
+    public void finishPostLayoutPolicyLw() {
         // If we are not currently showing a dream then remember the current
         // lockscreen state.  We will use this to determine whether the dream
         // started while the lockscreen was showing and remember this state
@@ -1733,41 +1733,6 @@
             mDreamingLockscreen = mService.mPolicy.isKeyguardShowingAndNotOccluded();
         }
 
-        if (getStatusBar() != null) {
-            if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar
-                    + " top=" + mTopFullscreenOpaqueWindowState);
-            final boolean forceShowStatusBar = (getStatusBar().getAttrs().privateFlags
-                    & PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR) != 0;
-
-            boolean topAppHidesStatusBar = topAppHidesStatusBar();
-            if (mForceStatusBar || forceShowStatusBar) {
-                if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced");
-                // Maintain fullscreen layout until incoming animation is complete.
-                topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
-            } else if (mTopFullscreenOpaqueWindowState != null) {
-                topIsFullscreen = topAppHidesStatusBar;
-                // The subtle difference between the window for mTopFullscreenOpaqueWindowState
-                // and mTopIsFullscreen is that mTopIsFullscreen is set only if the window
-                // requests to hide the status bar.  Not sure if there is another way that to be the
-                // case though.
-                if (!topIsFullscreen) {
-                    topAppHidesStatusBar = false;
-                }
-            }
-            StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
-            if (statusBar != null) {
-                statusBar.setTopAppHidesStatusBar(topAppHidesStatusBar);
-            }
-        }
-
-        if (mTopIsFullscreen != topIsFullscreen) {
-            if (!topIsFullscreen) {
-                // Force another layout when status bar becomes fully shown.
-                changes |= FINISH_LAYOUT_REDO_LAYOUT;
-            }
-            mTopIsFullscreen = topIsFullscreen;
-        }
-
         updateSystemBarAttributes();
 
         if (mShowingDream != mLastShowingDream) {
@@ -1777,7 +1742,6 @@
         }
 
         mService.mPolicy.setAllowLockscreenWhenOn(getDisplayId(), mAllowLockscreenWhenOn);
-        return changes;
     }
 
     /**
@@ -2441,6 +2405,18 @@
         mForceShowSystemBars = multiWindowTaskVisible || freeformRootTaskVisible;
         mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
 
+        final boolean topAppHidesStatusBar = topAppHidesStatusBar();
+        if (getStatusBar() != null) {
+            final StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
+            if (statusBar != null) {
+                statusBar.setTopAppHidesStatusBar(topAppHidesStatusBar);
+            }
+        }
+
+        // If the top app is not fullscreen, only the default rotation animation is allowed.
+        mTopIsFullscreen = topAppHidesStatusBar
+                && (mNotificationShade == null || !mNotificationShade.isVisible());
+
         int appearance = APPEARANCE_OPAQUE_NAVIGATION_BARS | APPEARANCE_OPAQUE_STATUS_BARS;
         appearance = configureStatusBarOpacity(appearance);
         appearance = configureNavBarOpacity(appearance, multiWindowTaskVisible,
@@ -2781,7 +2757,6 @@
             }
         }
         pw.print(prefix); pw.print("mTopIsFullscreen="); pw.println(mTopIsFullscreen);
-        pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
         pw.print(prefix); pw.print("mForceShowNavigationBarEnabled=");
         pw.print(mForceShowNavigationBarEnabled);
         pw.print(" mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 262ddae..43ff580 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -24,6 +24,7 @@
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
 
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
 import static com.android.server.wm.DisplayRotationProto.FIXED_TO_USER_ROTATION_MODE;
@@ -32,7 +33,6 @@
 import static com.android.server.wm.DisplayRotationProto.LAST_ORIENTATION;
 import static com.android.server.wm.DisplayRotationProto.ROTATION;
 import static com.android.server.wm.DisplayRotationProto.USER_ROTATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_ACTIVE;
@@ -747,10 +747,11 @@
         final boolean forceJumpcut = !mDisplayPolicy.isScreenOnFully()
                 || !mService.mPolicy.okToAnimate(false /* ignoreScreenOn */);
         final WindowState topFullscreen = mDisplayPolicy.getTopFullscreenOpaqueWindow();
-        if (DEBUG_ANIM) Slog.i(TAG, "selectRotationAnimation topFullscreen="
-                + topFullscreen + " rotationAnimation="
-                + (topFullscreen == null ? 0 : topFullscreen.getAttrs().rotationAnimation)
-                + " forceJumpcut=" + forceJumpcut);
+        ProtoLog.i(WM_DEBUG_ANIM, "selectRotationAnimation topFullscreen=%s"
+                + " rotationAnimation=%d forceJumpcut=%b",
+                topFullscreen,
+                topFullscreen == null ? 0 : topFullscreen.getAttrs().rotationAnimation,
+                forceJumpcut);
         if (forceJumpcut) {
             mTmpRotationAnim.mExit = R.anim.rotation_animation_jump_exit;
             mTmpRotationAnim.mEnter = R.anim.rotation_animation_enter;
diff --git a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
index 60d2a5d..27d46ec 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.WindowConfiguration;
 import android.content.pm.ActivityInfo;
 import android.os.UserHandle;
 import android.util.ArraySet;
@@ -63,13 +64,14 @@
     }
 
     /**
-     * @see DisplayWindowPolicyController#canContainActivities(List)
+     * @see DisplayWindowPolicyController#canContainActivities(List, int)
      */
-    public boolean canContainActivities(@NonNull List<ActivityInfo> activities) {
+    public boolean canContainActivities(@NonNull List<ActivityInfo> activities,
+            @WindowConfiguration.WindowingMode int windowingMode) {
         if (mDisplayWindowPolicyController == null) {
             return true;
         }
-        return mDisplayWindowPolicyController.canContainActivities(activities);
+        return mDisplayWindowPolicyController.canContainActivities(activities, windowingMode);
     }
 
     /**
@@ -126,6 +128,17 @@
         }
     }
 
+    /**
+     * @see DisplayWindowPolicyController#isWindowingModeSupported(int)
+     */
+    public final boolean isWindowingModeSupported(
+            @WindowConfiguration.WindowingMode int windowingMode) {
+        if (mDisplayWindowPolicyController == null) {
+            return true;
+        }
+        return mDisplayWindowPolicyController.isWindowingModeSupported(windowingMode);
+    }
+
     void dump(String prefix, PrintWriter pw) {
         if (mDisplayWindowPolicyController != null) {
             pw.println();
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index aa5e20d..7844bff 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -108,8 +108,11 @@
                     && childTaskFragment.getTopNonFinishingActivity() != null) {
                 childTaskFragment.updateActivityVisibilities(starting, configChanges,
                         preserveWindows, notifyClients);
+                // The TaskFragment should fully occlude the activities below if the bounds
+                // equals to its parent task, unless it is translucent.
                 mBehindFullyOccludedContainer |=
-                        childTaskFragment.getBounds().equals(mTaskFragment.getBounds());
+                        (childTaskFragment.getBounds().equals(mTaskFragment.getBounds())
+                                && !childTaskFragment.isTranslucent(starting));
                 if (mAboveTop && mTop.getTaskFragment() == childTaskFragment) {
                     mAboveTop = false;
                 }
diff --git a/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java b/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java
index 5e8d795..5d088d8 100644
--- a/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java
+++ b/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java
@@ -41,9 +41,6 @@
     private final String[] mDefaultDenylist;
     private final Object mLock = new Object();
 
-    private DeviceConfigInterface mDeviceConfig;
-    private OnPropertiesChangedListener mListener = new OnPropertiesChangedListener();
-
     static HighRefreshRateDenylist create(@NonNull Resources r) {
         return new HighRefreshRateDenylist(r, DeviceConfigInterface.REAL);
     }
@@ -51,10 +48,9 @@
     @VisibleForTesting
     HighRefreshRateDenylist(Resources r, DeviceConfigInterface deviceConfig) {
         mDefaultDenylist = r.getStringArray(R.array.config_highRefreshRateBlacklist);
-        mDeviceConfig = deviceConfig;
-        mDeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
-                BackgroundThread.getExecutor(), mListener);
-        final String property = mDeviceConfig.getProperty(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+        deviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+                BackgroundThread.getExecutor(), new OnPropertiesChangedListener());
+        final String property = deviceConfig.getProperty(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
                 KEY_HIGH_REFRESH_RATE_BLACKLIST);
         updateDenylist(property);
     }
@@ -95,14 +91,6 @@
         }
     }
 
-    /** Used to prevent WmTests leaking issues. */
-    @VisibleForTesting
-    void dispose() {
-        mDeviceConfig.removeOnPropertiesChangedListener(mListener);
-        mDeviceConfig = null;
-        mDenylistedPackages.clear();
-    }
-
     private class OnPropertiesChangedListener implements DeviceConfig.OnPropertiesChangedListener {
         public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
             if (properties.getKeyset().contains(KEY_HIGH_REFRESH_RATE_BLACKLIST)) {
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 199517c..0d4cfa3 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -29,6 +29,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.graphics.Rect;
 import android.os.Trace;
 import android.util.proto.ProtoOutputStream;
 import android.view.InsetsSource;
@@ -79,8 +80,8 @@
     }
 
     @Override
-    void updateSourceFrame() {
-        super.updateSourceFrame();
+    void updateSourceFrame(Rect frame) {
+        super.updateSourceFrame(frame);
         onSourceChanged();
     }
 
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 398816b..9844cb5 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -344,7 +344,6 @@
 
             // Navigation bar doesn't get influenced by anything else
             if (type == ITYPE_NAVIGATION_BAR || type == ITYPE_EXTRA_NAVIGATION_BAR) {
-                state.removeSource(ITYPE_IME);
                 state.removeSource(ITYPE_STATUS_BAR);
                 state.removeSource(ITYPE_CLIMATE_BAR);
                 state.removeSource(ITYPE_CAPTION_BAR);
@@ -424,14 +423,12 @@
                 return state;
             }
         } else if (w.mActivityRecord != null && w.mActivityRecord.mImeInsetsFrozenUntilStartInput) {
-            // During switching tasks with gestural navigation, if the IME is attached to
-            // one app window on that time, even the next app window is behind the IME window,
-            // conceptually the window should not receive the IME insets if the next window is
-            // not eligible IME requester and ready to show IME on top of it.
-            final boolean shouldImeAttachedToApp = mDisplayContent.shouldImeAttachedToApp();
+            // During switching tasks with gestural navigation, before the next IME input target
+            // starts the input, we should adjust and freeze the last IME visibility of the window
+            // in case delivering obsoleted IME insets state during transitioning.
             final InsetsSource originalImeSource = originalState.peekSource(ITYPE_IME);
 
-            if (shouldImeAttachedToApp && originalImeSource != null) {
+            if (originalImeSource != null) {
                 final boolean imeVisibility =
                         w.mActivityRecord.mLastImeShown || w.getRequestedVisibility(ITYPE_IME);
                 final InsetsState state = copyState ? new InsetsState(originalState)
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 047bf2f..f3f08b2 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -84,6 +84,7 @@
     private TriConsumer<DisplayFrames, WindowContainer, Rect> mImeFrameProvider;
     private final Rect mImeOverrideFrame = new Rect();
     private boolean mIsLeashReadyForDispatching;
+    private final Rect mSourceFrame = new Rect();
     private final Rect mLastSourceFrame = new Rect();
 
     private final Consumer<Transaction> mSetLeashPositionConsumer = t -> {
@@ -183,8 +184,8 @@
         mImeFrameProvider = imeFrameProvider;
         if (windowContainer == null) {
             setServerVisible(false);
-            mSource.setFrame(new Rect());
             mSource.setVisibleFrame(null);
+            mSourceFrame.setEmpty();
         } else {
             mWindowContainer.getProvidedInsetsSources().put(mSource.getType(), mSource);
             if (mControllable) {
@@ -208,7 +209,7 @@
      * The source frame can affect the layout of other windows, so this should be called once the
      * window container gets laid out.
      */
-    void updateSourceFrame() {
+    void updateSourceFrame(Rect frame) {
         if (mWindowContainer == null) {
             return;
         }
@@ -230,39 +231,25 @@
             return;
         }
 
-        if (win.mGivenInsetsPending) {
-            // If the given insets are pending, they are not reliable for now. The source frame
-            // should be updated after the new given insets are sent to window manager.
-            return;
-        }
-
-        // Make sure we set the valid source frame only when server visible is true, because the
-        // frame may not yet determined that server side doesn't think the window is ready to
-        // visible. (i.e. No surface, pending insets that were given during layout, etc..)
-        if (mServerVisible) {
-            mTmpRect.set(win.getFrame());
-            if (mFrameProvider != null) {
-                mFrameProvider.accept(mWindowContainer.getDisplayContent().mDisplayFrames,
-                        mWindowContainer, mTmpRect);
-            } else {
-                mTmpRect.inset(win.mGivenContentInsets);
-            }
+        mSourceFrame.set(frame);
+        if (mFrameProvider != null) {
+            mFrameProvider.accept(mWindowContainer.getDisplayContent().mDisplayFrames,
+                    mWindowContainer, mSourceFrame);
         } else {
-            mTmpRect.setEmpty();
+            mSourceFrame.inset(win.mGivenContentInsets);
         }
-        mSource.setFrame(mTmpRect);
+        updateSourceFrameForServerVisibility();
 
         if (mImeFrameProvider != null) {
-            mImeOverrideFrame.set(win.getFrame());
+            mImeOverrideFrame.set(frame);
             mImeFrameProvider.accept(mWindowContainer.getDisplayContent().mDisplayFrames,
-                    mWindowContainer,
-                    mImeOverrideFrame);
+                    mWindowContainer, mImeOverrideFrame);
         }
 
         if (win.mGivenVisibleInsets.left != 0 || win.mGivenVisibleInsets.top != 0
                 || win.mGivenVisibleInsets.right != 0
                 || win.mGivenVisibleInsets.bottom != 0) {
-            mTmpRect.set(win.getFrame());
+            mTmpRect.set(frame);
             mTmpRect.inset(win.mGivenVisibleInsets);
             mSource.setVisibleFrame(mTmpRect);
         } else {
@@ -270,13 +257,24 @@
         }
     }
 
+    private void updateSourceFrameForServerVisibility() {
+        // Make sure we set the valid source frame only when server visible is true, because the
+        // frame may not yet determined that server side doesn't think the window is ready to
+        // visible. (i.e. No surface, pending insets that were given during layout, etc..)
+        if (mServerVisible) {
+            mSource.setFrame(mSourceFrame);
+        } else {
+            mSource.setFrame(0, 0, 0, 0);
+        }
+    }
+
     /** @return A new source computed by the specified window frame in the given display frames. */
-    InsetsSource createSimulatedSource(DisplayFrames displayFrames, Rect winFrame) {
+    InsetsSource createSimulatedSource(DisplayFrames displayFrames, Rect frame) {
         // Don't copy visible frame because it might not be calculated in the provided display
         // frames and it is not significant for this usage.
         final InsetsSource source = new InsetsSource(mSource.getType());
         source.setVisible(mSource.isVisible());
-        mTmpRect.set(winFrame);
+        mTmpRect.set(frame);
         if (mFrameProvider != null) {
             mFrameProvider.accept(displayFrames, mWindowContainer, mTmpRect);
         }
@@ -296,7 +294,6 @@
                 ? windowState.wouldBeVisibleIfPolicyIgnored() && windowState.isVisibleByPolicy()
                 : mWindowContainer.isVisibleRequested();
         setServerVisible(isServerVisible);
-        updateSourceFrame();
         if (mControl != null) {
             boolean changed = false;
             final Point position = getWindowFrameSurfacePosition();
@@ -496,6 +493,7 @@
     @VisibleForTesting
     void setServerVisible(boolean serverVisible) {
         mServerVisible = serverVisible;
+        updateSourceFrameForServerVisibility();
         updateVisibility();
     }
 
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 78608e2..a19d72e 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -30,7 +30,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.graphics.Rect;
 import android.os.Trace;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -204,23 +203,6 @@
         }
     }
 
-    /**
-     * Computes insets state of the insets provider window in the display frames.
-     *
-     * @param win The owner window of insets provider.
-     * @param displayFrames The display frames to create insets source.
-     * @param winFrame The frame of the insets source window.
-     */
-    void computeSimulatedState(WindowState win, DisplayFrames displayFrames, Rect winFrame) {
-        final InsetsState state = displayFrames.mInsetsState;
-        for (int i = mProviders.size() - 1; i >= 0; i--) {
-            final WindowContainerInsetsSourceProvider provider = mProviders.valueAt(i);
-            if (provider.mWindowContainer == win) {
-                state.addSource(provider.createSimulatedSource(displayFrames, winFrame));
-            }
-        }
-    }
-
     boolean isFakeTarget(@InternalInsetsType int type, InsetsControlTarget target) {
         return mTypeFakeControlTargetMap.get(type) == target;
     }
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 7bf150b..2ebb597 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -28,6 +28,7 @@
 import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
 import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
+import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_SUBTLE_WINDOW_ANIMATIONS;
@@ -408,6 +409,25 @@
     }
 
     /**
+     * Called when keyguard going away state changed.
+     */
+    private void handleKeyguardGoingAwayChanged(DisplayContent dc) {
+        mService.deferWindowLayout();
+        try {
+            dc.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, 0 /* transitFlags */);
+            // We are deprecating TRANSIT_KEYGUARD_GOING_AWAY for Shell transition and use
+            // TRANSIT_FLAG_KEYGUARD_GOING_AWAY to indicate that it should animate keyguard going
+            // away.
+            dc.mAtmService.getTransitionController().requestTransitionIfNeeded(
+                    TRANSIT_OPEN, TRANSIT_FLAG_KEYGUARD_GOING_AWAY, null /* trigger */, dc);
+            updateKeyguardSleepToken();
+            mWindowManager.executeAppTransition();
+        } finally {
+            mService.continueWindowLayout();
+        }
+    }
+
+    /**
      * Called when somebody wants to dismiss the Keyguard via the flag.
      */
     private void handleDismissKeyguard(int displayId) {
@@ -533,11 +553,13 @@
         }
 
         /**
-         * Updates {@link #mOccluded}, {@link #mTopTurnScreenOnActivity} and
-         * {@link #mDismissingKeyguardActivity} if the top task could be visible.
+         * Updates keyguard status if the top task could be visible. The top task may occlude
+         * keyguard, request to dismiss keyguard or make insecure keyguard go away based on its
+         * properties.
          */
         void updateVisibility(KeyguardController controller, DisplayContent display) {
             final boolean lastOccluded = mOccluded;
+            final boolean lastKeyguardGoingAway = mKeyguardGoingAway;
 
             final ActivityRecord lastDismissKeyguardActivity = mDismissingKeyguardActivity;
             final ActivityRecord lastTurnScreenOnActivity = mTopTurnScreenOnActivity;
@@ -561,14 +583,18 @@
                     mTopTurnScreenOnActivity = top;
                 }
 
-                final boolean showWhenLocked = top.canShowWhenLocked();
-                if (showWhenLocked) {
+                final boolean isKeyguardSecure = controller.mWindowManager.isKeyguardSecure(
+                        controller.mService.getCurrentUserId());
+                if (top.mDismissKeyguardIfInsecure && mKeyguardShowing && !isKeyguardSecure) {
+                    mKeyguardGoingAway = true;
+                } else if (top.canShowWhenLocked()) {
                     mTopOccludesActivity = top;
                 }
 
                 // Only the top activity may control occluded, as we can't occlude the Keyguard
                 // if the top app doesn't want to occlude it.
-                occludedByActivity = showWhenLocked || (mDismissingKeyguardActivity != null
+                occludedByActivity = mTopOccludesActivity != null
+                        || (mDismissingKeyguardActivity != null
                         && task.topRunningActivity() == mDismissingKeyguardActivity
                         && controller.canShowWhileOccluded(
                                 true /* dismissKeyguard */, false /* showWhenLocked */));
@@ -583,10 +609,8 @@
                     && top.getActivityType() == ACTIVITY_TYPE_DREAM);
             mOccluded = mShowingDream || occludedByActivity;
             mRequestDismissKeyguard = lastDismissKeyguardActivity != mDismissingKeyguardActivity
-                    && !mOccluded
-                    && mDismissingKeyguardActivity != null
-                    && controller.mWindowManager.isKeyguardSecure(
-                    controller.mService.getCurrentUserId());
+                    && !mOccluded && !mKeyguardGoingAway
+                    && mDismissingKeyguardActivity != null;
 
             if (mTopTurnScreenOnActivity != lastTurnScreenOnActivity
                     && mTopTurnScreenOnActivity != null
@@ -598,6 +622,8 @@
 
             if (lastOccluded != mOccluded) {
                 controller.handleOccludedChanged(mDisplayId, mTopOccludesActivity);
+            } else if (!lastKeyguardGoingAway && mKeyguardGoingAway) {
+                controller.handleKeyguardGoingAwayChanged(display);
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/LaunchParamsController.java b/services/core/java/com/android/server/wm/LaunchParamsController.java
index 8e5d73f..7bd2a4a 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsController.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsController.java
@@ -142,18 +142,6 @@
         mService.deferWindowLayout();
 
         try {
-            if (mTmpParams.mPreferredTaskDisplayArea != null
-                    && task.getDisplayArea() != mTmpParams.mPreferredTaskDisplayArea) {
-                mService.mRootWindowContainer.moveRootTaskToTaskDisplayArea(task.getRootTaskId(),
-                        mTmpParams.mPreferredTaskDisplayArea, true /* onTop */);
-            }
-
-            if (mTmpParams.hasWindowingMode() && task.isRootTask()
-                    && mTmpParams.mWindowingMode != task.getWindowingMode()) {
-                task.setWindowingMode(task.getDisplayArea().validateWindowingMode(
-                        mTmpParams.mWindowingMode, activity, task));
-            }
-
             if (mTmpParams.mBounds.isEmpty()) {
                 return false;
             }
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 8866343..0038c71 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -145,6 +145,14 @@
             return;
         }
         updateRoundedCorners(w);
+        // If there is another main window that is not an application-starting window, we should
+        // update rounded corners for it as well, to avoid flickering rounded corners.
+        final WindowState nonStartingAppW = mActivityRecord.findMainWindow(
+                /* includeStartingApp= */ false);
+        if (nonStartingAppW != null && nonStartingAppW != w) {
+            updateRoundedCorners(nonStartingAppW);
+        }
+
         updateWallpaperForLetterbox(w);
         if (shouldShowLetterboxUi(w)) {
             if (mLetterbox == null) {
diff --git a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
index 61f9fe2..d7e725b 100644
--- a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
@@ -174,5 +174,9 @@
         }
 
         void dumpDebugInner(ProtoOutputStream proto);
+
+        default WindowAnimationSpec asWindowAnimationSpec() {
+            return null;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/MirrorActiveUids.java b/services/core/java/com/android/server/wm/MirrorActiveUids.java
index 4e7f1d4..b9aa959 100644
--- a/services/core/java/com/android/server/wm/MirrorActiveUids.java
+++ b/services/core/java/com/android/server/wm/MirrorActiveUids.java
@@ -19,7 +19,7 @@
 import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
 
 import android.app.ActivityManager.ProcessState;
-import android.util.SparseArray;
+import android.util.SparseIntArray;
 
 import java.io.PrintWriter;
 
@@ -29,15 +29,14 @@
  * adjustment) or getting state from window manager (background start check).
  */
 class MirrorActiveUids {
-    private final SparseArray<UidRecord> mUidStates = new SparseArray<>();
+    /** Uid -> process state. */
+    private final SparseIntArray mUidStates = new SparseIntArray();
+
+    /** Uid -> number of non-app visible windows belong to the uid. */
+    private final SparseIntArray mNumNonAppVisibleWindowMap = new SparseIntArray();
 
     synchronized void onUidActive(int uid, int procState) {
-        UidRecord r = mUidStates.get(uid);
-        if (r == null) {
-            r = new UidRecord();
-            mUidStates.put(uid, r);
-        }
-        r.mProcState = procState;
+        mUidStates.put(uid, procState);
     }
 
     synchronized void onUidInactive(int uid) {
@@ -45,22 +44,28 @@
     }
 
     synchronized void onUidProcStateChanged(int uid, int procState) {
-        final UidRecord r = mUidStates.get(uid);
-        if (r != null) {
-            r.mProcState = procState;
+        final int index = mUidStates.indexOfKey(uid);
+        if (index >= 0) {
+            mUidStates.setValueAt(index, procState);
         }
     }
 
     synchronized @ProcessState int getUidState(int uid) {
-        final UidRecord r = mUidStates.get(uid);
-        return r != null ? r.mProcState : PROCESS_STATE_NONEXISTENT;
+        return mUidStates.get(uid, PROCESS_STATE_NONEXISTENT);
     }
 
     /** Called when the surface of non-application (exclude toast) window is shown or hidden. */
     synchronized void onNonAppSurfaceVisibilityChanged(int uid, boolean visible) {
-        final UidRecord r = mUidStates.get(uid);
-        if (r != null) {
-            r.mNumNonAppVisibleWindow += visible ? 1 : -1;
+        final int index = mNumNonAppVisibleWindowMap.indexOfKey(uid);
+        if (index >= 0) {
+            final int num = mNumNonAppVisibleWindowMap.valueAt(index) + (visible ? 1 : -1);
+            if (num > 0) {
+                mNumNonAppVisibleWindowMap.setValueAt(index, num);
+            } else {
+                mNumNonAppVisibleWindowMap.removeAt(index);
+            }
+        } else if (visible) {
+            mNumNonAppVisibleWindowMap.append(uid, 1);
         }
     }
 
@@ -70,23 +75,15 @@
      * {@link VisibleActivityProcessTracker}.
      */
     synchronized boolean hasNonAppVisibleWindow(int uid) {
-        final UidRecord r = mUidStates.get(uid);
-        return r != null && r.mNumNonAppVisibleWindow > 0;
+        return mNumNonAppVisibleWindowMap.get(uid) > 0;
     }
 
     synchronized void dump(PrintWriter pw, String prefix) {
-        pw.print(prefix + "NumNonAppVisibleWindowByUid:[");
-        for (int i = mUidStates.size() - 1; i >= 0; i--) {
-            final UidRecord r = mUidStates.valueAt(i);
-            if (r.mNumNonAppVisibleWindow > 0) {
-                pw.print(" " + mUidStates.keyAt(i) + ":" + r.mNumNonAppVisibleWindow);
-            }
+        pw.print(prefix + "NumNonAppVisibleWindowUidMap:[");
+        for (int i = mNumNonAppVisibleWindowMap.size() - 1; i >= 0; i--) {
+            pw.print(" " + mNumNonAppVisibleWindowMap.keyAt(i) + ":"
+                    + mNumNonAppVisibleWindowMap.valueAt(i));
         }
         pw.println("]");
     }
-
-    private static final class UidRecord {
-        @ProcessState int mProcState;
-        int mNumNonAppVisibleWindow;
-    }
 }
diff --git a/services/core/java/com/android/server/wm/PinnedTaskController.java b/services/core/java/com/android/server/wm/PinnedTaskController.java
index 06e3a73..43d0776 100644
--- a/services/core/java/com/android/server/wm/PinnedTaskController.java
+++ b/services/core/java/com/android/server/wm/PinnedTaskController.java
@@ -92,6 +92,7 @@
 
     // The set of actions and aspect-ratio for the that are currently allowed on the PiP activity
     private ArrayList<RemoteAction> mActions = new ArrayList<>();
+    private RemoteAction mCloseAction;
     private float mAspectRatio = -1f;
     private float mExpandedAspectRatio = 0f;
 
@@ -154,7 +155,7 @@
             mPinnedTaskListener = listener;
             notifyImeVisibilityChanged(mIsImeShowing, mImeHeight);
             notifyMovementBoundsChanged(false /* fromImeAdjustment */);
-            notifyActionsChanged(mActions);
+            notifyActionsChanged(mActions, mCloseAction);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to register pinned task listener", e);
         }
@@ -408,12 +409,13 @@
     /**
      * Sets the current set of actions.
      */
-    void setActions(List<RemoteAction> actions) {
+    void setActions(List<RemoteAction> actions, RemoteAction closeAction) {
         mActions.clear();
         if (actions != null) {
             mActions.addAll(actions);
         }
-        notifyActionsChanged(mActions);
+        mCloseAction = closeAction;
+        notifyActionsChanged(mActions, closeAction);
     }
 
     /**
@@ -450,10 +452,10 @@
     /**
      * Notifies listeners that the PIP actions have changed.
      */
-    private void notifyActionsChanged(List<RemoteAction> actions) {
+    private void notifyActionsChanged(List<RemoteAction> actions, RemoteAction closeAction) {
         if (mPinnedTaskListener != null) {
             try {
-                mPinnedTaskListener.onActionsChanged(new ParceledListSlice(actions));
+                mPinnedTaskListener.onActionsChanged(new ParceledListSlice(actions), closeAction);
             } catch (RemoteException e) {
                 Slog.e(TAG_WM, "Error delivering actions changed event.", e);
             }
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index a407021..e21ae05 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -281,6 +281,7 @@
                             task.setCanAffectSystemUiFlags(behindSystemBars);
                         }
                     }
+                    InputMethodManagerInternal.get().maybeFinishStylusHandwriting();
                     if (!behindSystemBars) {
                         // Hiding IME if IME window is not attached to app.
                         // Since some windowing mode is not proper to snapshot Task with IME window
@@ -553,10 +554,6 @@
 
             mPendingStart = false;
 
-            // Perform layout if it was scheduled before to make sure that we get correct content
-            // insets for the target app window after a rotation
-            mDisplayContent.performLayout(false /* initial */, false /* updateInputWindows */);
-
             final Rect contentInsets;
             final WindowState targetAppMainWindow = getTargetAppMainWindow();
             if (targetAppMainWindow != null) {
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index eeac230..4a0a6e3 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -23,6 +23,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Binder;
@@ -49,6 +50,7 @@
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.ArrayList;
+import java.util.function.Consumer;
 
 /**
  * Helper class to run app animations in a remote process.
@@ -72,6 +74,8 @@
     private FinishedCallback mFinishedCallback;
     private boolean mCanceled;
     private boolean mLinkedToDeathOfRunner;
+    @Nullable
+    private Runnable mOnRemoteAnimationReady;
 
     RemoteAnimationController(WindowManagerService service, DisplayContent displayContent,
             RemoteAnimationAdapter remoteAnimationAdapter, Handler handler) {
@@ -101,6 +105,11 @@
         return adapters;
     }
 
+    /** Sets callback to run before starting remote animation. */
+    void setOnRemoteAnimationReady(@Nullable Runnable onRemoteAnimationReady) {
+        mOnRemoteAnimationReady = onRemoteAnimationReady;
+    }
+
     /**
      * Called when the transition is ready to be started, and all leashes have been set up.
      */
@@ -110,7 +119,7 @@
             ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS,
                     "goodToGo(): Animation canceled already");
             onAnimationFinished();
-            invokeAnimationCancelled();
+            invokeAnimationCancelled("already_cancelled");
             return;
         }
 
@@ -129,10 +138,15 @@
                     "goodToGo(): No apps to animate, mPendingAnimations=%d",
                     mPendingAnimations.size());
             onAnimationFinished();
-            invokeAnimationCancelled();
+            invokeAnimationCancelled("no_app_targets");
             return;
         }
 
+        if (mOnRemoteAnimationReady != null) {
+            mOnRemoteAnimationReady.run();
+            mOnRemoteAnimationReady = null;
+        }
+
         // Create the remote wallpaper animation targets (if any)
         final RemoteAnimationTarget[] wallpaperTargets = createWallpaperAnimations();
 
@@ -169,7 +183,7 @@
             mCanceled = true;
         }
         onAnimationFinished();
-        invokeAnimationCancelled();
+        invokeAnimationCancelled(reason);
     }
 
     private void writeStartDebugStatement() {
@@ -292,16 +306,22 @@
                 mService.closeSurfaceTransaction("RemoteAnimationController#finished");
             }
         }
+        // Reset input for all activities when the remote animation is finished.
+        final Consumer<ActivityRecord> updateActivities =
+                activity -> activity.setDropInputForAnimation(false);
+        mDisplayContent.forAllActivities(updateActivities);
         setRunningRemoteAnimation(false);
         ProtoLog.i(WM_DEBUG_REMOTE_ANIMATIONS, "Finishing remote animation");
     }
 
-    private void invokeAnimationCancelled() {
+    private void invokeAnimationCancelled(String reason) {
+        ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "cancelAnimation(): reason=%s", reason);
         try {
             mRemoteAnimationAdapter.getRunner().onAnimationCancelled();
         } catch (RemoteException e) {
             Slog.e(TAG, "Failed to notify cancel", e);
         }
+        mOnRemoteAnimationReady = null;
     }
 
     private void releaseFinishedCallback() {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 2355333..cc99f37 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2754,7 +2754,7 @@
         // First preference goes to the launch root task set in the activity options.
         if (options != null) {
             final Task candidateRoot = Task.fromWindowContainerToken(options.getLaunchRootTask());
-            if (canLaunchOnDisplay(r, candidateRoot)) {
+            if (candidateRoot != null && canLaunchOnDisplay(r, candidateRoot)) {
                 return candidateRoot;
             }
         }
@@ -3376,11 +3376,17 @@
                 return new ArrayList<>();
             }
         } else {
+            final RecentTasks recentTasks = mWindowManager.mAtmService.getRecentTasks();
+            final int recentsComponentUid = recentTasks != null
+                    ? recentTasks.getRecentsComponentUid()
+                    : -1;
             final ArrayList<ActivityRecord> activities = new ArrayList<>();
-            forAllRootTasks(rootTask -> {
-                if (!dumpVisibleRootTasksOnly || rootTask.shouldBeVisible(null)) {
-                    activities.addAll(rootTask.getDumpActivitiesLocked(name, userId));
+            forAllLeafTasks(task -> {
+                final boolean isRecents = (task.effectiveUid == recentsComponentUid);
+                if (!dumpVisibleRootTasksOnly || task.shouldBeVisible(null) || isRecents) {
+                    activities.addAll(task.getDumpActivitiesLocked(name, userId));
                 }
+                return false;
             });
             return activities;
         }
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 0c609191..f75a06d 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -116,6 +116,8 @@
     private float mLastReportedAnimatorScale;
     private String mPackageName;
     private String mRelayoutTag;
+    private String mUpdateViewVisibilityTag;
+    private String mUpdateWindowLayoutTag;
     private final InsetsVisibilities mDummyRequestedVisibilities = new InsetsVisibilities();
     private final InsetsSourceControl[] mDummyControls =  new InsetsSourceControl[0];
     final boolean mSetsUnrestrictedKeepClearAreas;
@@ -223,6 +225,27 @@
     }
 
     @Override
+    public int updateVisibility(IWindow client, WindowManager.LayoutParams attrs,
+            int viewVisibility, MergedConfiguration outMergedConfiguration,
+            SurfaceControl outSurfaceControl, InsetsState outInsetsState,
+            InsetsSourceControl[] outActiveControls) {
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mUpdateViewVisibilityTag);
+        int res = mService.updateViewVisibility(this, client, attrs, viewVisibility,
+                outMergedConfiguration, outSurfaceControl, outInsetsState, outActiveControls);
+        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+        return res;
+    }
+
+    @Override
+    public void updateLayout(IWindow window, WindowManager.LayoutParams attrs, int flags,
+            ClientWindowFrames clientFrames, int requestedWidth, int requestedHeight) {
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mUpdateWindowLayoutTag);
+        mService.updateWindowLayout(this, window, attrs, flags, clientFrames, requestedWidth,
+                requestedHeight);
+        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+    }
+
+    @Override
     public void prepareToReplaceWindows(IBinder appToken, boolean childrenOnly) {
         mService.setWillReplaceWindows(appToken, childrenOnly);
     }
@@ -232,14 +255,14 @@
             int requestedWidth, int requestedHeight, int viewFlags, int flags,
             ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
             SurfaceControl outSurfaceControl, InsetsState outInsetsState,
-            InsetsSourceControl[] outActiveControls) {
+            InsetsSourceControl[] outActiveControls, Bundle outSyncSeqIdBundle) {
         if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
                 + Binder.getCallingPid());
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
         int res = mService.relayoutWindow(this, window, attrs,
                 requestedWidth, requestedHeight, viewFlags, flags,
                 outFrames, mergedConfiguration, outSurfaceControl, outInsetsState,
-                outActiveControls);
+                outActiveControls, outSyncSeqIdBundle);
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
                 + Binder.getCallingPid());
@@ -265,9 +288,9 @@
 
     @Override
     public void finishDrawing(IWindow window,
-            @Nullable SurfaceControl.Transaction postDrawTransaction) {
+            @Nullable SurfaceControl.Transaction postDrawTransaction, int seqId) {
         if (DEBUG) Slog.v(TAG_WM, "IWindow finishDrawing called for " + window);
-        mService.finishDrawingWindow(this, window, postDrawTransaction);
+        mService.finishDrawingWindow(this, window, postDrawTransaction, seqId);
     }
 
     @Override
@@ -689,6 +712,8 @@
             if (wpc != null) {
                 mPackageName = wpc.mInfo.packageName;
                 mRelayoutTag = "relayoutWindow: " + mPackageName;
+                mUpdateViewVisibilityTag = "updateVisibility: " + mPackageName;
+                mUpdateWindowLayoutTag = "updateLayout: " + mPackageName;
             } else {
                 Slog.e(TAG_WM, "Unknown process pid=" + mPid);
             }
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index 92e2ee6..b576709 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -26,13 +26,22 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.annotation.Nullable;
+import android.graphics.Canvas;
+import android.graphics.Insets;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
 import android.hardware.power.Boost;
 import android.os.Handler;
 import android.os.PowerManagerInternal;
 import android.util.ArrayMap;
+import android.util.Log;
 import android.view.Choreographer;
+import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
+import android.view.animation.Animation;
+import android.view.animation.Transformation;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -40,6 +49,8 @@
 import com.android.server.AnimationThread;
 import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.function.Supplier;
 
 /**
@@ -73,6 +84,10 @@
 
     @GuardedBy("mLock")
     @VisibleForTesting
+    final ArrayMap<SurfaceControl, RunningAnimation> mPreProcessingAnimations = new ArrayMap<>();
+
+    @GuardedBy("mLock")
+    @VisibleForTesting
     final ArrayMap<SurfaceControl, RunningAnimation> mRunningAnimations = new ArrayMap<>();
 
     @GuardedBy("mLock")
@@ -136,23 +151,64 @@
         synchronized (mLock) {
             final RunningAnimation runningAnim = new RunningAnimation(a, animationLeash,
                     finishCallback);
-            mPendingAnimations.put(animationLeash, runningAnim);
-            if (!mAnimationStartDeferred) {
-                mChoreographer.postFrameCallback(this::startAnimations);
+            boolean requiresEdgeExtension = requiresEdgeExtension(a);
+
+            if (requiresEdgeExtension) {
+                mPreProcessingAnimations.put(animationLeash, runningAnim);
+
+                // We must wait for t to be committed since otherwise the leash doesn't have the
+                // windows we want to screenshot and extend as children.
+                t.addTransactionCommittedListener(Runnable::run, () -> {
+                    final WindowAnimationSpec animationSpec = a.asWindowAnimationSpec();
+                    final Runnable cleanUpEdgeExtension = edgeExtendWindow(animationLeash,
+                            animationSpec.getRootTaskBounds(), animationSpec.getAnimation(),
+                            mFrameTransaction);
+
+                    runningAnim.mFinishCallback = () -> {
+                        cleanUpEdgeExtension.run();
+                        finishCallback.run();
+                    };
+
+                    synchronized (mLock) {
+                        // only run if animation is not yet canceled by this point
+                        if (mPreProcessingAnimations.get(animationLeash) == runningAnim) {
+                            mPreProcessingAnimations.remove(animationLeash);
+                            mPendingAnimations.put(animationLeash, runningAnim);
+                            if (!mAnimationStartDeferred) {
+                                mChoreographer.postFrameCallback(this::startAnimations);
+                            }
+                        }
+                    }
+                });
             }
 
-            // Some animations (e.g. move animations) require the initial transform to be applied
-            // immediately.
-            applyTransformation(runningAnim, t, 0 /* currentPlayTime */);
+            if (!requiresEdgeExtension) {
+                mPendingAnimations.put(animationLeash, runningAnim);
+                if (!mAnimationStartDeferred) {
+                    mChoreographer.postFrameCallback(this::startAnimations);
+                }
+
+                // Some animations (e.g. move animations) require the initial transform to be
+                // applied immediately.
+                applyTransformation(runningAnim, t, 0 /* currentPlayTime */);
+            }
         }
     }
 
+    private boolean requiresEdgeExtension(AnimationSpec a) {
+        return a.asWindowAnimationSpec() != null && a.asWindowAnimationSpec().hasExtension();
+    }
+
     void onAnimationCancelled(SurfaceControl leash) {
         synchronized (mLock) {
             if (mPendingAnimations.containsKey(leash)) {
                 mPendingAnimations.remove(leash);
                 return;
             }
+            if (mPreProcessingAnimations.containsKey(leash)) {
+                mPreProcessingAnimations.remove(leash);
+                return;
+            }
             final RunningAnimation anim = mRunningAnimations.get(leash);
             if (anim != null) {
                 mRunningAnimations.remove(leash);
@@ -264,10 +320,133 @@
         mApplyScheduled = false;
     }
 
+    private Runnable edgeExtendWindow(SurfaceControl leash, Rect bounds, Animation a,
+            Transaction transaction) {
+        final Transformation transformationAtStart = new Transformation();
+        a.getTransformationAt(0, transformationAtStart);
+        final Transformation transformationAtEnd = new Transformation();
+        a.getTransformationAt(1, transformationAtEnd);
+
+        // We want to create an extension surface that is the maximal size and the animation will
+        // take care of cropping any part that overflows.
+        final Insets maxExtensionInsets = Insets.min(
+                transformationAtStart.getInsets(), transformationAtEnd.getInsets());
+
+        final int targetSurfaceHeight = bounds.height();
+        final int targetSurfaceWidth = bounds.width();
+
+        final List<SurfaceControl> extensionSurfaces = new ArrayList<>();
+
+        if (maxExtensionInsets.left < 0) {
+            final Rect edgeBounds = new Rect(0, 0, 1, targetSurfaceHeight);
+            final Rect extensionRect = new Rect(0, 0,
+                    -maxExtensionInsets.left, targetSurfaceHeight);
+            final int xPos = maxExtensionInsets.left;
+            final int yPos = 0;
+            final SurfaceControl extensionSurface = createExtensionSurface(leash, edgeBounds,
+                    extensionRect, xPos, yPos, "Left Edge Extension", transaction);
+            extensionSurfaces.add(extensionSurface);
+        }
+
+        if (maxExtensionInsets.top < 0) {
+            final Rect edgeBounds = new Rect(0, 0, targetSurfaceWidth, 1);
+            final Rect extensionRect = new Rect(0, 0,
+                    targetSurfaceWidth, -maxExtensionInsets.top);
+            final int xPos = 0;
+            final int yPos = maxExtensionInsets.top;
+            final SurfaceControl extensionSurface = createExtensionSurface(leash, edgeBounds,
+                    extensionRect, xPos, yPos, "Top Edge Extension", transaction);
+            extensionSurfaces.add(extensionSurface);
+        }
+
+        if (maxExtensionInsets.right < 0) {
+            final Rect edgeBounds = new Rect(targetSurfaceWidth - 1, 0,
+                    targetSurfaceWidth, targetSurfaceHeight);
+            final Rect extensionRect = new Rect(0, 0,
+                    -maxExtensionInsets.right, targetSurfaceHeight);
+            final int xPos = targetSurfaceWidth;
+            final int yPos = 0;
+            final SurfaceControl extensionSurface = createExtensionSurface(leash, edgeBounds,
+                    extensionRect, xPos, yPos, "Right Edge Extension", transaction);
+            extensionSurfaces.add(extensionSurface);
+        }
+
+        if (maxExtensionInsets.bottom < 0) {
+            final Rect edgeBounds = new Rect(0, targetSurfaceHeight - 1,
+                    targetSurfaceWidth, targetSurfaceHeight);
+            final Rect extensionRect = new Rect(0, 0,
+                    targetSurfaceWidth, -maxExtensionInsets.bottom);
+            final int xPos = maxExtensionInsets.left;
+            final int yPos = targetSurfaceHeight;
+            final SurfaceControl extensionSurface = createExtensionSurface(leash, edgeBounds,
+                    extensionRect, xPos, yPos, "Bottom Edge Extension", transaction);
+            extensionSurfaces.add(extensionSurface);
+        }
+
+        Runnable cleanUp = () -> {
+            for (final SurfaceControl extensionSurface : extensionSurfaces) {
+                if (extensionSurface != null) {
+                    transaction.remove(extensionSurface);
+                }
+            }
+        };
+
+        return cleanUp;
+    }
+
+    private SurfaceControl createExtensionSurface(SurfaceControl surfaceToExtend, Rect edgeBounds,
+            Rect extensionRect, int xPos, int yPos, String layerName,
+            Transaction startTransaction) {
+        final SurfaceControl edgeExtensionLayer = new SurfaceControl.Builder()
+                .setName(layerName)
+                .setParent(surfaceToExtend)
+                .setHidden(true)
+                .setCallsite("DefaultTransitionHandler#startAnimation")
+                .setOpaque(true)
+                .setBufferSize(extensionRect.width(), extensionRect.height())
+                .build();
+
+        SurfaceControl.LayerCaptureArgs captureArgs =
+                new SurfaceControl.LayerCaptureArgs.Builder(surfaceToExtend)
+                        .setSourceCrop(edgeBounds)
+                        .setFrameScale(1)
+                        .setPixelFormat(PixelFormat.RGBA_8888)
+                        .setChildrenOnly(true)
+                        .setAllowProtected(true)
+                        .build();
+        final SurfaceControl.ScreenshotHardwareBuffer edgeBuffer =
+                SurfaceControl.captureLayers(captureArgs);
+
+        if (edgeBuffer == null) {
+            Log.e("SurfaceAnimationRunner", "Failed to create edge extension - "
+                    + "edge buffer is null");
+            return null;
+        }
+
+        android.graphics.BitmapShader shader =
+                new android.graphics.BitmapShader(edgeBuffer.asBitmap(),
+                        android.graphics.Shader.TileMode.CLAMP,
+                        android.graphics.Shader.TileMode.CLAMP);
+        final Paint paint = new Paint();
+        paint.setShader(shader);
+
+        final Surface surface = new Surface(edgeExtensionLayer);
+        Canvas c = surface.lockHardwareCanvas();
+        c.drawRect(extensionRect, paint);
+        surface.unlockCanvasAndPost(c);
+        surface.release();
+
+        startTransaction.setLayer(edgeExtensionLayer, Integer.MIN_VALUE);
+        startTransaction.setPosition(edgeExtensionLayer, xPos, yPos);
+        startTransaction.setVisibility(edgeExtensionLayer, true);
+
+        return edgeExtensionLayer;
+    }
+
     private static final class RunningAnimation {
         final AnimationSpec mAnimSpec;
         final SurfaceControl mLeash;
-        final Runnable mFinishCallback;
+        Runnable mFinishCallback;
         ValueAnimator mAnim;
 
         @GuardedBy("mCancelLock")
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 53e3378..fbf0426 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -16,10 +16,10 @@
 
 package com.android.server.wm;
 
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM;
 import static com.android.server.wm.SurfaceAnimatorProto.ANIMATION_ADAPTER;
 import static com.android.server.wm.SurfaceAnimatorProto.ANIMATION_START_DELAYED;
 import static com.android.server.wm.SurfaceAnimatorProto.LEASH;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
@@ -32,8 +32,11 @@
 import android.view.SurfaceControl.Transaction;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.ProtoLogImpl;
+import com.android.internal.protolog.common.ProtoLog;
 
 import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.function.Supplier;
@@ -185,10 +188,16 @@
         }
         mAnimatable.onLeashAnimationStarting(t, mLeash);
         if (mAnimationStartDelayed) {
-            if (DEBUG_ANIM) Slog.i(TAG, "Animation start delayed");
+            ProtoLog.i(WM_DEBUG_ANIM, "Animation start delayed for %s", mAnimatable);
             return;
         }
         mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback);
+        if (ProtoLogImpl.isEnabled(WM_DEBUG_ANIM)) {
+            StringWriter sw = new StringWriter();
+            PrintWriter pw = new PrintWriter(sw);
+            mAnimation.dump(pw, "");
+            ProtoLog.d(WM_DEBUG_ANIM, "Animation start for %s, anim=%s", mAnimatable, sw);
+        }
         if (snapshotAnim != null) {
             mSnapshot = freezer.takeSnapshotForAnimation();
             if (mSnapshot == null) {
@@ -340,7 +349,8 @@
      *                      to another animator.
      */
     private void cancelAnimation(Transaction t, boolean restarting, boolean forwardCancel) {
-        if (DEBUG_ANIM) Slog.i(TAG, "Cancelling animation restarting=" + restarting);
+        ProtoLog.i(WM_DEBUG_ANIM, "Cancelling animation restarting=%b for %s",
+                restarting, mAnimatable);
         final SurfaceControl leash = mLeash;
         final AnimationAdapter animation = mAnimation;
         final @AnimationType int animationType = mAnimationType;
@@ -419,7 +429,8 @@
         final boolean reparent = surface != null && (curAnimationLeash == null
                 || curAnimationLeash.equals(leash));
         if (reparent) {
-            if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to original parent: " + parent);
+            ProtoLog.i(WM_DEBUG_ANIM, "Reparenting to original parent: %s for %s",
+                    parent, animatable);
             // We shouldn't really need these isValid checks but we do
             // b/130364451
             if (surface.isValid() && parent != null && parent.isValid()) {
@@ -444,7 +455,7 @@
     static SurfaceControl createAnimationLeash(Animatable animatable, SurfaceControl surface,
             Transaction t, @AnimationType int type, int width, int height, int x, int y,
             boolean hidden, Supplier<Transaction> transactionFactory) {
-        if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to leash");
+        ProtoLog.i(WM_DEBUG_ANIM, "Reparenting to leash for %s", animatable);
         final SurfaceControl.Builder builder = animatable.makeAnimationLeash()
                 .setParent(animatable.getAnimationLeashParent())
                 .setName(surface + " - animation-leash of " + animationTypeToString(type))
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 8edb313..731a045 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -72,6 +72,7 @@
 import static com.android.internal.policy.DecorView.DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP;
 import static com.android.internal.policy.DecorView.DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BACK_PREVIEW;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
@@ -609,6 +610,12 @@
 
     boolean mLastSurfaceShowing = true;
 
+    /**
+     * Tracks if a back gesture is in progress.
+     * Skips any system transition animations if this is set to {@code true}.
+     */
+    boolean mBackGestureStarted = false;
+
     private Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
             Intent _affinityIntent, String _affinity, String _rootAffinity,
             ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
@@ -1623,12 +1630,16 @@
     }
 
     ActivityRecord performClearTop(ActivityRecord newR, int launchFlags) {
+        // The task should be preserved for putting new activity in case the last activity is
+        // finished if it is normal launch mode and not single top ("clear-task-top").
+        mReuseTask = true;
         mTaskSupervisor.beginDeferResume();
         final ActivityRecord result;
         try {
             result = clearTopActivities(newR, launchFlags);
         } finally {
             mTaskSupervisor.endDeferResume();
+            mReuseTask = false;
         }
         return result;
     }
@@ -2349,6 +2360,20 @@
         return parentTask == null ? null : parentTask.getOrganizedTask();
     }
 
+    /** @return the first create-by-organizer task. */
+    @Nullable
+    Task getCreatedByOrganizerTask() {
+        if (mCreatedByOrganizer) {
+            return this;
+        }
+        final WindowContainer parent = getParent();
+        if (parent == null) {
+            return null;
+        }
+        final Task parentTask = parent.asTask();
+        return parentTask == null ? null : parentTask.getCreatedByOrganizerTask();
+    }
+
     // TODO(task-merge): Figure out what's the right thing to do for places that used it.
     boolean isRootTask() {
         return getRootTask() == this;
@@ -3286,9 +3311,10 @@
             mTmpDimBoundsRect.offsetTo(0, 0);
         }
 
-        updateShadowsRadius(isFocused(), getSyncTransaction());
+        final SurfaceControl.Transaction t = getSyncTransaction();
+        updateShadowsRadius(isFocused(), t);
 
-        if (mDimmer.updateDims(getPendingTransaction(), mTmpDimBoundsRect)) {
+        if (mDimmer.updateDims(t, mTmpDimBoundsRect)) {
             scheduleAnimation();
         }
 
@@ -3298,7 +3324,7 @@
         final boolean show = isVisible() || isAnimating(TRANSITION | PARENTS | CHILDREN);
         if (mSurfaceControl != null) {
             if (show != mLastSurfaceShowing) {
-                getSyncTransaction().setVisibility(mSurfaceControl, show);
+                t.setVisibility(mSurfaceControl, show);
             }
         }
         mLastSurfaceShowing = show;
@@ -3322,6 +3348,14 @@
                     }
                 });
             }
+        } else if (mBackGestureStarted) {
+            // Cancel playing transitions if a back navigation animation is in progress.
+            // This bit is set by {@link BackNavigationController} when a back gesture is started.
+            // It is used as a one-off transition overwrite that is cleared when the back gesture
+            // is committed and triggers a transition, or when the gesture is cancelled.
+            mBackGestureStarted = false;
+            mDisplayContent.mSkipAppTransitionAnimation = true;
+            ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Skipping app transition animation. task=%s", this);
         } else {
             super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources);
         }
@@ -3403,7 +3437,7 @@
         info.positionInParent = getRelativePosition();
 
         info.pictureInPictureParams = getPictureInPictureParams(top);
-        info.preferDockBigOverlays = getPreferDockBigOverlays();
+        info.shouldDockBigOverlays = shouldDockBigOverlays();
         if (info.pictureInPictureParams != null
                 && info.pictureInPictureParams.isLaunchIntoPip()
                 && top.getTopMostActivity().getLastParentBeforePip() != null) {
@@ -3456,9 +3490,9 @@
                 ? null : new PictureInPictureParams(topMostActivity.pictureInPictureArgs);
     }
 
-    private boolean getPreferDockBigOverlays() {
+    private boolean shouldDockBigOverlays() {
         final ActivityRecord topMostActivity = getTopMostActivity();
-        return topMostActivity != null && topMostActivity.preferDockBigOverlays;
+        return topMostActivity != null && topMostActivity.shouldDockBigOverlays;
     }
 
     Rect getDisplayCutoutInsets() {
@@ -4354,7 +4388,7 @@
         }
     }
 
-    void onPreferDockBigOverlaysChanged() {
+    void onShouldDockBigOverlaysChanged() {
         dispatchTaskInfoChangedIfNeeded(true /* force */);
     }
 
@@ -6079,7 +6113,7 @@
     /**
      * Sets the current picture-in-picture actions.
      */
-    void setPictureInPictureActions(List<RemoteAction> actions) {
+    void setPictureInPictureActions(List<RemoteAction> actions, RemoteAction closeAction) {
         if (!mWmService.mAtmService.mSupportsPictureInPicture) {
             return;
         }
@@ -6088,7 +6122,7 @@
             return;
         }
 
-        getDisplayContent().getPinnedTaskController().setActions(actions);
+        getDisplayContent().getPinnedTaskController().setActions(actions, closeAction);
     }
 
     public DisplayInfo getDisplayInfo() {
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index 3b79274..61963c4 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -20,6 +20,7 @@
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ITaskStackListener;
 import android.app.TaskInfo;
+import android.app.TaskStackListener;
 import android.content.ComponentName;
 import android.os.Binder;
 import android.os.Handler;
@@ -286,6 +287,9 @@
         if (listener instanceof Binder) {
             synchronized (mLocalTaskStackListeners) {
                 if (!mLocalTaskStackListeners.contains(listener)) {
+                    if (listener instanceof TaskStackListener) {
+                        ((TaskStackListener) listener).setIsLocal();
+                    }
                     mLocalTaskStackListeners.add(listener);
                 }
             }
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 2f50b14..7a7bf1f 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -824,9 +824,19 @@
     }
 
     void setBackgroundColor(@ColorInt int colorInt) {
+        setBackgroundColor(colorInt, false /* restore */);
+    }
+
+    void setBackgroundColor(@ColorInt int colorInt, boolean restore) {
         mBackgroundColor = colorInt;
         Color color = Color.valueOf(colorInt);
-        mColorLayerCounter++;
+
+        // We don't want to increment the mColorLayerCounter if we are restoring the background
+        // color after a surface migration because in that case the mColorLayerCounter already
+        // accounts for setting that background color.
+        if (!restore) {
+            mColorLayerCounter++;
+        }
 
         // Only apply the background color if the TDA is actually attached and has a valid surface
         // to set the background color on. We still want to keep track of the background color state
@@ -855,7 +865,7 @@
         super.migrateToNewSurfaceControl(t);
 
         if (mColorLayerCounter > 0) {
-            setBackgroundColor(mBackgroundColor);
+            setBackgroundColor(mBackgroundColor, true /* restore */);
         }
 
         if (mSplitScreenDividerAnchor == null) {
@@ -1115,9 +1125,9 @@
         if ((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0
                 && mLaunchAdjacentFlagRootTask != null) {
             // If the adjacent launch is coming from the same root, launch to adjacent root instead.
-            if (sourceTask != null
-                    && sourceTask.getRootTask().mTaskId == mLaunchAdjacentFlagRootTask.mTaskId
-                    && mLaunchAdjacentFlagRootTask.getAdjacentTaskFragment() != null) {
+            if (sourceTask != null && mLaunchAdjacentFlagRootTask.getAdjacentTaskFragment() != null
+                    && (sourceTask == mLaunchAdjacentFlagRootTask
+                    || sourceTask.isDescendantOf(mLaunchAdjacentFlagRootTask))) {
                 return mLaunchAdjacentFlagRootTask.getAdjacentTaskFragment().asTask();
             } else {
                 return mLaunchAdjacentFlagRootTask;
@@ -1131,18 +1141,22 @@
                         ? launchRootTask.getAdjacentTaskFragment() : null;
                 final Task adjacentRootTask =
                         adjacentTaskFragment != null ? adjacentTaskFragment.asTask() : null;
-                if (sourceTask != null && sourceTask.getRootTask() == adjacentRootTask) {
+                if (sourceTask != null && adjacentRootTask != null
+                        && (sourceTask == adjacentRootTask
+                        || sourceTask.isDescendantOf(adjacentRootTask))) {
                     return adjacentRootTask;
                 } else {
                     return launchRootTask;
                 }
             }
         }
-        // For better split UX, If task launch by the source task which root task is created by
-        // organizer, it should also launch in that root too.
-        if (sourceTask != null && sourceTask.getRootTask().mCreatedByOrganizer) {
-            return sourceTask.getRootTask();
+
+        // For a better split UX, If a task is launching from a created-by-organizer task, it should
+        // be launched into the same created-by-organizer task as well.
+        if (sourceTask != null) {
+            return sourceTask.getCreatedByOrganizerTask();
         }
+
         return null;
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 3985cbc..23df429 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -63,8 +63,6 @@
 import static com.android.server.wm.TaskFragmentProto.MIN_HEIGHT;
 import static com.android.server.wm.TaskFragmentProto.MIN_WIDTH;
 import static com.android.server.wm.TaskFragmentProto.WINDOW_CONTAINER;
-import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
-import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowContainerChildProto.TASK_FRAGMENT;
 
 import android.annotation.IntDef;
@@ -242,7 +240,7 @@
 
     /** Client assigned unique token for this TaskFragment if this is created by an organizer. */
     @Nullable
-    private IBinder mFragmentToken;
+    private final IBinder mFragmentToken;
 
     /**
      * Whether to delay the last activity of TaskFragment being immediately removed while finishing.
@@ -407,6 +405,12 @@
             Slog.d(TAG, "setResumedActivity taskFrag:" + this + " + from: "
                     + mResumedActivity + " to:" + r + " reason:" + reason);
         }
+
+        if (r != null && mResumedActivity == null) {
+            // Task is becoming active.
+            getTask().touchActiveTime();
+        }
+
         final ActivityRecord prevR = mResumedActivity;
         mResumedActivity = r;
         mTaskSupervisor.updateTopResumedActivityIfNeeded();
@@ -520,7 +524,16 @@
                 || isAllowedToEmbedActivityInTrustedMode(a);
     }
 
+    /**
+     * Checks if the organized task fragment is allowed to embed activity in untrusted mode.
+     */
     boolean isAllowedToEmbedActivityInUntrustedMode(@NonNull ActivityRecord a) {
+        final WindowContainer parent = getParent();
+        if (parent == null || !parent.getBounds().contains(getBounds())) {
+            // Without full trust between the host and the embedded activity, we don't allow
+            // TaskFragment to have bounds outside of the parent bounds.
+            return false;
+        }
         return (a.info.flags & FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING)
                 == FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
     }
@@ -1461,7 +1474,8 @@
             // next activity.
             final boolean lastResumedCanPip = prev.checkEnterPictureInPictureState(
                     "shouldAutoPipWhilePausing", userLeaving);
-            if (lastResumedCanPip && prev.pictureInPictureArgs.isAutoEnterEnabled()) {
+            if (userLeaving && lastResumedCanPip
+                    && prev.pictureInPictureArgs.isAutoEnterEnabled()) {
                 shouldAutoPip = true;
             } else if (!lastResumedCanPip) {
                 // If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous
@@ -2370,8 +2384,7 @@
         if (!hasChild()) {
             return false;
         }
-        return isAnimating(TRANSITION | CHILDREN, WindowState.EXIT_ANIMATING_TYPES)
-                || inTransition();
+        return isExitAnimationRunningSelfOrChild() || inTransition();
     }
 
     @Override
@@ -2392,10 +2405,18 @@
     void removeImmediately() {
         mIsRemovalRequested = false;
         resetAdjacentTaskFragment();
+        cleanUp();
         super.removeImmediately();
         sendTaskFragmentVanished();
     }
 
+    /** Called on remove to cleanup. */
+    private void cleanUp() {
+        if (mIsEmbedded) {
+            mAtmService.mWindowOrganizerController.cleanUpEmbeddedTaskFragment(this);
+        }
+    }
+
     @Override
     Dimmer getDimmer() {
         // If the window is in an embedded TaskFragment, we want to dim at the TaskFragment.
@@ -2419,7 +2440,7 @@
         // Bounds need to be relative, as the dim layer is a child.
         final Rect dimBounds = getBounds();
         dimBounds.offsetTo(0 /* newLeft */, 0 /* newTop */);
-        if (mDimmer.updateDims(getPendingTransaction(), dimBounds)) {
+        if (mDimmer.updateDims(getSyncTransaction(), dimBounds)) {
             scheduleAnimation();
         }
     }
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 19f921d..0a92ffc 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -140,7 +140,7 @@
                 mLastSentTaskFragmentInfos.put(tf, info);
                 tf.mTaskFragmentAppearedSent = true;
             } catch (RemoteException e) {
-                Slog.e(TAG, "Exception sending onTaskFragmentAppeared callback", e);
+                Slog.d(TAG, "Exception sending onTaskFragmentAppeared callback", e);
             }
             onTaskFragmentParentInfoChanged(organizer, tf);
         }
@@ -150,7 +150,7 @@
             try {
                 organizer.onTaskFragmentVanished(tf.getTaskFragmentInfo());
             } catch (RemoteException e) {
-                Slog.e(TAG, "Exception sending onTaskFragmentVanished callback", e);
+                Slog.d(TAG, "Exception sending onTaskFragmentVanished callback", e);
             }
             tf.mTaskFragmentAppearedSent = false;
             mLastSentTaskFragmentInfos.remove(tf);
@@ -175,7 +175,7 @@
                 organizer.onTaskFragmentInfoChanged(tf.getTaskFragmentInfo());
                 mLastSentTaskFragmentInfos.put(tf, info);
             } catch (RemoteException e) {
-                Slog.e(TAG, "Exception sending onTaskFragmentInfoChanged callback", e);
+                Slog.d(TAG, "Exception sending onTaskFragmentInfoChanged callback", e);
             }
         }
 
@@ -198,7 +198,7 @@
                 organizer.onTaskFragmentParentInfoChanged(tf.getFragmentToken(), parentConfig);
                 mLastSentTaskFragmentParentConfigs.put(tf, new Configuration(parentConfig));
             } catch (RemoteException e) {
-                Slog.e(TAG, "Exception sending onTaskFragmentParentInfoChanged callback", e);
+                Slog.d(TAG, "Exception sending onTaskFragmentParentInfoChanged callback", e);
             }
         }
 
@@ -210,7 +210,7 @@
             try {
                 organizer.onTaskFragmentError(errorCallbackToken, exceptionBundle);
             } catch (RemoteException e) {
-                Slog.e(TAG, "Exception sending onTaskFragmentError callback", e);
+                Slog.d(TAG, "Exception sending onTaskFragmentError callback", e);
             }
         }
     }
@@ -304,18 +304,7 @@
         synchronized (mGlobalLock) {
             final TaskFragmentOrganizerState organizerState =
                     mTaskFragmentOrganizerState.get(organizer.asBinder());
-            if (organizerState == null) {
-                return null;
-            }
-            for (TaskFragment tf : organizerState.mOrganizedTaskFragments) {
-                if (!tf.isAllowedToBeEmbeddedInTrustedMode()) {
-                    // Disable client-driven animations for organizer if at least one of the
-                    // embedded task fragments is not embedding in trusted mode.
-                    // TODO(b/197364677): replace with a stub or Shell-driven one instead of skip?
-                    return null;
-                }
-            }
-            return organizerState.mRemoteAnimationDefinition;
+            return organizerState != null ? organizerState.mRemoteAnimationDefinition : null;
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index ff5bfbe..3a8c8c7 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -31,6 +31,7 @@
 import android.app.WindowConfiguration;
 import android.content.Intent;
 import android.content.pm.ParceledListSlice;
+import android.graphics.Rect;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.Parcel;
@@ -67,7 +68,8 @@
 class TaskOrganizerController extends ITaskOrganizerController.Stub {
     private static final String TAG = "TaskOrganizerController";
 
-    private class DeathRecipient implements IBinder.DeathRecipient {
+    @VisibleForTesting
+    class DeathRecipient implements IBinder.DeathRecipient {
         ITaskOrganizer mTaskOrganizer;
 
         DeathRecipient(ITaskOrganizer organizer) {
@@ -77,7 +79,7 @@
         @Override
         public void binderDied() {
             synchronized (mGlobalLock) {
-                final TaskOrganizerState state = mTaskOrganizerStates.remove(
+                final TaskOrganizerState state = mTaskOrganizerStates.get(
                         mTaskOrganizer.asBinder());
                 if (state != null) {
                     state.dispose();
@@ -170,7 +172,8 @@
         }
     }
 
-    private class TaskOrganizerState {
+    @VisibleForTesting
+    class TaskOrganizerState {
         private final TaskOrganizerCallbacks mOrganizer;
         private final DeathRecipient mDeathRecipient;
         private final ArrayList<Task> mOrganizedTasks = new ArrayList<>();
@@ -191,6 +194,11 @@
             mUid = uid;
         }
 
+        @VisibleForTesting
+        DeathRecipient getDeathRecipient() {
+            return mDeathRecipient;
+        }
+
         /**
          * Register this task with this state, but doesn't trigger the task appeared callback to
          * the organizer.
@@ -265,7 +273,7 @@
 
             // Remove organizer state after removing tasks so we get a chance to send
             // onTaskVanished.
-            mTaskOrganizerStates.remove(asBinder());
+            mTaskOrganizerStates.remove(mOrganizer.getBinder());
         }
 
         void unlinkDeath() {
@@ -467,10 +475,12 @@
         }
     }
 
-    static SurfaceControl applyStartingWindowAnimation(WindowContainer window) {
+    static SurfaceControl applyStartingWindowAnimation(WindowState window) {
+        final SurfaceControl.Transaction t = window.getPendingTransaction();
+        final Rect mainFrame = window.getRelativeFrame();
         final StartingWindowAnimationAdaptor adaptor = new StartingWindowAnimationAdaptor();
-        window.startAnimation(window.getPendingTransaction(), adaptor, false,
-                ANIMATION_TYPE_STARTING_REVEAL);
+        window.startAnimation(t, adaptor, false, ANIMATION_TYPE_STARTING_REVEAL);
+        t.setPosition(adaptor.mAnimationLeash, mainFrame.left, mainFrame.top);
         return adaptor.mAnimationLeash;
     }
 
@@ -523,8 +533,6 @@
                     final SurfaceControl.Transaction t = mainWindow.getPendingTransaction();
                     removalInfo.windowAnimationLeash = applyStartingWindowAnimation(mainWindow);
                     removalInfo.mainFrame = mainWindow.getRelativeFrame();
-                    t.setPosition(removalInfo.windowAnimationLeash,
-                            removalInfo.mainFrame.left, removalInfo.mainFrame.top);
                 }
             }
         }
@@ -596,7 +604,7 @@
     private void onTaskVanishedInternal(ITaskOrganizer organizer, Task task) {
         for (int i = mPendingTaskEvents.size() - 1; i >= 0; i--) {
             PendingTaskEvent entry = mPendingTaskEvents.get(i);
-            if (task.mTaskId == entry.mTask.mTaskId) {
+            if (task.mTaskId == entry.mTask.mTaskId && entry.mTaskOrg == organizer) {
                 // This task is vanished so remove all pending event of it.
                 mPendingTaskEvents.remove(i);
                 if (entry.mEventType == PendingTaskEvent.EVENT_APPEARED) {
@@ -693,9 +701,16 @@
                     }
                     break;
                 case PendingTaskEvent.EVENT_VANISHED:
-                    state = mTaskOrganizerStates.get(event.mTaskOrg.asBinder());
-                    if (state != null) {
-                        state.mOrganizer.onTaskVanished(task);
+                    // TaskOrganizerState cannot be used here because it might have already been
+                    // removed.
+                    // The state is removed when an organizer dies or is unregistered. In order to
+                    // send the pending vanished task events, the mTaskOrg from event is used.
+                    // These events should not ideally be sent and will be removed as part of
+                    // b/224812558.
+                    try {
+                        event.mTaskOrg.onTaskVanished(task.getTaskInfo());
+                    } catch (RemoteException ex) {
+                        Slog.e(TAG, "Exception sending onTaskVanished callback", ex);
                     }
                     mLastSentTaskInfos.remove(task);
                     break;
@@ -812,7 +827,7 @@
                 }
 
                 // Avoid WindowState#getRootTask() so we don't attribute system windows to a task.
-                final Task task = imeLayeringTarget.getWindow().asTask();
+                final Task task = imeLayeringTarget.getWindow().getTask();
                 if (task == null) {
                     return null;
                 }
@@ -1045,4 +1060,9 @@
         }
         pw.println();
     }
+
+    @VisibleForTesting
+    TaskOrganizerState getTaskOrganizerState(IBinder taskOrganizer) {
+        return mTaskOrganizerStates.get(taskOrganizer);
+    }
 }
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index cde9927..814656d 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -480,12 +480,17 @@
         }
         final HardwareBuffer buffer = screenshotBuffer == null ? null
                 : screenshotBuffer.getHardwareBuffer();
-        if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) {
+        if (isInvalidHardwareBuffer(buffer)) {
             return null;
         }
         return screenshotBuffer;
     }
 
+    static boolean isInvalidHardwareBuffer(HardwareBuffer buffer) {
+        return buffer == null || buffer.isClosed() // This must be checked before getting size.
+                || buffer.getWidth() <= 1 || buffer.getHeight() <= 1;
+    }
+
     @Nullable
     TaskSnapshot snapshotTask(Task task) {
         return snapshotTask(task, PixelFormat.UNKNOWN);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index 9fbcd7c..03098e3 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -407,6 +407,10 @@
         }
 
         boolean writeBuffer() {
+            if (TaskSnapshotController.isInvalidHardwareBuffer(mSnapshot.getHardwareBuffer())) {
+                Slog.e(TAG, "Invalid task snapshot hw buffer, taskId=" + mTaskId);
+                return false;
+            }
             final Bitmap bitmap = Bitmap.wrapHardwareBuffer(
                     mSnapshot.getHardwareBuffer(), mSnapshot.getColorSpace());
             if (bitmap == null) {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 4c23f39..973f983 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -189,6 +189,9 @@
     private boolean mNavBarAttachedToApp = false;
     private int mRecentsDisplayId = INVALID_DISPLAY;
 
+    /** @see #setCanPipOnFinish */
+    private boolean mCanPipOnFinish = true;
+
     Transition(@TransitionType int type, @TransitionFlags int flags,
             TransitionController controller, BLASTSyncEngine syncEngine) {
         mType = type;
@@ -216,6 +219,7 @@
     }
 
     Task getTransientLaunchRestoreTarget(@NonNull WindowContainer container) {
+        if (mTransientLaunches == null) return null;
         for (int i = 0; i < mTransientLaunches.size(); ++i) {
             if (mTransientLaunches.keyAt(i).isDescendantOf(container)) {
                 return mTransientLaunches.valueAt(i);
@@ -447,6 +451,15 @@
     }
 
     /**
+     * Set whether this transition can start a pip-enter transition when finished. This is usually
+     * true, but gets set to false when recents decides that it wants to finish its animation but
+     * not actually finish its animation (yeah...).
+     */
+    void setCanPipOnFinish(boolean canPipOnFinish) {
+        mCanPipOnFinish = canPipOnFinish;
+    }
+
+    /**
      * The transition has finished animating and is ready to finalize WM state. This should not
      * be called directly; use {@link TransitionController#finishTransition} instead.
      */
@@ -474,7 +487,7 @@
                 // activity in a bad state.
                 if (!visibleAtTransitionEnd && !ar.isVisibleRequested()) {
                     boolean commitVisibility = true;
-                    if (ar.isVisible() && ar.getTask() != null) {
+                    if (mCanPipOnFinish && ar.isVisible() && ar.getTask() != null) {
                         if (ar.pictureInPictureArgs != null
                                 && ar.pictureInPictureArgs.isAutoEnterEnabled()) {
                             if (mTransientLaunches != null) {
@@ -491,7 +504,8 @@
                             // Avoid commit visibility to false here, or else we will get a sudden
                             // "flash" / surface going invisible for a split second.
                             commitVisibility = false;
-                        } else {
+                        } else if (ar.getDeferHidingClient()) {
+                            // Legacy PIP-enter requires pause event with user-leaving.
                             mController.mAtm.mTaskSupervisor.mUserLeaving = true;
                             ar.getTaskFragment().startPausing(false /* uiSleeping */,
                                     null /* resuming */, "finishTransition");
@@ -518,7 +532,6 @@
                     // Legacy dispatch relies on this (for now).
                     ar.mEnteringAnimation = visibleAtTransitionEnd;
                 }
-                mController.dispatchLegacyAppTransitionFinished(ar);
             }
             final WallpaperWindowToken wt = mParticipants.valueAt(i).asWallpaperToken();
             if (wt != null) {
@@ -530,6 +543,15 @@
                 }
             }
         }
+        // dispatch legacy callback in a different loop. This is because multiple legacy handlers
+        // (fixed-rotation/displaycontent) make global changes, so we want to ensure that we've
+        // processed all the participants first (in particular, we want to trigger pip-enter first)
+        for (int i = 0; i < mParticipants.size(); ++i) {
+            final ActivityRecord ar = mParticipants.valueAt(i).asActivityRecord();
+            if (ar != null) {
+                mController.dispatchLegacyAppTransitionFinished(ar);
+            }
+        }
         if (activitiesWentInvisible) {
             // Always schedule stop processing when transition finishes because activities don't
             // stop while they are in a transition thus their stop could still be pending.
@@ -1125,7 +1147,6 @@
                 continue;
             }
             targets.add(wc);
-            targets.mValidParticipants.add(wc);
         }
         ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "  Initial targets: %s",
                 targets.mArray);
@@ -1143,15 +1164,17 @@
     private static void populateParentChanges(Targets targets,
             ArrayMap<WindowContainer, ChangeInfo> changes) {
         final ArrayList<WindowContainer<?>> intermediates = new ArrayList<>();
-        for (int i = targets.mValidParticipants.size() - 1; i >= 0; --i) {
-            WindowContainer<?> wc = targets.mValidParticipants.get(i);
-            // Go up if the participant has been represented by its parent.
-            while (targets.mArray.indexOfValue(wc) < 0 && wc.getParent() != null) {
-                wc = wc.getParent();
-            }
+        // Make a copy to iterate because the original array may be modified.
+        final ArrayList<WindowContainer<?>> targetList = new ArrayList<>(targets.mArray.size());
+        for (int i = targets.mArray.size() - 1; i >= 0; --i) {
+            targetList.add(targets.mArray.valueAt(i));
+        }
+        for (int i = targetList.size() - 1; i >= 0; --i) {
+            final WindowContainer<?> wc = targetList.get(i);
             // Wallpaper must belong to the top (regardless of how nested it is in DisplayAreas).
             final boolean skipIntermediateReports = isWallpaper(wc);
             intermediates.clear();
+            boolean foundParentInTargets = false;
             // Collect the intermediate parents between target and top changed parent.
             for (WindowContainer<?> p = wc.getParent(); p != null; p = p.getParent()) {
                 final ChangeInfo parentChange = changes.get(p);
@@ -1165,19 +1188,19 @@
                     // The chain above the parent was processed.
                     break;
                 }
-                if (targets.mValidParticipants.contains(p)) {
+                if (targetList.contains(p)) {
                     if (skipIntermediateReports) {
                         changes.get(wc).mParent = p;
                     } else {
                         intermediates.add(p);
                     }
-                    // The parent reaches a participant.
+                    foundParentInTargets = true;
                     break;
                 } else if (reportIfNotTop(p) && !skipIntermediateReports) {
                     intermediates.add(p);
                 }
             }
-            if (intermediates.isEmpty()) continue;
+            if (!foundParentInTargets || intermediates.isEmpty()) continue;
             // Add any always-report parents along the way.
             changes.get(wc).mParent = intermediates.get(0);
             for (int j = 0; j < intermediates.size() - 1; j++) {
@@ -1655,8 +1678,6 @@
     private static class Targets {
         /** All targets. Its keys (depth) are sorted in ascending order naturally. */
         final SparseArray<WindowContainer<?>> mArray = new SparseArray<>();
-        /** The initial participants which have changes. */
-        final ArrayList<WindowContainer<?>> mValidParticipants = new ArrayList<>();
         /** The targets which were represented by their parent. */
         private ArrayList<WindowContainer<?>> mRemovedTargets;
         private int mDepthFactor;
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 8840cd5..23479a2 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -99,9 +99,6 @@
     // TODO(b/188595497): remove when not needed.
     final StatusBarManagerInternal mStatusBar;
 
-    /** Pending transitions from Shell that are waiting the SyncEngine to be free. */
-    private final ArrayList<PendingStartTransition> mPendingTransitions = new ArrayList<>();
-
     TransitionController(ActivityTaskManagerService atm,
             TaskSnapshotController taskSnapshotController) {
         mAtm = atm;
@@ -146,7 +143,7 @@
     }
 
     /** Starts Collecting */
-    private void moveToCollecting(@NonNull Transition transition) {
+    void moveToCollecting(@NonNull Transition transition) {
         if (mCollectingTransition != null) {
             throw new IllegalStateException("Simultaneous transition collection not supported.");
         }
@@ -160,26 +157,6 @@
         dispatchLegacyAppTransitionPending();
     }
 
-    /** Creates a transition representation but doesn't start collecting. */
-    @NonNull
-    PendingStartTransition createPendingTransition(@WindowManager.TransitionType int type) {
-        if (mTransitionPlayer == null) {
-            throw new IllegalStateException("Shell Transitions not enabled");
-        }
-        final PendingStartTransition out = new PendingStartTransition(new Transition(type,
-                0 /* flags */, this, mAtm.mWindowManager.mSyncEngine));
-        mPendingTransitions.add(out);
-        // We want to start collecting immediately when the engine is free, otherwise it may
-        // be busy again.
-        out.setStartSync(() -> {
-            mPendingTransitions.remove(out);
-            moveToCollecting(out.mTransition);
-        });
-        ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Creating PendingTransition: %s",
-                out.mTransition);
-        return out;
-    }
-
     void registerTransitionPlayer(@Nullable ITransitionPlayer player,
             @Nullable IApplicationThread appThread) {
         try {
@@ -243,9 +220,13 @@
         return isCollecting() || isPlaying();
     }
 
-    /** @return {@code true} if wc is in a participant subtree */
+    /** @return {@code true} if a transition is running in a participant subtree of wc */
     boolean inTransition(@NonNull WindowContainer wc) {
-        if (isCollecting(wc)) return true;
+        if (isCollecting()) {
+            for (WindowContainer p = wc; p != null; p = p.getParent()) {
+                if (isCollecting(p)) return true;
+            }
+        }
         for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) {
             for (WindowContainer p = wc; p != null; p = p.getParent()) {
                 if (mPlayingTransitions.get(i).mParticipants.contains(p)) {
@@ -597,24 +578,16 @@
         if (!mPlayingTransitions.isEmpty()) {
             state = LEGACY_STATE_RUNNING;
         } else if ((mCollectingTransition != null && mCollectingTransition.getLegacyIsReady())
-                || !mPendingTransitions.isEmpty()) {
-            // The transition may not be "ready", but we have transition waiting to start, so it
-            // can't be IDLE for test purpose. Ideally, we should have a STATE_COLLECTING.
+                || mAtm.mWindowManager.mSyncEngine.hasPendingSyncSets()) {
+            // The transition may not be "ready", but we have a sync-transaction waiting to start.
+            // Usually the pending transaction is for a transition, so assuming that is the case,
+            // we can't be IDLE for test purposes. Ideally, we should have a STATE_COLLECTING.
             state = LEGACY_STATE_READY;
         }
         proto.write(AppTransitionProto.APP_TRANSITION_STATE, state);
         proto.end(token);
     }
 
-    /** Represents a startTransition call made while there is other active BLAST SyncGroup. */
-    class PendingStartTransition extends WindowOrganizerController.PendingTransaction {
-        final Transition mTransition;
-
-        PendingStartTransition(Transition transition) {
-            mTransition = transition;
-        }
-    }
-
     static class TransitionMetricsReporter extends ITransitionMetricsReporter.Stub {
         private final ArrayMap<IBinder, LongConsumer> mMetricConsumers = new ArrayMap<>();
 
diff --git a/services/core/java/com/android/server/wm/WindowAnimationSpec.java b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
index 5bfd546..b6d668d 100644
--- a/services/core/java/com/android/server/wm/WindowAnimationSpec.java
+++ b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
@@ -21,6 +21,7 @@
 import static com.android.server.wm.WindowAnimationSpecProto.ANIMATION;
 import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_NONE;
 
+import android.graphics.Insets;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.SystemClock;
@@ -75,6 +76,11 @@
     }
 
     @Override
+    public WindowAnimationSpec asWindowAnimationSpec() {
+        return this;
+    }
+
+    @Override
     public boolean getShowWallpaper() {
         return mAnimation.getShowWallpaper();
     }
@@ -89,11 +95,27 @@
         return mAnimation.getBackgroundColor();
     }
 
+    /**
+     * @return If a window animation has outsets applied to it.
+     * @see Animation#hasExtension()
+     */
+    public boolean hasExtension() {
+        return mAnimation.hasExtension();
+    }
+
     @Override
     public long getDuration() {
         return mAnimation.computeDurationHint();
     }
 
+    public Rect getRootTaskBounds() {
+        return mRootTaskBounds;
+    }
+
+    public Animation getAnimation() {
+        return mAnimation;
+    }
+
     @Override
     public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
         final TmpValues tmp = mThreadLocalTmps.get();
@@ -106,7 +128,9 @@
         boolean cropSet = false;
         if (mRootTaskClipMode == ROOT_TASK_CLIP_NONE) {
             if (tmp.transformation.hasClipRect()) {
-                t.setWindowCrop(leash, tmp.transformation.getClipRect());
+                final Rect clipRect = tmp.transformation.getClipRect();
+                accountForExtension(tmp.transformation, clipRect);
+                t.setWindowCrop(leash, clipRect);
                 cropSet = true;
             }
         } else {
@@ -114,6 +138,7 @@
             if (tmp.transformation.hasClipRect()) {
                 mTmpRect.intersect(tmp.transformation.getClipRect());
             }
+            accountForExtension(tmp.transformation, mTmpRect);
             t.setWindowCrop(leash, mTmpRect);
             cropSet = true;
         }
@@ -125,6 +150,14 @@
         }
     }
 
+    private void accountForExtension(Transformation transformation, Rect clipRect) {
+        Insets extensionInsets = Insets.min(transformation.getInsets(), Insets.NONE);
+        if (!extensionInsets.equals(Insets.NONE)) {
+            // Extend the surface to allow for the edge extension to be visible
+            clipRect.inset(extensionInsets);
+        }
+    }
+
     @Override
     public long calculateStatusBarTransitionStartTime() {
         TranslateAnimation openTranslateAnimation = findTranslateAnimation(mAnimation);
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index dab02de..99e39f1 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -33,6 +33,7 @@
 import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
 import static android.view.WindowManager.TRANSIT_CHANGE;
 
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
@@ -47,7 +48,6 @@
 import static com.android.server.wm.IdentifierProto.USER_ID;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
@@ -59,10 +59,8 @@
 import static com.android.server.wm.WindowContainerProto.SURFACE_CONTROL;
 import static com.android.server.wm.WindowContainerProto.VISIBLE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowManagerService.logWithStack;
 import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_AFTER_ANIM;
 
 import android.annotation.CallSuper;
@@ -107,6 +105,7 @@
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.ColorUtils;
+import com.android.internal.protolog.ProtoLogImpl;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.ToBooleanFunction;
 import com.android.server.wm.SurfaceAnimator.Animatable;
@@ -1175,21 +1174,17 @@
         return mTransitionController.inTransition(this);
     }
 
-    boolean inAppOrRecentsTransition() {
+    boolean isExitAnimationRunningSelfOrChild() {
         if (!mTransitionController.isShellTransitionsEnabled()) {
-            return isAnimating(PARENTS | TRANSITION,
-                    ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS);
+            return isAnimating(TRANSITION | CHILDREN, WindowState.EXIT_ANIMATING_TYPES);
         }
-        for (WindowContainer p = this; p != null; p = p.getParent()) {
-            if (mTransitionController.isCollecting(p)) {
-                return true;
-            }
+        if (mTransitionController.isCollecting(this)) {
+            return true;
         }
-        if (inTransition() || mTransitionController.inRecentsTransition(this)) return true;
 
         for (int i = mChildren.size() - 1; i >= 0; --i) {
             WindowContainer child = mChildren.get(i);
-            if (child.inAppOrRecentsTransition()) {
+            if (child.isExitAnimationRunningSelfOrChild()) {
                 return true;
             }
         }
@@ -2731,9 +2726,8 @@
             @Nullable OnAnimationFinishedCallback animationFinishedCallback,
             @Nullable Runnable animationCancelledCallback,
             @Nullable AnimationAdapter snapshotAnim) {
-        if (DEBUG_ANIM) {
-            Slog.v(TAG, "Starting animation on " + this + ": type=" + type + ", anim=" + anim);
-        }
+        ProtoLog.v(WM_DEBUG_ANIM, "Starting animation on %s: type=%d, anim=%s",
+                this, type, anim);
 
         // TODO: This should use isVisible() but because isVisible has a really weird meaning at
         // the moment this doesn't work for all animatable window containers.
@@ -3102,9 +3096,9 @@
                 // ActivityOption#makeCustomAnimation or WindowManager#overridePendingTransition.
                 a.restrictDuration(MAX_APP_TRANSITION_DURATION);
             }
-            if (DEBUG_ANIM) {
-                logWithStack(TAG, "Loaded animation " + a + " for " + this
-                        + ", duration: " + ((a != null) ? a.getDuration() : 0));
+            if (ProtoLogImpl.isEnabled(WM_DEBUG_ANIM)) {
+                ProtoLog.i(WM_DEBUG_ANIM, "Loaded animation %s for %s, duration: %d, stack=%s",
+                        a, this, ((a != null) ? a.getDuration() : 0), Debug.getCallers(20));
             }
             final int containingWidth = frame.width();
             final int containingHeight = frame.height();
@@ -3876,7 +3870,8 @@
         try {
             overlay.getRemoteInterface().onConfigurationChanged(getConfiguration());
         } catch (Exception e) {
-            Slog.e(TAG, "Error sending initial configuration change to WindowContainer overlay");
+            ProtoLog.e(WM_DEBUG_ANIM,
+                    "Error sending initial configuration change to WindowContainer overlay");
             removeTrustedOverlay(overlay);
         }
     }
diff --git a/services/core/java/com/android/server/wm/WindowManagerConstants.java b/services/core/java/com/android/server/wm/WindowManagerConstants.java
index bdbcd16..1931be4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerConstants.java
+++ b/services/core/java/com/android/server/wm/WindowManagerConstants.java
@@ -91,12 +91,6 @@
         updateSystemGestureExcludedByPreQStickyImmersive();
     }
 
-    @VisibleForTesting
-    void dispose() {
-        mDeviceConfig.removeOnPropertiesChangedListener(mListenerAndroid);
-        mDeviceConfig.removeOnPropertiesChangedListener(mListenerWindowManager);
-    }
-
     private void onAndroidPropertiesChanged(DeviceConfig.Properties properties) {
         synchronized (mGlobalLock) {
             boolean updateSystemGestureExclusionLimit = false;
diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
index c954700..42b556f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
@@ -34,7 +34,6 @@
     static final String TAG_WM = "WindowManager";
 
     static final boolean DEBUG = false;
-    static final boolean DEBUG_ANIM = false;
     static final boolean DEBUG_LAYOUT = false;
     static final boolean DEBUG_LAYERS = false;
     static final boolean DEBUG_INPUT = false;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 6718235..92864b6 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -89,7 +89,6 @@
 import static android.view.WindowManager.TRANSIT_NONE;
 import static android.view.WindowManager.TRANSIT_RELAUNCH;
 import static android.view.WindowManagerGlobal.ADD_OKAY;
-import static android.view.WindowManagerGlobal.RELAYOUT_RES_BLAST_SYNC;
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID;
 import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_MULTIPLIER;
@@ -98,6 +97,7 @@
 import static android.window.WindowProviderService.isWindowProviderService;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BOOT;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
@@ -119,7 +119,6 @@
 import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL;
 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
-import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
@@ -745,6 +744,9 @@
 
     private final DisplayHashController mDisplayHashController;
 
+    volatile float mMaximumObscuringOpacityForTouch =
+            InputManager.DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH;
+
     @VisibleForTesting
     final WindowContextListenerController mWindowContextListenerController =
             new WindowContextListenerController();
@@ -782,6 +784,8 @@
                 DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR);
         private final Uri mDisplaySettingsPathUri = Settings.Global.getUriFor(
                 DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH);
+        private final Uri mMaximumObscuringOpacityForTouchUri = Settings.Global.getUriFor(
+                Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH);
 
         public SettingsObserver() {
             super(new Handler());
@@ -806,6 +810,8 @@
                     UserHandle.USER_ALL);
             resolver.registerContentObserver(mDisplaySettingsPathUri, false, this,
                     UserHandle.USER_ALL);
+            resolver.registerContentObserver(mMaximumObscuringOpacityForTouchUri, false, this,
+                    UserHandle.USER_ALL);
         }
 
         @Override
@@ -849,6 +855,11 @@
                 return;
             }
 
+            if (mMaximumObscuringOpacityForTouchUri.equals(uri)) {
+                updateMaximumObscuringOpacityForTouch();
+                return;
+            }
+
             @UpdateAnimationScaleMode
             final int mode;
             if (mWindowAnimationScaleUri.equals(uri)) {
@@ -868,6 +879,14 @@
         void loadSettings() {
             updateSystemUiSettings(false /* handleChange */);
             updatePointerLocation();
+            updateMaximumObscuringOpacityForTouch();
+        }
+
+        void updateMaximumObscuringOpacityForTouch() {
+            ContentResolver resolver = mContext.getContentResolver();
+            mMaximumObscuringOpacityForTouch = Settings.Global.getFloat(resolver,
+                    Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH,
+                    InputManager.DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH);
         }
 
         void updateSystemUiSettings(boolean handleChange) {
@@ -2138,6 +2157,7 @@
                         w.mGivenTouchableRegion.scale(w.mGlobalScale);
                     }
                     w.setDisplayLayoutNeeded();
+                    w.updateSourceFrame(w.getFrame());
                     mWindowPlacerLocked.performSurfacePlacement();
                     w.getDisplayContent().getInputMonitor().updateInputWindowsLw(true);
 
@@ -2192,7 +2212,7 @@
             int requestedWidth, int requestedHeight, int viewVisibility, int flags,
             ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
             SurfaceControl outSurfaceControl, InsetsState outInsetsState,
-            InsetsSourceControl[] outActiveControls) {
+            InsetsSourceControl[] outActiveControls, Bundle outSyncIdBundle) {
         Arrays.fill(outActiveControls, null);
         int result = 0;
         boolean configChanged;
@@ -2483,19 +2503,20 @@
             ProtoLog.v(WM_DEBUG_FOCUS, "Relayout of %s: focusMayChange=%b",
                     win, focusMayChange);
 
-            result |= mInTouchMode ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0;
-
             if (DEBUG_LAYOUT) {
                 Slog.v(TAG_WM, "Relayout complete " + win + ": outFrames=" + outFrames);
             }
             win.mInRelayout = false;
 
             if (mUseBLASTSync && win.useBLASTSync() && viewVisibility != View.GONE
-                    && win.mNextRelayoutUseSync) {
+                    && (win.mSyncSeqId > win.mLastSeqIdSentToRelayout)) {
                 win.prepareDrawHandlers();
                 win.markRedrawForSyncReported();
-                win.mNextRelayoutUseSync = false;
-                result |= RELAYOUT_RES_BLAST_SYNC;
+
+                win.mLastSeqIdSentToRelayout = win.mSyncSeqId;
+                outSyncIdBundle.putInt("seqid", win.mSyncSeqId);
+            } else {
+                outSyncIdBundle.putInt("seqid", -1);
             }
 
             if (configChanged) {
@@ -2540,17 +2561,19 @@
             transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
         }
 
+        String reason = null;
         if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
+            reason = "applyAnimation";
             focusMayChange = true;
             win.mAnimatingExit = true;
-        } else if (win.mDisplayContent.okToAnimate() && win.isAnimating(TRANSITION | PARENTS,
-                WindowState.EXIT_ANIMATING_TYPES)) {
+        } else if (win.mDisplayContent.okToAnimate() && win.isExitAnimationRunningSelfOrParent()) {
             // Currently in a hide animation... turn this into
             // an exit.
             win.mAnimatingExit = true;
         } else if (win.mDisplayContent.okToAnimate()
                 && win.mDisplayContent.mWallpaperController.isWallpaperTarget(win)
                 && win.mAttrs.type != TYPE_NOTIFICATION_SHADE) {
+            reason = "isWallpaperTarget";
             // If the wallpaper is currently behind this app window, we need to change both of them
             // inside of a transaction to avoid artifacts.
             // For NotificationShade, sysui is in charge of running window animation and it updates
@@ -2566,6 +2589,10 @@
             win.mDestroying = true;
             win.destroySurface(false, stopped);
         }
+        if (reason != null) {
+            ProtoLog.d(WM_DEBUG_ANIM, "Set animatingExit: reason=startExitingAnimation/%s win=%s",
+                    reason, win);
+        }
         if (mAccessibilityController.hasCallbacks()) {
             mAccessibilityController.onWindowTransition(win, transit);
         }
@@ -2600,6 +2627,19 @@
         return result;
     }
 
+    int updateViewVisibility(Session session, IWindow client, LayoutParams attrs,
+            int viewVisibility, MergedConfiguration outMergedConfiguration,
+            SurfaceControl outSurfaceControl, InsetsState outInsetsState,
+            InsetsSourceControl[] outActiveControls) {
+        // TODO(b/161810301): Finish the implementation.
+        return 0;
+    }
+
+    void updateWindowLayout(Session session, IWindow client, LayoutParams attrs, int flags,
+            ClientWindowFrames clientWindowFrames, int requestedWidth, int requestedHeight) {
+        // TODO(b/161810301): Finish the implementation.
+    }
+
     public boolean outOfMemoryWindow(Session session, IWindow client) {
         final long origId = Binder.clearCallingIdentity();
 
@@ -2617,7 +2657,7 @@
     }
 
     void finishDrawingWindow(Session session, IWindow client,
-            @Nullable SurfaceControl.Transaction postDrawTransaction) {
+            @Nullable SurfaceControl.Transaction postDrawTransaction, int seqId) {
         if (postDrawTransaction != null) {
             postDrawTransaction.sanitize();
         }
@@ -2628,7 +2668,7 @@
                 WindowState win = windowForClientLocked(session, client, false);
                 ProtoLog.d(WM_DEBUG_ADD_REMOVE, "finishDrawingWindow: %s mDrawState=%s",
                         win, (win != null ? win.mWinAnimator.drawStateToString() : "null"));
-                if (win != null && win.finishDrawing(postDrawTransaction)) {
+                if (win != null && win.finishDrawing(postDrawTransaction, seqId)) {
                     if (win.hasWallpaper()) {
                         win.getDisplayContent().pendingLayoutChanges |=
                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
@@ -3262,7 +3302,7 @@
         mContext.enforceCallingOrSelfPermission(
                 Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE,
                 Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE
-                        + " permission required to read keyguard visibility");
+                        + " permission required to subscribe to keyguard locked state changes");
     }
 
     private void dispatchKeyguardLockedState() {
@@ -3741,7 +3781,8 @@
      * Sets the touch mode state.
      *
      * To be able to change touch mode state, the caller must either own the focused window, or must
-     * have the MODIFY_TOUCH_MODE_STATE permission. Instrumented processes are allowed to switch
+     * have the {@link android.Manifest.permission#MODIFY_TOUCH_MODE_STATE} permission. Instrumented
+     * process, sourced with {@link android.Manifest.permission#MODIFY_TOUCH_MODE_STATE}, may switch
      * touch mode at any time.
      *
      * @param mode the touch mode to set
@@ -3754,9 +3795,10 @@
             }
             final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
-
-            final boolean hasPermission = mAtmService.isInstrumenting(pid)
-                    || checkCallingPermission(MODIFY_TOUCH_MODE_STATE, "setInTouchMode()");
+            final boolean hasPermission =
+                    mAtmService.instrumentationSourceHasPermission(pid, MODIFY_TOUCH_MODE_STATE)
+                            || checkCallingPermission(MODIFY_TOUCH_MODE_STATE, "setInTouchMode()",
+                                                      /* printlog= */ false);
             final long token = Binder.clearCallingIdentity();
             try {
                 if (mInputManager.setInTouchMode(mode, pid, uid, hasPermission)) {
@@ -9003,13 +9045,18 @@
         }
 
         TaskSnapshot taskSnapshot;
-        synchronized (mGlobalLock) {
-            Task task = mRoot.anyTaskForId(taskId, MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
-            if (task == null) {
-                throw new IllegalArgumentException(
-                        "Failed to find matching task for taskId=" + taskId);
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                Task task = mRoot.anyTaskForId(taskId, MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
+                if (task == null) {
+                    throw new IllegalArgumentException(
+                            "Failed to find matching task for taskId=" + taskId);
+                }
+                taskSnapshot = mTaskSnapshotController.captureTaskSnapshot(task, false);
             }
-            taskSnapshot = mTaskSnapshotController.captureTaskSnapshot(task, false);
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
 
         if (taskSnapshot == null || taskSnapshot.getHardwareBuffer() == null) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 1cf4c1b..5a2f28f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -566,9 +566,14 @@
         try (ZipOutputStream out = new ZipOutputStream(getRawOutputStream())) {
             ArrayList<Pair<String, ByteTransferPipe>> requestList = new ArrayList<>();
             synchronized (mInternal.mGlobalLock) {
+                final RecentTasks recentTasks = mInternal.mAtmService.getRecentTasks();
+                final int recentsComponentUid = recentTasks != null
+                        ? recentTasks.getRecentsComponentUid()
+                        : -1;
                 // Request dump from all windows parallelly before writing to disk.
                 mInternal.mRoot.forAllWindows(w -> {
-                    if (w.isVisible()) {
+                    final boolean isRecents = (w.getUid() == recentsComponentUid);
+                    if (w.isVisible() || isRecents) {
                         ByteTransferPipe pipe = null;
                         try {
                             pipe = new ByteTransferPipe();
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 81344ac..b5cf708 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -19,8 +19,6 @@
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
 import static android.app.ActivityManager.isStartResultSuccessful;
 import static android.view.Display.DEFAULT_DISPLAY;
-import static android.window.WindowContainerTransaction.Change.CHANGE_BOUNDS_TRANSACTION;
-import static android.window.WindowContainerTransaction.Change.CHANGE_BOUNDS_TRANSACTION_RECT;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
@@ -94,13 +92,14 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.function.IntSupplier;
 
 /**
  * Server side implementation for the interface for organizing windows
  * @see android.window.WindowOrganizer
  */
 class WindowOrganizerController extends IWindowOrganizerController.Stub
-        implements BLASTSyncEngine.TransactionReadyListener, BLASTSyncEngine.SyncEngineListener {
+        implements BLASTSyncEngine.TransactionReadyListener {
 
     private static final String TAG = "WindowOrganizerController";
 
@@ -123,21 +122,6 @@
     private final HashMap<Integer, IWindowContainerTransactionCallback>
             mTransactionCallbacksByPendingSyncId = new HashMap();
 
-    /**
-     * A queue of transaction waiting for their turn to sync. Currently {@link BLASTSyncEngine} only
-     * supports 1 sync at a time, so we have to queue them.
-     *
-     * WMCore has enough information to ensure that it won't end up collecting multiple transitions
-     * in parallel by itself; however, Shell can start transitions/apply sync transaction at
-     * arbitrary times via {@link WindowOrganizerController#startTransition} and
-     * {@link WindowOrganizerController#applySyncTransaction}, so we have to support those coming in
-     * at any time (even while already syncing).
-     *
-     * This is really just a back-up for unrealistic situations (eg. during tests). In practice,
-     * this shouldn't ever happen.
-     */
-    private final ArrayList<PendingTransaction> mPendingTransactions = new ArrayList<>();
-
     final TaskOrganizerController mTaskOrganizerController;
     final DisplayAreaOrganizerController mDisplayAreaOrganizerController;
     final TaskFragmentOrganizerController mTaskFragmentOrganizerController;
@@ -161,7 +145,6 @@
     void setWindowManager(WindowManagerService wms) {
         mTransitionController = new TransitionController(mService, wms.mTaskSnapshotController);
         mTransitionController.registerLegacyListener(wms.mActivityManagerAppTransitionNotifier);
-        wms.mSyncEngine.setSyncEngineListener(this);
     }
 
     TransitionController getTransitionController() {
@@ -232,16 +215,12 @@
                 } else {
                     // Because the BLAST engine only supports one sync at a time, queue the
                     // transaction.
-                    final PendingTransaction pt = new PendingTransaction();
-                    // Start sync group immediately when the SyncEngine is free.
-                    pt.setStartSync(() ->
-                            mService.mWindowManager.mSyncEngine.startSyncSet(syncGroup));
-                    // Those will be post so that it won't interrupt ongoing transition.
-                    pt.setStartTransaction(() -> {
-                        applyTransaction(t, syncId, null /*transition*/, caller);
-                        setSyncReady(syncId);
-                    });
-                    mPendingTransactions.add(pt);
+                    mService.mWindowManager.mSyncEngine.queueSyncSet(
+                            () -> mService.mWindowManager.mSyncEngine.startSyncSet(syncGroup),
+                            () -> {
+                                applyTransaction(t, syncId, null /*transition*/, caller);
+                                setSyncReady(syncId);
+                            });
                 }
                 return syncId;
             }
@@ -284,19 +263,24 @@
                     // transition starts collecting. This should almost never happen except during
                     // tests.
                     if (mService.mWindowManager.mSyncEngine.hasActiveSync()) {
-                        Slog.e(TAG, "startTransition() while one is already collecting.");
-                        final TransitionController.PendingStartTransition pt =
-                                mTransitionController.createPendingTransition(type);
-                        // Those will be post so that it won't interrupt ongoing transition.
-                        pt.setStartTransaction(() -> {
-                            pt.mTransition.start();
-                            applyTransaction(wct, -1 /*syncId*/, pt.mTransition, caller);
-                            if (needsSetReady) {
-                                pt.mTransition.setAllReady();
-                            }
-                        });
-                        mPendingTransactions.add(pt);
-                        return pt.mTransition;
+                        Slog.w(TAG, "startTransition() while one is already collecting.");
+                        final Transition nextTransition = new Transition(type, 0 /* flags */,
+                                mTransitionController, mService.mWindowManager.mSyncEngine);
+                        ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+                                "Creating Pending Transition: %s", nextTransition);
+                        mService.mWindowManager.mSyncEngine.queueSyncSet(
+                                // Make sure to collect immediately to prevent another transition
+                                // from sneaking in before it. Note: moveToCollecting internally
+                                // calls startSyncSet.
+                                () -> mTransitionController.moveToCollecting(nextTransition),
+                                () -> {
+                                    nextTransition.start();
+                                    applyTransaction(wct, -1 /*syncId*/, nextTransition, caller);
+                                    if (needsSetReady) {
+                                        nextTransition.setAllReady();
+                                    }
+                                });
+                        return nextTransition;
                     }
                     transition = mTransitionController.createTransition(type);
                 }
@@ -427,6 +411,14 @@
                 }
                 if (transition != null) transition.collect(wc);
 
+                if (finishTransition != null) {
+                    // Deal with edge-cases in recents where it pretends to finish itself.
+                    if ((entry.getValue().getChangeMask()
+                            & WindowContainerTransaction.Change.CHANGE_FORCE_NO_PIP) != 0) {
+                        finishTransition.setCanPipOnFinish(false /* canPipOnFinish */);
+                    }
+                }
+
                 int containerEffect = applyWindowContainerChange(wc, entry.getValue());
                 effects |= containerEffect;
 
@@ -680,7 +672,7 @@
                         break;
                     }
                 }
-                effects |= deleteTaskFragment(taskFragment, errorCallbackToken);
+                effects |= deleteTaskFragment(taskFragment, organizer, errorCallbackToken);
                 break;
             }
             case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT: {
@@ -698,8 +690,7 @@
                         .startActivityInTaskFragment(tf, activityIntent, activityOptions,
                                 hop.getCallingActivity(), caller.mUid, caller.mPid);
                 if (!isStartResultSuccessful(result)) {
-                    sendTaskFragmentOperationFailure(tf.getTaskFragmentOrganizer(),
-                            errorCallbackToken,
+                    sendTaskFragmentOperationFailure(organizer, errorCallbackToken,
                             convertStartFailureToThrowable(result, activityIntent));
                 } else {
                     effects |= TRANSACT_EFFECTS_LIFECYCLE;
@@ -709,13 +700,20 @@
             case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT: {
                 final IBinder fragmentToken = hop.getNewParent();
                 final ActivityRecord activity = ActivityRecord.forTokenLocked(hop.getContainer());
-                if (!mLaunchTaskFragments.containsKey(fragmentToken) || activity == null) {
+                final TaskFragment parent = mLaunchTaskFragments.get(fragmentToken);
+                if (parent == null || activity == null) {
                     final Throwable exception = new IllegalArgumentException(
                             "Not allowed to operate with invalid fragment token or activity.");
                     sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
                     break;
                 }
-                activity.reparent(mLaunchTaskFragments.get(fragmentToken), POSITION_TOP);
+                if (!parent.isAllowedToEmbedActivity(activity)) {
+                    final Throwable exception = new SecurityException(
+                            "The task fragment is not trusted to embed the given activity.");
+                    sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
+                    break;
+                }
+                activity.reparent(parent, POSITION_TOP);
                 effects |= TRANSACT_EFFECTS_LIFECYCLE;
                 break;
             }
@@ -810,26 +808,8 @@
                 launchOpts.remove(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
                 final SafeActivityOptions safeOptions =
                         SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid);
-                final Integer[] starterResult = {null};
-                // startActivityFromRecents should not be called in lock.
-                mService.mH.post(() -> {
-                    try {
-                        starterResult[0] = mService.mTaskSupervisor.startActivityFromRecents(
-                                caller.mPid, caller.mUid, taskId, safeOptions);
-                    } catch (Throwable t) {
-                        starterResult[0] = ActivityManager.START_CANCELED;
-                        Slog.w(TAG, t);
-                    }
-                    synchronized (mGlobalLock) {
-                        mGlobalLock.notifyAll();
-                    }
-                });
-                while (starterResult[0] == null) {
-                    try {
-                        mGlobalLock.wait();
-                    } catch (InterruptedException ignored) {
-                    }
-                }
+                waitAsyncStart(() -> mService.mTaskSupervisor.startActivityFromRecents(
+                        caller.mPid, caller.mUid, taskId, safeOptions));
                 break;
             }
             case HIERARCHY_OP_TYPE_PENDING_INTENT: {
@@ -838,22 +818,22 @@
                         mService.mContext.getContentResolver())
                         : null;
 
-                Bundle options = null;
+                ActivityOptions activityOptions = null;
                 if (hop.getPendingIntent().isActivity()) {
                     // Set the context display id as preferred for this activity launches, so that
                     // it can land on caller's display. Or just brought the task to front at the
                     // display where it was on since it has higher preference.
-                    ActivityOptions activityOptions = hop.getLaunchOptions() != null
+                    activityOptions = hop.getLaunchOptions() != null
                             ? new ActivityOptions(hop.getLaunchOptions())
                             : ActivityOptions.makeBasic();
                     activityOptions.setCallerDisplayId(DEFAULT_DISPLAY);
-                    options = activityOptions.toBundle();
                 }
-
-                mService.mAmInternal.sendIntentSender(hop.getPendingIntent().getTarget(),
+                final Bundle options = activityOptions != null ? activityOptions.toBundle() : null;
+                waitAsyncStart(() -> mService.mAmInternal.sendIntentSender(
+                        hop.getPendingIntent().getTarget(),
                         hop.getPendingIntent().getWhitelistToken(), 0 /* code */,
                         hop.getActivityIntent(), resolvedType, null /* finishReceiver */,
-                        null /* requiredPermission */, options);
+                        null /* requiredPermission */, options));
                 break;
             }
             case HIERARCHY_OP_TYPE_START_SHORTCUT: {
@@ -877,12 +857,14 @@
                 final WindowContainer newParent = hop.getNewParent() != null
                         ? WindowContainer.fromBinder(hop.getNewParent())
                         : null;
-                if (oldParent == null || !oldParent.isAttached()) {
+                if (oldParent == null || oldParent.asTaskFragment() == null
+                        || !oldParent.isAttached()) {
                     Slog.e(TAG, "Attempt to operate on unknown or detached container: "
                             + oldParent);
                     break;
                 }
-                reparentTaskFragment(oldParent, newParent, errorCallbackToken);
+                reparentTaskFragment(oldParent.asTaskFragment(), newParent, organizer,
+                        errorCallbackToken);
                 effects |= TRANSACT_EFFECTS_LIFECYCLE;
                 break;
             }
@@ -914,6 +896,31 @@
         return effects;
     }
 
+    /**
+     * Post and wait for the result of the activity start to prevent potential deadlock against
+     * {@link WindowManagerGlobalLock}.
+     */
+    private void waitAsyncStart(IntSupplier startActivity) {
+        final Integer[] starterResult = {null};
+        mService.mH.post(() -> {
+            try {
+                starterResult[0] = startActivity.getAsInt();
+            } catch (Throwable t) {
+                starterResult[0] = ActivityManager.START_CANCELED;
+                Slog.w(TAG, t);
+            }
+            synchronized (mGlobalLock) {
+                mGlobalLock.notifyAll();
+            }
+        });
+        while (starterResult[0] == null) {
+            try {
+                mGlobalLock.wait();
+            } catch (InterruptedException ignored) {
+            }
+        }
+    }
+
     private int sanitizeAndApplyHierarchyOp(WindowContainer container,
             WindowContainerTransaction.HierarchyOp hop) {
         final Task task = container.asTask();
@@ -1176,23 +1183,6 @@
     }
 
     @Override
-    public void onSyncEngineFree() {
-        if (mPendingTransactions.isEmpty()) {
-            return;
-        }
-
-        ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "PendingStartTransaction found");
-        final PendingTransaction pt = mPendingTransactions.remove(0);
-        pt.startSync();
-        // Post this so that the now-playing transition setup isn't interrupted.
-        mService.mH.post(() -> {
-            synchronized (mGlobalLock) {
-                pt.startTransaction();
-            }
-        });
-    }
-
-    @Override
     public void registerTransitionPlayer(ITransitionPlayer player) {
         enforceTaskPermission("registerTransitionPlayer()");
         final int callerPid = Binder.getCallingPid();
@@ -1238,7 +1228,7 @@
         mService.enforceTaskPermission(func);
     }
 
-    private void enforceTaskPermission(String func, WindowContainerTransaction t) {
+    private void enforceTaskPermission(String func, @Nullable WindowContainerTransaction t) {
         if (t == null || t.getTaskFragmentOrganizer() == null) {
             enforceTaskPermission(func);
             return;
@@ -1263,14 +1253,11 @@
         while (entries.hasNext()) {
             final Map.Entry<IBinder, WindowContainerTransaction.Change> entry = entries.next();
             // Only allow to apply changes to TaskFragment that is created by this organizer.
-            WindowContainer wc = WindowContainer.fromBinder(entry.getKey());
+            final WindowContainer wc = WindowContainer.fromBinder(entry.getKey());
             enforceTaskFragmentOrganized(func, wc, organizer);
             enforceTaskFragmentConfigChangeAllowed(func, wc, entry.getValue(), organizer);
         }
 
-        // TODO(b/197364677): Enforce safety of hierarchy operations in untrusted mode. E.g. one
-        // could first change a trusted TF, and then start/reparent untrusted activity there.
-
         // Hierarchy changes
         final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps();
         for (int i = hops.size() - 1; i >= 0; i--) {
@@ -1344,8 +1331,6 @@
      * Makes sure that SurfaceControl transactions and the ability to set bounds outside of the
      * parent bounds are not allowed for embedding without full trust between the host and the
      * target.
-     * TODO(b/197364677): Allow SC transactions when the client-driven animations are protected from
-     * tapjacking.
      */
     private void enforceTaskFragmentConfigChangeAllowed(String func, @Nullable WindowContainer wc,
             WindowContainerTransaction.Change change, ITaskFragmentOrganizer organizer) {
@@ -1353,35 +1338,48 @@
             Slog.e(TAG, "Attempt to operate on task fragment that no longer exists");
             return;
         }
-        // Check if TaskFragment is embedded in fully trusted mode
-        if (wc.asTaskFragment().isAllowedToBeEmbeddedInTrustedMode()) {
-            // Fully trusted, no need to check further
-            return;
-        }
-
         if (change == null) {
             return;
         }
         final int changeMask = change.getChangeMask();
-        if ((changeMask & (CHANGE_BOUNDS_TRANSACTION | CHANGE_BOUNDS_TRANSACTION_RECT)) != 0) {
+        if (changeMask != 0) {
+            // None of the change should be requested from a TaskFragment organizer.
             String msg = "Permission Denial: " + func + " from pid="
                     + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
-                    + " trying to apply SurfaceControl changes to TaskFragment in non-trusted "
-                    + "embedding mode, TaskFragmentOrganizer=" + organizer;
+                    + " trying to apply changes of " + changeMask + " to TaskFragment"
+                    + " TaskFragmentOrganizer=" + organizer;
+            Slog.w(TAG, msg);
+            throw new SecurityException(msg);
+        }
+        // Check if TaskFragment is embedded in fully trusted mode.
+        if (wc.asTaskFragment().isAllowedToBeEmbeddedInTrustedMode()) {
+            // Fully trusted, no need to check further
+            return;
+        }
+        final WindowContainer wcParent = wc.getParent();
+        if (wcParent == null) {
+            Slog.e(TAG, "Attempt to apply config change on task fragment that has no parent");
+            return;
+        }
+        final Configuration requestedConfig = change.getConfiguration();
+        final Configuration parentConfig = wcParent.getConfiguration();
+        if (parentConfig.screenWidthDp < requestedConfig.screenWidthDp
+                || parentConfig.screenHeightDp < requestedConfig.screenHeightDp
+                || parentConfig.smallestScreenWidthDp < requestedConfig.smallestScreenWidthDp) {
+            String msg = "Permission Denial: " + func + " from pid="
+                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+                    + " trying to apply screen width/height greater than parent's for non-trusted"
+                    + " host, TaskFragmentOrganizer=" + organizer;
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
         if (change.getWindowSetMask() == 0) {
-            // Nothing else to check.
+            // No bounds change.
             return;
         }
-        WindowConfiguration requestedWindowConfig = change.getConfiguration().windowConfiguration;
-        WindowContainer wcParent = wc.getParent();
-        if (wcParent == null) {
-            Slog.e(TAG, "Attempt to set bounds on task fragment that has no parent");
-            return;
-        }
-        if (!wcParent.getBounds().contains(requestedWindowConfig.getBounds())) {
+        final WindowConfiguration requestedWindowConfig = requestedConfig.windowConfiguration;
+        final WindowConfiguration parentWindowConfig = parentConfig.windowConfiguration;
+        if (!parentWindowConfig.getBounds().contains(requestedWindowConfig.getBounds())) {
             String msg = "Permission Denial: " + func + " from pid="
                     + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
                     + " trying to apply bounds outside of parent for non-trusted host,"
@@ -1389,6 +1387,17 @@
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
+        if (requestedWindowConfig.getAppBounds() != null
+                && parentWindowConfig.getAppBounds() != null
+                && !parentWindowConfig.getAppBounds().contains(
+                        requestedWindowConfig.getAppBounds())) {
+            String msg = "Permission Denial: " + func + " from pid="
+                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+                    + " trying to apply app bounds outside of parent for non-trusted host,"
+                    + " TaskFragmentOrganizer=" + organizer;
+            Slog.w(TAG, msg);
+            throw new SecurityException(msg);
+        }
     }
 
     void createTaskFragment(@NonNull TaskFragmentCreationParams creationParams,
@@ -1414,7 +1423,7 @@
         if (ownerActivity.getTask().effectiveUid != ownerActivity.getUid()
                 || ownerActivity.getTask().effectiveUid != caller.mUid) {
             final Throwable exception =
-                    new IllegalArgumentException("Not allowed to operate with the ownerToken while "
+                    new SecurityException("Not allowed to operate with the ownerToken while "
                             + "the root activity of the target task belong to the different app");
             sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
             return;
@@ -1431,33 +1440,46 @@
         mLaunchTaskFragments.put(creationParams.getFragmentToken(), taskFragment);
     }
 
-    void reparentTaskFragment(@NonNull WindowContainer oldParent,
-            @Nullable WindowContainer newParent,  @Nullable IBinder errorCallbackToken) {
-        WindowContainer parent = newParent;
-        if (parent == null && oldParent.asTaskFragment() != null) {
-            parent = oldParent.asTaskFragment().getTask();
+    void reparentTaskFragment(@NonNull TaskFragment oldParent, @Nullable WindowContainer newParent,
+            @Nullable ITaskFragmentOrganizer organizer, @Nullable IBinder errorCallbackToken) {
+        final TaskFragment newParentTF;
+        if (newParent == null) {
+            // Use the old parent's parent if the caller doesn't specify the new parent.
+            newParentTF = oldParent.getTask();
+        } else {
+            newParentTF = newParent.asTaskFragment();
         }
-        if (parent == null) {
+        if (newParentTF == null) {
             final Throwable exception =
                     new IllegalArgumentException("Not allowed to operate with invalid container");
-            sendTaskFragmentOperationFailure(oldParent.asTaskFragment().getTaskFragmentOrganizer(),
-                    errorCallbackToken, exception);
+            sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
             return;
         }
+        if (newParentTF.getTaskFragmentOrganizer() != null) {
+            // We are reparenting activities to a new embedded TaskFragment, this operation is only
+            // allowed if the new parent is trusted by all reparent activities.
+            final boolean isEmbeddingDisallowed = oldParent.forAllActivities(activity ->
+                    !newParentTF.isAllowedToEmbedActivity(activity));
+            if (isEmbeddingDisallowed) {
+                final Throwable exception = new SecurityException(
+                        "The new parent is not trusted to embed the activities.");
+                sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
+                return;
+            }
+        }
         while (oldParent.hasChild()) {
-            oldParent.getChildAt(0).reparent(parent, POSITION_TOP);
+            oldParent.getChildAt(0).reparent(newParentTF, POSITION_TOP);
         }
     }
 
     private int deleteTaskFragment(@NonNull TaskFragment taskFragment,
-            @Nullable IBinder errorCallbackToken) {
+            @Nullable ITaskFragmentOrganizer organizer, @Nullable IBinder errorCallbackToken) {
         final int index = mLaunchTaskFragments.indexOfValue(taskFragment);
         if (index < 0) {
             final Throwable exception =
                     new IllegalArgumentException("Not allowed to operate with invalid "
                             + "taskFragment");
-            sendTaskFragmentOperationFailure(taskFragment.getTaskFragmentOrganizer(),
-                    errorCallbackToken, exception);
+            sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
             return 0;
         }
         mLaunchTaskFragments.removeAt(index);
@@ -1470,6 +1492,10 @@
         return mLaunchTaskFragments.get(tfToken);
     }
 
+    void cleanUpEmbeddedTaskFragment(TaskFragment taskFragment) {
+        mLaunchTaskFragments.remove(taskFragment.getFragmentToken());
+    }
+
     static class CallerInfo {
         final int mPid;
         final int mUid;
@@ -1505,38 +1531,4 @@
                         + result + " when starting " + intent);
         }
     }
-
-    /**
-     *  Represents a sync {@link WindowContainerTransaction} call made while there is other active
-     *  {@link BLASTSyncEngine.SyncGroup}.
-     */
-    static class PendingTransaction {
-        private Runnable mStartSync;
-        private Runnable mStartTransaction;
-
-        /**
-         * The callback will be called immediately when the {@link BLASTSyncEngine} is free. One
-         * should call {@link BLASTSyncEngine#startSyncSet(BLASTSyncEngine.SyncGroup)} here to
-         * reserve the {@link BLASTSyncEngine}.
-         */
-        void setStartSync(@NonNull Runnable callback) {
-            mStartSync = callback;
-        }
-
-        /**
-         * The callback will be post to the main handler after the {@link BLASTSyncEngine} is free
-         * to apply the pending {@link WindowContainerTransaction}.
-         */
-        void setStartTransaction(@NonNull Runnable callback) {
-            mStartTransaction = callback;
-        }
-
-        private void startSync() {
-            mStartSync.run();
-        }
-
-        private void startTransaction() {
-            mStartTransaction.run();
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index db687f6..b20781f 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -37,6 +37,9 @@
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
+import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
+import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
+import static android.view.WindowCallbacks.RESIZE_MODE_INVALID;
 import static android.view.WindowInsets.Type.systemBars;
 import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
 import static android.view.WindowLayout.UNSPECIFIED_LENGTH;
@@ -98,13 +101,12 @@
 import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
-import static android.view.WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_DOCKED;
-import static android.view.WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_FREEFORM;
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME;
 import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_MULTIPLIER;
 import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BACK_PREVIEW;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
@@ -134,14 +136,13 @@
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_STARTING_REVEAL;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
+import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowContainerChildProto.WINDOW;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_POWER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
@@ -251,6 +252,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.policy.KeyInterceptionInfo;
+import com.android.internal.protolog.ProtoLogImpl;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.ToBooleanFunction;
@@ -261,6 +263,7 @@
 import dalvik.annotation.optimization.NeverCompile;
 
 import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -368,7 +371,8 @@
     private boolean mDragResizingChangeReported = true;
     private int mResizeMode;
     private boolean mRedrawForSyncReported;
-    boolean mNextRelayoutUseSync;
+    int mSyncSeqId = 0;
+    int mLastSeqIdSentToRelayout = 0;
 
     /**
      * {@code true} when the client was still drawing for sync when the sync-set was finished or
@@ -859,6 +863,7 @@
     /**
      * @see #setOnBackInvokedCallback(IOnBackInvokedCallback)
      */
+    // TODO(b/224856664): Consolidate application and system callback into one.
     private IOnBackInvokedCallback mApplicationOnBackInvokedCallback;
     private IOnBackInvokedCallback mSystemOnBackInvokedCallback;
 
@@ -1124,7 +1129,9 @@
                 this, onBackInvokedCallback);
         if (priority >= 0) {
             mApplicationOnBackInvokedCallback = onBackInvokedCallback;
+            mSystemOnBackInvokedCallback = null;
         } else {
+            mApplicationOnBackInvokedCallback = null;
             mSystemOnBackInvokedCallback = onBackInvokedCallback;
         }
     }
@@ -1393,15 +1400,19 @@
     }
 
     // TODO(b/161810301): Make the frame be passed from the client side.
-    void setFrame() {
-        // TODO(b/161810301): Set the window frame here. We don't have to do it now because
-        //                    DisplayPolicy has already done it for the window.
-
+    void setFrames(ClientWindowFrames clientWindowFrames) {
         mHaveFrame = true;
 
         final WindowFrames windowFrames = mWindowFrames;
+        mTmpRect.set(windowFrames.mParentFrame);
+        windowFrames.mDisplayFrame.set(clientWindowFrames.displayFrame);
+        windowFrames.mParentFrame.set(clientWindowFrames.parentFrame);
+        windowFrames.mFrame.set(clientWindowFrames.frame);
+        windowFrames.setParentFrameWasClippedByDisplayCutout(
+                clientWindowFrames.isParentFrameClippedByDisplayCutout);
 
-        if (mRequestedWidth != mLastRequestedWidth || mRequestedHeight != mLastRequestedHeight) {
+        if (mRequestedWidth != mLastRequestedWidth || mRequestedHeight != mLastRequestedHeight
+                || !mTmpRect.equals(windowFrames.mParentFrame)) {
             mLastRequestedWidth = mRequestedWidth;
             mLastRequestedHeight = mRequestedHeight;
             windowFrames.setContentChanged(true);
@@ -1430,16 +1441,6 @@
         windowFrames.mRelFrame.offsetTo(windowFrames.mFrame.left - parentLeft,
                 windowFrames.mFrame.top - parentTop);
 
-        if (DEBUG_LAYOUT || DEBUG) {
-            final int pw = windowFrames.mParentFrame.width();
-            final int ph = windowFrames.mParentFrame.height();
-            Slog.v(TAG, "Resolving (mRequestedWidth="
-                    + mRequestedWidth + ", mRequestedheight="
-                    + mRequestedHeight + ") to" + " (pw=" + pw + ", ph=" + ph
-                    + "): frame=" + windowFrames.mFrame.toShortString()
-                    + " " + mAttrs.getTitle());
-        }
-
         if (mAttrs.type == TYPE_DOCK_DIVIDER) {
             if (!windowFrames.mFrame.equals(windowFrames.mLastFrame)) {
                 mMovedByResize = true;
@@ -1454,9 +1455,19 @@
             }
         }
 
-        // Update the source frame to provide insets to other windows during layout.
-        if (mControllableInsetProvider != null) {
-            mControllableInsetProvider.updateSourceFrame();
+        updateSourceFrame(windowFrames.mFrame);
+    }
+
+    void updateSourceFrame(Rect winFrame) {
+        if (mGivenInsetsPending) {
+            // The given insets are pending, and they are not reliable for now. The source frame
+            // should be updated after the new given insets are sent to window manager.
+            return;
+        }
+        final SparseArray<InsetsSource> providedSources = getProvidedInsetsSources();
+        final InsetsStateController controller = getDisplayContent().getInsetsStateController();
+        for (int i = providedSources.size() - 1; i >= 0; i--) {
+            controller.getSourceProvider(providedSources.keyAt(i)).updateSourceFrame(winFrame);
         }
     }
 
@@ -2232,6 +2243,8 @@
             // Mark all relevant flags for that onExitAnimationDone will proceed all the way
             // to actually remove it.
             if (!visible && isVisibleNow && mActivityRecord.isAnimating(PARENTS | TRANSITION)) {
+                ProtoLog.d(WM_DEBUG_ANIM,
+                        "Set animatingExit: reason=onAppVisibilityChanged win=%s", this);
                 mAnimatingExit = true;
                 mRemoveOnExit = true;
                 mWindowRemovalAllowed = true;
@@ -2571,6 +2584,8 @@
                     // been removed. We probably need another flag to indicate that window removal
                     // should be deffered vs. overloading the flag that says we are playing an exit
                     // animation.
+                    ProtoLog.v(WM_DEBUG_ANIM,
+                            "Set animatingExit: reason=remove/replaceWindow win=%s", this);
                     mAnimatingExit = true;
                     mReplacingRemoveRequested = true;
                     return;
@@ -2599,6 +2614,8 @@
 
                     // Try starting an animation.
                     if (mWinAnimator.applyAnimationLocked(transit, false)) {
+                        ProtoLog.v(WM_DEBUG_ANIM,
+                                "Set animatingExit: reason=remove/applyAnimation win=%s", this);
                         mAnimatingExit = true;
 
                         // mAnimatingExit affects canAffectSystemUiFlags(). Run layout such that
@@ -2610,8 +2627,7 @@
                         mWmService.mAccessibilityController.onWindowTransition(this, transit);
                     }
                 }
-                final boolean isAnimating = mAnimatingExit
-                        || isAnimating(TRANSITION | PARENTS, EXIT_ANIMATING_TYPES);
+                final boolean isAnimating = mAnimatingExit || isExitAnimationRunningSelfOrParent();
                 final boolean lastWindowIsStartingWindow = startingWindow && mActivityRecord != null
                         && mActivityRecord.isLastWindow(this);
                 // We delay the removal of a window if it has a showing surface that can be used to run
@@ -2626,6 +2642,8 @@
                     // The exit animation is running or should run... wait for it!
                     ProtoLog.v(WM_DEBUG_ADD_REMOVE,
                             "Not removing %s due to exit animation", this);
+                    ProtoLog.v(WM_DEBUG_ANIM, "Set animatingExit: reason=remove/isAnimating win=%s",
+                            this);
                     setupWindowForRemoveOnExit();
                     if (mActivityRecord != null) {
                         mActivityRecord.updateReportedVisibilityLocked();
@@ -3585,6 +3603,7 @@
         // Clear animating flags now, since the surface is now gone. (Note this is true even
         // if the surface is saved, to outside world the surface is still NO_SURFACE.)
         mAnimatingExit = false;
+        ProtoLog.d(WM_DEBUG_ANIM, "Clear animatingExit: reason=destroySurface win=%s", this);
 
         if (useBLASTSync()) {
             immediatelyNotifyBlastSync();
@@ -3861,25 +3880,6 @@
             outFrames.displayFrame.scale(mInvGlobalScale);
         }
 
-        final Rect backdropFrame = outFrames.backdropFrame;
-        // When the task is docked, we send fullscreen sized backdropFrame as soon as resizing
-        // start even if we haven't received the relayout window, so that the client requests
-        // the relayout sooner. When dragging stops, backdropFrame needs to stay fullscreen
-        // until the window to small size, otherwise the multithread renderer will shift last
-        // one or more frame to wrong offset. So here we send fullscreen backdrop if either
-        // isDragResizing() or isDragResizeChanged() is true.
-        final boolean resizing = isDragResizing() || isDragResizeChanged();
-        if (!resizing || getWindowConfiguration().useWindowFrameForBackdrop()) {
-            // Surface position is now inherited from parent, and BackdropFrameRenderer uses
-            // backdrop frame to position content. Thus we just keep the size of backdrop frame,
-            // and remove the offset to avoid double offset from display origin.
-            backdropFrame.set(outFrames.frame);
-            backdropFrame.offsetTo(0, 0);
-        } else {
-            final DisplayInfo displayInfo = getDisplayInfo();
-            backdropFrame.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
-        }
-
         // Note: in the cases where the window is tied to an activity, we should not send a
         // configuration update when the window has requested to be hidden. Doing so can lead to
         // the client erroneously accepting a configuration that would have otherwise caused an
@@ -3936,17 +3936,34 @@
                 true /* useLatestConfig */, false /* relayoutVisible */);
         final boolean syncRedraw = shouldSendRedrawForSync();
         final boolean reportDraw = syncRedraw || drawPending;
-        final boolean forceRelayout = syncRedraw || reportOrientation || isDragResizeChanged();
+        final boolean isDragResizeChanged = isDragResizeChanged();
+        final boolean forceRelayout = syncRedraw || reportOrientation || isDragResizeChanged;
         final DisplayContent displayContent = getDisplayContent();
         final boolean alwaysConsumeSystemBars =
                 displayContent.getDisplayPolicy().areSystemBarsForcedShownLw();
         final int displayId = displayContent.getDisplayId();
 
+        if (isDragResizeChanged) {
+            setDragResizing();
+        }
+        int resizeMode = RESIZE_MODE_INVALID;
+        if (isDragResizing()) {
+            switch (getResizeMode()) {
+                case DRAG_RESIZE_MODE_FREEFORM:
+                    resizeMode = RESIZE_MODE_FREEFORM;
+                    break;
+                case DRAG_RESIZE_MODE_DOCKED_DIVIDER:
+                    resizeMode = RESIZE_MODE_DOCKED_DIVIDER;
+                    break;
+            }
+        }
+
         markRedrawForSyncReported();
 
         try {
             mClient.resized(mClientWindowFrames, reportDraw, mLastReportedConfiguration,
-                    forceRelayout, alwaysConsumeSystemBars, displayId);
+                    forceRelayout, alwaysConsumeSystemBars, displayId, mSyncSeqId, resizeMode);
+
             if (drawPending && reportOrientation && mOrientationChanging) {
                 mOrientationChangeRedrawRequestTime = SystemClock.elapsedRealtime();
                 ProtoLog.v(WM_DEBUG_ORIENTATION,
@@ -4657,8 +4674,7 @@
 
         // Force the show in the next prepareSurfaceLocked() call.
         mWinAnimator.mLastAlpha = -1;
-        if (DEBUG_ANIM) Slog.v(TAG,
-                "performShowLocked: mDrawState=HAS_DRAWN in " + this);
+        ProtoLog.v(WM_DEBUG_ANIM, "performShowLocked: mDrawState=HAS_DRAWN in %s", this);
         mWinAnimator.mDrawState = HAS_DRAWN;
         mWmService.scheduleAnimationLocked();
 
@@ -4977,6 +4993,27 @@
         return false;
     }
 
+    boolean isExitAnimationRunningSelfOrParent() {
+        return inTransitionSelfOrParent()
+                || isAnimating(0 /* flags */, ANIMATION_TYPE_WINDOW_ANIMATION);
+    }
+
+    boolean isExitAnimationRunningSelfOrChild() {
+        return isAnimating(CHILDREN, ANIMATION_TYPE_WINDOW_ANIMATION);
+    }
+
+    /**
+     * @return {@code true} if self or the parent container of the window is in transition.
+     * (e.g. The app or recents transition)
+     */
+    boolean inTransitionSelfOrParent() {
+        if (!mTransitionController.isShellTransitionsEnabled()) {
+            return isAnimating(PARENTS | TRANSITION,
+                    ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS);
+        }
+        return mTransitionController.inTransition(this);
+    }
+
     private boolean shouldFinishAnimatingExit() {
         // Exit animation might be applied soon.
         if (inTransition()) {
@@ -4988,7 +5025,7 @@
             return true;
         }
         // Exit animation is running.
-        if (isAnimating(TRANSITION | PARENTS, EXIT_ANIMATING_TYPES)) {
+        if (isExitAnimationRunningSelfOrParent()) {
             ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "shouldWaitAnimatingExit: isAnimating: %s",
                     this);
             return false;
@@ -5020,9 +5057,17 @@
     }
 
     void onExitAnimationDone() {
-        if (DEBUG_ANIM) Slog.v(TAG, "onExitAnimationDone in " + this
-                + ": exiting=" + mAnimatingExit + " remove=" + mRemoveOnExit
-                + " selfAnimating=" + isAnimating());
+        if (ProtoLogImpl.isEnabled(WM_DEBUG_ANIM)) {
+            final AnimationAdapter animationAdapter = mSurfaceAnimator.getAnimation();
+            StringWriter sw = new StringWriter();
+            if (animationAdapter != null) {
+                PrintWriter pw = new PrintWriter(sw);
+                animationAdapter.dump(pw, "");
+            }
+            ProtoLog.v(WM_DEBUG_ANIM, "onExitAnimationDone in %s"
+                            + ": exiting=%b remove=%b selfAnimating=%b anim=%s",
+                    this, mAnimatingExit, mRemoveOnExit, isAnimating(), sw);
+        }
 
         if (!mChildren.isEmpty()) {
             // Copying to a different list as multiple children can be removed.
@@ -5076,12 +5121,13 @@
             }
         }
         mAnimatingExit = false;
+        ProtoLog.d(WM_DEBUG_ANIM, "Clear animatingExit: reason=exitAnimationDone win=%s", this);
         getDisplayContent().mWallpaperController.hideWallpapers(this);
     }
 
     @Override
     boolean handleCompleteDeferredRemoval() {
-        if (mRemoveOnExit && !isSelfAnimating(0 /* flags */, EXIT_ANIMATING_TYPES)) {
+        if (mRemoveOnExit && !isSelfAnimating(0 /* flags */, ANIMATION_TYPE_WINDOW_ANIMATION)) {
             mRemoveOnExit = false;
             removeImmediately();
         }
@@ -5107,6 +5153,8 @@
             // show up with wrong position or scale.
             if (mAnimatingExit) {
                 mAnimatingExit = false;
+                ProtoLog.d(WM_DEBUG_ANIM, "Clear animatingExit: reason=clearAnimatingFlags win=%s",
+                        this);
                 didSomething = true;
             }
             if (mDestroying) {
@@ -5181,6 +5229,8 @@
                 cancelAnimation();
             }
             mAnimatingExit = false;
+            ProtoLog.d(WM_DEBUG_ANIM, "Clear animatingExit: reason=relayoutVisibleWindow win=%s",
+                    this);
         }
         if (mDestroying) {
             mDestroying = false;
@@ -5201,15 +5251,6 @@
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
 
-        if (isDragResizeChanged()) {
-            setDragResizing();
-        }
-        final boolean freeformResizing = isDragResizing()
-                && getResizeMode() == DRAG_RESIZE_MODE_FREEFORM;
-        final boolean dockedResizing = isDragResizing()
-                && getResizeMode() == DRAG_RESIZE_MODE_DOCKED_DIVIDER;
-        result |= freeformResizing ? RELAYOUT_RES_DRAG_RESIZING_FREEFORM : 0;
-        result |= dockedResizing ? RELAYOUT_RES_DRAG_RESIZING_DOCKED : 0;
         return result;
     }
 
@@ -5247,6 +5288,12 @@
         if (mControllableInsetProvider != null) {
             return;
         }
+        if (getDisplayContent().inTransition()) {
+            // Skip because the animation is usually unnoticeable (e.g. covered by rotation
+            // animation) and the animation bounds could be inconsistent, such as depending
+            // on when the window applies its draw transaction with new rotation.
+            return;
+        }
 
         final DisplayInfo displayInfo = getDisplayInfo();
         anim.initialize(mWindowFrames.mFrame.width(), mWindowFrames.mFrame.height(),
@@ -5268,7 +5315,7 @@
             return;
         }
 
-        if (DEBUG_ANIM) Slog.v(TAG, "Setting move animation on " + this);
+        ProtoLog.v(WM_DEBUG_ANIM, "Setting move animation on %s", this);
         final Point oldPosition = new Point();
         final Point newPosition = new Point();
         transformFrameToSurfacePosition(mWindowFrames.mLastFrame.left, mWindowFrames.mLastFrame.top,
@@ -5491,10 +5538,8 @@
         }
         float newHScale = mHScale * mGlobalScale * mWallpaperScale;
         float newVScale = mVScale * mGlobalScale * mWallpaperScale;
-        if (mLastHScale != newHScale ||
-            mLastVScale != newVScale ) {
-            getPendingTransaction().setMatrix(getSurfaceControl(),
-                newHScale, 0, 0, newVScale);
+        if (mLastHScale != newHScale || mLastVScale != newVScale) {
+            getSyncTransaction().setMatrix(mSurfaceControl, newHScale, 0, 0, newVScale);
             mLastHScale = newHScale;
             mLastVScale = newVScale;
         }
@@ -5914,7 +5959,7 @@
         // to draw even if the children draw first or don't need to sync, so we start
         // in WAITING state rather than READY.
         mSyncState = SYNC_STATE_WAITING_FOR_DRAW;
-        mNextRelayoutUseSync = true;
+        mSyncSeqId++;
         requestRedrawForSync();
         return true;
     }
@@ -5938,7 +5983,7 @@
         super.finishSync(outMergedTransaction, cancel);
     }
 
-    boolean finishDrawing(SurfaceControl.Transaction postDrawTransaction) {
+    boolean finishDrawing(SurfaceControl.Transaction postDrawTransaction, int syncSeqId) {
         if (mOrientationChangeRedrawRequestTime > 0) {
             final long duration =
                     SystemClock.elapsedRealtime() - mOrientationChangeRedrawRequestTime;
@@ -5985,7 +6030,7 @@
 
     void immediatelyNotifyBlastSync() {
         prepareDrawHandlers();
-        finishDrawing(null);
+        finishDrawing(null, Integer.MAX_VALUE);
         mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this);
         if (!useBLASTSync()) return;
     }
@@ -6057,7 +6102,7 @@
      */
     void applyWithNextDraw(Consumer<SurfaceControl.Transaction> consumer) {
         mPendingDrawHandlers.add(consumer);
-        mNextRelayoutUseSync = true;
+        mSyncSeqId++;
         requestRedrawForSync();
 
         mWmService.mH.sendNewMessageDelayed(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this,
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 285a6d5..5c0557f 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -23,6 +23,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.TRANSIT_OLD_NONE;
 
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_DRAW;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
@@ -34,7 +35,6 @@
 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
@@ -60,6 +60,7 @@
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 
+import com.android.internal.protolog.ProtoLogImpl;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.server.policy.WindowManagerPolicy;
 
@@ -178,10 +179,9 @@
 
     void onAnimationFinished() {
         // Done animating, clean up.
-        if (DEBUG_ANIM) Slog.v(
-                TAG, "Animation done in " + this + ": exiting=" + mWin.mAnimatingExit
-                        + ", reportedVisible="
-                        + (mWin.mActivityRecord != null && mWin.mActivityRecord.reportedVisible));
+        ProtoLog.v(WM_DEBUG_ANIM, "Animation done in %s: exiting=%b, reportedVisible=%b",
+                this, mWin.mAnimatingExit,
+                (mWin.mActivityRecord != null && mWin.mActivityRecord.reportedVisible));
 
         mWin.checkPolicyVisibilityChange();
         final DisplayContent displayContent = mWin.getDisplayContent();
@@ -264,9 +264,8 @@
         if (mDrawState != COMMIT_DRAW_PENDING && mDrawState != READY_TO_SHOW) {
             return false;
         }
-        if (DEBUG_ANIM) {
-            Slog.i(TAG, "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW " + mSurfaceController);
-        }
+        ProtoLog.i(WM_DEBUG_ANIM, "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW %s",
+                mSurfaceController);
         mDrawState = READY_TO_SHOW;
         boolean result = false;
         final ActivityRecord activity = mWin.mActivityRecord;
@@ -298,9 +297,7 @@
 
         w.setHasSurface(false);
 
-        if (DEBUG_ANIM) {
-            Slog.i(TAG, "createSurface " + this + ": mDrawState=DRAW_PENDING");
-        }
+        ProtoLog.i(WM_DEBUG_ANIM, "createSurface %s: mDrawState=DRAW_PENDING", this);
 
         resetDrawState();
 
@@ -503,8 +500,8 @@
                 }
             }
         } else {
-            if (DEBUG_ANIM && mWin.isAnimating(TRANSITION | PARENTS)) {
-                Slog.v(TAG, "prepareSurface: No changes in animation for " + this);
+            if (mWin.isAnimating(TRANSITION | PARENTS)) {
+                ProtoLog.v(WM_DEBUG_ANIM, "prepareSurface: No changes in animation for %s", this);
             }
         }
 
@@ -646,15 +643,12 @@
                             mWin.mAttrs, attr, TRANSIT_OLD_NONE);
                 }
             }
-            if (DEBUG_ANIM) Slog.v(TAG,
-                    "applyAnimation: win=" + this
-                    + " anim=" + anim + " attr=0x" + Integer.toHexString(attr)
-                    + " a=" + a
-                    + " transit=" + transit
-                    + " type=" + mAttrType
-                    + " isEntrance=" + isEntrance + " Callers " + Debug.getCallers(3));
+            if (ProtoLogImpl.isEnabled(WM_DEBUG_ANIM)) {
+                ProtoLog.v(WM_DEBUG_ANIM, "applyAnimation: win=%s"
+                        + " anim=%d attr=0x%x a=%s transit=%d type=%d isEntrance=%b Callers %s",
+                        this, anim, attr, a, transit, mAttrType, isEntrance, Debug.getCallers(20));
+            }
             if (a != null) {
-                if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + this);
                 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "WSA#startAnimation");
                 mWin.startAnimation(a);
                 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
diff --git a/services/core/jni/gnss/MeasurementCorrections.cpp b/services/core/jni/gnss/MeasurementCorrections.cpp
index 8a3d84c..07d0a45 100644
--- a/services/core/jni/gnss/MeasurementCorrections.cpp
+++ b/services/core/jni/gnss/MeasurementCorrections.cpp
@@ -44,6 +44,7 @@
 using ReflectingPlane_V1_0 =
         android::hardware::gnss::measurement_corrections::V1_0::ReflectingPlane;
 using ReflectingPlane_Aidl = android::hardware::gnss::measurement_corrections::ReflectingPlane;
+using ExcessPathInfo = SingleSatCorrection_Aidl::ExcessPathInfo;
 using GnssConstellationType_V1_0 = android::hardware::gnss::V1_0::GnssConstellationType;
 using GnssConstellationType_V2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
 using GnssConstellationType_Aidl = android::hardware::gnss::GnssConstellationType;
@@ -62,7 +63,7 @@
 jmethodID method_correctionsGetEnvironmentBearingDegrees;
 jmethodID method_correctionsGetEnvironmentBearingUncertaintyDegrees;
 jmethodID method_listSize;
-jmethodID method_correctionListGet;
+jmethodID method_listGet;
 jmethodID method_correctionSatFlags;
 jmethodID method_correctionSatConstType;
 jmethodID method_correctionSatId;
@@ -71,10 +72,17 @@
 jmethodID method_correctionSatEpl;
 jmethodID method_correctionSatEplUnc;
 jmethodID method_correctionSatRefPlane;
+jmethodID method_correctionSatAttenuation;
+jmethodID method_correctionSatExcessPathInfoList;
 jmethodID method_correctionPlaneLatDeg;
 jmethodID method_correctionPlaneLngDeg;
 jmethodID method_correctionPlaneAltDeg;
 jmethodID method_correctionPlaneAzimDeg;
+jmethodID method_excessPathInfoFlags;
+jmethodID method_excessPathInfoEpl;
+jmethodID method_excessPathInfoEplUnc;
+jmethodID method_excessPathInfoRefPlane;
+jmethodID method_excessPathInfoAttenuation;
 } // anonymous namespace
 
 void MeasurementCorrections_class_init_once(JNIEnv* env, jclass clazz) {
@@ -103,7 +111,7 @@
 
     jclass corrListClass = env->FindClass("java/util/List");
     method_listSize = env->GetMethodID(corrListClass, "size", "()I");
-    method_correctionListGet = env->GetMethodID(corrListClass, "get", "(I)Ljava/lang/Object;");
+    method_listGet = env->GetMethodID(corrListClass, "get", "(I)Ljava/lang/Object;");
 
     jclass singleSatCorrClass = env->FindClass("android/location/GnssSingleSatCorrection");
     method_correctionSatFlags =
@@ -121,12 +129,27 @@
             env->GetMethodID(singleSatCorrClass, "getExcessPathLengthUncertaintyMeters", "()F");
     method_correctionSatRefPlane = env->GetMethodID(singleSatCorrClass, "getReflectingPlane",
                                                     "()Landroid/location/GnssReflectingPlane;");
+    method_correctionSatAttenuation =
+            env->GetMethodID(singleSatCorrClass, "getCombinedAttenuationDb", "()F");
+    method_correctionSatExcessPathInfoList =
+            env->GetMethodID(singleSatCorrClass, "getGnssExcessPathInfoList", "()Ljava/util/List;");
 
     jclass refPlaneClass = env->FindClass("android/location/GnssReflectingPlane");
     method_correctionPlaneLatDeg = env->GetMethodID(refPlaneClass, "getLatitudeDegrees", "()D");
     method_correctionPlaneLngDeg = env->GetMethodID(refPlaneClass, "getLongitudeDegrees", "()D");
     method_correctionPlaneAltDeg = env->GetMethodID(refPlaneClass, "getAltitudeMeters", "()D");
     method_correctionPlaneAzimDeg = env->GetMethodID(refPlaneClass, "getAzimuthDegrees", "()D");
+
+    jclass excessPathInfoClass = env->FindClass("android/location/GnssExcessPathInfo");
+    method_excessPathInfoFlags = env->GetMethodID(excessPathInfoClass, "getFlags", "()I");
+    method_excessPathInfoEpl =
+            env->GetMethodID(excessPathInfoClass, "getExcessPathLengthMeters", "()F");
+    method_excessPathInfoEplUnc =
+            env->GetMethodID(excessPathInfoClass, "getExcessPathLengthUncertaintyMeters", "()F");
+    method_excessPathInfoRefPlane = env->GetMethodID(excessPathInfoClass, "getReflectingPlane",
+                                                     "()Landroid/location/GnssReflectingPlane;");
+    method_excessPathInfoAttenuation =
+            env->GetMethodID(excessPathInfoClass, "getAttenuationDb", "()F");
 }
 
 template <>
@@ -324,7 +347,8 @@
 SingleSatCorrection_V1_0
 MeasurementCorrectionsUtil::getSingleSatCorrection_1_0_withoutConstellation(
         JNIEnv* env, jobject singleSatCorrectionObj) {
-    jint correctionFlags = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags);
+    uint16_t corrFlags = static_cast<uint16_t>(
+            env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags));
     jint satId = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatId);
     jfloat carrierFreqHz =
             env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatCarrierFreq);
@@ -332,14 +356,16 @@
             env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatIsLosProb);
     jfloat eplMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl);
     jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEplUnc);
-    uint16_t corrFlags = static_cast<uint16_t>(correctionFlags);
 
     ReflectingPlane_V1_0 reflectingPlane;
-    if ((corrFlags & GnssSingleSatCorrectionFlags_V1_0::HAS_REFLECTING_PLANE) != 0)
-        MeasurementCorrectionsUtil::getReflectingPlane<ReflectingPlane_V1_0>(env,
-                                                                             singleSatCorrectionObj,
+    if ((corrFlags & GnssSingleSatCorrectionFlags_V1_0::HAS_REFLECTING_PLANE) != 0) {
+        jobject reflectingPlaneObj =
+                env->CallObjectMethod(singleSatCorrectionObj, method_correctionSatRefPlane);
+        MeasurementCorrectionsUtil::setReflectingPlane<ReflectingPlane_V1_0>(env,
+                                                                             reflectingPlaneObj,
                                                                              reflectingPlane);
-
+        env->DeleteLocalRef(reflectingPlaneObj);
+    }
     SingleSatCorrection_V1_0 singleSatCorrection = {
             .singleSatCorrectionFlags = corrFlags,
             .svid = static_cast<uint16_t>(satId),
@@ -349,13 +375,14 @@
             .excessPathLengthUncertaintyMeters = eplUncMeters,
             .reflectingPlane = reflectingPlane,
     };
-
     return singleSatCorrection;
 }
 
 SingleSatCorrection_Aidl MeasurementCorrectionsUtil::getSingleSatCorrection_Aidl(
         JNIEnv* env, jobject singleSatCorrectionObj) {
-    jint correctionFlags = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags);
+    int32_t corrFlags = static_cast<int32_t>(
+            env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags));
+    jint constType = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatConstType);
     jint satId = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatId);
     jfloat carrierFreqHz =
             env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatCarrierFreq);
@@ -363,15 +390,10 @@
             env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatIsLosProb);
     jfloat eplMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl);
     jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEplUnc);
-    int32_t corrFlags = static_cast<int32_t>(correctionFlags);
-
-    ReflectingPlane_Aidl reflectingPlane;
-    if ((corrFlags & SingleSatCorrection_Aidl::SINGLE_SAT_CORRECTION_HAS_REFLECTING_PLANE) != 0)
-        MeasurementCorrectionsUtil::getReflectingPlane<ReflectingPlane_Aidl>(env,
-                                                                             singleSatCorrectionObj,
-                                                                             reflectingPlane);
-
-    jint constType = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatConstType);
+    jfloat attenuationDb =
+            env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatAttenuation);
+    std::vector<ExcessPathInfo> excessPathInfos =
+            MeasurementCorrectionsUtil::getExcessPathInfoList(env, singleSatCorrectionObj);
 
     SingleSatCorrection_Aidl singleSatCorrection;
     singleSatCorrection.singleSatCorrectionFlags = corrFlags;
@@ -379,9 +401,10 @@
     singleSatCorrection.svid = static_cast<int32_t>(satId);
     singleSatCorrection.carrierFrequencyHz = carrierFreqHz;
     singleSatCorrection.probSatIsLos = probSatIsLos;
-    singleSatCorrection.excessPathLengthMeters = eplMeters;
-    singleSatCorrection.excessPathLengthUncertaintyMeters = eplUncMeters;
-    singleSatCorrection.reflectingPlane = reflectingPlane;
+    singleSatCorrection.combinedExcessPathLengthMeters = eplMeters;
+    singleSatCorrection.combinedExcessPathLengthUncertaintyMeters = eplUncMeters;
+    singleSatCorrection.combinedAttenuationDb = attenuationDb;
+    singleSatCorrection.excessPathInfos = excessPathInfos;
 
     return singleSatCorrection;
 }
@@ -391,8 +414,7 @@
         hardware::hidl_vec<SingleSatCorrection_V1_0>& list) {
     for (uint16_t i = 0; i < list.size(); ++i) {
         jobject singleSatCorrectionObj =
-                env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
-
+                env->CallObjectMethod(singleSatCorrectionList, method_listGet, i);
         SingleSatCorrection_V1_0 singleSatCorrection =
                 getSingleSatCorrection_1_0_withoutConstellation(env, singleSatCorrectionObj);
 
@@ -410,7 +432,7 @@
         hardware::hidl_vec<SingleSatCorrection_V1_1>& list) {
     for (uint16_t i = 0; i < list.size(); ++i) {
         jobject singleSatCorrectionObj =
-                env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
+                env->CallObjectMethod(singleSatCorrectionList, method_listGet, i);
 
         SingleSatCorrection_V1_0 singleSatCorrection_1_0 =
                 getSingleSatCorrection_1_0_withoutConstellation(env, singleSatCorrectionObj);
@@ -431,7 +453,7 @@
         JNIEnv* env, jobject singleSatCorrectionList, std::vector<SingleSatCorrection_Aidl>& list) {
     for (uint16_t i = 0; i < list.size(); ++i) {
         jobject singleSatCorrectionObj =
-                env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
+                env->CallObjectMethod(singleSatCorrectionList, method_listGet, i);
 
         SingleSatCorrection_Aidl singleSatCorrection_Aidl =
                 getSingleSatCorrection_Aidl(env, singleSatCorrectionObj);
@@ -441,4 +463,63 @@
     }
 }
 
+template <>
+void MeasurementCorrectionsUtil::setReflectingPlaneAzimuthDegrees<ReflectingPlane_V1_0>(
+        ReflectingPlane_V1_0& reflectingPlane, double azimuthDegreeRefPlane) {
+    reflectingPlane.azimuthDegrees = azimuthDegreeRefPlane;
+}
+
+template <>
+void MeasurementCorrectionsUtil::setReflectingPlaneAzimuthDegrees<ReflectingPlane_Aidl>(
+        ReflectingPlane_Aidl& reflectingPlane, double azimuthDegreeRefPlane) {
+    reflectingPlane.reflectingPlaneAzimuthDegrees = azimuthDegreeRefPlane;
+}
+
+std::vector<ExcessPathInfo> MeasurementCorrectionsUtil::getExcessPathInfoList(
+        JNIEnv* env, jobject singleSatCorrectionObj) {
+    jobject excessPathInfoListObj =
+            env->CallObjectMethod(singleSatCorrectionObj, method_correctionSatExcessPathInfoList);
+
+    int len = env->CallIntMethod(excessPathInfoListObj, method_listSize);
+    std::vector<ExcessPathInfo> list(len);
+    for (int i = 0; i < len; ++i) {
+        jobject excessPathInfoObj = env->CallObjectMethod(excessPathInfoListObj, method_listGet, i);
+        list[i] = getExcessPathInfo(env, excessPathInfoObj);
+        env->DeleteLocalRef(excessPathInfoObj);
+    }
+    env->DeleteLocalRef(excessPathInfoListObj);
+    return list;
+}
+
+ExcessPathInfo MeasurementCorrectionsUtil::getExcessPathInfo(JNIEnv* env,
+                                                             jobject excessPathInfoObj) {
+    ExcessPathInfo excessPathInfo;
+    jint flags = env->CallIntMethod(excessPathInfoObj, method_excessPathInfoFlags);
+    excessPathInfo.excessPathInfoFlags = flags;
+    if ((flags & ExcessPathInfo::EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH) != 0) {
+        jfloat epl = env->CallFloatMethod(excessPathInfoObj, method_excessPathInfoEpl);
+        excessPathInfo.excessPathLengthMeters = epl;
+    }
+    if ((flags & ExcessPathInfo::EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC) != 0) {
+        jfloat eplUnc = env->CallFloatMethod(excessPathInfoObj, method_excessPathInfoEplUnc);
+        excessPathInfo.excessPathLengthUncertaintyMeters = eplUnc;
+    }
+    if ((flags & ExcessPathInfo::EXCESS_PATH_INFO_HAS_REFLECTING_PLANE) != 0) {
+        ReflectingPlane_Aidl reflectingPlane;
+        jobject reflectingPlaneObj =
+                env->CallObjectMethod(excessPathInfoObj, method_excessPathInfoRefPlane);
+        MeasurementCorrectionsUtil::setReflectingPlane<ReflectingPlane_Aidl>(env,
+                                                                             reflectingPlaneObj,
+                                                                             reflectingPlane);
+        env->DeleteLocalRef(reflectingPlaneObj);
+        excessPathInfo.reflectingPlane = reflectingPlane;
+    }
+    if ((flags & ExcessPathInfo::EXCESS_PATH_INFO_HAS_ATTENUATION) != 0) {
+        jfloat attenuation =
+                env->CallFloatMethod(excessPathInfoObj, method_excessPathInfoAttenuation);
+        excessPathInfo.attenuationDb = attenuation;
+    }
+    return excessPathInfo;
+}
+
 } // namespace android::gnss
diff --git a/services/core/jni/gnss/MeasurementCorrections.h b/services/core/jni/gnss/MeasurementCorrections.h
index a2e6027..598ad48 100644
--- a/services/core/jni/gnss/MeasurementCorrections.h
+++ b/services/core/jni/gnss/MeasurementCorrections.h
@@ -43,7 +43,7 @@
 extern jmethodID method_correctionsGetEnvironmentBearingDegrees;
 extern jmethodID method_correctionsGetEnvironmentBearingUncertaintyDegrees;
 extern jmethodID method_listSize;
-extern jmethodID method_correctionListGet;
+extern jmethodID method_listGet;
 extern jmethodID method_correctionSatFlags;
 extern jmethodID method_correctionSatConstType;
 extern jmethodID method_correctionSatId;
@@ -52,6 +52,7 @@
 extern jmethodID method_correctionSatEpl;
 extern jmethodID method_correctionSatEplUnc;
 extern jmethodID method_correctionSatRefPlane;
+extern jmethodID method_correctionSatExcessPathInfos;
 extern jmethodID method_correctionPlaneLatDeg;
 extern jmethodID method_correctionPlaneLngDeg;
 extern jmethodID method_correctionPlaneAltDeg;
@@ -130,14 +131,20 @@
     static bool translateMeasurementCorrections(JNIEnv* env, jobject correctionsObj,
                                                 T& corrections);
     template <class T>
-    static void getReflectingPlane(JNIEnv* env, jobject singleSatCorrectionObj, T& reflectingPlane);
+    static void setReflectingPlane(JNIEnv* env, jobject reflectingPlaneObj, T& reflectingPlane);
+    template <class T>
+    static void setReflectingPlaneAzimuthDegrees(T& reflectingPlane, double azimuthDegreeRefPlane);
+
+    static std::vector<
+            android::hardware::gnss::measurement_corrections::SingleSatCorrection::ExcessPathInfo>
+    getExcessPathInfoList(JNIEnv* env, jobject correctionsObj);
+    static android::hardware::gnss::measurement_corrections::SingleSatCorrection::ExcessPathInfo
+    getExcessPathInfo(JNIEnv* env, jobject correctionsObj);
 };
 
 template <class T>
-void MeasurementCorrectionsUtil::getReflectingPlane(JNIEnv* env, jobject singleSatCorrectionObj,
+void MeasurementCorrectionsUtil::setReflectingPlane(JNIEnv* env, jobject reflectingPlaneObj,
                                                     T& reflectingPlane) {
-    jobject reflectingPlaneObj =
-            env->CallObjectMethod(singleSatCorrectionObj, method_correctionSatRefPlane);
     jdouble latitudeDegreesRefPlane =
             env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneLatDeg);
     jdouble longitudeDegreesRefPlane =
@@ -149,8 +156,7 @@
     reflectingPlane.latitudeDegrees = latitudeDegreesRefPlane;
     reflectingPlane.longitudeDegrees = longitudeDegreesRefPlane;
     reflectingPlane.altitudeMeters = altitudeDegreesRefPlane;
-    reflectingPlane.azimuthDegrees = azimuthDegreeRefPlane;
-    env->DeleteLocalRef(reflectingPlaneObj);
+    setReflectingPlaneAzimuthDegrees<T>(reflectingPlane, azimuthDegreeRefPlane);
 }
 
 } // namespace android::gnss
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 1c6a3b5..0cd9494 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -106,7 +106,6 @@
     register_android_server_HardwarePropertiesManagerService(env);
     register_android_server_storage_AppFuse(env);
     register_android_server_SyntheticPasswordManager(env);
-    register_android_graphics_GraphicsStatsService(env);
     register_android_hardware_display_DisplayViewport(env);
     register_android_server_am_CachedAppOptimizer(env);
     register_android_server_am_LowMemDetector(env);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index 2f5ab0b..48c4052 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -1227,5 +1227,12 @@
 
         pw.print("mSsidDenylist=");
         pw.println(mSsidDenylist);
+
+        if (mFactoryResetProtectionPolicy != null) {
+            pw.println("mFactoryResetProtectionPolicy:");
+            pw.increaseIndent();
+            mFactoryResetProtectionPolicy.dump(pw);
+            pw.decreaseIndent();
+        }
     }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 200b120..834f65f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -15,6 +15,7 @@
  */
 package com.android.server.devicepolicy;
 
+import android.accounts.Account;
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
 import android.app.admin.DevicePolicyDrawableResource;
@@ -30,6 +31,7 @@
 
 import com.android.server.SystemService;
 
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -138,6 +140,11 @@
         return null;
     }
 
+    public void finalizeWorkProfileProvisioning(
+            UserHandle managedProfileUser, Account migratedAccount) {
+
+    }
+
     public void provisionFullyManagedDevice(
             FullyManagedDeviceProvisioningParams provisioningParams, String callerPackage) {
     }
@@ -171,7 +178,7 @@
     public void setDrawables(@NonNull List<DevicePolicyDrawableResource> drawables){}
 
     @Override
-    public void resetDrawables(@NonNull String[] drawableIds){}
+    public void resetDrawables(@NonNull List<String> drawableIds){}
 
     @Override
     public ParcelableResource getDrawable(
@@ -183,10 +190,20 @@
     public void setStrings(@NonNull List<DevicePolicyStringResource> strings){}
 
     @Override
-    public void resetStrings(String[] stringIds){}
+    public void resetStrings(@NonNull List<String> stringIds){}
 
     @Override
     public ParcelableResource getString(String stringId) {
         return null;
     }
+
+    @Override
+    public boolean shouldAllowBypassingDevicePolicyManagementRoleQualification() {
+        return false;
+    }
+
+    @Override
+    public List<UserHandle> getPolicyManagedProfiles(UserHandle userHandle) {
+        return Collections.emptyList();
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java
index e70c071..82fe8b9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java
@@ -16,18 +16,12 @@
 
 package com.android.server.devicepolicy;
 
-import static android.app.admin.DevicePolicyResources.Drawables.Source.UPDATABLE_DRAWABLE_SOURCES;
-import static android.app.admin.DevicePolicyResources.Drawables.Style;
-import static android.app.admin.DevicePolicyResources.Drawables.Style.UPDATABLE_DRAWABLE_STYLES;
-import static android.app.admin.DevicePolicyResources.Drawables.UPDATABLE_DRAWABLE_IDS;
-import static android.app.admin.DevicePolicyResources.Strings.UPDATABLE_STRING_IDS;
-
 import static java.util.Objects.requireNonNull;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.admin.DevicePolicyDrawableResource;
-import android.app.admin.DevicePolicyResources.Drawables;
+import android.app.admin.DevicePolicyResources;
 import android.app.admin.DevicePolicyStringResource;
 import android.app.admin.ParcelableResource;
 import android.os.Environment;
@@ -113,7 +107,7 @@
             Objects.requireNonNull(drawableSource, "drawableSource must be provided.");
             Objects.requireNonNull(resource, "ParcelableResource must be provided.");
 
-            if (Drawables.Source.UNDEFINED.equals(drawableSource)) {
+            if (DevicePolicyResources.UNDEFINED.equals(drawableSource)) {
                 updated |= updateDrawable(drawableId, drawableStyle, resource);
             } else {
                 updated |= updateDrawableForSource(drawableId, drawableSource, resource);
@@ -130,12 +124,6 @@
 
     private boolean updateDrawable(
             String drawableId, String drawableStyle, ParcelableResource updatableResource) {
-        if (!UPDATABLE_DRAWABLE_IDS.contains(drawableId)) {
-            Log.w(TAG, "Updating a resource for an unknown drawable id " + drawableId);
-        }
-        if (!UPDATABLE_DRAWABLE_STYLES.contains(drawableStyle)) {
-            Log.w(TAG, "Updating a resource for an unknown style id " + drawableStyle);
-        }
         synchronized (mLock) {
             if (!mUpdatedDrawablesForStyle.containsKey(drawableId)) {
                 mUpdatedDrawablesForStyle.put(drawableId, new HashMap<>());
@@ -153,12 +141,6 @@
     // TODO(b/214576716): change this to respect style
     private boolean updateDrawableForSource(
             String drawableId, String drawableSource, ParcelableResource updatableResource) {
-        if (!UPDATABLE_DRAWABLE_IDS.contains(drawableId)) {
-            Log.w(TAG, "Updating a resource for an unknown drawable id " + drawableId);
-        }
-        if (!UPDATABLE_DRAWABLE_SOURCES.contains(drawableSource)) {
-            Log.w(TAG, "Updating a resource for an unknown source id " + drawableSource);
-        }
         synchronized (mLock) {
             if (!mUpdatedDrawablesForSource.containsKey(drawableId)) {
                 mUpdatedDrawablesForSource.put(drawableId, new HashMap<>());
@@ -176,11 +158,11 @@
     /**
      * Returns {@code false} if no resources were removed.
      */
-    boolean removeDrawables(@NonNull String[] drawableIds) {
+    boolean removeDrawables(@NonNull List<String> drawableIds) {
         synchronized (mLock) {
             boolean removed = false;
-            for (int i = 0; i < drawableIds.length; i++) {
-                String drawableId = drawableIds[i];
+            for (int i = 0; i < drawableIds.size(); i++) {
+                String drawableId = drawableIds.get(i);
                 removed |= mUpdatedDrawablesForStyle.remove(drawableId) != null
                         || mUpdatedDrawablesForSource.remove(drawableId) != null;
             }
@@ -195,31 +177,18 @@
     @Nullable
     ParcelableResource getDrawable(
             String drawableId, String drawableStyle, String drawableSource) {
-        if (!UPDATABLE_DRAWABLE_IDS.contains(drawableId)) {
-            Log.w(TAG, "Getting an updated resource for an unknown drawable id " + drawableId);
-        }
-        if (!UPDATABLE_DRAWABLE_STYLES.contains(drawableStyle)) {
-            Log.w(TAG, "Getting an updated resource for an unknown drawable style "
-                    + drawableStyle);
-        }
-        if (!UPDATABLE_DRAWABLE_SOURCES.contains(drawableSource)) {
-            Log.w(TAG, "Getting an updated resource for an unknown drawable Source "
-                    + drawableSource);
-        }
-        if (mUpdatedDrawablesForSource.containsKey(drawableId)
-                && mUpdatedDrawablesForSource.get(drawableId).containsKey(drawableSource)) {
-            return mUpdatedDrawablesForSource.get(drawableId).get(drawableSource);
-        }
-        if (!mUpdatedDrawablesForStyle.containsKey(drawableId)) {
-            Log.d(TAG, "No updated drawable found for drawable id " + drawableId);
-            return null;
-        }
-        if (mUpdatedDrawablesForStyle.get(drawableId).containsKey(drawableStyle)) {
-            return mUpdatedDrawablesForStyle.get(drawableId).get(drawableStyle);
-        }
-
-        if (mUpdatedDrawablesForStyle.get(drawableId).containsKey(Style.DEFAULT)) {
-            return mUpdatedDrawablesForStyle.get(drawableId).get(Style.DEFAULT);
+        synchronized (mLock) {
+            if (mUpdatedDrawablesForSource.containsKey(drawableId)
+                    && mUpdatedDrawablesForSource.get(drawableId).containsKey(drawableSource)) {
+                return mUpdatedDrawablesForSource.get(drawableId).get(drawableSource);
+            }
+            if (!mUpdatedDrawablesForStyle.containsKey(drawableId)) {
+                Log.d(TAG, "No updated drawable found for drawable id " + drawableId);
+                return null;
+            }
+            if (mUpdatedDrawablesForStyle.get(drawableId).containsKey(drawableStyle)) {
+                return mUpdatedDrawablesForStyle.get(drawableId).get(drawableStyle);
+            }
         }
         Log.d(TAG, "No updated drawable found for drawable id " + drawableId);
         return null;
@@ -249,9 +218,6 @@
     }
 
     private boolean updateString(String stringId, ParcelableResource updatableResource) {
-        if (!UPDATABLE_STRING_IDS.contains(stringId)) {
-            Log.w(TAG, "Updating a resource for an unknown string id " + stringId);
-        }
         synchronized (mLock) {
             ParcelableResource current = mUpdatedStrings.get(stringId);
             if (updatableResource.equals(current)) {
@@ -265,11 +231,11 @@
     /**
      * Returns {@code false} if no resources were removed.
      */
-    boolean removeStrings(@NonNull String[] stringIds) {
+    boolean removeStrings(@NonNull List<String> stringIds) {
         synchronized (mLock) {
             boolean removed = false;
-            for (int i = 0; i < stringIds.length; i++) {
-                String stringId = stringIds[i];
+            for (int i = 0; i < stringIds.size(); i++) {
+                String stringId = stringIds.get(i);
                 removed |= mUpdatedStrings.remove(stringId) != null;
             }
             if (!removed) {
@@ -282,14 +248,11 @@
 
     @Nullable
     ParcelableResource getString(String stringId) {
-        if (!UPDATABLE_STRING_IDS.contains(stringId)) {
-            Log.w(TAG, "Getting an updated resource for an unknown string id " + stringId);
+        synchronized (mLock) {
+            if (mUpdatedStrings.containsKey(stringId)) {
+                return mUpdatedStrings.get(stringId);
+            }
         }
-
-        if (mUpdatedStrings.containsKey(stringId)) {
-            return mUpdatedStrings.get(stringId);
-        }
-
         Log.d(TAG, "No updated string found for string id " + stringId);
         return null;
     }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 3d40f48..b0fe397 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -27,6 +27,7 @@
 import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE;
 import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE;
 import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
+import static android.app.admin.DevicePolicyManager.ACTION_MANAGED_PROFILE_PROVISIONED;
 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
@@ -45,6 +46,7 @@
 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
 import static android.app.admin.DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE;
 import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_IDS;
 import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE;
 import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE_DRAWABLE;
@@ -112,6 +114,8 @@
 import static android.app.admin.DevicePolicyResources.Strings.Core.NETWORK_LOGGING_MESSAGE;
 import static android.app.admin.DevicePolicyResources.Strings.Core.NETWORK_LOGGING_TITLE;
 import static android.app.admin.DevicePolicyResources.Strings.Core.NOTIFICATION_WORK_PROFILE_CONTENT_DESCRIPTION;
+import static android.app.admin.DevicePolicyResources.Strings.Core.PERSONAL_APP_SUSPENSION_MESSAGE;
+import static android.app.admin.DevicePolicyResources.Strings.Core.PERSONAL_APP_SUSPENSION_SOON_MESSAGE;
 import static android.app.admin.DevicePolicyResources.Strings.Core.PERSONAL_APP_SUSPENSION_TITLE;
 import static android.app.admin.DevicePolicyResources.Strings.Core.PERSONAL_APP_SUSPENSION_TURN_ON_PROFILE;
 import static android.app.admin.DevicePolicyResources.Strings.Core.PRINTING_DISABLED_NAMED_ADMIN;
@@ -170,7 +174,6 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.ActivityTaskManager;
-import android.app.ActivityThread;
 import android.app.AlarmManager;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
@@ -1161,7 +1164,7 @@
                             policy.mAdminList.remove(i);
                             policy.mAdminMap.remove(aa.info.getComponent());
                             pushActiveAdminPackagesLocked(userHandle);
-                            pushMeteredDisabledPackagesLocked(userHandle);
+                            pushMeteredDisabledPackages(userHandle);
                         }
                     }
                 } catch (RemoteException re) {
@@ -2122,7 +2125,7 @@
                 + "profile: %d", doUserId, poUserId);
 
         Slogf.i(LOG_TAG, "Giving the PO additional power...");
-        markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(poAdminComponent, poUserId);
+        setProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(poAdminComponent, poUserId, true);
         Slogf.i(LOG_TAG, "Migrating DO policies to PO...");
         moveDoPoliciesToProfileParentAdminLocked(doAdmin, poAdmin.getParentActiveAdmin());
         migratePersonalAppSuspensionLocked(doUserId, poUserId, poAdmin);
@@ -3568,7 +3571,7 @@
             for (int i = users.size() - 1; i >= 0; --i) {
                 final int userId = users.get(i).id;
                 mInjector.getNetworkPolicyManagerInternal().setMeteredRestrictedPackagesAsync(
-                        getMeteredDisabledPackagesLocked(userId), userId);
+                        getMeteredDisabledPackages(userId), userId);
             }
         }
     }
@@ -7028,14 +7031,13 @@
 
     private String getGenericWipeReason(
             boolean calledByProfileOwnerOnOrgOwnedDevice, boolean calledOnParentInstance) {
-        DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
         return calledByProfileOwnerOnOrgOwnedDevice && !calledOnParentInstance
-                ? dpm.getString(WORK_PROFILE_DELETED_ORG_OWNED_MESSAGE,
-                        () -> mContext.getString(
-                                R.string.device_ownership_relinquished))
-                : dpm.getString(WORK_PROFILE_DELETED_GENERIC_MESSAGE,
-                        () -> mContext.getString(
-                                R.string.work_profile_deleted_description_dpm_wipe));
+                ? getUpdatableString(
+                        WORK_PROFILE_DELETED_ORG_OWNED_MESSAGE,
+                        R.string.device_ownership_relinquished)
+                : getUpdatableString(
+                        WORK_PROFILE_DELETED_GENERIC_MESSAGE,
+                        R.string.work_profile_deleted_description_dpm_wipe);
     }
 
     /**
@@ -7131,9 +7133,7 @@
     }
 
     private String getWorkProfileDeletedTitle() {
-        DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
-        return dpm.getString(WORK_PROFILE_DELETED_TITLE,
-                () -> mContext.getString(R.string.work_profile_deleted));
+        return getUpdatableString(WORK_PROFILE_DELETED_TITLE, R.string.work_profile_deleted);
     }
 
     private void clearWipeProfileNotification() {
@@ -7233,7 +7233,7 @@
             return;
         }
         Preconditions.checkCallAuthorization(
-                hasCallingOrSelfPermission(permission.SEND_LOST_MODE_LOCATION_UPDATES));
+                hasCallingOrSelfPermission(permission.TRIGGER_LOST_MODE));
 
         synchronized (getLockObject()) {
             final ActiveAdmin admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked(
@@ -7447,10 +7447,9 @@
     }
 
     private String getFailedPasswordAttemptWipeMessage() {
-        DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
-        return dpm.getString(WORK_PROFILE_DELETED_FAILED_PASSWORD_ATTEMPTS_MESSAGE,
-                () -> mContext.getString(
-                        R.string.work_profile_deleted_reason_maximum_password_failure));
+        return getUpdatableString(
+                WORK_PROFILE_DELETED_FAILED_PASSWORD_ATTEMPTS_MESSAGE,
+               R.string.work_profile_deleted_reason_maximum_password_failure);
     }
 
     /**
@@ -12270,7 +12269,7 @@
                         + " only profile owner or device owner may control the preferential"
                         + " network service");
         synchronized (getLockObject()) {
-            final ActiveAdmin requiredAdmin = getProfileOwnerAdminLocked(
+            final ActiveAdmin requiredAdmin = getDeviceOrProfileOwnerAdminLocked(
                     caller.getUserId());
             if (!requiredAdmin.mPreferentialNetworkServiceConfigs.equals(
                     preferentialNetworkServiceConfigs)) {
@@ -12300,7 +12299,8 @@
                         + " only profile owner or device owner may retrieve the preferential"
                         + " network service configurations");
         synchronized (getLockObject()) {
-            final ActiveAdmin requiredAdmin = getProfileOwnerAdminLocked(caller.getUserId());
+            final ActiveAdmin requiredAdmin = getDeviceOrProfileOwnerAdminLocked(
+                    caller.getUserId());
             return requiredAdmin.mPreferentialNetworkServiceConfigs;
         }
     }
@@ -12647,15 +12647,13 @@
     }
 
     private String getLocationChangedTitle() {
-        DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
-        return dpm.getString(LOCATION_CHANGED_TITLE,
-                () -> mContext.getString(R.string.location_changed_notification_title));
+        return getUpdatableString(
+                LOCATION_CHANGED_TITLE, R.string.location_changed_notification_title);
     }
 
     private String getLocationChangedText() {
-        DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
-        return dpm.getString(LOCATION_CHANGED_MESSAGE,
-                () -> mContext.getString(R.string.location_changed_notification_text));
+        return getUpdatableString(
+                LOCATION_CHANGED_MESSAGE, R.string.location_changed_notification_text);
     }
 
     @Override
@@ -13254,19 +13252,13 @@
                     Slogf.e(LOG_TAG, "appLabel is inexplicably null");
                     return null;
                 }
-                DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
-                return dpm.getString(
+                return getUpdatableString(
                         PRINTING_DISABLED_NAMED_ADMIN,
-                        () -> getDefaultPrintingDisabledMsg(appLabel),
+                        R.string.printing_disabled_by,
                         appLabel);
             }
         }
 
-        private String getDefaultPrintingDisabledMsg(CharSequence appLabel) {
-            return ((Context) ActivityThread.currentActivityThread().getSystemUiContext())
-                        .getResources().getString(R.string.printing_disabled_by, appLabel);
-        }
-
         @Override
         protected DevicePolicyCache getDevicePolicyCache() {
             return mPolicyCache;
@@ -13994,16 +13986,10 @@
                         return;
                     }
                 }
-                try {
-                    if (!isRuntimePermission(permission)) {
-                        callback.sendResult(null);
-                        return;
-                    }
-                } catch (NameNotFoundException e) {
-                    throw new RemoteException("Cannot check if " + permission
-                            + "is a runtime permission", e, false, true);
+                if (!isRuntimePermission(permission)) {
+                    callback.sendResult(null);
+                    return;
                 }
-
                 if (grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED
                         || grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED
                         || grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT) {
@@ -14116,11 +14102,15 @@
         });
     }
 
-    public boolean isRuntimePermission(String permissionName) throws NameNotFoundException {
-        final PackageManager packageManager = mInjector.getPackageManager();
-        PermissionInfo permissionInfo = packageManager.getPermissionInfo(permissionName, 0);
-        return (permissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
-                == PermissionInfo.PROTECTION_DANGEROUS;
+    private boolean isRuntimePermission(String permissionName) {
+        try {
+            final PackageManager packageManager = mInjector.getPackageManager();
+            PermissionInfo permissionInfo = packageManager.getPermissionInfo(permissionName, 0);
+            return (permissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
+                    == PermissionInfo.PROTECTION_DANGEROUS;
+        } catch (NameNotFoundException e) {
+            return false;
+        }
     }
 
     @Override
@@ -14701,7 +14691,7 @@
                 final List<String> excludedPkgs = removeInvalidPkgsForMeteredDataRestriction(
                         caller.getUserId(), packageNames);
                 admin.meteredDisabledPackages = packageNames;
-                pushMeteredDisabledPackagesLocked(caller.getUserId());
+                pushMeteredDisabledPackages(caller.getUserId());
                 saveSettingsLocked(caller.getUserId());
                 return excludedPkgs;
             });
@@ -14772,7 +14762,8 @@
     }
 
     @Override
-    public void markProfileOwnerOnOrganizationOwnedDevice(ComponentName who, int userId) {
+    public void setProfileOwnerOnOrganizationOwnedDevice(ComponentName who, int userId,
+            boolean isProfileOwnerOnOrganizationOwnedDevice) {
         if (!mHasFeature) {
             return;
         }
@@ -14804,13 +14795,14 @@
 
         // Grant access under lock.
         synchronized (getLockObject()) {
-            markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(who, userId);
+            setProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(who, userId,
+                    isProfileOwnerOnOrganizationOwnedDevice);
         }
     }
 
     @GuardedBy("getLockObject()")
-    private void markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(
-            ComponentName who, int userId) {
+    private void setProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(
+            ComponentName who, int userId, boolean isProfileOwnerOnOrganizationOwnedDevice) {
         // Make sure that the user has a profile owner and that the specified
         // component is the profile owner of that user.
         if (!isProfileOwner(who, userId)) {
@@ -14819,7 +14811,8 @@
                     who.flattenToString(), userId));
         }
 
-        Slogf.i(LOG_TAG, "Marking %s as profile owner on organization-owned device for user %d",
+        Slogf.i(LOG_TAG, "%s %s as profile owner on organization-owned device for user %d",
+                isProfileOwnerOnOrganizationOwnedDevice ? "Marking" : "Unmarking",
                 who.flattenToString(), userId);
 
         // First, set restriction on removing the profile.
@@ -14836,32 +14829,36 @@
                                 + " on user %d", parentUser.getIdentifier()));
             }
 
-            mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, true,
+            mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
+                    isProfileOwnerOnOrganizationOwnedDevice,
                     parentUser);
-            mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, true,
+            mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER,
+                    isProfileOwnerOnOrganizationOwnedDevice,
                     parentUser);
         });
 
-        // markProfileOwnerOfOrganizationOwnedDevice will trigger writing of the profile owner
+        // setProfileOwnerOfOrganizationOwnedDevice will trigger writing of the profile owner
         // data, no need to do it manually.
-        mOwners.markProfileOwnerOfOrganizationOwnedDevice(userId);
+        mOwners.setProfileOwnerOfOrganizationOwnedDevice(userId,
+                isProfileOwnerOnOrganizationOwnedDevice);
     }
 
-    private void pushMeteredDisabledPackagesLocked(int userId) {
+    private void pushMeteredDisabledPackages(int userId) {
+        wtfIfInLock();
         mInjector.getNetworkPolicyManagerInternal().setMeteredRestrictedPackages(
-                getMeteredDisabledPackagesLocked(userId), userId);
+                getMeteredDisabledPackages(userId), userId);
     }
 
-    private Set<String> getMeteredDisabledPackagesLocked(int userId) {
-        final ComponentName who = getOwnerComponent(userId);
-        final Set<String> restrictedPkgs = new ArraySet<>();
-        if (who != null) {
-            final ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userId);
+    private Set<String> getMeteredDisabledPackages(int userId) {
+        synchronized (getLockObject()) {
+            final Set<String> restrictedPkgs = new ArraySet<>();
+            final ActiveAdmin admin = getDeviceOrProfileOwnerAdminLocked(userId);
             if (admin != null && admin.meteredDisabledPackages != null) {
                 restrictedPkgs.addAll(admin.meteredDisabledPackages);
             }
+
+            return restrictedPkgs;
         }
-        return restrictedPkgs;
     }
 
     @Override
@@ -15305,13 +15302,13 @@
                 resetGlobalProxyLocked(policy);
             }
             pushActiveAdminPackagesLocked(userHandle);
-            pushMeteredDisabledPackagesLocked(userHandle);
             saveSettingsLocked(userHandle);
             updateMaximumTimeToLockLocked(userHandle);
             policy.mRemovingAdmins.remove(adminReceiver);
 
             Slogf.i(LOG_TAG, "Device admin " + adminReceiver + " removed from user " + userHandle);
         }
+        pushMeteredDisabledPackages(userHandle);
         // The removed admin might have disabled camera, so update user
         // restrictions.
         pushUserRestrictions(userHandle);
@@ -15867,15 +15864,13 @@
     }
 
     private String getNetworkLoggingTitle() {
-        DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
-        return dpm.getString(NETWORK_LOGGING_TITLE,
-                () -> mContext.getString(R.string.network_logging_notification_title));
+        return getUpdatableString(
+                NETWORK_LOGGING_TITLE, R.string.network_logging_notification_title);
     }
 
     private String getNetworkLoggingText() {
-        DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
-        return dpm.getString(NETWORK_LOGGING_MESSAGE,
-                () -> mContext.getString(R.string.network_logging_notification_text));
+        return getUpdatableString(
+                NETWORK_LOGGING_MESSAGE, R.string.network_logging_notification_text);
     }
 
     private void handleCancelNetworkLoggingNotification() {
@@ -17462,35 +17457,31 @@
     }
 
     private String getPersonalAppSuspensionButtonText() {
-        DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
-        return dpm.getString(PERSONAL_APP_SUSPENSION_TURN_ON_PROFILE,
-                () -> mContext.getString(R.string.personal_apps_suspended_turn_profile_on));
+        return getUpdatableString(
+                PERSONAL_APP_SUSPENSION_TURN_ON_PROFILE,
+                R.string.personal_apps_suspended_turn_profile_on);
     }
 
     private String getPersonalAppSuspensionTitle() {
-        DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
-        return dpm.getString(PERSONAL_APP_SUSPENSION_TITLE,
-                () -> mContext.getString(R.string.personal_apps_suspension_title));
+        return getUpdatableString(
+                PERSONAL_APP_SUSPENSION_TITLE, R.string.personal_apps_suspension_title);
     }
 
     private String getPersonalAppSuspensionText() {
-        DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
-        return dpm.getString(PERSONAL_APP_SUSPENSION_TITLE,
-                () -> mContext.getString(R.string.personal_apps_suspension_text));
+        return getUpdatableString(
+                PERSONAL_APP_SUSPENSION_MESSAGE, R.string.personal_apps_suspension_text);
     }
 
     private String getPersonalAppSuspensionSoonText(String date, String time, int maxDays) {
-        DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
-        return dpm.getString(PERSONAL_APP_SUSPENSION_TITLE,
-                () -> mContext.getString(
-                        R.string.personal_apps_suspension_soon_text, date, time, maxDays),
+        return getUpdatableString(
+                PERSONAL_APP_SUSPENSION_SOON_MESSAGE, R.string.personal_apps_suspension_soon_text,
                 date, time, maxDays);
     }
 
     private String getWorkProfileContentDescription() {
-        DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
-        return dpm.getString(NOTIFICATION_WORK_PROFILE_CONTENT_DESCRIPTION,
-                () -> mContext.getString(R.string.notification_work_profile_content_description));
+        return getUpdatableString(
+                NOTIFICATION_WORK_PROFILE_CONTENT_DESCRIPTION,
+                R.string.notification_work_profile_content_description);
     }
 
     @Override
@@ -17781,7 +17772,8 @@
 
             if (provisioningParams.isOrganizationOwnedProvisioning()) {
                 synchronized (getLockObject()) {
-                    markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(admin, userInfo.id);
+                    setProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(admin, userInfo.id,
+                            true);
                 }
             }
 
@@ -17808,6 +17800,35 @@
         }
     }
 
+    @Override
+    public void finalizeWorkProfileProvisioning(UserHandle managedProfileUser,
+            Account migratedAccount) {
+        Preconditions.checkCallAuthorization(
+                hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
+
+        if (!isManagedProfile(managedProfileUser.getIdentifier())) {
+            throw new IllegalStateException("Given user is not a managed profile");
+        }
+        ComponentName profileOwnerComponent =
+                mOwners.getProfileOwnerComponent(managedProfileUser.getIdentifier());
+        if (profileOwnerComponent == null) {
+            throw new IllegalStateException("There is no profile owner on the given profile");
+        }
+        Intent primaryProfileSuccessIntent = new Intent(ACTION_MANAGED_PROFILE_PROVISIONED);
+        primaryProfileSuccessIntent.setPackage(profileOwnerComponent.getPackageName());
+        primaryProfileSuccessIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES
+                | Intent.FLAG_RECEIVER_FOREGROUND);
+        primaryProfileSuccessIntent.putExtra(Intent.EXTRA_USER, managedProfileUser);
+
+        if (migratedAccount != null) {
+            primaryProfileSuccessIntent.putExtra(EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE,
+                    migratedAccount);
+        }
+
+        mContext.sendBroadcastAsUser(primaryProfileSuccessIntent,
+                UserHandle.of(getProfileParentId(managedProfileUser.getIdentifier())));
+    }
+
     /**
      * Callback called at the beginning of {@link #createAndProvisionManagedProfile(
      * ManagedProfileProvisioningParams, String)} after the relevant prechecks have passed.
@@ -18384,14 +18405,8 @@
             } else {
                 preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_DEFAULT);
             }
-            List<Integer> allowedUids = Arrays.stream(
-                    preferentialNetworkServiceConfig.getIncludedUids()).boxed().collect(
-                    Collectors.toList());
-            List<Integer> excludedUids = Arrays.stream(
-                    preferentialNetworkServiceConfig.getExcludedUids()).boxed().collect(
-                    Collectors.toList());
-            preferenceBuilder.setIncludedUids(allowedUids);
-            preferenceBuilder.setExcludedUids(excludedUids);
+            preferenceBuilder.setIncludedUids(preferentialNetworkServiceConfig.getIncludedUids());
+            preferenceBuilder.setExcludedUids(preferentialNetworkServiceConfig.getExcludedUids());
             preferenceBuilder.setPreferenceEnterpriseId(
                     preferentialNetworkServiceConfig.getNetworkId());
 
@@ -18688,13 +18703,14 @@
         mInjector.binderWithCleanCallingIdentity(() -> {
             if (mDeviceManagementResourcesProvider.updateDrawables(drawables)) {
                 sendDrawableUpdatedBroadcast(
-                        drawables.stream().map(s -> s.getDrawableId()).toArray(String[]::new));
+                        drawables.stream().map(s -> s.getDrawableId()).collect(
+                                Collectors.toList()));
             }
         });
     }
 
     @Override
-    public void resetDrawables(@NonNull String[] drawableIds) {
+    public void resetDrawables(@NonNull List<String> drawableIds) {
         Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
                 android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
 
@@ -18715,7 +18731,7 @@
                         drawableId, drawableStyle, drawableSource));
     }
 
-    private void sendDrawableUpdatedBroadcast(String[] drawableIds) {
+    private void sendDrawableUpdatedBroadcast(List<String> drawableIds) {
         sendResourceUpdatedBroadcast(EXTRA_RESOURCE_TYPE_DRAWABLE, drawableIds);
     }
 
@@ -18729,12 +18745,12 @@
         mInjector.binderWithCleanCallingIdentity(() -> {
             if (mDeviceManagementResourcesProvider.updateStrings(strings))
             sendStringsUpdatedBroadcast(
-                    strings.stream().map(s -> s.getStringId()).toArray(String[]::new));
+                    strings.stream().map(s -> s.getStringId()).collect(Collectors.toList()));
         });
     }
 
     @Override
-    public void resetStrings(String[] stringIds) {
+    public void resetStrings(@NonNull List<String> stringIds) {
         Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
                 android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
 
@@ -18751,13 +18767,13 @@
                 mDeviceManagementResourcesProvider.getString(stringId));
     }
 
-    private void sendStringsUpdatedBroadcast(String[] stringIds) {
+    private void sendStringsUpdatedBroadcast(List<String> stringIds) {
         sendResourceUpdatedBroadcast(EXTRA_RESOURCE_TYPE_STRING, stringIds);
     }
 
-    private void sendResourceUpdatedBroadcast(int resourceType, String[] resourceIds) {
+    private void sendResourceUpdatedBroadcast(int resourceType, List<String> resourceIds) {
         final Intent intent = new Intent(ACTION_DEVICE_POLICY_RESOURCE_UPDATED);
-        intent.putExtra(EXTRA_RESOURCE_IDS, resourceIds);
+        intent.putExtra(EXTRA_RESOURCE_IDS, resourceIds.toArray(String[]::new));
         intent.putExtra(EXTRA_RESOURCE_TYPE, resourceType);
         intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
         intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -18769,6 +18785,18 @@
         }
     }
 
+    private String getUpdatableString(
+            String updatableStringId, int defaultStringId, Object... formatArgs) {
+        ParcelableResource resource = mDeviceManagementResourcesProvider.getString(
+                updatableStringId);
+        if (resource == null) {
+            return ParcelableResource.loadDefaultString(() ->
+                    mContext.getString(defaultStringId, formatArgs));
+        }
+        return resource.getString(
+                mContext, () -> mContext.getString(defaultStringId, formatArgs), formatArgs);
+    }
+
     public boolean isDpcDownloaded() {
         Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
                 android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
@@ -18790,4 +18818,36 @@
         mInjector.binderWithCleanCallingIdentity(() -> Settings.Secure.putInt(
                 mContext.getContentResolver(), MANAGED_PROVISIONING_DPC_DOWNLOADED, setTo));
     }
+
+    @Override
+    public boolean shouldAllowBypassingDevicePolicyManagementRoleQualification() {
+        Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_ROLE_HOLDERS));
+        return mInjector.binderWithCleanCallingIdentity(() -> {
+            if (mUserManager.getUserCount() > 1) {
+                return false;
+            }
+            AccountManager am = AccountManager.get(mContext);
+            Account[] accounts = am.getAccounts();
+            return accounts.length == 0;
+        });
+    }
+
+    @Override
+    public List<UserHandle> getPolicyManagedProfiles(@NonNull UserHandle user) {
+        Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
+        int userId = user.getIdentifier();
+        return mInjector.binderWithCleanCallingIdentity(() -> {
+            List<UserInfo> userProfiles = mUserManager.getProfiles(userId);
+            List<UserHandle> result = new ArrayList<>();
+            for (int i = 0; i < userProfiles.size(); i++) {
+                UserInfo userInfo = userProfiles.get(i);
+                if (userInfo.isManagedProfile() && hasProfileOwner(userInfo.id)) {
+                    result.add(new UserHandle(userInfo.id));
+                }
+            }
+            return result;
+        });
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
index e1d720c..1fa2f53 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
@@ -340,7 +340,7 @@
 
     private int runMarkProfileOwnerOnOrganizationOwnedDevice(PrintWriter pw) {
         parseArgs(/* canHaveName= */ false);
-        mService.markProfileOwnerOnOrganizationOwnedDevice(mComponent, mUserId);
+        mService.setProfileOwnerOnOrganizationOwnedDevice(mComponent, mUserId, true);
         pw.printf("Success\n");
         return 0;
     }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java b/services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java
index 964be38..c72e1ea 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java
@@ -16,6 +16,8 @@
 
 package com.android.server.devicepolicy;
 
+import static com.android.server.FactoryResetter.setFactoryResetting;
+
 import android.annotation.Nullable;
 import android.app.admin.DevicePolicySafetyChecker;
 import android.content.Context;
@@ -36,7 +38,10 @@
 
 /**
  * Entry point for "factory reset" requests.
+ *
+ * @deprecated TODO(b/225012970): should be moved to {@code com.android.server.FactoryResetter}
  */
+@Deprecated
 public final class FactoryResetter {
 
     private static final String TAG = FactoryResetter.class.getSimpleName();
@@ -60,6 +65,8 @@
         Preconditions.checkCallAuthorization(mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.MASTER_CLEAR) == PackageManager.PERMISSION_GRANTED);
 
+        setFactoryResetting(mContext);
+
         if (mSafetyChecker == null) {
             factoryResetInternalUnchecked();
             return true;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index fe8f223..b0fdd72 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -620,18 +620,15 @@
         }
     }
 
-    /**
-     * Sets the indicator that the profile owner manages an organization-owned device,
-     * then write to file.
-     */
-    void markProfileOwnerOfOrganizationOwnedDevice(int userId) {
+    /** Set whether the profile owner manages an organization-owned device, then write to file. */
+    void setProfileOwnerOfOrganizationOwnedDevice(int userId, boolean isOrganizationOwnedDevice) {
         synchronized (mLock) {
             OwnerInfo profileOwner = mProfileOwners.get(userId);
             if (profileOwner != null) {
-                profileOwner.isOrganizationOwnedDevice = true;
+                profileOwner.isOrganizationOwnedDevice = isOrganizationOwnedDevice;
             } else {
                 Slog.e(TAG, String.format(
-                        "No profile owner for user %d to set as org-owned.", userId));
+                        "No profile owner for user %d to set org-owned flag.", userId));
             }
             writeProfileOwner(userId);
         }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
index 4620ea6..9a8e421 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
@@ -31,6 +31,7 @@
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.admin.DeviceAdminReceiver;
+import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -54,7 +55,9 @@
 import java.io.FileNotFoundException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.security.SecureRandom;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
 
 /**
  * Class managing bugreport collection upon device owner's request.
@@ -78,6 +81,9 @@
     private final DevicePolicyManagerService mService;
     private final DevicePolicyManagerService.Injector mInjector;
 
+    private final SecureRandom mRng = new SecureRandom();
+
+    private final AtomicLong mRemoteBugreportNonce = new AtomicLong();
     private final AtomicBoolean mRemoteBugreportServiceIsActive = new AtomicBoolean();
     private final AtomicBoolean mRemoteBugreportSharingAccepted = new AtomicBoolean();
     private final Context mContext;
@@ -197,8 +203,13 @@
 
         final long callingIdentity = mInjector.binderClearCallingIdentity();
         try {
-            mInjector.getIActivityManager().requestRemoteBugReport();
+            long nonce;
+            do {
+                nonce = mRng.nextLong();
+            } while (nonce == 0);
+            mInjector.getIActivityManager().requestRemoteBugReport(nonce);
 
+            mRemoteBugreportNonce.set(nonce);
             mRemoteBugreportServiceIsActive.set(true);
             mRemoteBugreportSharingAccepted.set(false);
             registerRemoteBugreportReceivers();
@@ -232,6 +243,11 @@
     }
 
     private void onBugreportFinished(Intent intent) {
+        long nonce = intent.getLongExtra(DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_NONCE, 0);
+        if (nonce == 0 || mRemoteBugreportNonce.get() != nonce) {
+            Slogf.w(LOG_TAG, "Invalid nonce provided, ignoring " + nonce);
+            return;
+        }
         mHandler.removeCallbacks(mRemoteBugreportTimeoutRunnable);
         mRemoteBugreportServiceIsActive.set(false);
         final Uri bugreportUri = intent.getData();
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 0e96567..a49577b 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -111,6 +111,11 @@
                             true);
 }
 
+static bool getEnableReadTimeoutsAfterInstall() {
+    return android::base::GetBoolProperty("debug.incremental.enable_read_timeouts_after_install",
+                                          true);
+}
+
 static bool getEnforceReadLogsMaxIntervalForSystemDataLoaders() {
     return android::base::GetBoolProperty("debug.incremental.enforce_readlogs_max_interval_for_"
                                           "system_dataloaders",
@@ -853,7 +858,7 @@
 
     // Always enable long read timeouts after installation is complete.
     std::unique_lock l(ifs->lock);
-    ifs->setReadTimeoutsRequested(true);
+    ifs->setReadTimeoutsRequested(getEnableReadTimeoutsAfterInstall());
     applyStorageParamsLocked(*ifs);
 }
 
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index fa2850a..73f0a74 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -293,8 +293,6 @@
             "com.android.server.wifi.p2p.WifiP2pService";
     private static final String LOWPAN_SERVICE_CLASS =
             "com.android.server.lowpan.LowpanService";
-    private static final String ETHERNET_SERVICE_CLASS =
-            "com.android.server.ethernet.EthernetService";
     private static final String JOB_SCHEDULER_SERVICE_CLASS =
             "com.android.server.job.JobSchedulerService";
     private static final String LOCK_SETTINGS_SERVICE_CLASS =
@@ -423,6 +421,8 @@
 
     private static final String SDK_SANDBOX_MANAGER_SERVICE_CLASS =
             "com.android.server.sdksandbox.SdkSandboxManagerService$Lifecycle";
+    private static final String AD_SERVICES_MANAGER_SERVICE_CLASS =
+            "com.android.server.adservices.AdServicesManagerService$Lifecycle";
 
     private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector";
 
@@ -1486,8 +1486,9 @@
 
             // TelecomLoader hooks into classes with defined HFP logic,
             // so check for either telephony or microphone.
-            if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_MICROPHONE) ||
-                    mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_MICROPHONE)
+                    || mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELECOM)
+                    || mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
                 t.traceBegin("StartTelecomLoaderService");
                 mSystemServiceManager.startService(TelecomLoaderService.class);
                 t.traceEnd();
@@ -1993,13 +1994,6 @@
                 t.traceEnd();
             }
 
-            if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET) ||
-                    mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
-                t.traceBegin("StartEthernet");
-                mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS);
-                t.traceEnd();
-            }
-
             t.traceBegin("StartPacProxyService");
             try {
                 pacProxyService = new PacProxyService(context);
@@ -2608,6 +2602,11 @@
         mSystemServiceManager.startService(SDK_SANDBOX_MANAGER_SERVICE_CLASS);
         t.traceEnd();
 
+        // AdServicesManagerService (PP API service)
+        t.traceBegin("StartAdServicesManagerService");
+        mSystemServiceManager.startService(AD_SERVICES_MANAGER_SERVICE_CLASS);
+        t.traceEnd();
+
         if (safeMode) {
             mActivityManagerService.enterSafeMode();
         }
diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java
index ca67bcb..e1fe1d8 100644
--- a/services/midi/java/com/android/server/midi/MidiService.java
+++ b/services/midi/java/com/android/server/midi/MidiService.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothUuid;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -151,6 +152,8 @@
     private static final UUID MIDI_SERVICE = UUID.fromString(
             "03B80E5A-EDE8-4B33-A751-6CE34EC4C700");
 
+    private final HashSet<ParcelUuid> mNonMidiUUIDs = new HashSet<ParcelUuid>();
+
     // PackageMonitor for listening to package changes
     private final PackageMonitor mPackageMonitor = new PackageMonitor() {
         @Override
@@ -643,6 +646,55 @@
         return false;
     }
 
+    private static void dumpIntentExtras(Intent intent) {
+        String action = intent.getAction();
+        Log.d(TAG, "Intent: " + action);
+        Bundle bundle = intent.getExtras();
+        if (bundle != null) {
+            for (String key : bundle.keySet()) {
+                Log.d(TAG, "  " + key + " : "
+                        + (bundle.get(key) != null ? bundle.get(key) : "NULL"));
+            }
+        }
+    }
+
+    private static boolean isBleTransport(Intent intent) {
+        Bundle bundle = intent.getExtras();
+        boolean isBle = false;
+        if (bundle != null) {
+            isBle = bundle.getInt(BluetoothDevice.EXTRA_TRANSPORT, BluetoothDevice.TRANSPORT_AUTO)
+                    == BluetoothDevice.TRANSPORT_LE;
+        }
+        return isBle;
+    }
+
+    private void dumpUuids(BluetoothDevice btDevice) {
+        Log.d(TAG, "UUIDs for " + btDevice);
+
+        ParcelUuid[] uuidParcels = btDevice.getUuids();
+        if (uuidParcels == null) {
+            Log.d(TAG, "No UUID Parcels");
+            return;
+        }
+
+        for (ParcelUuid parcel : uuidParcels) {
+            UUID uuid = parcel.getUuid();
+            Log.d(TAG, " uuid:" + uuid);
+        }
+    }
+
+    private boolean hasNonMidiUuids(BluetoothDevice btDevice) {
+        ParcelUuid[] uuidParcels = btDevice.getUuids();
+        // The assumption is that these services are indicative of devices that
+        // ARE NOT MIDI devices.
+        for (ParcelUuid parcel : uuidParcels) {
+            if (mNonMidiUUIDs.contains(parcel)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private final BroadcastReceiver mBleMidiReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -655,10 +707,27 @@
             switch (action) {
                 case BluetoothDevice.ACTION_ACL_CONNECTED: {
                     Log.d(TAG, "ACTION_ACL_CONNECTED");
+                    dumpIntentExtras(intent);
+                    // BLE-MIDI controllers are by definition BLE, so if this device
+                    // isn't, it CAN'T be a midi device
+                    if (!isBleTransport(intent)) {
+                        Log.i(TAG, "No BLE transport - NOT MIDI");
+                        break;
+                    }
+
+                    Log.d(TAG, "BLE Device");
                     BluetoothDevice btDevice =
                             intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-                    // We can't determine here if this is a BLD-MIDI device, so go ahead and try
-                    // to open as a MIDI device, further down it will get figured out.
+                    dumpUuids(btDevice);
+
+                    // See if there are any service UUIDs and if so do any of them indicate a
+                    // Non-MIDI device (headset, headphones, QWERTY keyboard....)
+                    if (hasNonMidiUuids(btDevice)) {
+                        Log.d(TAG, "Non-MIDI service UUIDs found. NOT MIDI");
+                        break;
+                    }
+
+                    Log.d(TAG, "Potential MIDI Device.");
                     openBluetoothDevice(btDevice);
                 }
                 break;
@@ -689,6 +758,17 @@
         context.registerReceiver(mBleMidiReceiver, filter);
 
         mBluetoothServiceUid = -1;
+
+        mNonMidiUUIDs.add(BluetoothUuid.A2DP_SINK);     // Headphones?
+        mNonMidiUUIDs.add(BluetoothUuid.A2DP_SOURCE);   // Headset?
+        mNonMidiUUIDs.add(BluetoothUuid.ADV_AUDIO_DIST);
+        mNonMidiUUIDs.add(BluetoothUuid.AVRCP_CONTROLLER);
+        mNonMidiUUIDs.add(BluetoothUuid.HFP);
+        mNonMidiUUIDs.add(BluetoothUuid.HSP);
+        mNonMidiUUIDs.add(BluetoothUuid.HID);
+        mNonMidiUUIDs.add(BluetoothUuid.LE_AUDIO);
+        mNonMidiUUIDs.add(BluetoothUuid.HOGP);
+        mNonMidiUUIDs.add(BluetoothUuid.HEARING_AID);
     }
 
     private void onUnlockUser() {
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index b0d23a4..66e840b 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -235,8 +235,11 @@
 
     // Event observers
     private void registerObservers() {
-        registerAppLaunchObserver();
-        registerOTAObserver();
+        BackgroundThread.get().getThreadHandler().post(
+                () -> {
+                    registerAppLaunchObserver();
+                    registerOTAObserver();
+                });
     }
 
     private final AppLaunchObserver mAppLaunchObserver = new AppLaunchObserver();
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index 8f81e93..7a9c412 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -143,6 +143,7 @@
         AndroidPackage::getLogo,
         AndroidPackage::getLocaleConfigRes,
         AndroidPackage::getManageSpaceActivityName,
+        AndroidPackage::getMaxSdkVersion,
         AndroidPackage::getMemtagMode,
         AndroidPackage::getMinSdkVersion,
         AndroidPackage::getNativeHeapZeroInitialized,
diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml
index 3cab5ec..7714cf0 100644
--- a/services/tests/mockingservicestests/AndroidManifest.xml
+++ b/services/tests/mockingservicestests/AndroidManifest.xml
@@ -31,6 +31,7 @@
     <uses-permission android:name="android.permission.WAKE_LOCK"/>
     <uses-permission
         android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"/>
+    <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
 
     <!-- needed by MasterClearReceiverTest to display a system dialog -->
     <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/>
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index f05658b..4a51e41 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -217,6 +217,8 @@
     @Mock
     private AppOpsManager mAppOpsManager;
     @Mock
+    private BatteryManager mBatteryManager;
+    @Mock
     private DeviceIdleInternal mDeviceIdleInternal;
     @Mock
     private PermissionManagerServiceInternal mPermissionManagerInternal;
@@ -453,6 +455,7 @@
                         eq(Manifest.permission.USE_EXACT_ALARM), anyInt(), anyInt(), anyString()));
 
         when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);
+        when(mMockContext.getSystemService(BatteryManager.class)).thenReturn(mBatteryManager);
 
         registerAppIds(new String[]{TEST_CALLING_PACKAGE},
                 new Integer[]{UserHandle.getAppId(TEST_CALLING_UID)});
@@ -477,6 +480,8 @@
 
         // Other boot phases don't matter
         mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
+
+        verify(mBatteryManager).isCharging();
         setTareEnabled(false);
         mAppStandbyWindow = mService.mConstants.APP_STANDBY_WINDOW;
         mAllowWhileIdleWindow = mService.mConstants.ALLOW_WHILE_IDLE_WINDOW;
@@ -494,9 +499,9 @@
 
         final ArgumentCaptor<AlarmManagerService.UninstallReceiver> packageReceiverCaptor =
                 ArgumentCaptor.forClass(AlarmManagerService.UninstallReceiver.class);
-        verify(mMockContext).registerReceiver(packageReceiverCaptor.capture(),
+        verify(mMockContext).registerReceiverForAllUsers(packageReceiverCaptor.capture(),
                 argThat((filter) -> filter.hasAction(Intent.ACTION_PACKAGE_ADDED)
-                        && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED)));
+                        && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED)), isNull(), isNull());
         mPackageChangesReceiver = packageReceiverCaptor.getValue();
 
         assertEquals(mService.mExactAlarmCandidates, Collections.emptySet());
@@ -1101,6 +1106,7 @@
                 new Intent(parole ? BatteryManager.ACTION_CHARGING
                         : BatteryManager.ACTION_DISCHARGING));
         assertAndHandleMessageSync(CHARGING_STATUS_CHANGED);
+        assertEquals(parole, mService.mAppStandbyParole);
     }
 
     @Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
index 0535513..47d4c8d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
@@ -19,6 +19,8 @@
 import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
 import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
 import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.Manifest.permission.CAMERA;
+import static android.Manifest.permission.RECORD_AUDIO;
 import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
 import static android.app.ActivityManager.PROCESS_STATE_TOP;
 import static android.app.ActivityManager.RESTRICTION_LEVEL_ADAPTIVE_BUCKET;
@@ -26,6 +28,14 @@
 import static android.app.ActivityManager.RESTRICTION_LEVEL_EXEMPTED;
 import static android.app.ActivityManager.RESTRICTION_LEVEL_RESTRICTED_BUCKET;
 import static android.app.ActivityManager.isLowRamDeviceStatic;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.app.AppOpsManager.OP_ACTIVATE_PLATFORM_VPN;
+import static android.app.AppOpsManager.OP_ACTIVATE_VPN;
+import static android.app.AppOpsManager.OP_CAMERA;
+import static android.app.AppOpsManager.OP_FINE_LOCATION;
+import static android.app.AppOpsManager.OP_NONE;
+import static android.app.AppOpsManager.OP_RECORD_AUDIO;
 import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_SYSTEM;
 import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_USER;
 import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
@@ -51,6 +61,7 @@
 import static com.android.internal.notification.SystemNotificationChannels.ABUSIVE_BACKGROUND_APPS;
 import static com.android.server.am.AppBatteryTracker.AppBatteryPolicy.getFloatArray;
 import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE_INDEX_BACKGROUND;
+import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE_INDEX_CACHED;
 import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE_INDEX_FOREGROUND;
 import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE_INDEX_FOREGROUND_SERVICE;
 import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATT_DIMENS;
@@ -58,6 +69,7 @@
 import static com.android.server.am.AppRestrictionController.STOCK_PM_FLAGS;
 import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_FGS_LOCATION;
 import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_FGS_MEDIA_PLAYBACK;
+import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_FGS_WITH_NOTIFICATION;
 import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_MEDIA_SESSION;
 import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_PERMISSION;
 
@@ -112,6 +124,7 @@
 import android.os.UserHandle;
 import android.permission.PermissionManager;
 import android.provider.DeviceConfig;
+import android.service.notification.StatusBarNotification;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 import android.util.Pair;
@@ -119,6 +132,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.R;
+import com.android.internal.app.IAppOpsService;
 import com.android.server.AppStateTracker;
 import com.android.server.DeviceIdleInternal;
 import com.android.server.am.AppBatteryExemptionTracker.AppBatteryExemptionPolicy;
@@ -231,6 +245,7 @@
     @Mock private MediaSessionManager mMediaSessionManager;
     @Mock private RoleManager mRoleManager;
     @Mock private TelephonyManager mTelephonyManager;
+    @Mock private IAppOpsService mIAppOpsService;
 
     private long mCurrentTimeMillis;
 
@@ -296,21 +311,21 @@
                 doReturn(new String[]{packageName})
                         .when(mPackageManager)
                         .getPackagesForUid(eq(uid));
-                doReturn(AppOpsManager.MODE_IGNORED)
-                        .when(mAppOpsManager)
-                        .checkOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, uid, packageName);
-                doReturn(AppOpsManager.MODE_IGNORED)
-                        .when(mAppOpsManager)
-                        .checkOpNoThrow(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, uid, packageName);
+                final int[] ops = new int[] {
+                    OP_ACTIVATE_VPN,
+                    OP_ACTIVATE_PLATFORM_VPN,
+                    OP_FINE_LOCATION,
+                    OP_CAMERA,
+                    OP_RECORD_AUDIO,
+                };
+                for (int op : ops) {
+                    setAppOpState(packageName, uid, op, false);
+                }
                 final String[] permissions = new String[] {ACCESS_BACKGROUND_LOCATION,
-                        ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION};
+                        ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION, CAMERA, RECORD_AUDIO,
+                };
                 for (String permission : permissions) {
-                    doReturn(PERMISSION_DENIED)
-                            .when(mPermissionManagerServiceInternal)
-                            .checkUidPermission(uid, permission);
-                    doReturn(PERMISSION_DENIED)
-                            .when(mPermissionManagerServiceInternal)
-                            .checkPermission(packageName, permission, userId);
+                    setPermissionState(packageName, uid, permission, false);
                 }
             }
             doReturn(appStandbyInfoList).when(mAppStandbyInternal).getAppStandbyBuckets(userId);
@@ -563,6 +578,7 @@
         DeviceConfigSession<Float> bgCurrentDrainBgRestrictedThreshold = null;
         DeviceConfigSession<Boolean> bgPromptFgsWithNotiToBgRestricted = null;
         DeviceConfigSession<Long> bgNotificationMinInterval = null;
+        DeviceConfigSession<Integer> bgBatteryExemptionTypes = null;
 
         mBgRestrictionController.addAppBackgroundRestrictionListener(listener);
 
@@ -624,20 +640,29 @@
                     ConstantsObserver.DEFAULT_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL_MS);
             bgNotificationMinInterval.set(windowMs);
 
+            bgBatteryExemptionTypes = new DeviceConfigSession<>(
+                    DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                    AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES,
+                    DeviceConfig::getInt,
+                    mContext.getResources().getInteger(
+                            R.integer.config_bg_current_drain_exempted_types));
+            bgBatteryExemptionTypes.set(0);
+
             mCurrentTimeMillis = 10_000L;
             doReturn(mCurrentTimeMillis - windowMs).when(stats).getStatsStartTimestamp();
             doReturn(mCurrentTimeMillis).when(stats).getStatsEndTimestamp();
             doReturn(statsList).when(mBatteryStatsInternal).getBatteryUsageStats(anyObject());
-            doReturn(true).when(mNotificationManagerInternal).isNotificationShown(
-                    testPkgName, null, notificationId, testUser);
             mAppFGSTracker.onForegroundServiceStateChanged(testPkgName, testUid,
                     testPid, true);
             mAppFGSTracker.onForegroundServiceNotificationUpdated(
                     testPkgName, testUid, notificationId);
+            mAppFGSTracker.mNotificationListener.onNotificationPosted(new StatusBarNotification(
+                    testPkgName, null, notificationId, null, testUid, testPid,
+                    new Notification(), UserHandle.of(testUser), null, mCurrentTimeMillis), null);
 
             runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
                     new double[]{restrictBucketThresholdMah - 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     () -> {
                         doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
                         doReturn(mCurrentTimeMillis + windowMs)
@@ -654,7 +679,7 @@
 
             runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
                     new double[]{restrictBucketThresholdMah + 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     () -> {
                         doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
                         doReturn(mCurrentTimeMillis + windowMs)
@@ -672,7 +697,7 @@
 
             runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
                     new double[]{restrictBucketThresholdMah - 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     () -> {
                         doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
                         doReturn(mCurrentTimeMillis + windowMs)
@@ -696,7 +721,7 @@
             // Trigger user interaction.
             runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
                     new double[]{restrictBucketThresholdMah - 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     () -> {
                         doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
                         doReturn(mCurrentTimeMillis + windowMs)
@@ -719,8 +744,8 @@
             clearInvocations(mInjector.getAppStandbyInternal());
 
             runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
-                    new double[]{restrictBucketThresholdMah + 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    zeros, new double[]{0, restrictBucketThresholdMah - 1},
+                    zeros, new double[]{restrictBucketThresholdMah + 1, 0},
                     () -> {
                         doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
                         doReturn(mCurrentTimeMillis + windowMs)
@@ -738,8 +763,8 @@
             clearInvocations(mInjector.getAppStandbyInternal());
             // Drain a bit more, there shouldn't be any level changes.
             runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
-                    new double[]{restrictBucketThresholdMah + 2, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    zeros, new double[]{0, restrictBucketThresholdMah - 1},
+                    zeros, new double[]{restrictBucketThresholdMah + 2, 0},
                     () -> {
                         doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
                         doReturn(mCurrentTimeMillis + windowMs)
@@ -771,7 +796,7 @@
 
             runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
                     new double[]{bgRestrictedThresholdMah + 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     () -> {
                         doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
                         doReturn(mCurrentTimeMillis + windowMs)
@@ -809,7 +834,7 @@
 
             runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
                     new double[]{bgRestrictedThresholdMah + 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     () -> {
                         doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
                         doReturn(mCurrentTimeMillis + windowMs)
@@ -848,7 +873,7 @@
 
             runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
                     new double[]{bgRestrictedThresholdMah + 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     () -> {
                         doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
                         doReturn(mCurrentTimeMillis + windowMs)
@@ -912,6 +937,7 @@
             closeIfNotNull(bgCurrentDrainBgRestrictedThreshold);
             closeIfNotNull(bgPromptFgsWithNotiToBgRestricted);
             closeIfNotNull(bgNotificationMinInterval);
+            closeIfNotNull(bgBatteryExemptionTypes);
         }
     }
 
@@ -1129,51 +1155,51 @@
 
             // Long-running FGS with type "location", but ran for a very short time.
             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_LOCATION, 0, null, null, null,
+                    FOREGROUND_SERVICE_TYPE_LOCATION, 0, null, OP_NONE, null, null,
                     timeout(windowMs * 2).times(2));
 
             // Long-running FGS with type "location", and ran for a while.
             // We shouldn't see notifications in this case.
             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_LOCATION, thresholdMs * 2, null, null, null,
+                    FOREGROUND_SERVICE_TYPE_LOCATION, thresholdMs * 2, null, OP_NONE, null, null,
                     timeout(windowMs * 2).times(0));
 
             // Long-running FGS with background location permission.
             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_LOCATION, 0, ACCESS_BACKGROUND_LOCATION, null, null,
-                    timeout(windowMs * 2).times(0));
+                    FOREGROUND_SERVICE_TYPE_LOCATION, 0, ACCESS_BACKGROUND_LOCATION, OP_NONE,
+                    null, null, timeout(windowMs * 2).times(0));
 
             // Long-running FGS with type "mediaPlayback", but ran for a very short time.
             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, 0, null, null, null,
+                    FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, 0, null, OP_NONE, null, null,
                     timeout(windowMs * 2).times(2));
 
             // Long-running FGS with type "mediaPlayback", and ran for a while.
             // We shouldn't see notifications in this case.
             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, thresholdMs * 2, null, null, null,
-                    timeout(windowMs * 2).times(0));
+                    FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, thresholdMs * 2, null, OP_NONE,
+                    null, null, timeout(windowMs * 2).times(0));
 
             // Long-running FGS with type "camera", and ran for a while.
             // We shouldn't see notifications in this case.
             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_CAMERA, thresholdMs * 2, null, null, null,
+                    FOREGROUND_SERVICE_TYPE_CAMERA, thresholdMs * 2, null, OP_NONE, null, null,
                     timeout(windowMs * 2).times(0));
 
             // Long-running FGS with type "location|mediaPlayback", but ran for a very short time.
             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
                     FOREGROUND_SERVICE_TYPE_LOCATION | FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK,
-                    0, null, null, null, timeout(windowMs * 2).times(2));
+                    0, null, OP_NONE, null, null, timeout(windowMs * 2).times(2));
 
             // Long-running FGS with type "location|mediaPlayback", and ran for a while.
             // We shouldn't see notifications in this case.
             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
                     FOREGROUND_SERVICE_TYPE_LOCATION | FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK,
-                    thresholdMs * 2, null, null, null, timeout(windowMs * 2).times(0));
+                    thresholdMs * 2, null, OP_NONE, null, null, timeout(windowMs * 2).times(0));
 
             // Long-running FGS with a media session starts/stops right away.
             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_NONE, 0, null,
+                    FOREGROUND_SERVICE_TYPE_NONE, 0, null, OP_NONE,
                     List.of(Pair.create(createMediaControllers(
                             new String[] {testPkgName1}, new int[] {testUid1}), 0L)), null,
                     timeout(windowMs * 2).times(2));
@@ -1181,14 +1207,14 @@
             // Long-running FGS with media session, and ran for a while.
             // We shouldn't see notifications in this case.
             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_NONE, thresholdMs * 2, null,
+                    FOREGROUND_SERVICE_TYPE_NONE, thresholdMs * 2, null, OP_NONE,
                     List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
                             new int[] {testUid1}), thresholdMs * 2)), null,
                     timeout(windowMs * 2).times(0));
 
             // Long-running FGS with 2 media sessions start/stop right away
             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_NONE, 0, null,
+                    FOREGROUND_SERVICE_TYPE_NONE, 0, null, OP_NONE,
                     List.of(Pair.create(createMediaControllers(
                             new String[] {testPkgName1, testPkgName2},
                             new int[] {testUid1, testUid2}), 0L)), null,
@@ -1196,7 +1222,7 @@
 
             // Long-running FGS with 2 media sessions start/stop interlaced.
             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_NONE, 0, null,
+                    FOREGROUND_SERVICE_TYPE_NONE, 0, null, OP_NONE,
                     List.of(Pair.create(createMediaControllers(
                                     new String[] {testPkgName1, testPkgName2},
                                     new int[] {testUid1, testUid2}), thresholdMs),
@@ -1214,17 +1240,17 @@
 
             // Long-running FGS with top state for a very short time.
             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_NONE, 0, null, null, List.of(0L),
+                    FOREGROUND_SERVICE_TYPE_NONE, 0, null, OP_NONE, null, List.of(0L),
                     timeout(windowMs * 2).times(2));
 
             // Long-running FGS with top state for extended time.
             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_NONE, 0, null, null, List.of(0L, windowMs * 2, 0L),
-                    timeout(windowMs * 2).times(0));
+                    FOREGROUND_SERVICE_TYPE_NONE, 0, null, OP_NONE, null,
+                    List.of(0L, windowMs * 2, 0L), timeout(windowMs * 2).times(0));
 
             // Long-running FGS with top state, on and off frequently.
             runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_NONE, 0, null, null,
+                    FOREGROUND_SERVICE_TYPE_NONE, 0, null, OP_NONE, null,
                     List.of(0L, thresholdMs / 10, thresholdMs / 10, thresholdMs / 10,
                             thresholdMs / 10, thresholdMs / 10, thresholdMs / 10),
                     timeout(windowMs * 2).times(2));
@@ -1243,18 +1269,19 @@
     }
 
     private void runTestLongFGSExemptionOnce(String packageName, int uid, int pid,
-            int serviceType, long sleepMs, String perm,
+            int serviceType, long sleepMs, String perm, int op,
             List<Pair<List<MediaController>, Long>> mediaControllers, List<Long> topStateChanges,
             VerificationMode mode) throws Exception {
         runExemptionTestOnce(
-                packageName, uid, pid, serviceType, sleepMs, true, perm, mediaControllers,
-                topStateChanges, true, true,
+                packageName, uid, pid, serviceType, sleepMs, true, false, perm, op,
+                mediaControllers, topStateChanges, true, true,
                 () -> checkNotificationShown(new String[] {packageName}, mode, false)
         );
     }
 
     private void runExemptionTestOnce(String packageName, int uid, int pid,
-            int serviceType, long sleepMs, boolean stopAfterSleep, String perm,
+            int serviceType, long sleepMs, boolean stopAfterSleep,
+            boolean withNotification, String perm, int op,
             List<Pair<List<MediaController>, Long>> mediaControllers,
             List<Long> topStateChanges, boolean resetFGSTracker, boolean resetController,
             RunnableWithException r) throws Exception {
@@ -1299,14 +1326,25 @@
                         FOREGROUND_SERVICE_TYPE_NONE);
             }
         }
-
+        if (withNotification) {
+            final int notificationId = 1000;
+            mAppFGSTracker.onForegroundServiceNotificationUpdated(
+                    packageName, uid, notificationId);
+            final StatusBarNotification noti = new StatusBarNotification(
+                    packageName, null, notificationId, null, uid, pid,
+                    new Notification(), UserHandle.of(UserHandle.getUserId(uid)),
+                    null, mCurrentTimeMillis);
+            mAppFGSTracker.mNotificationListener.onNotificationPosted(noti, null);
+            Thread.sleep(sleepMs);
+            if (stopAfterSleep) {
+                mAppFGSTracker.mNotificationListener.onNotificationRemoved(noti, null, 0);
+            }
+        }
         if (perm != null) {
-            doReturn(PERMISSION_GRANTED)
-                    .when(mPermissionManagerServiceInternal)
-                    .checkPermission(packageName, perm, UserHandle.getUserId(uid));
-            doReturn(PERMISSION_GRANTED)
-                    .when(mPermissionManagerServiceInternal)
-                    .checkUidPermission(uid, perm);
+            setPermissionState(packageName, uid, perm, true);
+            if (op != OP_NONE) {
+                setAppOpState(packageName, uid, op, true);
+            }
             mInjector.getAppPermissionTracker().onPermissionsChanged(uid);
         }
 
@@ -1327,12 +1365,10 @@
         mAppFGSTracker.onForegroundServiceStateChanged(packageName, uid, pid, false);
 
         if (perm != null) {
-            doReturn(PERMISSION_DENIED)
-                    .when(mPermissionManagerServiceInternal)
-                    .checkPermission(packageName, perm, UserHandle.getUserId(uid));
-            doReturn(PERMISSION_DENIED)
-                    .when(mPermissionManagerServiceInternal)
-                    .checkUidPermission(uid, perm);
+            setPermissionState(packageName, uid, perm, false);
+            if (op != OP_NONE) {
+                setAppOpState(packageName, uid, op, false);
+            }
             mInjector.getAppPermissionTracker().onPermissionsChanged(uid);
         }
         if (topStateThread != null) {
@@ -1510,7 +1546,8 @@
                     mContext.getResources().getInteger(
                             R.integer.config_bg_current_drain_exempted_types));
             bgBatteryExemptionTypes.set(STATE_TYPE_MEDIA_SESSION | STATE_TYPE_FGS_MEDIA_PLAYBACK
-                    | STATE_TYPE_FGS_LOCATION | STATE_TYPE_PERMISSION);
+                    | STATE_TYPE_FGS_LOCATION | STATE_TYPE_PERMISSION
+                    | STATE_TYPE_FGS_WITH_NOTIFICATION);
 
             bgPermissionMonitorEnabled = new DeviceConfigSession<>(
                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -1543,19 +1580,19 @@
             // Run with a media playback service which starts/stops immediately, we should
             // goto the restricted bucket.
             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, 0, true,
-                    null, null, null, listener, stats, uids,
+                    FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, 0, true, false,
+                    null, OP_NONE, null, null, listener, stats, uids,
                     new double[]{restrictBucketThresholdMah + 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
-                    null, windowMs, null, null, null);
+                    null, windowMs, null, null, null, null);
 
             // Run with a media playback service with extended time. We should be back to normal.
             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
                     FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
-                    null, null, null, listener, stats, uids,
+                    false, null, OP_NONE, null, null, listener, stats, uids,
                     new double[]{restrictBucketThresholdMah + 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     true, RESTRICTION_LEVEL_ADAPTIVE_BUCKET, timeout, false,
                     () -> {
                         // A user interaction will bring it back to normal.
@@ -1572,116 +1609,119 @@
                                 eq(REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE),
                                 eq(REASON_MAIN_USAGE),
                                 eq(REASON_SUB_USAGE_USER_INTERACTION));
-                    }, windowMs, null, null, null);
+                    }, windowMs, null, null, null, null);
 
             // Start over.
             resetBgRestrictionController();
-            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
             mAppBatteryPolicy.reset();
 
             // Run with a media playback service with extended time, with higher current drain.
             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
                     FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
-                    null, null, null, listener, stats, uids,
+                    false, null, OP_NONE, null, null, listener, stats, uids,
                     new double[]{restrictBucketHighThresholdMah - 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
-                    null, windowMs, null, null, null);
+                    null, windowMs, null, null, null, null);
 
             // Run with a media playback service with extended time, with even higher current drain.
             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
                     FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
-                    null, null, null, listener, stats, uids,
+                    false, null, OP_NONE, null, null, listener, stats, uids,
                     new double[]{restrictBucketHighThresholdMah + 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
-                    null, windowMs, null, null, null);
+                    null, windowMs, null, null, null, null);
 
             // Start over.
             resetBgRestrictionController();
-            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
             mAppBatteryPolicy.reset();
 
             // Run with a media session with extended time, with higher current drain.
             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, null,
+                    FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
+                    null, OP_NONE,
                     List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
-                                new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
+                          new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
                     null, listener, stats, uids,
                     new double[]{restrictBucketHighThresholdMah - 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
-                    null, windowMs, null, null, null);
+                    null, windowMs, null, null, null, null);
 
             // Run with a media session with extended time, with even higher current drain.
             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, null,
+                    FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
+                    null, OP_NONE,
                     List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
-                                new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
+                          new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
                     null, listener, stats, uids,
                     new double[]{restrictBucketHighThresholdMah + 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
-                    null, windowMs, null, null, null);
+                    null, windowMs, null, null, null, null);
 
             // Start over.
             resetBgRestrictionController();
-            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
             mAppBatteryPolicy.reset();
 
             // Run with a media session with extended time, with moderate current drain,
             // but it ran on the top when the location service is active.
             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, null,
+                    FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
+                    null, OP_NONE,
                     List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
-                                new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
+                          new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
                     List.of(0L, timeout * 2), listener, stats, uids,
                     new double[]{restrictBucketThresholdMah + 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
-                    null, windowMs, null, null, null);
+                    null, windowMs, null, null, null, null);
 
             // Start over.
             resetBgRestrictionController();
-            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
             mAppBatteryPolicy.reset();
 
             // Run with a location service with extended time, with higher current drain.
             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false,
-                    null, null, null, listener, stats, uids,
+                    FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false, false,
+                    null, OP_NONE, null, null, listener, stats, uids,
                     new double[]{restrictBucketHighThresholdMah - 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
-                    null, windowMs, null, null, null);
+                    null, windowMs, null, null, null, null);
 
             // Run with a location service with extended time, with even higher current drain.
             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false,
-                    null, null, null, listener, stats, uids,
+                    FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false, false,
+                    null, OP_NONE, null, null, listener, stats, uids,
                     new double[]{restrictBucketHighThresholdMah + 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
-                    null, windowMs, null, null, null);
+                    null, windowMs, null, null, null, null);
 
             // Start over.
             resetBgRestrictionController();
-            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
             mAppBatteryPolicy.reset();
 
             // Run with a location service with extended time, with moderate current drain,
             // but it ran on the top when the location service is active.
             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false,
-                    null, null, List.of(0L, timeout * 2), listener, stats, uids,
+                    FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false, false,
+                    null, OP_NONE, null, List.of(0L, timeout * 2), listener, stats, uids,
                     new double[]{restrictBucketThresholdMah + 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
-                    null, windowMs, null, null, null);
+                    null, windowMs, null, null, null, null);
 
             // Start over.
             resetBgRestrictionController();
-            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
             mAppBatteryPolicy.reset();
 
             // Turn off the higher threshold for bg location access.
@@ -1689,25 +1729,25 @@
 
             // Run with bg location permission, with moderate current drain.
             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_NONE, 0, false,
-                    ACCESS_BACKGROUND_LOCATION, null, null, listener, stats, uids,
+                    FOREGROUND_SERVICE_TYPE_NONE, 0, false, false,
+                    ACCESS_BACKGROUND_LOCATION, OP_NONE, null, null, listener, stats, uids,
                     new double[]{restrictBucketThresholdMah - 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
-                    null, windowMs, null, null, null);
+                    null, windowMs, null, null, null, null);
 
             // Run with bg location permission, with a bit higher current drain.
             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_NONE, 0, false,
-                    ACCESS_BACKGROUND_LOCATION, null, null, listener, stats, uids,
+                    FOREGROUND_SERVICE_TYPE_NONE, 0, false, false,
+                    ACCESS_BACKGROUND_LOCATION, OP_NONE, null, null, listener, stats, uids,
                     new double[]{restrictBucketThresholdMah + 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
-                    null, windowMs, null, null, null);
+                    null, windowMs, null, null, null, null);
 
             // Start over.
             resetBgRestrictionController();
-            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
             mAppBatteryPolicy.reset();
 
             // Turn on the higher threshold for bg location access.
@@ -1715,21 +1755,21 @@
 
             // Run with bg location permission, with higher current drain.
             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_NONE, 0, false,
-                    ACCESS_BACKGROUND_LOCATION , null, null, listener, stats, uids,
+                    FOREGROUND_SERVICE_TYPE_NONE, 0, false, false,
+                    ACCESS_BACKGROUND_LOCATION, OP_NONE, null, null, listener, stats, uids,
                     new double[]{restrictBucketHighThresholdMah - 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     true , RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
-                    null, windowMs, null,  null, null);
+                    null, windowMs, null,  null, null, null);
 
             // Run with bg location permission, with even higher current drain.
             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_NONE, 0, false,
-                    ACCESS_BACKGROUND_LOCATION , null, null, listener, stats, uids,
+                    FOREGROUND_SERVICE_TYPE_NONE, 0, false, false,
+                    ACCESS_BACKGROUND_LOCATION, OP_NONE, null, null, listener, stats, uids,
                     new double[]{restrictBucketHighThresholdMah + 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
-                    null, windowMs, null,  null, null);
+                    null, windowMs, null,  null, null, null);
 
             // Now turn off the event duration based feature flag.
             bgCurrentDrainEventDurationBasedThresholdEnabled.set(false);
@@ -1738,7 +1778,7 @@
 
             // Start over.
             resetBgRestrictionController();
-            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
             mAppBatteryPolicy.reset();
 
             waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
@@ -1746,19 +1786,19 @@
             // Run with a media playback service which starts/stops immediately, we should
             // goto the restricted bucket.
             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, 0, true,
-                    null, null, null, listener, stats, uids,
+                    FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, 0, true, false,
+                    null, OP_NONE, null, null, listener, stats, uids,
                     new double[]{restrictBucketThresholdMah + 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
-                    null, windowMs, null, null, null);
+                    null, windowMs, null, null, null, null);
 
             // Run with a media playback service with extended time. We should be back to normal.
             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
                     FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
-                    null, null, null, listener, stats, uids,
+                    false, null, OP_NONE, null, null, listener, stats, uids,
                     new double[]{restrictBucketThresholdMah + 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     true, RESTRICTION_LEVEL_ADAPTIVE_BUCKET, timeout, false,
                     () -> {
                         // A user interaction will bring it back to normal.
@@ -1775,121 +1815,166 @@
                                 eq(REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE),
                                 eq(REASON_MAIN_USAGE),
                                 eq(REASON_SUB_USAGE_USER_INTERACTION));
-                    }, windowMs, null, null, null);
+                    }, windowMs, null, null, null, null);
 
             // Start over.
             resetBgRestrictionController();
-            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
             mAppBatteryPolicy.reset();
 
-            final double[] initialBg = {1, 1}, initialFgs = {1, 1}, initialFg = zeros;
+            final double[] initialBg = {1, 1}, initialFgs = {1, 1}, initialFg = zeros,
+                    initialCached = {1, 1};
 
             // Run with a media playback service with extended time, with higher current drain.
             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
                     FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
-                    null, null, null, listener, stats, uids,
+                    false, null, OP_NONE, null, null, listener, stats, uids,
                     new double[]{restrictBucketHighThresholdMah - 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
-                    null, windowMs, initialBg, initialFgs, initialFg);
+                    null, windowMs, initialBg, initialFgs, initialFg, initialCached);
 
             // Run with a media playback service with extended time, with even higher current drain,
             // it still should stay in the current restriction level as we exempt the media
             // playback.
             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
                     FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
-                    null, null, null, listener, stats, uids,
+                    false, null, OP_NONE, null, null, listener, stats, uids,
                     new double[]{restrictBucketHighThresholdMah + 100, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
-                    null, windowMs, initialBg, initialFgs, initialFg);
+                    null, windowMs, initialBg, initialFgs, initialFg, initialCached);
 
             // Set the policy to exempt media session and permission.
             bgBatteryExemptionTypes.set(STATE_TYPE_MEDIA_SESSION | STATE_TYPE_PERMISSION);
             // Start over.
             resetBgRestrictionController();
-            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
             mAppBatteryPolicy.reset();
 
             // Run with coarse location permission, with high current drain.
             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_NONE, 0, false,
-                    ACCESS_COARSE_LOCATION, null, null, listener, stats, uids,
+                    FOREGROUND_SERVICE_TYPE_NONE, 0, false, false,
+                    ACCESS_COARSE_LOCATION, OP_NONE, null, null, listener, stats, uids,
                     new double[]{restrictBucketThresholdMah + 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
-                    null, windowMs, initialBg, initialFgs, initialFg);
+                    null, windowMs, initialBg, initialFgs, initialFg, initialCached);
 
             // Start over.
             resetBgRestrictionController();
-            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
             mAppBatteryPolicy.reset();
 
             // Run with fine location permission, with high current drain.
             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_NONE, 0, false,
-                    ACCESS_FINE_LOCATION, null, null, listener, stats, uids,
+                    FOREGROUND_SERVICE_TYPE_NONE, 0, false, false,
+                    ACCESS_FINE_LOCATION, OP_FINE_LOCATION, null, null, listener, stats, uids,
                     new double[]{restrictBucketThresholdMah + 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
-                    null, windowMs, initialBg, initialFgs, initialFg);
+                    null, windowMs, initialBg, initialFgs, initialFg, initialCached);
 
             // Start over.
             resetBgRestrictionController();
-            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
             mAppBatteryPolicy.reset();
 
             // Run with a media session with extended time, with higher current drain.
             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, null,
+                    FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
+                    null, OP_NONE,
                     List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
-                                new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
+                          new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
                     null, listener, stats, uids,
                     new double[]{restrictBucketHighThresholdMah - 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
-                    null, windowMs, initialBg, initialFgs, initialFg);
+                    null, windowMs, initialBg, initialFgs, initialFg, initialCached);
 
             // Run with a media session with extended time, with even higher current drain.
             // it still should stay in the current restriction level as we exempt the media
             // session.
             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, null,
+                    FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
+                    null, OP_NONE,
                     List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
-                                new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
+                          new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
                     null, listener, stats, uids,
                     new double[]{restrictBucketHighThresholdMah + 100, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
-                    null, windowMs, initialBg, initialFgs, initialFg);
+                    null, windowMs, initialBg, initialFgs, initialFg, initialCached);
+
+            // Set the policy to exempt fgs with notifications.
+            bgBatteryExemptionTypes.set(STATE_TYPE_FGS_WITH_NOTIFICATION);
+            // Start over.
+            resetBgRestrictionController();
+            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
+            mAppBatteryPolicy.reset();
+
+            // Run with a FGS with notification posted/removed immediately, we should
+            // goto the restricted bucket.
+            runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
+                    FOREGROUND_SERVICE_TYPE_NONE, 0, true, true,
+                    null, OP_NONE, null, null, listener, stats, uids,
+                    new double[]{restrictBucketThresholdMah + 1, 0},
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
+                    false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
+                    null, windowMs, null, null, null, null);
+
+            // Run with a service with notification for extended time. We should be back to normal.
+            runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
+                    FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false,
+                    true, null, OP_NONE, null, null, listener, stats, uids,
+                    new double[]{restrictBucketThresholdMah + 1, 0},
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
+                    true, RESTRICTION_LEVEL_ADAPTIVE_BUCKET, timeout, false,
+                    () -> {
+                        // A user interaction will bring it back to normal.
+                        mIdleStateListener.onUserInteractionStarted(testPkgName1,
+                                UserHandle.getUserId(testUid1));
+                        waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
+                        // It should have been back to normal.
+                        listener.verify(timeout, testUid1, testPkgName1,
+                                RESTRICTION_LEVEL_ADAPTIVE_BUCKET);
+                        verify(mInjector.getAppStandbyInternal(), times(1)).maybeUnrestrictApp(
+                                eq(testPkgName1),
+                                eq(UserHandle.getUserId(testUid1)),
+                                eq(REASON_MAIN_FORCED_BY_SYSTEM),
+                                eq(REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE),
+                                eq(REASON_MAIN_USAGE),
+                                eq(REASON_SUB_USAGE_USER_INTERACTION));
+                    }, windowMs, null, null, null, null);
 
             // Set the policy to exempt all.
             bgBatteryExemptionTypes.set(STATE_TYPE_MEDIA_SESSION | STATE_TYPE_FGS_MEDIA_PLAYBACK
-                    | STATE_TYPE_FGS_LOCATION | STATE_TYPE_PERMISSION);
+                    | STATE_TYPE_FGS_LOCATION | STATE_TYPE_PERMISSION
+                    | STATE_TYPE_FGS_WITH_NOTIFICATION);
 
             // Start over.
             resetBgRestrictionController();
-            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+            setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
             mAppBatteryPolicy.reset();
 
             // Run with a location service with extended time, with higher current drain.
             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false,
-                    null, null, null, listener, stats, uids,
+                    FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false, false,
+                    null, OP_NONE, null, null, listener, stats, uids,
                     new double[]{restrictBucketHighThresholdMah - 1, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
-                    null, windowMs, initialBg, initialFgs, initialFg);
+                    null, windowMs, initialBg, initialFgs, initialFg, initialCached);
 
             // Run with a location service with extended time, with even higher current drain.
             // it still should stay in the current restriction level as we exempt the location.
             runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
-                    FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false,
-                    null, null, null, listener, stats, uids,
+                    FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false, false,
+                    null, OP_NONE, null, null, listener, stats, uids,
                     new double[]{restrictBucketHighThresholdMah + 100, 0},
-                    new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+                    new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
                     true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
-                    null, windowMs, initialBg, initialFgs, initialFg);
+                    null, windowMs, initialBg, initialFgs, initialFg, initialCached);
         } finally {
             closeIfNotNull(bgCurrentDrainMonitor);
             closeIfNotNull(bgCurrentDrainWindow);
@@ -1909,40 +1994,39 @@
     }
 
     private void runTestBgCurrentDrainExemptionOnce(String packageName, int uid, int pid,
-            int serviceType, long sleepMs, boolean stopAfterSleep, String perm,
-            List<Pair<List<MediaController>, Long>> mediaControllers,
+            int serviceType, long sleepMs, boolean stopAfterSleep, boolean withNotification,
+            String perm, int op, List<Pair<List<MediaController>, Long>> mediaControllers,
             List<Long> topStateChanges, TestAppRestrictionLevelListener listener,
             BatteryUsageStats stats, int[] uids, double[] bg, double[] fgs, double[] fg,
-            boolean expectingTimeout, int expectingLevel, long timeout, boolean resetFGSTracker,
-            RunnableWithException extraVerifiers, long windowMs,
-            double[] initialBg, double[] initialFgs, double[] initialFg) throws Exception {
+            double[] cached, boolean expectingTimeout, int expectingLevel, long timeout,
+            boolean resetFGSTracker, RunnableWithException extraVerifiers, long windowMs,
+            double[] initialBg, double[] initialFgs, double[] initialFg, double[] initialCached)
+            throws Exception {
         listener.mLatchHolder[0] = new CountDownLatch(1);
         if (initialBg != null) {
             doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
             doReturn(mCurrentTimeMillis + windowMs).when(stats).getStatsEndTimestamp();
             mCurrentTimeMillis += windowMs + 1;
-            setUidBatteryConsumptions(stats, uids, initialBg, initialFgs, initialFg);
+            setUidBatteryConsumptions(stats, uids, initialBg, initialFgs, initialFg, initialCached);
             mAppBatteryExemptionTracker.reset();
             mAppBatteryPolicy.reset();
         }
         if (perm != null) {
-            doReturn(PERMISSION_GRANTED)
-                    .when(mPermissionManagerServiceInternal)
-                    .checkPermission(packageName, perm, UserHandle.getUserId(uid));
-            doReturn(PERMISSION_GRANTED)
-                    .when(mPermissionManagerServiceInternal)
-                    .checkUidPermission(uid, perm);
+            setPermissionState(packageName, uid, perm, true);
+            if (op != OP_NONE) {
+                setAppOpState(packageName, uid, op, true);
+            }
             mInjector.getAppPermissionTracker().onPermissionsChanged(uid);
         }
         waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
         runExemptionTestOnce(
-                packageName, uid, pid, serviceType, sleepMs, stopAfterSleep,
-                perm, mediaControllers, topStateChanges, resetFGSTracker, false,
+                packageName, uid, pid, serviceType, sleepMs, stopAfterSleep, withNotification,
+                perm, op, mediaControllers, topStateChanges, resetFGSTracker, false,
                 () -> {
                     clearInvocations(mInjector.getAppStandbyInternal());
                     clearInvocations(mBgRestrictionController);
-                    runTestBgCurrentDrainMonitorOnce(listener, stats, uids, bg, fgs, fg, false,
-                            () -> {
+                    runTestBgCurrentDrainMonitorOnce(listener, stats, uids, bg, fgs, fg, cached,
+                            false, () -> {
                                 doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
                                 doReturn(mCurrentTimeMillis + windowMs)
                                         .when(stats).getStatsEndTimestamp();
@@ -1985,16 +2069,36 @@
                 }
         );
         if (perm != null) {
-            doReturn(PERMISSION_DENIED)
-                    .when(mPermissionManagerServiceInternal)
-                    .checkPermission(packageName, perm, UserHandle.getUserId(uid));
-            doReturn(PERMISSION_DENIED)
-                    .when(mPermissionManagerServiceInternal)
-                    .checkUidPermission(uid, perm);
+            setPermissionState(packageName, uid, perm, false);
+            if (op != OP_NONE) {
+                setAppOpState(packageName, uid, op, false);
+            }
             mInjector.getAppPermissionTracker().onPermissionsChanged(uid);
         }
     }
 
+    private void setPermissionState(String packageName, int uid, String perm, boolean granted) {
+        doReturn(granted ? PERMISSION_GRANTED : PERMISSION_DENIED)
+                .when(mPermissionManagerServiceInternal)
+                .checkUidPermission(uid, perm);
+        doReturn(granted ? PERMISSION_GRANTED : PERMISSION_DENIED)
+                .when(mPermissionManagerServiceInternal)
+                .checkPermission(packageName, perm, UserHandle.getUserId(uid));
+    }
+
+    private void setAppOpState(String packageName, int uid, int op, boolean granted) {
+        try {
+            doReturn(granted ? MODE_ALLOWED : MODE_IGNORED)
+                    .when(mAppOpsManager)
+                    .checkOpNoThrow(op, uid, packageName);
+            doReturn(granted ? MODE_ALLOWED : MODE_IGNORED)
+                    .when(mIAppOpsService)
+                    .checkOperation(op, uid, packageName);
+        } catch (RemoteException e) {
+            // Ignore.
+        }
+    }
+
     @Test
     public void testExcessiveBroadcasts() throws Exception {
         final long windowMs = 5_000;
@@ -2180,30 +2284,33 @@
 
     private void runTestBgCurrentDrainMonitorOnce(TestAppRestrictionLevelListener listener,
             BatteryUsageStats stats, int[] uids, double[] bg, double[] fgs, double[] fg,
-            RunnableWithException runnable) throws Exception {
-        runTestBgCurrentDrainMonitorOnce(listener, stats, uids, bg, fgs, fg, true, runnable);
+            double[] cached, RunnableWithException runnable) throws Exception {
+        runTestBgCurrentDrainMonitorOnce(listener, stats, uids, bg, fgs, fg, cached, true,
+                runnable);
     }
 
     private void runTestBgCurrentDrainMonitorOnce(TestAppRestrictionLevelListener listener,
             BatteryUsageStats stats, int[] uids, double[] bg, double[] fgs, double[] fg,
-            boolean resetListener, RunnableWithException runnable) throws Exception {
+            double[] cached, boolean resetListener, RunnableWithException runnable)
+            throws Exception {
         if (resetListener) {
             listener.mLatchHolder[0] = new CountDownLatch(1);
         }
-        setUidBatteryConsumptions(stats, uids, bg, fgs, fg);
+        setUidBatteryConsumptions(stats, uids, bg, fgs, fg, cached);
         runnable.run();
     }
 
     private void setUidBatteryConsumptions(BatteryUsageStats stats, int[] uids, double[] bg,
-            double[] fgs, double[] fg) {
+            double[] fgs, double[] fg, double[] cached) {
         ArrayList<UidBatteryConsumer> consumers = new ArrayList<>();
         for (int i = 0; i < uids.length; i++) {
-            consumers.add(mockUidBatteryConsumer(uids[i], bg[i], fgs[i], fg[i]));
+            consumers.add(mockUidBatteryConsumer(uids[i], bg[i], fgs[i], fg[i], cached[i]));
         }
         doReturn(consumers).when(stats).getUidBatteryConsumers();
     }
 
-    private UidBatteryConsumer mockUidBatteryConsumer(int uid, double bg, double fgs, double fg) {
+    private UidBatteryConsumer mockUidBatteryConsumer(int uid, double bg, double fgs, double fg,
+            double cached) {
         UidBatteryConsumer uidConsumer = mock(UidBatteryConsumer.class);
         doReturn(uid).when(uidConsumer).getUid();
         doReturn(bg).when(uidConsumer).getConsumedPower(
@@ -2212,6 +2319,8 @@
                 eq(BATT_DIMENS[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]));
         doReturn(fg).when(uidConsumer).getConsumedPower(
                 eq(BATT_DIMENS[BATTERY_USAGE_INDEX_FOREGROUND]));
+        doReturn(cached).when(uidConsumer).getConsumedPower(
+                eq(BATT_DIMENS[BATTERY_USAGE_INDEX_CACHED]));
         return uidConsumer;
     }
 
@@ -2512,7 +2621,7 @@
         final LinkedList<UidStateEventWithBattery> result = new LinkedList<>();
         for (int i = 0; i < isStart.length; i++) {
             result.add(new UidStateEventWithBattery(isStart[i], timestamps[i],
-                        new ImmutableBatteryUsage(0.0d, 0.0d, batteryUsage[i], 0.0d), null));
+                        new ImmutableBatteryUsage(0.0d, 0.0d, batteryUsage[i], 0.0d, 0.0d), null));
         }
         return result;
     }
@@ -2748,6 +2857,11 @@
         RoleManager getRoleManager() {
             return BackgroundRestrictionTest.this.mRoleManager;
         }
+
+        @Override
+        IAppOpsService getIAppOpsService() {
+            return BackgroundRestrictionTest.this.mIAppOpsService;
+        }
     }
 
     private class TestAppBatteryTrackerInjector extends TestBaseTrackerInjector<AppBatteryPolicy> {
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 50a0a68..c747a5f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -63,6 +63,7 @@
 import static com.android.server.am.ProcessList.VISIBLE_APP_ADJ;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.AdditionalAnswers.answer;
 import static org.mockito.Mockito.any;
@@ -444,7 +445,7 @@
 
     @SuppressWarnings("GuardedBy")
     @Test
-    public void testUpdateOomAdj_DoOne_PerceptibleRecent() {
+    public void testUpdateOomAdj_DoOne_PerceptibleRecent_FgService() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
         app.mServices.setHasForegroundServices(true, 0);
@@ -458,6 +459,70 @@
 
     @SuppressWarnings("GuardedBy")
     @Test
+    public void testUpdateOomAdj_DoOne_PerceptibleRecent_AlmostPerceptibleService() {
+        // Grace period allows the adjustment.
+        {
+            ProcessRecord system = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                    MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+            ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                    MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, true));
+            long nowUptime = SystemClock.uptimeMillis();
+            app.mState.setLastTopTime(nowUptime);
+            // Simulate the system starting and binding to a service in the app.
+            ServiceRecord s = bindService(app, system,
+                    null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
+            s.lastTopAlmostPerceptibleBindRequestUptimeMs = nowUptime;
+            s.getConnections().clear();
+            app.mServices.updateHasTopStartedAlmostPerceptibleServices();
+            sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+            sService.mOomAdjuster.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+            assertEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ, app.mState.getSetAdj());
+        }
+
+        // Out of grace period but valid binding allows the adjustment.
+        {
+            ProcessRecord system = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                    MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+            ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                    MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, true));
+            long nowUptime = SystemClock.uptimeMillis();
+            app.mState.setLastTopTime(nowUptime);
+            // Simulate the system starting and binding to a service in the app.
+            ServiceRecord s = bindService(app, system,
+                    null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
+            s.lastTopAlmostPerceptibleBindRequestUptimeMs =
+                    nowUptime - 2 * sService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
+            app.mServices.updateHasTopStartedAlmostPerceptibleServices();
+            sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+            sService.mOomAdjuster.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+            assertEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ, app.mState.getSetAdj());
+        }
+
+        // Out of grace period and no valid binding so no adjustment.
+        {
+            ProcessRecord system = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                    MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+            ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                    MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, true));
+            long nowUptime = SystemClock.uptimeMillis();
+            app.mState.setLastTopTime(nowUptime);
+            // Simulate the system starting and binding to a service in the app.
+            ServiceRecord s = bindService(app, system,
+                    null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
+            s.lastTopAlmostPerceptibleBindRequestUptimeMs =
+                    nowUptime - 2 * sService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
+            s.getConnections().clear();
+            app.mServices.updateHasTopStartedAlmostPerceptibleServices();
+            sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+            sService.mOomAdjuster.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+            assertNotEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ, app.mState.getSetAdj());
+        }
+    }
+    @SuppressWarnings("GuardedBy")
+    @Test
     public void testUpdateOomAdj_DoOne_Toast() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
index 575e351..319a769 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
@@ -19,6 +19,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 import static com.android.server.app.GameServiceProviderInstanceImplTest.FakeGameService.GameServiceState;
 
@@ -26,19 +27,21 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verifyZeroInteractions;
 
 import android.Manifest;
 import android.annotation.Nullable;
 import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityManagerInternal;
 import android.app.ActivityTaskManager;
 import android.app.IActivityManager;
 import android.app.IActivityTaskManager;
+import android.app.IProcessObserver;
 import android.app.ITaskStackListener;
 import android.content.ComponentName;
 import android.content.Context;
@@ -135,6 +138,8 @@
     private MockitoSession mMockingSession;
     private GameServiceProviderInstance mGameServiceProviderInstance;
     @Mock
+    private ActivityManagerInternal mMockActivityManagerInternal;
+    @Mock
     private IActivityTaskManager mMockActivityTaskManager;
     @Mock
     private WindowManagerService mMockWindowManagerService;
@@ -151,6 +156,7 @@
     private FakeGameSessionService mFakeGameSessionService;
     private FakeServiceConnector<IGameSessionService> mFakeGameSessionServiceConnector;
     private ArrayList<ITaskStackListener> mTaskStackListeners;
+    private ArrayList<IProcessObserver> mProcessObservers;
     private ArrayList<TaskSystemBarsListener> mTaskSystemBarsListeners;
     private ArrayList<RunningTaskInfo> mRunningTaskInfos;
 
@@ -185,6 +191,16 @@
             return null;
         }).when(mMockActivityTaskManager).unregisterTaskStackListener(any());
 
+        mProcessObservers = new ArrayList<>();
+        doAnswer(invocation -> {
+            mProcessObservers.add(invocation.getArgument(0));
+            return null;
+        }).when(mMockActivityManager).registerProcessObserver(any());
+        doAnswer(invocation -> {
+            mProcessObservers.remove(invocation.getArgument(0));
+            return null;
+        }).when(mMockActivityManager).unregisterProcessObserver(any());
+
         mTaskSystemBarsListeners = new ArrayList<>();
         doAnswer(invocation -> {
             mTaskSystemBarsListeners.add(invocation.getArgument(0));
@@ -206,6 +222,7 @@
                 mMockContext,
                 mFakeGameClassifier,
                 mMockActivityManager,
+                mMockActivityManagerInternal,
                 mMockActivityTaskManager,
                 mMockWindowManagerService,
                 mMockWindowManagerInternal,
@@ -429,6 +446,214 @@
     }
 
     @Test
+    public void gameProcessStopped_soleProcess_destroysGameSession() throws Exception {
+        int gameProcessId = 1000;
+
+        mGameServiceProviderInstance.start();
+
+        startTask(10, GAME_A_MAIN_ACTIVITY);
+        startProcessForPackage(gameProcessId, GAME_A_PACKAGE);
+
+        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
+        mFakeGameService.requestCreateGameSession(10);
+
+        FakeGameSession gameSession10 = new FakeGameSession();
+        SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+        mFakeGameSessionService.removePendingFutureForTaskId(10)
+                .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+        assertThat(gameSession10.mIsDestroyed).isFalse();
+
+        // Death of the sole game process destroys the game session.
+        dispatchProcessDied(gameProcessId);
+        assertThat(gameSession10.mIsDestroyed).isTrue();
+    }
+
+    @Test
+    public void gameProcessStopped_soleProcess_destroysMultipleGameSessionsForSamePackage()
+            throws Exception {
+        int gameProcessId = 1000;
+
+        mGameServiceProviderInstance.start();
+
+        // Multiple tasks exist for the same package.
+        startTask(10, GAME_A_MAIN_ACTIVITY);
+        startTask(11, GAME_A_MAIN_ACTIVITY);
+        startProcessForPackage(gameProcessId, GAME_A_PACKAGE);
+
+        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
+        mFakeGameService.requestCreateGameSession(10);
+        mFakeGameService.requestCreateGameSession(11);
+
+        FakeGameSession gameSession10 = new FakeGameSession();
+        SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+        mFakeGameSessionService.removePendingFutureForTaskId(10)
+                .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+        FakeGameSession gameSession11 = new FakeGameSession();
+        SurfacePackage mockSurfacePackage11 = Mockito.mock(SurfacePackage.class);
+        mFakeGameSessionService.removePendingFutureForTaskId(11)
+                .complete(new CreateGameSessionResult(gameSession11, mockSurfacePackage11));
+
+        assertThat(gameSession10.mIsDestroyed).isFalse();
+        assertThat(gameSession11.mIsDestroyed).isFalse();
+
+        // Death of the sole game process destroys both game sessions.
+        dispatchProcessDied(gameProcessId);
+        assertThat(gameSession10.mIsDestroyed).isTrue();
+        assertThat(gameSession11.mIsDestroyed).isTrue();
+    }
+
+    @Test
+    public void gameProcessStopped_multipleProcesses_gameSessionDestroyedWhenAllDead()
+            throws Exception {
+        int firstGameProcessId = 1000;
+        int secondGameProcessId = 1001;
+
+        mGameServiceProviderInstance.start();
+
+        startTask(10, GAME_A_MAIN_ACTIVITY);
+        startProcessForPackage(firstGameProcessId, GAME_A_PACKAGE);
+        startProcessForPackage(secondGameProcessId, GAME_A_PACKAGE);
+
+        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
+        mFakeGameService.requestCreateGameSession(10);
+
+        FakeGameSession gameSession10 = new FakeGameSession();
+        SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+        mFakeGameSessionService.removePendingFutureForTaskId(10)
+                .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+        assertThat(gameSession10.mIsDestroyed).isFalse();
+
+        // Death of the first process (with the second one still alive) does not destroy the game
+        // session.
+        dispatchProcessDied(firstGameProcessId);
+        assertThat(gameSession10.mIsDestroyed).isFalse();
+
+        // Death of the second process does destroy the game session.
+        dispatchProcessDied(secondGameProcessId);
+        assertThat(gameSession10.mIsDestroyed).isTrue();
+    }
+
+    @Test
+    public void gameProcessCreatedAfterInitialProcessDead_newGameSessionCreated() throws Exception {
+        int firstGameProcessId = 1000;
+        int secondGameProcessId = 1000;
+
+        mGameServiceProviderInstance.start();
+
+        startTask(10, GAME_A_MAIN_ACTIVITY);
+        startProcessForPackage(firstGameProcessId, GAME_A_PACKAGE);
+
+        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
+        mFakeGameService.requestCreateGameSession(10);
+
+        FakeGameSession gameSession10 = new FakeGameSession();
+        SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+        mFakeGameSessionService.removePendingFutureForTaskId(10)
+                .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+        assertThat(gameSession10.mIsDestroyed).isFalse();
+
+        // After the first game process dies, the game session should be destroyed.
+        dispatchProcessDied(firstGameProcessId);
+        assertThat(gameSession10.mIsDestroyed).isTrue();
+
+        // However, when a new process for the game starts, a new game session should be created.
+        startProcessForPackage(secondGameProcessId, GAME_A_PACKAGE);
+        // Verify that a new pending game session is created for the game's taskId.
+        assertNotNull(mFakeGameSessionService.removePendingFutureForTaskId(10));
+    }
+
+    @Test
+    public void gameProcessCreatedAfterInitialProcessDead_multipleGameSessionsCreatedSamePackage()
+            throws Exception {
+        int firstGameProcessId = 1000;
+        int secondGameProcessId = 1000;
+
+        mGameServiceProviderInstance.start();
+
+        // Multiple tasks exist for the same package.
+        startTask(10, GAME_A_MAIN_ACTIVITY);
+        startTask(11, GAME_A_MAIN_ACTIVITY);
+        startProcessForPackage(firstGameProcessId, GAME_A_PACKAGE);
+
+        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
+
+        mFakeGameService.requestCreateGameSession(10);
+        mFakeGameService.requestCreateGameSession(11);
+
+        FakeGameSession gameSession10 = new FakeGameSession();
+        SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+        mFakeGameSessionService.removePendingFutureForTaskId(10)
+                .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+        FakeGameSession gameSession11 = new FakeGameSession();
+        SurfacePackage mockSurfacePackage11 = Mockito.mock(SurfacePackage.class);
+        mFakeGameSessionService.removePendingFutureForTaskId(11)
+                .complete(new CreateGameSessionResult(gameSession11, mockSurfacePackage11));
+
+        assertThat(gameSession10.mIsDestroyed).isFalse();
+        assertThat(gameSession11.mIsDestroyed).isFalse();
+
+        // After the first game process dies, both game sessions for the package should be
+        // destroyed.
+        dispatchProcessDied(firstGameProcessId);
+        assertThat(gameSession10.mIsDestroyed).isTrue();
+        assertThat(gameSession11.mIsDestroyed).isTrue();
+
+        // However, when a new process for the game starts, new game sessions for the same
+        // package should be created.
+        startProcessForPackage(secondGameProcessId, GAME_A_PACKAGE);
+        // Verify that new pending game sessions were created for each of the game's taskIds.
+        assertNotNull(mFakeGameSessionService.removePendingFutureForTaskId(10));
+        assertNotNull(mFakeGameSessionService.removePendingFutureForTaskId(11));
+    }
+
+    @Test
+    public void gameProcessStarted_gameSessionNotRequested_doesNothing() throws Exception {
+        int gameProcessId = 1000;
+
+        mGameServiceProviderInstance.start();
+
+        // A game task and process are started, but requestCreateGameSession is never called.
+        startTask(10, GAME_A_MAIN_ACTIVITY);
+        startProcessForPackage(gameProcessId, GAME_A_PACKAGE);
+
+        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
+
+        // No game session should be created.
+        assertThat(mFakeGameSessionService.getCapturedCreateInvocations()).isEmpty();
+    }
+
+    @Test
+    public void processActivityAndDeath_notForGame_gameSessionUnaffected() throws Exception {
+        mGameServiceProviderInstance.start();
+
+        startTask(10, GAME_A_MAIN_ACTIVITY);
+
+        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
+        mFakeGameService.requestCreateGameSession(10);
+
+        FakeGameSession gameSession10 = new FakeGameSession();
+        SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+        mFakeGameSessionService.removePendingFutureForTaskId(10)
+                .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+
+        // Process activity for a process without a known package is ignored.
+        startProcessForPackage(1000, /*packageName=*/ null);
+        dispatchProcessActivity(1000);
+        dispatchProcessDied(1000);
+
+        // Process activity for a process with a different package is ignored
+        startProcessForPackage(1001, GAME_B_PACKAGE);
+        dispatchProcessActivity(1001);
+        dispatchProcessDied(1001);
+
+        // Death of a process for which there was no activity is ignored
+        dispatchProcessDied(1002);
+
+        // Despite all the process activity and death, the game session is not destroyed.
+        assertThat(gameSession10.mIsDestroyed).isFalse();
+    }
+
+    @Test
     public void taskSystemBarsListenerChanged_noAssociatedGameSession_doesNothing() {
         mGameServiceProviderInstance.start();
 
@@ -900,7 +1125,8 @@
                 mFakeGameSessionService.getCapturedCreateInvocations())
                 .mGameSessionController.restartGame(11);
 
-        verifyZeroInteractions(mMockActivityManager);
+        verify(mMockActivityManager).registerProcessObserver(any());
+        verifyNoMoreInteractions(mMockActivityManager);
         assertThat(mMockContext.getLastStartedIntent()).isNull();
     }
 
@@ -932,7 +1158,6 @@
         dispatchTaskRemoved(taskId);
     }
 
-
     private void dispatchTaskRemoved(int taskId) {
         dispatchTaskChangeEvent(taskStackListener -> {
             taskStackListener.onTaskRemoved(taskId);
@@ -958,6 +1183,37 @@
         }
     }
 
+    private void startProcessForPackage(int processId, @Nullable String packageName) {
+        if (packageName != null) {
+            when(mMockActivityManagerInternal.getPackageNameByPid(processId)).thenReturn(
+                    packageName);
+        }
+
+        dispatchProcessActivity(processId);
+    }
+
+    private void dispatchProcessActivity(int processId) {
+        dispatchProcessChangedEvent(processObserver -> {
+            // Neither uid nor foregroundActivities are used by the implementation being tested.
+            processObserver.onForegroundActivitiesChanged(processId, /*uid=*/
+                    0, /*foregroundActivities=*/ false);
+        });
+    }
+
+    private void dispatchProcessDied(int processId) {
+        dispatchProcessChangedEvent(processObserver -> {
+            // The uid param is not used by the implementation being tested.
+            processObserver.onProcessDied(processId, /*uid=*/ 0);
+        });
+    }
+
+    private void dispatchProcessChangedEvent(
+            ThrowingConsumer<IProcessObserver> processObserverConsumer) {
+        for (IProcessObserver processObserver : mProcessObservers) {
+            processObserverConsumer.accept(processObserver);
+        }
+    }
+
     private void mockPermissionGranted(String permission) {
         mMockContext.setPermission(permission, PackageManager.PERMISSION_GRANTED);
     }
diff --git a/services/tests/mockingservicestests/src/com/android/server/devicepolicy/FactoryResetterTest.java b/services/tests/mockingservicestests/src/com/android/server/devicepolicy/FactoryResetterTest.java
index 457c8db..4ffa0fb 100644
--- a/services/tests/mockingservicestests/src/com/android/server/devicepolicy/FactoryResetterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/devicepolicy/FactoryResetterTest.java
@@ -14,11 +14,13 @@
  * limitations under the License.
  */
 
+// TODO(b/225012970): should be moved to com.android.server
 package com.android.server.devicepolicy;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.FactoryResetter.isFactoryResetting;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -165,6 +167,7 @@
                 .factoryReset();
 
         assertThat(success).isTrue();
+        assertThat(isFactoryResetting()).isTrue();
         verifyWipeAdoptableStorageCalled();
         verifyWipeFactoryResetProtectionNotCalled();
         verifyRebootWipeUserDataMinimumArgsCalled();
@@ -179,6 +182,7 @@
                 .build().factoryReset();
 
         assertThat(success).isTrue();
+        assertThat(isFactoryResetting()).isTrue();
         verifyWipeAdoptableStorageNotCalled();
         verifyWipeFactoryResetProtectionCalled();
         verifyRebootWipeUserDataMinimumArgsCalled();
@@ -198,6 +202,7 @@
                 .build().factoryReset();
 
         assertThat(success).isTrue();
+        assertThat(isFactoryResetting()).isTrue();
         verifyWipeAdoptableStorageCalled();
         verifyWipeFactoryResetProtectionCalled();
         verifyRebootWipeUserDataAllArgsCalled();
@@ -211,6 +216,7 @@
                 .setSafetyChecker(mSafetyChecker).build().factoryReset();
 
         assertThat(success).isFalse();
+        assertThat(isFactoryResetting()).isTrue();
         verifyWipeAdoptableStorageNotCalled();
         verifyWipeFactoryResetProtectionNotCalled();
         verifyRebootWipeUserDataNotCalled();
@@ -238,6 +244,7 @@
                 .build().factoryReset();
 
         assertThat(success).isFalse();
+        assertThat(isFactoryResetting()).isTrue();
         verifyWipeAdoptableStorageCalled();
         verifyWipeFactoryResetProtectionCalled();
         verifyRebootWipeUserDataAllArgsCalled();
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 784f732..617321b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -118,6 +118,7 @@
         LocalServices.removeServiceForTest(LightsManager.class);
         LocalServices.addService(LightsManager.class, mMockedLightsManager);
         mInjector = new Injector();
+        when(mSurfaceControlProxy.getBootDisplayModeSupport()).thenReturn(true);
         mAdapter = new LocalDisplayAdapter(mMockedSyncRoot, mMockedContext, mHandler,
                 mListener, mInjector);
         spyOn(mAdapter);
@@ -177,7 +178,7 @@
         // This should be public
         assertDisplayPrivateFlag(mListener.addedDisplays.get(0).getDisplayDeviceInfoLocked(),
                 PORT_A, false);
-        // This should be public
+        // This should be private
         assertDisplayPrivateFlag(mListener.addedDisplays.get(1).getDisplayDeviceInfoLocked(),
                 PORT_B, true);
         // This should be public
@@ -904,7 +905,6 @@
                 .thenReturn(display.dynamicInfo);
         when(mSurfaceControlProxy.getDesiredDisplayModeSpecs(display.token))
                 .thenReturn(display.desiredDisplayModeSpecs);
-        when(mSurfaceControlProxy.getBootDisplayModeSupport()).thenReturn(true);
     }
 
     private void updateAvailableDisplays() {
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
index f9bdad6..296e8a3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -30,7 +30,6 @@
 import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -56,11 +55,6 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
-import android.platform.test.annotations.LargeTest;
-import android.util.Log;
-import android.util.SparseArray;
-import android.util.SparseBooleanArray;
-import android.util.SparseLongArray;
 
 import com.android.server.AppStateTracker;
 import com.android.server.AppStateTrackerImpl;
@@ -82,16 +76,10 @@
 import java.time.Clock;
 import java.time.Duration;
 import java.time.ZoneOffset;
-import java.util.Random;
 
 public class JobSchedulerServiceTest {
     private static final String TAG = JobSchedulerServiceTest.class.getSimpleName();
 
-    private static final int[] sRegJobPriorities = {
-            JobInfo.PRIORITY_HIGH, JobInfo.PRIORITY_DEFAULT,
-            JobInfo.PRIORITY_LOW, JobInfo.PRIORITY_MIN
-    };
-
     private JobSchedulerService mService;
 
     private MockitoSession mMockingSession;
@@ -769,7 +757,7 @@
         job.setStandbyBucket(RARE_INDEX);
 
         // Not enough RARE jobs to run.
-        mService.mPendingJobs.clear();
+        mService.mPendingJobQueue.clear();
         maybeQueueFunctor.reset();
         for (int i = 0; i < mService.mConstants.MIN_READY_NON_ACTIVE_JOBS_COUNT / 2; ++i) {
             maybeQueueFunctor.accept(job);
@@ -778,10 +766,10 @@
             assertEquals(sElapsedRealtimeClock.millis(), job.getFirstForceBatchedTimeElapsed());
         }
         maybeQueueFunctor.postProcessLocked();
-        assertEquals(0, mService.mPendingJobs.size());
+        assertEquals(0, mService.mPendingJobQueue.size());
 
         // Enough RARE jobs to run.
-        mService.mPendingJobs.clear();
+        mService.mPendingJobQueue.clear();
         maybeQueueFunctor.reset();
         for (int i = 0; i < mService.mConstants.MIN_READY_NON_ACTIVE_JOBS_COUNT; ++i) {
             maybeQueueFunctor.accept(job);
@@ -790,10 +778,10 @@
             assertEquals(sElapsedRealtimeClock.millis(), job.getFirstForceBatchedTimeElapsed());
         }
         maybeQueueFunctor.postProcessLocked();
-        assertEquals(5, mService.mPendingJobs.size());
+        assertEquals(5, mService.mPendingJobQueue.size());
 
         // Not enough RARE jobs to run, but a non-batched job saves the day.
-        mService.mPendingJobs.clear();
+        mService.mPendingJobQueue.clear();
         maybeQueueFunctor.reset();
         JobStatus activeJob = createJobStatus(
                 "testRareJobBatching",
@@ -807,10 +795,10 @@
         }
         maybeQueueFunctor.accept(activeJob);
         maybeQueueFunctor.postProcessLocked();
-        assertEquals(3, mService.mPendingJobs.size());
+        assertEquals(3, mService.mPendingJobQueue.size());
 
         // Not enough RARE jobs to run, but an old RARE job saves the day.
-        mService.mPendingJobs.clear();
+        mService.mPendingJobQueue.clear();
         maybeQueueFunctor.reset();
         JobStatus oldRareJob = createJobStatus("testRareJobBatching", createJobInfo());
         oldRareJob.setStandbyBucket(RARE_INDEX);
@@ -826,7 +814,7 @@
         maybeQueueFunctor.accept(oldRareJob);
         assertEquals(oldBatchTime, oldRareJob.getFirstForceBatchedTimeElapsed());
         maybeQueueFunctor.postProcessLocked();
-        assertEquals(3, mService.mPendingJobs.size());
+        assertEquals(3, mService.mPendingJobQueue.size());
     }
 
     /** Tests that jobs scheduled by the app itself are counted towards scheduling limits. */
@@ -914,358 +902,4 @@
                             0, ""));
         }
     }
-
-    @Test
-    public void testPendingJobSorting() {
-        // First letter in job variable name indicate regular (r) or expedited (e).
-        // Capital letters in job variable name indicate the app/UID.
-        // Numbers in job variable name indicate the enqueue time.
-        // Expected sort order:
-        //   eA7 > rA1 > eB6 > rB2 > eC3 > rD4 > eE5 > eF9 > rF8 > eC11 > rC10 > rG12 > rG13 > eE14
-        // Intentions:
-        //   * A jobs let us test skipping both regular and expedited jobs of other apps
-        //   * B jobs let us test skipping only regular job of another app without going too far
-        //   * C jobs test that regular jobs don't skip over other app's jobs and that EJs only
-        //     skip up to level of the earliest regular job
-        //   * E jobs test that expedited jobs don't skip the line when the app has no regular jobs
-        //   * F jobs test correct expedited/regular ordering doesn't push jobs too high in list
-        //   * G jobs test correct ordering for regular jobs
-        //   * H job tests correct behavior when enqueue times are the same
-        JobStatus rA1 = createJobStatus("testPendingJobSorting", createJobInfo(1), 1);
-        JobStatus rB2 = createJobStatus("testPendingJobSorting", createJobInfo(2), 2);
-        JobStatus eC3 = createJobStatus("testPendingJobSorting",
-                createJobInfo(3).setExpedited(true), 3);
-        JobStatus rD4 = createJobStatus("testPendingJobSorting", createJobInfo(4), 4);
-        JobStatus eE5 = createJobStatus("testPendingJobSorting",
-                createJobInfo(5).setExpedited(true), 5);
-        JobStatus eB6 = createJobStatus("testPendingJobSorting",
-                createJobInfo(6).setExpedited(true), 2);
-        JobStatus eA7 = createJobStatus("testPendingJobSorting",
-                createJobInfo(7).setExpedited(true), 1);
-        JobStatus rH8 = createJobStatus("testPendingJobSorting", createJobInfo(8), 8);
-        JobStatus rF8 = createJobStatus("testPendingJobSorting", createJobInfo(8), 6);
-        JobStatus eF9 = createJobStatus("testPendingJobSorting",
-                createJobInfo(9).setExpedited(true), 6);
-        JobStatus rC10 = createJobStatus("testPendingJobSorting", createJobInfo(10), 3);
-        JobStatus eC11 = createJobStatus("testPendingJobSorting",
-                createJobInfo(11).setExpedited(true), 3);
-        JobStatus rG12 = createJobStatus("testPendingJobSorting", createJobInfo(12), 7);
-        JobStatus rG13 = createJobStatus("testPendingJobSorting", createJobInfo(13), 7);
-        JobStatus eE14 = createJobStatus("testPendingJobSorting",
-                createJobInfo(14).setExpedited(true), 5);
-
-        rA1.enqueueTime = 10;
-        rB2.enqueueTime = 20;
-        eC3.enqueueTime = 30;
-        rD4.enqueueTime = 40;
-        eE5.enqueueTime = 50;
-        eB6.enqueueTime = 60;
-        eA7.enqueueTime = 70;
-        rF8.enqueueTime = 80;
-        rH8.enqueueTime = 80;
-        eF9.enqueueTime = 90;
-        rC10.enqueueTime = 100;
-        eC11.enqueueTime = 110;
-        rG12.enqueueTime = 120;
-        rG13.enqueueTime = 130;
-        eE14.enqueueTime = 140;
-
-        mService.mPendingJobs.clear();
-        // Add in random order so sorting is apparent.
-        mService.mPendingJobs.add(eC3);
-        mService.mPendingJobs.add(eE5);
-        mService.mPendingJobs.add(rA1);
-        mService.mPendingJobs.add(rG13);
-        mService.mPendingJobs.add(rD4);
-        mService.mPendingJobs.add(eA7);
-        mService.mPendingJobs.add(rG12);
-        mService.mPendingJobs.add(rH8);
-        mService.mPendingJobs.add(rF8);
-        mService.mPendingJobs.add(eB6);
-        mService.mPendingJobs.add(eE14);
-        mService.mPendingJobs.add(eF9);
-        mService.mPendingJobs.add(rB2);
-        mService.mPendingJobs.add(rC10);
-        mService.mPendingJobs.add(eC11);
-
-        mService.mPendingJobComparator.refreshLocked();
-        mService.mPendingJobs.sort(mService.mPendingJobComparator);
-
-        final JobStatus[] expectedOrder = new JobStatus[]{
-                eA7, rA1, eB6, rB2, eC3, rD4, eE5, eF9, rH8, rF8, eC11, rC10, rG12, rG13, eE14};
-        for (int i = 0; i < expectedOrder.length; ++i) {
-            assertEquals("List wasn't correctly sorted @ index " + i,
-                    expectedOrder[i].getJobId(), mService.mPendingJobs.get(i).getJobId());
-        }
-    }
-
-    private void checkPendingJobInvariants() {
-        final SparseBooleanArray regJobSeen = new SparseBooleanArray();
-        // Latest priority enqueue times seen for each priority for each app.
-        final SparseArray<SparseLongArray> latestPriorityRegEnqueueTimesPerUid =
-                new SparseArray<>();
-        final SparseArray<SparseLongArray> latestPriorityEjEnqueueTimesPerUid = new SparseArray<>();
-        final long noEntry = -1;
-
-        for (int i = 0; i < mService.mPendingJobs.size(); ++i) {
-            final JobStatus job = mService.mPendingJobs.get(i);
-            final int uid = job.getSourceUid();
-
-            // Invariant #1: All jobs (for a UID) are sorted by priority order
-            // Invariant #2: Jobs (for a UID) with the same priority are sorted by enqueue time.
-            // Invariant #3: EJs (for a UID) should be before regular jobs
-
-            final int priority = job.getEffectivePriority();
-            final SparseArray<SparseLongArray> latestPriorityEnqueueTimesPerUid =
-                    job.isRequestedExpeditedJob()
-                            ? latestPriorityEjEnqueueTimesPerUid
-                            : latestPriorityRegEnqueueTimesPerUid;
-            SparseLongArray latestPriorityEnqueueTimes = latestPriorityEnqueueTimesPerUid.get(uid);
-            if (latestPriorityEnqueueTimes != null) {
-                // Invariant 1
-                for (int p = priority - 1; p >= JobInfo.PRIORITY_MIN; --p) {
-                    // If we haven't seen the priority, there shouldn't be an entry in the array.
-                    assertEquals("Jobs not properly sorted by priority for uid " + uid,
-                            noEntry, latestPriorityEnqueueTimes.get(p, noEntry));
-                }
-
-                // Invariant 2
-                final long lastSeenPriorityEnqueueTime =
-                        latestPriorityEnqueueTimes.get(priority, noEntry);
-                if (lastSeenPriorityEnqueueTime != noEntry) {
-                    assertTrue("Jobs with same priority not sorted by enqueue time: "
-                                    + lastSeenPriorityEnqueueTime + " vs " + job.enqueueTime,
-                            lastSeenPriorityEnqueueTime <= job.enqueueTime);
-                }
-            } else {
-                latestPriorityEnqueueTimes = new SparseLongArray();
-                latestPriorityEnqueueTimesPerUid.put(uid, latestPriorityEnqueueTimes);
-            }
-            latestPriorityEnqueueTimes.put(priority, job.enqueueTime);
-
-            // Invariant 3
-            if (!job.isRequestedExpeditedJob()) {
-                regJobSeen.put(uid, true);
-            } else if (regJobSeen.get(uid)) {
-                fail("UID " + uid + " had an EJ ordered after a regular job");
-            }
-        }
-    }
-
-    private static String sortedJobToString(JobStatus job) {
-        return "testJob " + job.getSourceUid() + "/" + job.getJobId()
-                + "/p" + job.getEffectivePriority()
-                + "/" + job.isRequestedExpeditedJob() + "@" + job.enqueueTime;
-    }
-
-    @Test
-    public void testPendingJobSorting_Random() {
-        Random random = new Random(1); // Always use the same series of pseudo random values.
-
-        mService.mPendingJobs.clear();
-
-        for (int i = 0; i < 5000; ++i) {
-            JobStatus job = createJobStatus("testPendingJobSorting_Random",
-                    createJobInfo(i).setExpedited(random.nextBoolean()), random.nextInt(250));
-            job.enqueueTime = random.nextInt(1_000_000);
-            mService.mPendingJobs.add(job);
-        }
-
-        mService.mPendingJobComparator.refreshLocked();
-        try {
-            mService.mPendingJobs.sort(mService.mPendingJobComparator);
-        } catch (Exception e) {
-            for (JobStatus toDump : mService.mPendingJobs) {
-                Log.i(TAG, sortedJobToString(toDump));
-            }
-            throw e;
-        }
-        checkPendingJobInvariants();
-    }
-
-    private int sign(int i) {
-        if (i > 0) {
-            return 1;
-        }
-        if (i < 0) {
-            return -1;
-        }
-        return 0;
-    }
-
-    @Test
-    public void testPendingJobSortingTransitivity() {
-        // Always use the same series of pseudo random values.
-        for (int seed : new int[]{1337, 7357, 606, 6357, 41106010, 3, 2, 1}) {
-            Random random = new Random(seed);
-
-            mService.mPendingJobs.clear();
-
-            for (int i = 0; i < 300; ++i) {
-                JobStatus job = createJobStatus("testPendingJobSortingTransitivity",
-                        createJobInfo(i).setExpedited(random.nextBoolean()), random.nextInt(50));
-                job.enqueueTime = random.nextInt(1_000_000);
-                job.overrideState = random.nextInt(4);
-                mService.mPendingJobs.add(job);
-            }
-
-            verifyPendingJobComparatorTransitivity();
-        }
-    }
-
-    @Test
-    @LargeTest
-    public void testPendingJobSortingTransitivity_Concentrated() {
-        // Always use the same series of pseudo random values.
-        for (int seed : new int[]{1337, 6000, 637739, 6357, 1, 7, 13}) {
-            Random random = new Random(seed);
-
-            mService.mPendingJobs.clear();
-
-            for (int i = 0; i < 300; ++i) {
-                JobStatus job = createJobStatus("testPendingJobSortingTransitivity_Concentrated",
-                        createJobInfo(i).setExpedited(random.nextFloat() < .03),
-                        random.nextInt(20));
-                job.enqueueTime = random.nextInt(250);
-                job.overrideState = random.nextFloat() < .01
-                        ? JobStatus.OVERRIDE_SORTING : JobStatus.OVERRIDE_NONE;
-                mService.mPendingJobs.add(job);
-                Log.d(TAG, sortedJobToString(job));
-            }
-
-            verifyPendingJobComparatorTransitivity();
-        }
-    }
-
-    @Test
-    public void testPendingJobSorting_Random_WithPriority() {
-        Random random = new Random(1); // Always use the same series of pseudo random values.
-
-        mService.mPendingJobs.clear();
-
-        for (int i = 0; i < 5000; ++i) {
-            final boolean isEj = random.nextBoolean();
-            final int priority;
-            if (isEj) {
-                priority = random.nextBoolean() ? JobInfo.PRIORITY_MAX : JobInfo.PRIORITY_HIGH;
-            } else {
-                priority = sRegJobPriorities[random.nextInt(sRegJobPriorities.length)];
-            }
-            JobStatus job = createJobStatus("testPendingJobSorting_Random_WithPriority",
-                    createJobInfo(i).setExpedited(isEj).setPriority(priority),
-                    random.nextInt(250));
-            job.enqueueTime = random.nextInt(1_000_000);
-            mService.mPendingJobs.add(job);
-        }
-
-        mService.mPendingJobComparator.refreshLocked();
-        try {
-            mService.mPendingJobs.sort(mService.mPendingJobComparator);
-        } catch (Exception e) {
-            for (JobStatus toDump : mService.mPendingJobs) {
-                Log.i(TAG, sortedJobToString(toDump));
-            }
-            throw e;
-        }
-        checkPendingJobInvariants();
-    }
-
-    @Test
-    public void testPendingJobSortingTransitivity_WithPriority() {
-        // Always use the same series of pseudo random values.
-        for (int seed : new int[]{1337, 7357, 606, 6357, 41106010, 3, 2, 1}) {
-            Random random = new Random(seed);
-
-            mService.mPendingJobs.clear();
-
-            for (int i = 0; i < 300; ++i) {
-                final boolean isEj = random.nextBoolean();
-                final int priority;
-                if (isEj) {
-                    priority = random.nextBoolean() ? JobInfo.PRIORITY_MAX : JobInfo.PRIORITY_HIGH;
-                } else {
-                    priority = sRegJobPriorities[random.nextInt(sRegJobPriorities.length)];
-                }
-                JobStatus job = createJobStatus("testPendingJobSortingTransitivity_WithPriority",
-                        createJobInfo(i).setExpedited(isEj).setPriority(priority),
-                        random.nextInt(50));
-                job.enqueueTime = random.nextInt(1_000_000);
-                job.overrideState = random.nextInt(4);
-                mService.mPendingJobs.add(job);
-            }
-
-            verifyPendingJobComparatorTransitivity();
-        }
-    }
-
-    @Test
-    @LargeTest
-    public void testPendingJobSortingTransitivity_Concentrated_WithPriority() {
-        // Always use the same series of pseudo random values.
-        for (int seed : new int[]{1337, 6000, 637739, 6357, 1, 7, 13}) {
-            Random random = new Random(seed);
-
-            mService.mPendingJobs.clear();
-
-            for (int i = 0; i < 300; ++i) {
-                final boolean isEj = random.nextFloat() < .03;
-                final int priority;
-                if (isEj) {
-                    priority = random.nextBoolean() ? JobInfo.PRIORITY_MAX : JobInfo.PRIORITY_HIGH;
-                } else {
-                    priority = sRegJobPriorities[random.nextInt(sRegJobPriorities.length)];
-                }
-                JobStatus job = createJobStatus(
-                        "testPendingJobSortingTransitivity_Concentrated_WithPriority",
-                        createJobInfo(i).setExpedited(isEj).setPriority(priority),
-                        random.nextInt(20));
-                job.enqueueTime = random.nextInt(250);
-                job.overrideState = random.nextFloat() < .01
-                        ? JobStatus.OVERRIDE_SORTING : JobStatus.OVERRIDE_NONE;
-                mService.mPendingJobs.add(job);
-                Log.d(TAG, sortedJobToString(job));
-            }
-
-            verifyPendingJobComparatorTransitivity();
-        }
-    }
-
-    private void verifyPendingJobComparatorTransitivity() {
-        mService.mPendingJobComparator.refreshLocked();
-
-        for (int i = 0; i < mService.mPendingJobs.size(); ++i) {
-            final JobStatus job1 = mService.mPendingJobs.get(i);
-
-            for (int j = 0; j < mService.mPendingJobs.size(); ++j) {
-                final JobStatus job2 = mService.mPendingJobs.get(j);
-                final int sign12 = sign(mService.mPendingJobComparator.compare(job1, job2));
-                final int sign21 = sign(mService.mPendingJobComparator.compare(job2, job1));
-                if (sign12 != -sign21) {
-                    final String job1String = sortedJobToString(job1);
-                    final String job2String = sortedJobToString(job2);
-                    fail("compare(" + job1String + ", " + job2String + ") != "
-                            + "-compare(" + job2String + ", " + job1String + ")");
-                }
-
-                for (int k = 0; k < mService.mPendingJobs.size(); ++k) {
-                    final JobStatus job3 = mService.mPendingJobs.get(k);
-                    final int sign23 = sign(mService.mPendingJobComparator.compare(job2, job3));
-                    final int sign13 = sign(mService.mPendingJobComparator.compare(job1, job3));
-
-                    // Confirm 1 < 2 < 3 or 1 > 2 > 3 or 1 == 2 == 3
-                    if ((sign12 == sign23 && sign12 != sign13)
-                            // Confirm that if 1 == 2, then (1 < 3 AND 2 < 3) OR (1 > 3 && 2 > 3)
-                            || (sign12 == 0 && sign13 != sign23)) {
-                        final String job1String = sortedJobToString(job1);
-                        final String job2String = sortedJobToString(job2);
-                        final String job3String = sortedJobToString(job3);
-                        fail("Transitivity fail"
-                                + ": compare(" + job1String + ", " + job2String + ")=" + sign12
-                                + ", compare(" + job2String + ", " + job3String + ")=" + sign23
-                                + ", compare(" + job1String + ", " + job3String + ")=" + sign13);
-                    }
-                }
-            }
-        }
-    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
index 8223b8c..444db91 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
@@ -19,7 +19,9 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
@@ -36,23 +38,21 @@
 import android.content.IntentFilter;
 import android.os.HandlerThread;
 import android.os.PowerManager;
-import android.util.ArraySet;
 
 import com.android.server.LocalServices;
 import com.android.server.PinnerService;
 import com.android.server.pm.dex.DexManager;
-import com.android.server.pm.dex.DexoptOptions;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.stream.Collectors;
@@ -66,9 +66,8 @@
 
     private static final long TEST_WAIT_TIMEOUT_MS = 10_000;
 
-    private static final ArraySet<String> DEFAULT_PACKAGE_LIST = new ArraySet<>(
-            Arrays.asList("aaa", "bbb"));
-    private static final ArraySet<String> EMPTY_PACKAGE_LIST = new ArraySet<>();
+    private static final List<String> DEFAULT_PACKAGE_LIST = List.of("aaa", "bbb");
+    private static final List<String> EMPTY_PACKAGE_LIST = List.of();
 
     @Mock
     private Context mContext;
@@ -116,9 +115,11 @@
         when(mInjector.getDataDirStorageLowBytes()).thenReturn(STORAGE_LOW_BYTES);
         when(mInjector.getDexOptThermalCutoff()).thenReturn(PowerManager.THERMAL_STATUS_CRITICAL);
         when(mInjector.getCurrentThermalStatus()).thenReturn(PowerManager.THERMAL_STATUS_NONE);
-        when(mDexOptHelper.getOptimizablePackages()).thenReturn(DEFAULT_PACKAGE_LIST);
+        when(mInjector.supportSecondaryDex()).thenReturn(true);
+        when(mDexOptHelper.getOptimizablePackages(any())).thenReturn(DEFAULT_PACKAGE_LIST);
         when(mDexOptHelper.performDexOptWithStatus(any())).thenReturn(
                 PackageDexOptimizer.DEX_OPT_PERFORMED);
+        when(mDexOptHelper.performDexOpt(any())).thenReturn(true);
 
         mService = new BackgroundDexOptService(mInjector);
     }
@@ -158,7 +159,7 @@
     @Test
     public void testNoExecutionForNoOptimizablePackages() {
         initUntilBootCompleted();
-        when(mDexOptHelper.getOptimizablePackages()).thenReturn(EMPTY_PACKAGE_LIST);
+        when(mDexOptHelper.getOptimizablePackages(any())).thenReturn(EMPTY_PACKAGE_LIST);
 
         assertThat(mService.onStartJob(mJobServiceForPostBoot,
                 mJobParametersForPostBoot)).isFalse();
@@ -418,26 +419,16 @@
         verifyPerformDexOpt(DEFAULT_PACKAGE_LIST, totalJobRuns);
     }
 
-    private void verifyPerformDexOpt(ArraySet<String> pkgs, int expectedRuns) {
-        ArgumentCaptor<DexoptOptions> dexOptOptions = ArgumentCaptor.forClass(DexoptOptions.class);
-        verify(mDexOptHelper, atLeastOnce()).performDexOptWithStatus(dexOptOptions.capture());
-        HashMap<String, Integer> primaryPkgs = new HashMap<>(); // K: pkg, V: dexopt runs left
-        for (String pkg : pkgs) {
-            primaryPkgs.put(pkg, expectedRuns);
-        }
-
-        for (DexoptOptions opt : dexOptOptions.getAllValues()) {
-            assertThat(pkgs).contains(opt.getPackageName());
-            assertThat(opt.isDexoptOnlySecondaryDex()).isFalse();
-            Integer count = primaryPkgs.get(opt.getPackageName());
-            assertThat(count).isNotNull();
-            if (count == 1) {
-                primaryPkgs.remove(opt.getPackageName());
-            } else {
-                primaryPkgs.put(opt.getPackageName(), count - 1);
+    private void verifyPerformDexOpt(List<String> pkgs, int expectedRuns) {
+        InOrder inOrder = inOrder(mDexOptHelper);
+        for (int i = 0; i < expectedRuns; i++) {
+            for (String pkg : pkgs) {
+                inOrder.verify(mDexOptHelper, times(1)).performDexOptWithStatus(argThat((option) ->
+                        option.getPackageName().equals(pkg) && !option.isDexoptOnlySecondaryDex()));
+                inOrder.verify(mDexOptHelper, times(1)).performDexOpt(argThat((option) ->
+                        option.getPackageName().equals(pkg) && option.isDexoptOnlySecondaryDex()));
             }
         }
-        assertThat(primaryPkgs).isEmpty();
     }
 
     private static class StartAndWaitThread extends Thread {
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/DeletePackageHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/DeletePackageHelperTest.kt
new file mode 100644
index 0000000..c9598bd
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/DeletePackageHelperTest.kt
@@ -0,0 +1,96 @@
+/*
+ * 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.server.pm
+
+import android.content.pm.PackageManager
+import android.content.pm.UserInfo
+import android.os.Build
+import android.util.Log
+import com.android.server.testutils.any
+import com.android.server.testutils.spy
+import com.android.server.testutils.whenever
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mockito.doAnswer
+
+@RunWith(JUnit4::class)
+class DeletePackageHelperTest {
+
+    @Rule
+    @JvmField
+    val rule = MockSystemRule()
+
+    private lateinit var mPms: PackageManagerService
+    private lateinit var mUserManagerInternal: UserManagerInternal
+
+    @Before
+    @Throws(Exception::class)
+    fun setup() {
+        Log.i("system.out", "setup", Exception())
+        rule.system().stageNominalSystemState()
+        rule.system().stageScanExistingPackage(
+            "a.data.package", 1L, rule.system().dataAppDirectory)
+
+        mUserManagerInternal = rule.mocks().injector.userManagerInternal
+        whenever(mUserManagerInternal.getUserIds()).thenReturn(intArrayOf(0, 1))
+
+        mPms = createPackageManagerService()
+        doAnswer { false }.`when`(mPms).isPackageDeviceAdmin(any(), any())
+        doAnswer { null }.`when`(mPms).freezePackageForDelete(any(), any(), any(), any())
+    }
+
+    private fun createPackageManagerService(): PackageManagerService {
+        return spy(PackageManagerService(rule.mocks().injector,
+            false /*coreOnly*/,
+            false /*factoryTest*/,
+            MockSystem.DEFAULT_VERSION_INFO.fingerprint,
+            false /*isEngBuild*/,
+            false /*isUserDebugBuild*/,
+            Build.VERSION_CODES.CUR_DEVELOPMENT,
+            Build.VERSION.INCREMENTAL))
+    }
+
+    @Test
+    fun deleteSystemPackageFailsIfNotAdmin() {
+        val ps = mPms.mSettings.getPackageLPr("a.data.package")
+        whenever(PackageManagerServiceUtils.isSystemApp(ps)).thenReturn(true)
+        whenever(mUserManagerInternal.getUserInfo(1)).thenReturn(UserInfo(1, "test", 0))
+
+        val dph = DeletePackageHelper(mPms)
+        val result = dph.deletePackageX("a.data.package", 1L, 1, 0, false)
+
+        assertThat(result).isEqualTo(PackageManager.DELETE_FAILED_USER_RESTRICTED)
+    }
+
+    @Test
+    fun deleteSystemPackageSucceedsIfAdmin() {
+        val ps = mPms.mSettings.getPackageLPr("a.data.package")
+        whenever(PackageManagerServiceUtils.isSystemApp(ps)).thenReturn(true)
+        whenever(mUserManagerInternal.getUserInfo(1)).thenReturn(
+            UserInfo(1, "test", UserInfo.FLAG_ADMIN))
+
+        val dph = DeletePackageHelper(mPms)
+        val result = dph.deletePackageX("a.data.package", 1L, 1,
+            PackageManager.DELETE_SYSTEM_APP, false)
+
+        assertThat(result).isEqualTo(PackageManager.DELETE_SUCCEEDED)
+    }
+}
\ No newline at end of file
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/OWNERS b/services/tests/mockingservicestests/src/com/android/server/pm/OWNERS
index 46b797b..5181af1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/OWNERS
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/OWNERS
@@ -1,3 +1,4 @@
 include /services/core/java/com/android/server/pm/OWNERS
 
+per-file BackgroundDexOptServiceUnitTest.java = file:/services/core/java/com/android/server/pm/dex/OWNERS
 per-file StagingManagerTest.java = dariofreni@google.com, ioffe@google.com, olilan@google.com
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
index 1319903..537a028 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
@@ -157,7 +157,7 @@
         rule.system().validateFinalState()
         whenever(appHibernationManager.isHibernatingGlobally(TEST_PACKAGE_2_NAME)).thenReturn(true)
 
-        val optimizablePkgs = DexOptHelper(pm).optimizablePackages
+        val optimizablePkgs = DexOptHelper(pm).getOptimizablePackages(pm.snapshotComputer())
 
         assertTrue(optimizablePkgs.contains(TEST_PACKAGE_NAME))
         assertFalse(optimizablePkgs.contains(TEST_PACKAGE_2_NAME))
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
index b063d22..97b52a9 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
@@ -24,7 +24,6 @@
 import android.os.storage.StorageManager
 import android.util.ArrayMap
 import android.util.PackageUtils
-import com.android.internal.util.FunctionalUtils
 import com.android.server.SystemConfig.SharedLibraryEntry
 import com.android.server.compat.PlatformCompat
 import com.android.server.extendedtestutils.wheneverStatic
@@ -35,7 +34,6 @@
 import com.android.server.testutils.any
 import com.android.server.testutils.eq
 import com.android.server.testutils.mock
-import com.android.server.testutils.mockThrowOnUnmocked
 import com.android.server.testutils.nullable
 import com.android.server.testutils.spy
 import com.android.server.testutils.whenever
@@ -59,6 +57,7 @@
 import kotlin.test.assertFalse
 import kotlin.test.assertTrue
 
+@Ignore("b/216603387")
 @RunWith(JUnit4::class)
 class SharedLibrariesImplTest {
 
@@ -85,6 +84,7 @@
     private lateinit var mSharedLibrariesImpl: SharedLibrariesImpl
     private lateinit var mPms: PackageManagerService
     private lateinit var mSettings: Settings
+    private lateinit var mComputer: Computer
 
     @Mock
     private lateinit var mDeletePackageHelper: DeletePackageHelper
@@ -114,22 +114,16 @@
         mSharedLibrariesImpl.setDeletePackageHelper(mDeletePackageHelper)
         addExistingSharedLibraries()
 
+        mComputer = mock {
+            whenever(sharedLibraries) { mSharedLibrariesImpl.sharedLibraries }
+            whenever(resolveInternalPackageName(anyString(), anyLong())) { arguments[0] }
+        }
+
         whenever(mSettings.getPackageLPr(any())) { mExistingSettings[arguments[0]] }
         whenever(mRule.mocks().injector.getSystemService(StorageManager::class.java))
             .thenReturn(mStorageManager)
         whenever(mStorageManager.findPathForUuid(nullable())).thenReturn(mFile)
-        doAnswer { it.arguments[0] }.`when`(mPms).resolveInternalPackageName(any(), any())
-        doAnswer {
-            mockThrowOnUnmocked<Computer> {
-                whenever(sharedLibraries) { mSharedLibrariesImpl.sharedLibraries }
-                whenever(resolveInternalPackageName(anyString(), anyLong())) {
-                    mPms.resolveInternalPackageName(getArgument(0), getArgument(1))
-                }
-                whenever(getPackageStateInternal(anyString())) {
-                    mPms.getPackageStateInternal(getArgument(0))
-                }
-            }
-        }.`when`(mPms).snapshotComputer()
+        doAnswer { mComputer }.`when`(mPms).snapshotComputer()
         whenever(mDeletePackageHelper.deletePackageX(any(), any(), any(), any(), any()))
             .thenReturn(PackageManager.DELETE_SUCCEEDED)
         whenever(mRule.mocks().injector.compatibility).thenReturn(mPlatformCompat)
@@ -189,7 +183,8 @@
 
     @Test
     fun removeSharedLibrary() {
-        doAnswer { mutableListOf(VersionedPackage(CONSUMER_PACKAGE_NAME, 1L)) }.`when`(mPms)
+        doAnswer { mutableListOf(VersionedPackage(CONSUMER_PACKAGE_NAME, 1L)) }
+            .`when`(mComputer)
             .getPackagesUsingSharedLibrary(any(), any(), any(), any())
         val staticInfo = mSharedLibrariesImpl
             .getSharedLibraryInfo(STATIC_LIB_NAME, STATIC_LIB_VERSION)!!
@@ -253,7 +248,6 @@
         assertThat(testPackageSetting.usesLibraryFiles).contains(builtinLibPath(BUILTIN_LIB_NAME))
     }
 
-    @Ignore("b/216603387")
     @Test
     fun updateSharedLibraries_withStaticLibPackage() {
         val testPackageSetting = mExistingSettings[STATIC_LIB_PACKAGE_NAME]!!
@@ -266,7 +260,6 @@
         assertThat(testPackageSetting.usesLibraryFiles).contains(apkPath(DYNAMIC_LIB_PACKAGE_NAME))
     }
 
-    @Ignore("b/216603387")
     @Test
     fun updateSharedLibraries_withConsumerPackage() {
         val testPackageSetting = mExistingSettings[CONSUMER_PACKAGE_NAME]!!
@@ -280,7 +273,6 @@
         assertThat(testPackageSetting.usesLibraryFiles).contains(apkPath(STATIC_LIB_PACKAGE_NAME))
     }
 
-    @Ignore("b/216603387")
     @Test
     fun updateAllSharedLibraries() {
         mExistingSettings.forEach {
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
index 5230ea7..4818573 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
@@ -104,9 +104,9 @@
             pms, rule.mocks().injector, broadcastHelper, protectedPackages)
         defaultAppProvider = rule.mocks().defaultAppProvider
         testHandler = rule.mocks().handler
-        packageSetting1 = pms.getPackageStateInternal(TEST_PACKAGE_1)!!
-        packageSetting2 = pms.getPackageStateInternal(TEST_PACKAGE_2)!!
-        ownerSetting = pms.getPackageStateInternal(DEVICE_OWNER_PACKAGE)!!
+        packageSetting1 = pms.snapshotComputer().getPackageStateInternal(TEST_PACKAGE_1)!!
+        packageSetting2 = pms.snapshotComputer().getPackageStateInternal(TEST_PACKAGE_2)!!
+        ownerSetting = pms.snapshotComputer().getPackageStateInternal(DEVICE_OWNER_PACKAGE)!!
         deviceOwnerUid = UserHandle.getUid(TEST_USER_ID, ownerSetting.appId)
         packagesToSuspend = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
         uidsToSuspend = intArrayOf(packageSetting1.appId, packageSetting2.appId)
@@ -270,7 +270,7 @@
         testHandler.flush()
         assertThat(failedNames).isEmpty()
 
-        val result = suspendPackageHelper.getSuspendedPackageAppExtras(
+        val result = suspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
             TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)!!
 
         assertThat(result.getString(TEST_PACKAGE_1)).isEqualTo(TEST_PACKAGE_1)
@@ -286,13 +286,13 @@
             null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)
         testHandler.flush()
         assertThat(failedNames).isEmpty()
-        assertThat(suspendPackageHelper.getSuspendingPackage(
+        assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
             TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
-        assertThat(suspendPackageHelper.getSuspendingPackage(
+        assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
             TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
-        assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(
+        assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
             TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isNotNull()
-        assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(
+        assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
             TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isNotNull()
 
         suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
@@ -311,13 +311,13 @@
             nullable(), nullable(), any(), eq(TEST_PACKAGE_2), nullable(), any(), any(),
             nullable(), nullable())
 
-        assertThat(suspendPackageHelper.getSuspendingPackage(
+        assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
             TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isNull()
-        assertThat(suspendPackageHelper.getSuspendingPackage(
+        assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
             TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isNull()
-        assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(
+        assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
             TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isNull()
-        assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(
+        assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
             TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isNull()
     }
 
@@ -331,7 +331,7 @@
         testHandler.flush()
         assertThat(failedNames).isEmpty()
 
-        val result = suspendPackageHelper.getSuspendedPackageLauncherExtras(
+        val result = suspendPackageHelper.getSuspendedPackageLauncherExtras(pms.snapshotComputer(),
             TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)!!
 
         assertThat(result.getString(TEST_PACKAGE_2)).isEqualTo(TEST_PACKAGE_2)
@@ -346,7 +346,7 @@
         testHandler.flush()
         assertThat(failedNames).isEmpty()
 
-        assertThat(suspendPackageHelper.isPackageSuspended(
+        assertThat(suspendPackageHelper.isPackageSuspended(pms.snapshotComputer(),
             TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isTrue()
     }
 
@@ -360,7 +360,7 @@
         testHandler.flush()
         assertThat(failedNames).isEmpty()
 
-        assertThat(suspendPackageHelper.getSuspendingPackage(
+        assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
             TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
     }
 
@@ -375,7 +375,7 @@
         testHandler.flush()
         assertThat(failedNames).isEmpty()
 
-        val result = suspendPackageHelper.getSuspendedDialogInfo(
+        val result = suspendPackageHelper.getSuspendedDialogInfo(pms.snapshotComputer(),
             TEST_PACKAGE_1, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)!!
 
         assertThat(result.title).isEqualTo(TEST_PACKAGE_1)
@@ -387,8 +387,8 @@
         mockAllowList(packageSetting1, allowList(10001, 10002, 10003))
         mockAllowList(packageSetting2, allowList(10001, 10002, 10003))
 
-        suspendPackageHelper.sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENDED,
-                packagesToSuspend, uidsToSuspend, TEST_USER_ID)
+        suspendPackageHelper.sendPackagesSuspendedForUser(pms.snapshotComputer(),
+            Intent.ACTION_PACKAGES_SUSPENDED, packagesToSuspend, uidsToSuspend, TEST_USER_ID)
         testHandler.flush()
         verify(broadcastHelper).sendPackageBroadcast(any(), nullable(), bundleCaptor.capture(),
                 anyInt(), nullable(), nullable(), any(), nullable(), any(), nullable())
@@ -406,8 +406,8 @@
         mockAllowList(packageSetting1, allowList(10001, 10002, 10003))
         mockAllowList(packageSetting2, allowList(10001, 10002, 10007))
 
-        suspendPackageHelper.sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENDED,
-                packagesToSuspend, uidsToSuspend, TEST_USER_ID)
+        suspendPackageHelper.sendPackagesSuspendedForUser(pms.snapshotComputer(),
+            Intent.ACTION_PACKAGES_SUSPENDED, packagesToSuspend, uidsToSuspend, TEST_USER_ID)
         testHandler.flush()
         verify(broadcastHelper, times(2)).sendPackageBroadcast(
                 any(), nullable(), bundleCaptor.capture(), anyInt(), nullable(), nullable(), any(),
@@ -429,8 +429,8 @@
         mockAllowList(packageSetting1, allowList(10001, 10002, 10003))
         mockAllowList(packageSetting2, null)
 
-        suspendPackageHelper.sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENDED,
-                packagesToSuspend, uidsToSuspend, TEST_USER_ID)
+        suspendPackageHelper.sendPackagesSuspendedForUser(pms.snapshotComputer(),
+            Intent.ACTION_PACKAGES_SUSPENDED, packagesToSuspend, uidsToSuspend, TEST_USER_ID)
         testHandler.flush()
         verify(broadcastHelper, times(2)).sendPackageBroadcast(
                 any(), nullable(), bundleCaptor.capture(), anyInt(), nullable(), nullable(), any(),
@@ -449,8 +449,9 @@
     @Test
     @Throws(Exception::class)
     fun sendPackagesSuspendModifiedForUser() {
-        suspendPackageHelper.sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED,
-                packagesToSuspend, uidsToSuspend, TEST_USER_ID)
+        suspendPackageHelper.sendPackagesSuspendedForUser(pms.snapshotComputer(),
+            Intent.ACTION_PACKAGES_SUSPENSION_CHANGED, packagesToSuspend, uidsToSuspend,
+            TEST_USER_ID)
         testHandler.flush()
         verify(broadcastHelper).sendPackageBroadcast(
                 eq(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED), nullable(), bundleCaptor.capture(),
@@ -483,13 +484,13 @@
         Mockito.doReturn(DIALER_PACKAGE).`when`(defaultAppProvider)
             .getDefaultDialer(eq(TEST_USER_ID))
         Mockito.doReturn(arrayOf(INSTALLER_PACKAGE)).`when`(pms).getKnownPackageNamesInternal(
-            eq(PackageManagerInternal.PACKAGE_INSTALLER), eq(TEST_USER_ID))
+            any(), eq(PackageManagerInternal.PACKAGE_INSTALLER), eq(TEST_USER_ID))
         Mockito.doReturn(arrayOf(UNINSTALLER_PACKAGE)).`when`(pms).getKnownPackageNamesInternal(
-            eq(PackageManagerInternal.PACKAGE_UNINSTALLER), eq(TEST_USER_ID))
+            any(), eq(PackageManagerInternal.PACKAGE_UNINSTALLER), eq(TEST_USER_ID))
         Mockito.doReturn(arrayOf(VERIFIER_PACKAGE)).`when`(pms).getKnownPackageNamesInternal(
-            eq(PackageManagerInternal.PACKAGE_VERIFIER), eq(TEST_USER_ID))
+            any(), eq(PackageManagerInternal.PACKAGE_VERIFIER), eq(TEST_USER_ID))
         Mockito.doReturn(arrayOf(PERMISSION_CONTROLLER_PACKAGE)).`when`(pms)
-            .getKnownPackageNamesInternal(
+            .getKnownPackageNamesInternal(any(),
                 eq(PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER), eq(TEST_USER_ID))
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java
index 8abe46f..9d26971 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -159,8 +159,8 @@
             .when(mockContext)
                 .getSystemService(PowerManager.class);
 
-        mDexManager = new DexManager(mockContext, mPM, /*PackageDexOptimizer*/ null,
-                mInstaller, mInstallLock);
+        mDexManager = new DexManager(mockContext, /*PackageDexOptimizer*/ null,
+                mInstaller, mInstallLock, mPM);
 
         // Foo and Bar are available to user0.
         // Only Bar is available to user1;
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
index 41d46f2..534d0a1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
@@ -21,7 +21,6 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
 import android.app.AlarmManager;
 import android.content.Context;
@@ -71,10 +70,10 @@
                 .strictness(Strictness.LENIENT)
                 .mockStatic(LocalServices.class)
                 .startMocking();
-        when(mIrs.getContext()).thenReturn(mContext);
-        when(mIrs.getCompleteEconomicPolicyLocked()).thenReturn(mEconomicPolicy);
-        when(mIrs.getLock()).thenReturn(mIrs);
-        when(mContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mock(AlarmManager.class));
+        doReturn(mContext).when(mIrs).getContext();
+        doReturn(mEconomicPolicy).when(mIrs).getCompleteEconomicPolicyLocked();
+        doReturn(mIrs).when(mIrs).getLock();
+        doReturn(mock(AlarmManager.class)).when(mContext).getSystemService(Context.ALARM_SERVICE);
         mScribe = new MockScribe(mIrs);
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
index ab29e59..c2cf2ff 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
@@ -109,6 +109,7 @@
         long lastReclamationTime = System.currentTimeMillis();
         long remainingConsumableNarcs = 2000L;
         long consumptionLimit = 500_000L;
+        when(mIrs.getConsumptionLimitLocked()).thenReturn(consumptionLimit);
 
         Ledger ledger = mScribeUnderTest.getLedgerLocked(TEST_USER_ID, TEST_PACKAGE);
         ledger.recordTransaction(new Ledger.Transaction(0, 1000L, 1, null, 2000, 0));
@@ -119,8 +120,13 @@
         mScribeUnderTest.setConsumptionLimitLocked(consumptionLimit);
         mScribeUnderTest.adjustRemainingConsumableNarcsLocked(
                 remainingConsumableNarcs - consumptionLimit);
-        mScribeUnderTest.writeImmediatelyForTesting();
 
+        assertEquals(lastReclamationTime, mScribeUnderTest.getLastReclamationTimeLocked());
+        assertEquals(remainingConsumableNarcs,
+                mScribeUnderTest.getRemainingConsumableNarcsLocked());
+        assertEquals(consumptionLimit, mScribeUnderTest.getSatiatedConsumptionLimitLocked());
+
+        mScribeUnderTest.writeImmediatelyForTesting();
         mScribeUnderTest.loadFromDiskLocked();
 
         assertEquals(lastReclamationTime, mScribeUnderTest.getLastReclamationTimeLocked());
diff --git a/services/tests/mockingservicestests/src/com/android/server/utils/TimingsTraceAndSlogTest.java b/services/tests/mockingservicestests/src/com/android/server/utils/TimingsTraceAndSlogTest.java
new file mode 100644
index 0000000..52cd29c
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/utils/TimingsTraceAndSlogTest.java
@@ -0,0 +1,165 @@
+/*
+ * 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.server.utils;
+
+import static android.os.Trace.TRACE_TAG_APP;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.contains;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.matches;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+
+import android.os.Trace;
+import android.util.Slog;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.dx.mockito.inline.extended.MockedVoidMethod;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoSession;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for {@link TimingsTraceAndSlog}.
+ *
+ * <p>Usage: {@code atest FrameworksMockingServicesTests:TimingsTraceAndSlogTest}
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TimingsTraceAndSlogTest {
+
+    private static final String TAG = "TEST";
+
+    private MockitoSession mSession;
+
+    @Before
+    public final void startMockSession() {
+        mSession = mockitoSession()
+                .spyStatic(Slog.class)
+                .spyStatic(Trace.class)
+                .startMocking();
+    }
+
+    @After
+    public final void finishMockSession() {
+        mSession.finishMocking();
+    }
+
+    @Test
+    public void testDifferentThreads() throws Exception {
+        TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+        // Should be able to log on the same thread
+        log.traceBegin("test");
+        log.traceEnd();
+        final List<String> errors = new ArrayList<>();
+        // Calling from a different thread should fail
+        Thread t = new Thread(() -> {
+            try {
+                log.traceBegin("test");
+                errors.add("traceBegin should fail on a different thread");
+            } catch (IllegalStateException expected) {
+            }
+            try {
+                log.traceEnd();
+                errors.add("traceEnd should fail on a different thread");
+            } catch (IllegalStateException expected) {
+            }
+            // Verify that creating a new log will work
+            TimingsTraceAndSlog log2 = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+            log2.traceBegin("test");
+            log2.traceEnd();
+
+        });
+        t.start();
+        t.join();
+        assertThat(errors).isEmpty();
+    }
+
+    @Test
+    public void testGetUnfinishedTracesForDebug() {
+        TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+        assertThat(log.getUnfinishedTracesForDebug()).isEmpty();
+
+        log.traceBegin("One");
+        assertThat(log.getUnfinishedTracesForDebug()).containsExactly("One").inOrder();
+
+        log.traceBegin("Two");
+        assertThat(log.getUnfinishedTracesForDebug()).containsExactly("One", "Two").inOrder();
+
+        log.traceEnd();
+        assertThat(log.getUnfinishedTracesForDebug()).containsExactly("One").inOrder();
+
+        log.traceEnd();
+        assertThat(log.getUnfinishedTracesForDebug()).isEmpty();
+    }
+
+    @Test
+    public void testLogDuration() throws Exception {
+        TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+        log.logDuration("logro", 42);
+        verify((MockedVoidMethod) () -> Slog.v(eq(TAG), contains("logro took to complete: 42ms")));
+    }
+
+    @Test
+    public void testOneLevel() throws Exception {
+        TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+        log.traceBegin("test");
+        log.traceEnd();
+
+        verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "test"));
+        verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP));
+        verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("test took to complete: \\dms")));
+    }
+
+    @Test
+    public void testMultipleLevels() throws Exception {
+        TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+        log.traceBegin("L1");
+        log.traceBegin("L2");
+        log.traceEnd();
+        log.traceEnd();
+
+        verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L1"));
+        verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L2"));
+        verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP), times(2)); // L1 and L2
+
+        verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L2 took to complete: \\d+ms")));
+        verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L1 took to complete: \\d+ms")));
+    }
+
+    @Test
+    public void testEndNoBegin() throws Exception {
+        TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+        log.traceEnd();
+        verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP));
+        verify((MockedVoidMethod) () -> Slog.d(eq(TAG), anyString()), never());
+        verify((MockedVoidMethod) () -> Slog.w(TAG, "traceEnd called more times than traceBegin"));
+    }
+}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 152f3b3..e3be3a7 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -64,6 +64,7 @@
         "testng",
         "junit",
         "platform-compat-test-rules",
+        "ActivityContext",
     ],
 
     aidl: {
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index a6194df..449177e 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -100,7 +100,7 @@
         android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"/>
     <uses-permission android:name="android.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY" />
     <uses-permission android:name="android.permission.READ_NEARBY_STREAMING_POLICY" />
-
+    <uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING" />
     <uses-permission android:name="android.permission.PACKAGE_VERIFICATION_AGENT" />
 
     <queries>
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index 1f016fb..56c5150 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -28,6 +28,8 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doCallRealMethod;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -61,10 +63,12 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.compatibility.common.util.TestUtils;
+import com.android.internal.compat.IPlatformCompat;
 import com.android.server.LocalServices;
 import com.android.server.accessibility.AccessibilityManagerService.AccessibilityDisplayListener;
 import com.android.server.accessibility.magnification.FullScreenMagnificationController;
 import com.android.server.accessibility.magnification.MagnificationController;
+import com.android.server.accessibility.magnification.MagnificationProcessor;
 import com.android.server.accessibility.magnification.WindowMagnificationManager;
 import com.android.server.accessibility.test.MessageCapturingHandler;
 import com.android.server.pm.UserManagerInternal;
@@ -185,7 +189,7 @@
         mA11yms.mUserStates.put(mA11yms.getCurrentUserIdLocked(), userState);
     }
 
-    private void setupAccessibilityServiceConnection() {
+    private void setupAccessibilityServiceConnection(int serviceInfoFlag) {
         final AccessibilityUserState userState = mA11yms.mUserStates.get(
                 mA11yms.getCurrentUserIdLocked());
         when(mMockServiceInfo.getResolveInfo()).thenReturn(mMockResolveInfo);
@@ -193,7 +197,12 @@
         mMockResolveInfo.serviceInfo.applicationInfo = mock(ApplicationInfo.class);
 
         when(mMockBinder.queryLocalInterface(any())).thenReturn(mMockServiceClient);
+        when(mMockSystemSupport.getKeyEventDispatcher()).thenReturn(mock(KeyEventDispatcher.class));
+        when(mMockSystemSupport.getMagnificationProcessor()).thenReturn(
+                mock(MagnificationProcessor.class));
         mTestableContext.addMockService(COMPONENT_NAME, mMockBinder);
+
+        mMockServiceInfo.flags = serviceInfoFlag;
         mAccessibilityServiceConnection = new AccessibilityServiceConnection(
                 userState,
                 mTestableContext,
@@ -256,7 +265,7 @@
     @SmallTest
     @Test
     public void testOnSystemActionsChanged() throws Exception {
-        setupAccessibilityServiceConnection();
+        setupAccessibilityServiceConnection(0);
         final AccessibilityUserState userState = mA11yms.mUserStates.get(
                 mA11yms.getCurrentUserIdLocked());
 
@@ -376,7 +385,7 @@
     @SmallTest
     @Test
     public void testOnClientChange_boundServiceCanControlMagnification_requestConnection() {
-        setupAccessibilityServiceConnection();
+        setupAccessibilityServiceConnection(0);
         when(mMockSecurityPolicy.canControlMagnification(any())).thenReturn(true);
 
         // Invokes client change to trigger onUserStateChanged.
@@ -385,6 +394,29 @@
         verify(mMockWindowMagnificationMgr).requestConnection(true);
     }
 
+    @Test
+    public void testUnbindIme_whenServiceUnbinds() {
+        setupAccessibilityServiceConnection(AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR);
+        mAccessibilityServiceConnection.unbindLocked();
+        verify(mMockSystemSupport, atLeastOnce()).unbindImeLocked(mAccessibilityServiceConnection);
+    }
+
+    @Test
+    public void testUnbindIme_whenServiceCrashed() {
+        setupAccessibilityServiceConnection(AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR);
+        mAccessibilityServiceConnection.binderDied();
+        verify(mMockSystemSupport).unbindImeLocked(mAccessibilityServiceConnection);
+    }
+
+    @Test
+    public void testUnbindIme_whenServiceStopsRequestingIme() {
+        setupAccessibilityServiceConnection(AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR);
+        doCallRealMethod().when(mMockServiceInfo).updateDynamicallyConfigurableProperties(
+                any(IPlatformCompat.class), any(AccessibilityServiceInfo.class));
+        mAccessibilityServiceConnection.setServiceInfo(new AccessibilityServiceInfo());
+        verify(mMockSystemSupport).unbindImeLocked(mAccessibilityServiceConnection);
+    }
+
     public static class FakeInputFilter extends AccessibilityInputFilter {
         FakeInputFilter(Context context,
                 AccessibilityManagerService service) {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
index 4651546..edacc16 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
@@ -16,8 +16,6 @@
 
 package com.android.server.accessibility;
 
-import static android.content.pm.PackageManagerInternal.PACKAGE_INSTALLER;
-
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
 import static junit.framework.Assert.assertFalse;
@@ -45,14 +43,10 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.InstallSourceInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.content.pm.SigningInfo;
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -63,7 +57,6 @@
 import android.view.accessibility.AccessibilityWindowInfo;
 
 import com.android.internal.R;
-import com.android.server.LocalServices;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -150,22 +143,12 @@
     @Mock
     private AccessibilityServiceInfo mMockA11yServiceInfo;
     @Mock
-    private ResolveInfo mMockResolveInfo;
-    @Mock
-    private ServiceInfo mMockServiceInfo;
-    @Mock
-    private ApplicationInfo mMockApplicationInfo;
-    @Mock
-    private ApplicationInfo mMockSourceApplicationInfo;
-    @Mock
-    private PackageInfo mMockSourcePackageInfo;
-    @Mock
     private PolicyWarningUIController mPolicyWarningUIController;
     @Mock
     private PackageManagerInternal mPackageManagerInternal;
 
     @Before
-    public void setUp() throws PackageManager.NameNotFoundException {
+    public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext.setMockPackageManager(mMockPackageManager);
         mContext.addMockSystemService(Context.USER_SERVICE, mMockUserManager);
@@ -612,8 +595,7 @@
     }
 
     @Test
-    public void onBoundServicesChanged_nonA11yTool_invokeAction()
-            throws PackageManager.NameNotFoundException {
+    public void onBoundServicesChanged_nonA11yTool_invokeAction() {
         final ArrayList<AccessibilityServiceConnection> boundServices = new ArrayList<>();
         boundServices.add(mMockA11yServiceConnection);
         initServiceInfoAndConnection(TEST_COMPONENT_NAME,
@@ -630,14 +612,11 @@
     }
 
     @Test
-    public void onBoundServicesChanged_sysA11yTool_noAction()
-            throws PackageManager.NameNotFoundException {
+    public void onBoundServicesChanged_isA11yTool_noAction() {
         final ArrayList<AccessibilityServiceConnection> boundServices = new ArrayList<>();
         initServiceInfoAndConnection(TEST_COMPONENT_NAME,
                 mMockA11yServiceConnection,
-                /* isAccessibilityTool= */ true,
-                /* isSystemApp= */true,
-                /* installSourceInfo= */ null);
+                /* isAccessibilityTool= */ true);
         boundServices.add(mMockA11yServiceConnection);
 
         mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, boundServices);
@@ -649,63 +628,7 @@
     }
 
     @Test
-    public void onBoundServicesChanged_nonSysA11yToolFromAllowedInstallerInAllowedList_noAction()
-            throws PackageManager.NameNotFoundException {
-        final ArrayList<AccessibilityServiceConnection> boundServices = new ArrayList<>();
-        final String allowedSourcePackageName = "com.allowed.install.package";
-        mContext.getOrCreateTestableResources().addOverride(R.array
-                        .config_accessibility_allowed_install_source,
-                new String[]{allowedSourcePackageName});
-        // The allowed Installer should be system app in the allowed list.
-        InstallSourceInfo allowedSource = initInstallSourceInfo(
-                allowedSourcePackageName, /* isSystemApp= */ true);
-        initServiceInfoAndConnection(TEST_COMPONENT_NAME,
-                mMockA11yServiceConnection,
-                /* isAccessibilityTool= */ true,
-                /* isSystemApp= */ false,
-                allowedSource);
-        boundServices.add(mMockA11yServiceConnection);
-
-        mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, boundServices);
-        verify(mPolicyWarningUIController, never()).onNonA11yCategoryServiceBound(anyInt(), any());
-
-        mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, new ArrayList<>());
-        verify(mPolicyWarningUIController, never()).onNonA11yCategoryServiceUnbound(anyInt(),
-                any());
-    }
-
-    @Test
-    public void onBoundServicesChanged_nonSysA11yToolFromValidInstallerWithoutAllowedList_noAction()
-            throws PackageManager.NameNotFoundException {
-        final ArrayList<AccessibilityServiceConnection> boundServices = new ArrayList<>();
-        final String validInstallerPackageName = "com.valid.install.package";
-        final String defaultInstallerPackageName = "com.default.install.package";
-        LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
-        when(mPackageManagerInternal.getKnownPackageNames(PACKAGE_INSTALLER,
-                TEST_USER_ID)).thenReturn(new String[]{defaultInstallerPackageName});
-        mContext.getOrCreateTestableResources().addOverride(R.array
-                        .config_accessibility_allowed_install_source,
-                new String[]{});
-        // The valid Installer should be system app and not the default installer.
-        InstallSourceInfo validSource = initInstallSourceInfo(
-                validInstallerPackageName, /* isSystemApp= */ true);
-        initServiceInfoAndConnection(TEST_COMPONENT_NAME,
-                mMockA11yServiceConnection, /* isAccessibilityTool= */ true,
-                /* isSystemApp= */ false,
-                validSource);
-        boundServices.add(mMockA11yServiceConnection);
-
-        mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, boundServices);
-        verify(mPolicyWarningUIController, never()).onNonA11yCategoryServiceBound(anyInt(), any());
-
-        mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, new ArrayList<>());
-        verify(mPolicyWarningUIController, never()).onNonA11yCategoryServiceUnbound(anyInt(),
-                any());
-    }
-
-    @Test
-    public void onSwitchUser_oldUserHadAction_invokeActionForOldUser()
-            throws PackageManager.NameNotFoundException {
+    public void onSwitchUser_oldUserHadAction_invokeActionForOldUser() {
         final int newUserId = 2;
         final ArrayList<AccessibilityServiceConnection> boundServices = new ArrayList<>();
         initServiceInfoAndConnection(TEST_COMPONENT_NAME,
@@ -725,35 +648,9 @@
 
     private void initServiceInfoAndConnection(ComponentName componentName,
             AccessibilityServiceConnection connection,
-            boolean isAccessibilityTool) throws PackageManager.NameNotFoundException {
-        initServiceInfoAndConnection(componentName, connection, isAccessibilityTool, false, null);
-    }
-
-    private void initServiceInfoAndConnection(ComponentName componentName,
-            AccessibilityServiceConnection connection,
-            boolean isAccessibilityTool, boolean isSystemApp, InstallSourceInfo installSourceInfo)
-            throws PackageManager.NameNotFoundException {
+            boolean isAccessibilityTool) {
         when(connection.getServiceInfo()).thenReturn(mMockA11yServiceInfo);
         when(mMockA11yServiceInfo.getComponentName()).thenReturn(componentName);
         when(mMockA11yServiceInfo.isAccessibilityTool()).thenReturn(isAccessibilityTool);
-        when(mMockA11yServiceInfo.getResolveInfo()).thenReturn(mMockResolveInfo);
-        mMockResolveInfo.serviceInfo = mMockServiceInfo;
-        mMockServiceInfo.applicationInfo = mMockApplicationInfo;
-        mMockServiceInfo.packageName = componentName.getPackageName();
-        when(mMockApplicationInfo.isSystemApp()).thenReturn(isSystemApp);
-        when(mMockPackageManager.getInstallSourceInfo(componentName.getPackageName())).thenReturn(
-                installSourceInfo);
-    }
-
-    private InstallSourceInfo initInstallSourceInfo(String packageName, boolean isSystemApp)
-            throws PackageManager.NameNotFoundException {
-        final InstallSourceInfo installSourceInfo = new InstallSourceInfo(
-                packageName, new SigningInfo(), null,
-                packageName, PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED);
-        when(mMockPackageManager.getPackageInfo(packageName, 0)).thenReturn(
-                mMockSourcePackageInfo);
-        mMockSourcePackageInfo.applicationInfo = mMockSourceApplicationInfo;
-        when(mMockSourceApplicationInfo.isSystemApp()).thenReturn(isSystemApp);
-        return installSourceInfo;
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
index 27637c2..ed0336a 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
@@ -21,6 +21,7 @@
 import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN;
 import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HIDDEN;
 import static android.accessibilityservice.AccessibilityService.SHOW_MODE_IGNORE_HARD_KEYBOARD;
+import static android.content.pm.PackageManager.FEATURE_WINDOW_MAGNIFICATION;
 import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
 import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
 import static android.view.accessibility.AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
@@ -42,6 +43,7 @@
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.graphics.Color;
 import android.provider.Settings;
@@ -92,6 +94,8 @@
 
     @Mock private AccessibilityUserState.ServiceInfoChangeListener mMockListener;
 
+    @Mock private PackageManager mMockPackageManager;
+
     @Mock private Context mMockContext;
 
     private MockContentResolver mMockResolver;
@@ -113,6 +117,8 @@
         when(mMockServiceInfo.getComponentName()).thenReturn(COMPONENT_NAME);
         when(mMockConnection.getServiceInfo()).thenReturn(mMockServiceInfo);
         when(mMockContext.getResources()).thenReturn(resources);
+        when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+        when(mMockPackageManager.hasSystemFeature(FEATURE_WINDOW_MAGNIFICATION)).thenReturn(true);
 
         mFocusStrokeWidthDefaultValue =
                 resources.getDimensionPixelSize(R.dimen.accessibility_focus_highlight_stroke_width);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/PolicyWarningUIControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/PolicyWarningUIControllerTest.java
index b8535c2..3cd967d 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/PolicyWarningUIControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/PolicyWarningUIControllerTest.java
@@ -116,8 +116,7 @@
         mMockResolveInfo.serviceInfo = mMockServiceInfo;
         when(mMockA11yServiceInfo.getResolveInfo()).thenReturn(mMockResolveInfo);
         when(mMockA11yServiceInfo.getComponentName()).thenReturn(TEST_COMPONENT_NAME);
-        when(mAccessibilitySecurityPolicy.isA11yCategoryService(
-                mMockA11yServiceInfo)).thenReturn(false);
+        when(mMockA11yServiceInfo.isAccessibilityTool()).thenReturn(false);
 
         mFakeNotificationController.onReceive(mContext,
                 PolicyWarningUIController.createIntent(mContext, TEST_USER_ID,
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
index f3a0b7f..0780d21 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
@@ -28,6 +28,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
@@ -45,13 +46,16 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.Region;
+import android.hardware.display.DisplayManagerInternal;
 import android.os.Looper;
+import android.view.DisplayInfo;
 import android.view.MagnificationSpec;
 import android.view.accessibility.MagnificationAnimationCallback;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.LocalServices;
 import com.android.server.accessibility.AccessibilityTraceManager;
 import com.android.server.accessibility.test.MessageCapturingHandler;
 import com.android.server.wm.WindowManagerInternal;
@@ -113,6 +117,8 @@
 
     FullScreenMagnificationController mFullScreenMagnificationController;
 
+    public DisplayManagerInternal mDisplayManagerInternalMock = mock(DisplayManagerInternal.class);
+
     @Before
     public void setUp() {
         Looper looper = InstrumentationRegistry.getContext().getMainLooper();
@@ -125,6 +131,12 @@
         when(mMockControllerCtx.getAnimationDuration()).thenReturn(1000L);
         initMockWindowManager();
 
+        final DisplayInfo displayInfo = new DisplayInfo();
+        displayInfo.logicalDensityDpi = 300;
+        doReturn(displayInfo).when(mDisplayManagerInternalMock).getDisplayInfo(anyInt());
+        LocalServices.removeServiceForTest(DisplayManagerInternal.class);
+        LocalServices.addService(DisplayManagerInternal.class, mDisplayManagerInternalMock);
+
         mFullScreenMagnificationController = new FullScreenMagnificationController(
                 mMockControllerCtx, new Object(), mRequestObserver, mScaleProvider);
     }
diff --git a/services/tests/servicestests/src/com/android/server/audio/AbsoluteVolumeBehaviorTest.java b/services/tests/servicestests/src/com/android/server/audio/AbsoluteVolumeBehaviorTest.java
new file mode 100644
index 0000000..ad2e7e4
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/audio/AbsoluteVolumeBehaviorTest.java
@@ -0,0 +1,290 @@
+/*
+ * 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.server.audio;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.argThat;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceInfo;
+import android.media.AudioDeviceVolumeManager;
+import android.media.AudioManager;
+import android.media.AudioSystem;
+import android.media.IAudioDeviceVolumeDispatcher;
+import android.media.VolumeInfo;
+import android.os.RemoteException;
+import android.os.test.TestLooper;
+
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.List;
+
+public class AbsoluteVolumeBehaviorTest {
+    private static final String TAG = "AbsoluteVolumeBehaviorTest";
+
+    private static final AudioDeviceAttributes DEVICE_SPEAKER_OUT = new AudioDeviceAttributes(
+            AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, "");
+
+    private Context mContext;
+    private String mPackageName;
+    private AudioSystemAdapter mSpyAudioSystem;
+    private SystemServerAdapter mSystemServer;
+    private SettingsAdapter mSettingsAdapter;
+    private TestLooper mTestLooper;
+
+    private AudioService mAudioService;
+
+    private IAudioDeviceVolumeDispatcher.Stub mMockDispatcher =
+            mock(IAudioDeviceVolumeDispatcher.Stub.class);
+
+    @Before
+    public void setUp() throws Exception {
+        mTestLooper = new TestLooper();
+        mContext = InstrumentationRegistry.getTargetContext();
+        mPackageName = mContext.getOpPackageName();
+        mSpyAudioSystem = spy(new NoOpAudioSystemAdapter());
+
+        mSystemServer = new NoOpSystemServerAdapter();
+        mSettingsAdapter = new NoOpSettingsAdapter();
+        mAudioService = new AudioService(mContext, mSpyAudioSystem, mSystemServer,
+                mSettingsAdapter, mTestLooper.getLooper()) {
+            @Override
+            public int getDeviceForStream(int stream) {
+                return AudioSystem.DEVICE_OUT_SPEAKER;
+            }
+        };
+
+        mTestLooper.dispatchAll();
+    }
+
+    @Test
+    public void registerDispatcher_setsVolumeBehaviorToAbsolute() {
+        List<VolumeInfo> volumes = Collections.singletonList(
+                new VolumeInfo.Builder(AudioManager.STREAM_MUSIC).build());
+
+        mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true,
+                mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, volumes, true);
+        mTestLooper.dispatchAll();
+
+        assertThat(mAudioService.getDeviceVolumeBehavior(DEVICE_SPEAKER_OUT))
+                .isEqualTo(AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
+    }
+
+    @Test
+    public void registerDispatcher_setsVolume() {
+        List<VolumeInfo> volumes = Collections.singletonList(
+                new VolumeInfo.Builder(AudioManager.STREAM_MUSIC)
+                        .setMinVolumeIndex(0)
+                        .setMaxVolumeIndex(250) // Max index is 10 times that of STREAM_MUSIC
+                        .setVolumeIndex(50)
+                        .build());
+
+        mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true,
+                mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, volumes, true);
+        mTestLooper.dispatchAll();
+
+        assertThat(mAudioService.getStreamVolume(AudioManager.STREAM_MUSIC))
+                .isEqualTo(5);
+    }
+
+    @Test
+    public void unregisterDispatcher_deviceBecomesVariableVolume_listenerNoLongerTriggered()
+            throws RemoteException {
+
+        List<VolumeInfo> volumes = Collections.singletonList(
+                new VolumeInfo.Builder(AudioManager.STREAM_MUSIC).build());
+
+        mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true,
+                mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, volumes, true);
+        mTestLooper.dispatchAll();
+
+        mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(false,
+                mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, volumes, true);
+        mTestLooper.dispatchAll();
+
+        assertThat(mAudioService.getDeviceVolumeBehavior(DEVICE_SPEAKER_OUT))
+                .isEqualTo(AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE);
+
+        mAudioService.setStreamVolume(AudioManager.STREAM_MUSIC, 15, 0, mPackageName);
+        mTestLooper.dispatchAll();
+
+        verify(mMockDispatcher, never()).dispatchDeviceVolumeChanged(
+                eq(DEVICE_SPEAKER_OUT), any());
+    }
+
+    @Test
+    public void setDeviceVolumeBehavior_unregistersDispatcher() throws RemoteException {
+        List<VolumeInfo> volumes = Collections.singletonList(
+                new VolumeInfo.Builder(AudioManager.STREAM_MUSIC).build());
+
+        mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true,
+                mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, volumes, true);
+        mTestLooper.dispatchAll();
+
+        mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT,
+                AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL, mPackageName);
+        mTestLooper.dispatchAll();
+
+        mAudioService.setStreamVolume(AudioManager.STREAM_MUSIC, 15, 0, mPackageName);
+        mTestLooper.dispatchAll();
+
+        verify(mMockDispatcher, never()).dispatchDeviceVolumeChanged(
+                eq(DEVICE_SPEAKER_OUT), any());
+    }
+
+    @Test
+    public void setStreamVolume_noAbsVolFlag_dispatchesVolumeChanged() throws RemoteException {
+        VolumeInfo volumeInfo = new VolumeInfo.Builder(AudioManager.STREAM_MUSIC)
+                .setMinVolumeIndex(0)
+                .setMaxVolumeIndex(250) // Max index is 10 times that of STREAM_MUSIC
+                .setVolumeIndex(50)
+                .build();
+
+        mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true,
+                mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT,
+                Collections.singletonList(volumeInfo), true);
+        mTestLooper.dispatchAll();
+
+        // Set stream volume without FLAG_ABSOLUTE_VOLUME
+        mAudioService.setStreamVolume(AudioManager.STREAM_MUSIC, 15, 0, mPackageName);
+        mTestLooper.dispatchAll();
+
+        // Dispatched volume index is scaled to the range in the initial VolumeInfo
+        verify(mMockDispatcher).dispatchDeviceVolumeChanged(DEVICE_SPEAKER_OUT,
+                new VolumeInfo.Builder(volumeInfo).setVolumeIndex(150).build());
+    }
+
+    @Test
+    public void setStreamVolume_absVolFlagSet_doesNotDispatchVolumeChanged()
+            throws RemoteException {
+        VolumeInfo volumeInfo = new VolumeInfo.Builder(AudioManager.STREAM_MUSIC)
+                .setMinVolumeIndex(0)
+                .setMaxVolumeIndex(250)
+                .setVolumeIndex(50)
+                .build();
+
+        mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true,
+                mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT,
+                Collections.singletonList(volumeInfo), true);
+        mTestLooper.dispatchAll();
+
+        // Set stream volume with FLAG_ABSOLUTE_VOLUME
+        mAudioService.setStreamVolume(AudioManager.STREAM_MUSIC, 15,
+                AudioManager.FLAG_ABSOLUTE_VOLUME, mPackageName);
+        mTestLooper.dispatchAll();
+
+        verify(mMockDispatcher, never()).dispatchDeviceVolumeChanged(eq(DEVICE_SPEAKER_OUT),
+                any());
+    }
+
+    @Test
+    public void adjustStreamVolume_handlesAdjust_noAbsVolFlag_noVolChange_dispatchesVolumeAdjusted()
+            throws RemoteException {
+        VolumeInfo volumeInfo = new VolumeInfo.Builder(AudioManager.STREAM_MUSIC)
+                .setMinVolumeIndex(0)
+                .setMaxVolumeIndex(250)
+                .setVolumeIndex(0)
+                .build();
+
+        // Register dispatcher with handlesVolumeAdjustment = true
+        mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true,
+                mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT,
+                Collections.singletonList(volumeInfo), true);
+        mTestLooper.dispatchAll();
+
+        // Adjust stream volume without FLAG_ABSOLUTE_VOLUME
+        mAudioService.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE,
+                0, mPackageName);
+        mTestLooper.dispatchAll();
+
+        // Stream volume does not change
+        assertThat(mAudioService.getStreamVolume(AudioManager.STREAM_MUSIC)).isEqualTo(0);
+        // Listener is notified via dispatchDeviceVolumeAdjusted
+        verify(mMockDispatcher, never()).dispatchDeviceVolumeChanged(eq(DEVICE_SPEAKER_OUT), any());
+        verify(mMockDispatcher).dispatchDeviceVolumeAdjusted(eq(DEVICE_SPEAKER_OUT),
+                argThat((VolumeInfo v) -> v.getStreamType() == AudioManager.STREAM_MUSIC),
+                eq(AudioManager.ADJUST_RAISE), eq(AudioDeviceVolumeManager.ADJUST_MODE_NORMAL));
+    }
+
+    @Test
+    public void adjustStreamVolume_noHandleAdjust_noAbsVolFlag_volChanges_dispatchesVolumeChanged()
+            throws RemoteException {
+        VolumeInfo volumeInfo = new VolumeInfo.Builder(AudioManager.STREAM_MUSIC)
+                .setMinVolumeIndex(0)
+                .setMaxVolumeIndex(250)
+                .setVolumeIndex(0)
+                .build();
+
+        // Register dispatcher with handlesVolumeAdjustment = false
+        mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true,
+                mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT,
+                Collections.singletonList(volumeInfo), false);
+        mTestLooper.dispatchAll();
+
+        // Adjust stream volume without FLAG_ABSOLUTE_VOLUME
+        mAudioService.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE,
+                0, mPackageName);
+        mTestLooper.dispatchAll();
+
+        // Stream volume changes
+        assertThat(mAudioService.getStreamVolume(AudioManager.STREAM_MUSIC)).isNotEqualTo(0);
+        // Listener is notified via dispatchDeviceVolumeChanged
+        verify(mMockDispatcher).dispatchDeviceVolumeChanged(eq(DEVICE_SPEAKER_OUT), any());
+        verify(mMockDispatcher, never()).dispatchDeviceVolumeAdjusted(eq(DEVICE_SPEAKER_OUT), any(),
+                anyInt(), anyInt());
+    }
+
+    @Test
+    public void adjustStreamVolume_absVolFlagSet_streamVolumeChanges_nothingDispatched()
+            throws RemoteException {
+        VolumeInfo volumeInfo = new VolumeInfo.Builder(AudioManager.STREAM_MUSIC)
+                .setMinVolumeIndex(0)
+                .setMaxVolumeIndex(250)
+                .setVolumeIndex(0)
+                .build();
+
+        mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true,
+                mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT,
+                Collections.singletonList(volumeInfo), true);
+        mTestLooper.dispatchAll();
+
+        // Adjust stream volume with FLAG_ABSOLUTE_VOLUME set
+        mAudioService.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE,
+                AudioManager.FLAG_ABSOLUTE_VOLUME, mPackageName);
+        mTestLooper.dispatchAll();
+
+        // Stream volume changes
+        assertThat(mAudioService.getStreamVolume(AudioManager.STREAM_MUSIC)).isNotEqualTo(0);
+        // Nothing is dispatched
+        verify(mMockDispatcher, never()).dispatchDeviceVolumeChanged(eq(DEVICE_SPEAKER_OUT), any());
+        verify(mMockDispatcher, never()).dispatchDeviceVolumeAdjusted(eq(DEVICE_SPEAKER_OUT), any(),
+                anyInt(), anyInt());
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioServiceTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioServiceTest.java
index c0ba3c7..91c45b4 100644
--- a/services/tests/servicestests/src/com/android/server/audio/AudioServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/AudioServiceTest.java
@@ -45,6 +45,7 @@
     private Context mContext;
     private AudioSystemAdapter mAudioSystem;
     @Spy private SystemServerAdapter mSpySystemServer;
+    private SettingsAdapter mSettingsAdapter;
     // the class being unit-tested here
     private AudioService mAudioService;
 
@@ -59,7 +60,9 @@
         mContext = InstrumentationRegistry.getTargetContext();
         mAudioSystem = new NoOpAudioSystemAdapter();
         mSpySystemServer = spy(new NoOpSystemServerAdapter());
-        mAudioService = new AudioService(mContext, mAudioSystem, mSpySystemServer);
+        mSettingsAdapter = new NoOpSettingsAdapter();
+        mAudioService = new AudioService(mContext, mAudioSystem, mSpySystemServer,
+                mSettingsAdapter, null);
     }
 
     /**
diff --git a/services/tests/servicestests/src/com/android/server/audio/DeviceVolumeBehaviorTest.java b/services/tests/servicestests/src/com/android/server/audio/DeviceVolumeBehaviorTest.java
new file mode 100644
index 0000000..d89c6d5
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/audio/DeviceVolumeBehaviorTest.java
@@ -0,0 +1,167 @@
+/*
+ * 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.server.audio;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.media.IDeviceVolumeBehaviorDispatcher;
+import android.os.test.TestLooper;
+
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests for AudioService's tracking and reporting of device volume behaviors.
+ */
+public class DeviceVolumeBehaviorTest {
+    private static final String TAG = "DeviceVolumeBehaviorTest";
+
+    private static final String PACKAGE_NAME = "";
+    private static final AudioDeviceAttributes DEVICE_SPEAKER_OUT = new AudioDeviceAttributes(
+            AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, "");
+
+    private Context mContext;
+    private AudioSystemAdapter mAudioSystem;
+    private SystemServerAdapter mSystemServer;
+    private SettingsAdapter mSettingsAdapter;
+    private TestLooper mTestLooper;
+
+    private AudioService mAudioService;
+
+    /**
+     * Volume behaviors that can be set using AudioService#setDeviceVolumeBehavior
+     */
+    public static final int[] BASIC_VOLUME_BEHAVIORS = {
+            AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE,
+            AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL,
+            AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED
+    };
+
+    @Before
+    public void setUp() throws Exception {
+        mTestLooper = new TestLooper();
+        mContext = InstrumentationRegistry.getTargetContext();
+        mAudioSystem = new NoOpAudioSystemAdapter();
+        mSystemServer = new NoOpSystemServerAdapter();
+        mSettingsAdapter = new NoOpSettingsAdapter();
+        mAudioService = new AudioService(mContext, mAudioSystem, mSystemServer,
+                mSettingsAdapter, mTestLooper.getLooper());
+        mTestLooper.dispatchAll();
+    }
+
+    @Test
+    public void setDeviceVolumeBehavior_changesDeviceVolumeBehavior() {
+        mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT,
+                AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED, PACKAGE_NAME);
+        mTestLooper.dispatchAll();
+
+        for (int behavior : BASIC_VOLUME_BEHAVIORS) {
+            mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT, behavior, PACKAGE_NAME);
+            mTestLooper.dispatchAll();
+
+            int actualBehavior = mAudioService.getDeviceVolumeBehavior(DEVICE_SPEAKER_OUT);
+
+            assertWithMessage("Expected volume behavior to be " + behavior
+                    + " but was instead " + actualBehavior)
+                    .that(actualBehavior).isEqualTo(behavior);
+        }
+    }
+
+    @Test
+    public void setToNewBehavior_triggersDeviceVolumeBehaviorDispatcher() {
+        TestDeviceVolumeBehaviorDispatcherStub dispatcher =
+                new TestDeviceVolumeBehaviorDispatcherStub();
+        mAudioService.registerDeviceVolumeBehaviorDispatcher(true, dispatcher);
+
+        mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT,
+                AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED, PACKAGE_NAME);
+        mTestLooper.dispatchAll();
+
+        for (int behavior : BASIC_VOLUME_BEHAVIORS) {
+            dispatcher.reset();
+            mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT, behavior, PACKAGE_NAME);
+            mTestLooper.dispatchAll();
+
+            assertThat(dispatcher.mTimesCalled).isEqualTo(1);
+            assertThat(dispatcher.mDevice).isEqualTo(DEVICE_SPEAKER_OUT);
+            assertWithMessage("Expected dispatched volume behavior to be " + behavior
+                    + " but was instead " + dispatcher.mVolumeBehavior)
+                    .that(dispatcher.mVolumeBehavior).isEqualTo(behavior);
+        }
+    }
+
+    @Test
+    public void setToSameBehavior_doesNotTriggerDeviceVolumeBehaviorDispatcher() {
+        mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT,
+                AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED, PACKAGE_NAME);
+        mTestLooper.dispatchAll();
+
+        TestDeviceVolumeBehaviorDispatcherStub dispatcher =
+                new TestDeviceVolumeBehaviorDispatcherStub();
+        mAudioService.registerDeviceVolumeBehaviorDispatcher(true, dispatcher);
+
+        mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT,
+                AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED, PACKAGE_NAME);
+        mTestLooper.dispatchAll();
+        assertThat(dispatcher.mTimesCalled).isEqualTo(0);
+    }
+
+    @Test
+    public void unregisterDeviceVolumeBehaviorDispatcher_noLongerTriggered() {
+        mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT,
+                AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED, PACKAGE_NAME);
+        mTestLooper.dispatchAll();
+
+        TestDeviceVolumeBehaviorDispatcherStub dispatcher =
+                new TestDeviceVolumeBehaviorDispatcherStub();
+        mAudioService.registerDeviceVolumeBehaviorDispatcher(true, dispatcher);
+        mAudioService.registerDeviceVolumeBehaviorDispatcher(false, dispatcher);
+
+        mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT,
+                AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL, PACKAGE_NAME);
+        mTestLooper.dispatchAll();
+        assertThat(dispatcher.mTimesCalled).isEqualTo(0);
+    }
+
+    private static class TestDeviceVolumeBehaviorDispatcherStub
+            extends IDeviceVolumeBehaviorDispatcher.Stub {
+
+        private AudioDeviceAttributes mDevice;
+        private int mVolumeBehavior;
+        private int mTimesCalled;
+
+        @Override
+        public void dispatchDeviceVolumeBehaviorChanged(@NonNull AudioDeviceAttributes device,
+                @AudioManager.DeviceVolumeBehavior int volumeBehavior) {
+            mDevice = device;
+            mVolumeBehavior = volumeBehavior;
+            mTimesCalled++;
+        }
+
+        public void reset() {
+            mTimesCalled = 0;
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
index 1f355b0..09e5d4b 100644
--- a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
+++ b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
@@ -17,10 +17,12 @@
 package com.android.server.audio;
 
 import android.annotation.NonNull;
+import android.media.AudioAttributes;
 import android.media.AudioDeviceAttributes;
 import android.media.AudioSystem;
 import android.util.Log;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -122,4 +124,11 @@
     public boolean isStreamActive(int stream, int inPastMs) {
         return mIsStreamActive;
     }
+
+    @Override
+    @NonNull
+    public ArrayList<AudioDeviceAttributes> getDevicesForAttributes(
+            @NonNull AudioAttributes attributes, boolean forVolume) {
+        return new ArrayList<>();
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/audio/NoOpSettingsAdapter.java b/services/tests/servicestests/src/com/android/server/audio/NoOpSettingsAdapter.java
new file mode 100644
index 0000000..bf80f27b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/audio/NoOpSettingsAdapter.java
@@ -0,0 +1,102 @@
+/*
+ * 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.server.audio;
+
+import android.content.ContentResolver;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class NoOpSettingsAdapter extends SettingsAdapter {
+
+    /**
+     * No-op methods for Settings.Global
+     */
+
+    private Map<String, Integer> mGlobalIntSettings = new HashMap<>();
+    private Map<String, String> mGlobalStringSettings = new HashMap<>();
+
+    @Override
+    public int getGlobalInt(ContentResolver cr, String name, int def) {
+        return mGlobalIntSettings.getOrDefault(name, def);
+    }
+
+    @Override
+    public String getGlobalString(ContentResolver resolver, String name) {
+        return mGlobalStringSettings.getOrDefault(name, null);
+    }
+
+    @Override
+    public boolean putGlobalInt(ContentResolver cr, String name, int value) {
+        mGlobalIntSettings.put(name, value);
+        return true;
+    }
+
+    @Override
+    public boolean putGlobalString(ContentResolver resolver, String name, String value) {
+        mGlobalStringSettings.put(name, value);
+        return true;
+    }
+
+    /**
+     * No-op methods for Settings.System
+     */
+
+    private Map<String, Integer> mSystemIntSettings = new HashMap<>();
+
+    @Override
+    public int getSystemIntForUser(ContentResolver cr, String name, int def, int userHandle) {
+        return mSystemIntSettings.getOrDefault(name, def);
+    }
+
+    @Override
+    public boolean putSystemIntForUser(ContentResolver cr, String name, int value, int userHandle) {
+        mSystemIntSettings.put(name, value);
+        return true;
+    }
+
+    /**
+     * No-op methods for Settings.Secure
+     */
+
+    private Map<String, Integer> mSecureIntSettings = new HashMap<>();
+    private Map<String, String> mSecureStringSettings = new HashMap<>();
+
+    @Override
+    public int getSecureIntForUser(ContentResolver cr, String name, int def, int userHandle) {
+        return mSecureIntSettings.getOrDefault(name, def);
+    }
+
+    @Override
+    public String getSecureStringForUser(ContentResolver resolver, String name, int userHandle) {
+        return mSecureStringSettings.getOrDefault(name, null);
+    }
+
+    @Override
+    public boolean putSecureIntForUser(ContentResolver cr, String name, int value, int userHandle) {
+        mSecureIntSettings.put(name, value);
+        return true;
+    }
+
+    @Override
+    public boolean putSecureStringForUser(ContentResolver cr, String name, String value,
+            int userHandle) {
+        mSecureStringSettings.put(name, value);
+        return true;
+    }
+}
+
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java
index eab96c0..c173473 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java
@@ -72,9 +72,11 @@
     @Mock
     private ClientMonitorCallback mClientCallback;
     @Mock
+    private ClientMonitorCallback mOnStartCallback;
+    @Mock
     private FakeHal mHal;
     @Captor
-    ArgumentCaptor<ClientMonitorCallback> mStartCallback;
+    ArgumentCaptor<ClientMonitorCallback> mStartedCallbackCaptor;
 
     private Handler mHandler;
     private BiometricSchedulerOperation mOperation;
@@ -91,17 +93,17 @@
         when(mClientMonitor.getCookie()).thenReturn(cookie);
         when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
 
-        assertThat(mOperation.isReadyToStart()).isEqualTo(cookie);
+        assertThat(mOperation.isReadyToStart(mOnStartCallback)).isEqualTo(cookie);
         assertThat(mOperation.isStarted()).isFalse();
         assertThat(mOperation.isCanceling()).isFalse();
         assertThat(mOperation.isFinished()).isFalse();
+        verify(mClientMonitor).waitForCookie(any());
 
-        final boolean started = mOperation.startWithCookie(
-                mock(ClientMonitorCallback.class), cookie);
+        final boolean started = mOperation.startWithCookie(mOnStartCallback, cookie);
 
         assertThat(started).isTrue();
-        verify(mClientMonitor).start(mStartCallback.capture());
-        mStartCallback.getValue().onClientStarted(mClientMonitor);
+        verify(mClientMonitor).start(mStartedCallbackCaptor.capture());
+        mStartedCallbackCaptor.getValue().onClientStarted(mClientMonitor);
         assertThat(mOperation.isStarted()).isTrue();
     }
 
@@ -112,14 +114,15 @@
         when(mClientMonitor.getCookie()).thenReturn(goodCookie);
         when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
 
-        assertThat(mOperation.isReadyToStart()).isEqualTo(goodCookie);
-        final boolean started = mOperation.startWithCookie(
-                mock(ClientMonitorCallback.class), badCookie);
+        assertThat(mOperation.isReadyToStart(mOnStartCallback)).isEqualTo(goodCookie);
+        final boolean started = mOperation.startWithCookie(mOnStartCallback, badCookie);
 
         assertThat(started).isFalse();
         assertThat(mOperation.isStarted()).isFalse();
         assertThat(mOperation.isCanceling()).isFalse();
         assertThat(mOperation.isFinished()).isFalse();
+        verify(mClientMonitor).waitForCookie(any());
+        verify(mClientMonitor, never()).start(any());
     }
 
     @Test
@@ -127,26 +130,25 @@
         when(mClientMonitor.getCookie()).thenReturn(0);
         when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
 
-        final ClientMonitorCallback cb = mock(ClientMonitorCallback.class);
-        mOperation.start(cb);
-        verify(mClientMonitor).start(mStartCallback.capture());
-        mStartCallback.getValue().onClientStarted(mClientMonitor);
+        mOperation.start(mOnStartCallback);
+        verify(mClientMonitor).start(mStartedCallbackCaptor.capture());
+        mStartedCallbackCaptor.getValue().onClientStarted(mClientMonitor);
 
         assertThat(mOperation.isStarted()).isTrue();
         assertThat(mOperation.isCanceling()).isFalse();
         assertThat(mOperation.isFinished()).isFalse();
 
         verify(mClientCallback).onClientStarted(eq(mClientMonitor));
-        verify(cb).onClientStarted(eq(mClientMonitor));
+        verify(mOnStartCallback).onClientStarted(eq(mClientMonitor));
         verify(mClientCallback, never()).onClientFinished(any(), anyBoolean());
-        verify(cb, never()).onClientFinished(any(), anyBoolean());
+        verify(mOnStartCallback, never()).onClientFinished(any(), anyBoolean());
 
-        mStartCallback.getValue().onClientFinished(mClientMonitor, true);
+        mStartedCallbackCaptor.getValue().onClientFinished(mClientMonitor, true);
 
         assertThat(mOperation.isFinished()).isTrue();
         assertThat(mOperation.isCanceling()).isFalse();
         verify(mClientMonitor).destroy();
-        verify(cb).onClientFinished(eq(mClientMonitor), eq(true));
+        verify(mOnStartCallback).onClientFinished(eq(mClientMonitor), eq(true));
     }
 
     @Test
@@ -154,8 +156,7 @@
         when(mClientMonitor.getCookie()).thenReturn(0);
         when(mClientMonitor.getFreshDaemon()).thenReturn(null);
 
-        final ClientMonitorCallback cb = mock(ClientMonitorCallback.class);
-        mOperation.start(cb);
+        mOperation.start(mOnStartCallback);
         verify(mClientMonitor, never()).start(any());
 
         assertThat(mOperation.isStarted()).isFalse();
@@ -163,9 +164,9 @@
         assertThat(mOperation.isFinished()).isTrue();
 
         verify(mClientCallback, never()).onClientStarted(eq(mClientMonitor));
-        verify(cb, never()).onClientStarted(eq(mClientMonitor));
+        verify(mOnStartCallback, never()).onClientStarted(eq(mClientMonitor));
         verify(mClientCallback).onClientFinished(eq(mClientMonitor), eq(false));
-        verify(cb).onClientFinished(eq(mClientMonitor), eq(false));
+        verify(mOnStartCallback).onClientFinished(eq(mClientMonitor), eq(false));
     }
 
     @Test
@@ -179,7 +180,7 @@
     public void cannotRestart() {
         when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
 
-        mOperation.start(mock(ClientMonitorCallback.class));
+        mOperation.start(mOnStartCallback);
 
         assertThrows(IllegalStateException.class,
                 () -> mOperation.start(mock(ClientMonitorCallback.class)));
@@ -202,7 +203,7 @@
     public void cannotAbortRunning() {
         when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
 
-        mOperation.start(mock(ClientMonitorCallback.class));
+        mOperation.start(mOnStartCallback);
 
         assertThrows(IllegalStateException.class, () -> mOperation.abort());
     }
@@ -211,11 +212,10 @@
     public void cancel() {
         when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
 
-        final ClientMonitorCallback startCb = mock(ClientMonitorCallback.class);
         final ClientMonitorCallback cancelCb = mock(ClientMonitorCallback.class);
-        mOperation.start(startCb);
-        verify(mClientMonitor).start(mStartCallback.capture());
-        mStartCallback.getValue().onClientStarted(mClientMonitor);
+        mOperation.start(mOnStartCallback);
+        verify(mClientMonitor).start(mStartedCallbackCaptor.capture());
+        mStartedCallbackCaptor.getValue().onClientStarted(mClientMonitor);
         mOperation.cancel(mHandler, cancelCb);
 
         assertThat(mOperation.isCanceling()).isTrue();
@@ -223,7 +223,7 @@
         verify(mClientMonitor, never()).cancelWithoutStarting(any());
         verify(mClientMonitor, never()).destroy();
 
-        mStartCallback.getValue().onClientFinished(mClientMonitor, true);
+        mStartedCallbackCaptor.getValue().onClientFinished(mClientMonitor, true);
 
         assertThat(mOperation.isFinished()).isTrue();
         assertThat(mOperation.isCanceling()).isFalse();
@@ -315,12 +315,10 @@
     private void cancelWatchdog(boolean start) {
         when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
 
-        final ClientMonitorCallback opStartCallback = mock(ClientMonitorCallback.class);
-        mOperation.start(opStartCallback);
+        mOperation.start(mOnStartCallback);
         if (start) {
-            verify(mClientMonitor).start(mStartCallback.capture());
-            mStartCallback.getValue().onClientStarted(mClientMonitor);
-            verify(opStartCallback).onClientStarted(eq(mClientMonitor));
+            verify(mClientMonitor).start(mStartedCallbackCaptor.capture());
+            mStartedCallbackCaptor.getValue().onClientStarted(mClientMonitor);
         }
         mOperation.cancel(mHandler, mock(ClientMonitorCallback.class));
 
@@ -331,7 +329,7 @@
 
         assertThat(mOperation.isFinished()).isTrue();
         assertThat(mOperation.isCanceling()).isFalse();
-        verify(opStartCallback).onClientFinished(eq(mClientMonitor), eq(false));
+        verify(mOnStartCallback).onClientFinished(eq(mClientMonitor), eq(false));
         verify(mClientMonitor).destroy();
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index 0fa2b41..45e3b43 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -196,7 +196,8 @@
         // Schedule a BiometricPrompt authentication request
         mScheduler.scheduleClientMonitor(client1, callback1);
 
-        assertNotEquals(0, mScheduler.mCurrentOperation.isReadyToStart());
+        assertNotEquals(0, mScheduler.mCurrentOperation.isReadyToStart(
+                mock(ClientMonitorCallback.class)));
         assertEquals(client1, mScheduler.mCurrentOperation.getClientMonitor());
         assertEquals(0, mScheduler.mPendingOperations.size());
 
@@ -436,7 +437,8 @@
             if (started || isEnroll) { // prep'd auth clients and enroll clients
                 assertTrue(mScheduler.mCurrentOperation.isStarted());
             } else {
-                assertNotEquals(0, mScheduler.mCurrentOperation.isReadyToStart());
+                assertNotEquals(0, mScheduler.mCurrentOperation.isReadyToStart(
+                        mock(ClientMonitorCallback.class)));
             }
         }
     }
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java
index dc39b6d..5012335 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.hardware.biometrics.BiometricOverlayConstants;
 import android.hardware.fingerprint.ISidefpsController;
@@ -29,6 +30,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.Mock;
@@ -43,6 +45,7 @@
 public class SensorOverlaysTest {
 
     private static final int SENSOR_ID = 11;
+    private static final long REQUEST_ID = 8;
 
     @Rule public final MockitoRule mockito = MockitoJUnit.rule();
 
@@ -50,6 +53,12 @@
     @Mock private ISidefpsController mSidefpsController;
     @Mock private AcquisitionClient<?> mAcquisitionClient;
 
+    @Before
+    public void setup() {
+        when(mAcquisitionClient.getRequestId()).thenReturn(REQUEST_ID);
+        when(mAcquisitionClient.hasRequestId()).thenReturn(true);
+    }
+
     @Test
     public void noopWhenBothNull() {
         final SensorOverlays useless = new SensorOverlays(null, null);
@@ -92,7 +101,8 @@
         sensorOverlays.show(SENSOR_ID, reason, mAcquisitionClient);
 
         if (udfps != null) {
-            verify(mUdfpsOverlayController).showUdfpsOverlay(eq(SENSOR_ID), eq(reason), any());
+            verify(mUdfpsOverlayController).showUdfpsOverlay(
+                    eq(REQUEST_ID), eq(SENSOR_ID), eq(reason), any());
         }
         if (sidefps != null) {
             verify(mSidefpsController).show(eq(SENSOR_ID), eq(reason));
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
index 52eee9a..8391914 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
@@ -18,9 +18,8 @@
 
 import static android.testing.TestableLooper.RunWithLooper;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -45,11 +44,15 @@
 import com.android.server.biometrics.log.BiometricLogger;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.function.Supplier;
 
 @Presubmit
@@ -61,9 +64,12 @@
     private static final String TAG = "UserAwareBiometricSchedulerTest";
     private static final int TEST_SENSOR_ID = 0;
 
+    @Rule
+    public final MockitoRule mockito = MockitoJUnit.rule();
+
     private Handler mHandler;
     private UserAwareBiometricScheduler mScheduler;
-    private IBinder mToken = new Binder();
+    private final IBinder mToken = new Binder();
 
     @Mock
     private Context mContext;
@@ -74,15 +80,14 @@
     @Mock
     private BiometricContext mBiometricContext;
 
-    private TestUserStartedCallback mUserStartedCallback = new TestUserStartedCallback();
-    private TestUserStoppedCallback mUserStoppedCallback = new TestUserStoppedCallback();
+    private final TestUserStartedCallback mUserStartedCallback = new TestUserStartedCallback();
+    private final TestUserStoppedCallback mUserStoppedCallback = new TestUserStoppedCallback();
     private int mCurrentUserId = UserHandle.USER_NULL;
     private boolean mStartOperationsFinish = true;
     private int mStartUserClientCount = 0;
 
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
         mHandler = new Handler(TestableLooper.get(this).getLooper());
         mScheduler = new UserAwareBiometricScheduler(TAG,
                 mHandler,
@@ -121,8 +126,8 @@
         mScheduler.scheduleClientMonitor(nextClient);
         waitForIdle();
 
-        assertEquals(0, mUserStoppedCallback.numInvocations);
-        assertEquals(1, mUserStartedCallback.numInvocations);
+        assertThat(mUserStoppedCallback.mNumInvocations).isEqualTo(0);
+        assertThat(mUserStartedCallback.mStartedUsers).containsExactly(0);
         verify(nextClient).start(any());
     }
 
@@ -142,9 +147,9 @@
             waitForIdle();
         }
 
-        assertEquals(0, mUserStoppedCallback.numInvocations);
-        assertEquals(0, mUserStartedCallback.numInvocations);
-        assertEquals(1, mStartUserClientCount);
+        assertThat(mUserStoppedCallback.mNumInvocations).isEqualTo(0);
+        assertThat(mUserStartedCallback.mStartedUsers).isEmpty();
+        assertThat(mStartUserClientCount).isEqualTo(1);
         for (BaseClientMonitor client : nextClients) {
             verify(client, never()).start(any());
         }
@@ -163,13 +168,13 @@
         final TestStartUserClient startUserClient =
                 (TestStartUserClient) mScheduler.mCurrentOperation.getClientMonitor();
         mScheduler.reset();
-        assertNull(mScheduler.mCurrentOperation);
+        assertThat(mScheduler.mCurrentOperation).isNull();
 
         final BiometricSchedulerOperation fakeOperation = new BiometricSchedulerOperation(
                 mock(BaseClientMonitor.class), new ClientMonitorCallback() {});
         mScheduler.mCurrentOperation = fakeOperation;
         startUserClient.mCallback.onClientFinished(startUserClient, true);
-        assertSame(fakeOperation, mScheduler.mCurrentOperation);
+        assertThat(fakeOperation).isSameInstanceAs(mScheduler.mCurrentOperation);
     }
 
     @Test
@@ -184,8 +189,8 @@
         waitForIdle();
 
         verify(nextClient).start(any());
-        assertEquals(0, mUserStoppedCallback.numInvocations);
-        assertEquals(0, mUserStartedCallback.numInvocations);
+        assertThat(mUserStoppedCallback.mNumInvocations).isEqualTo(0);
+        assertThat(mUserStartedCallback.mStartedUsers).isEmpty();
     }
 
     @Test
@@ -199,36 +204,67 @@
         mScheduler.scheduleClientMonitor(nextClient);
 
         waitForIdle();
-        assertEquals(1, mUserStoppedCallback.numInvocations);
+        assertThat(mUserStoppedCallback.mNumInvocations).isEqualTo(1);
 
         waitForIdle();
-        assertEquals(1, mUserStartedCallback.numInvocations);
+        assertThat(mUserStartedCallback.mStartedUsers).containsExactly(nextUserId);
 
         waitForIdle();
         verify(nextClient).start(any());
     }
 
+    @Test
+    public void testStartUser_alwaysStartsNextOperation() {
+        BaseClientMonitor nextClient = mock(BaseClientMonitor.class);
+        when(nextClient.getTargetUserId()).thenReturn(10);
+
+        mScheduler.scheduleClientMonitor(nextClient);
+
+        waitForIdle();
+        verify(nextClient).start(any());
+
+        // finish first operation
+        mScheduler.getInternalCallback().onClientFinished(nextClient, true /* success */);
+        waitForIdle();
+
+        // schedule second operation but swap out the current operation
+        // before it runs so that it's not current when it's completion callback runs
+        nextClient = mock(BaseClientMonitor.class);
+        when(nextClient.getTargetUserId()).thenReturn(11);
+        mUserStartedCallback.mAfterStart = () -> mScheduler.mCurrentOperation = null;
+        mScheduler.scheduleClientMonitor(nextClient);
+
+        waitForIdle();
+        verify(nextClient).start(any());
+        assertThat(mUserStartedCallback.mStartedUsers).containsExactly(10, 11).inOrder();
+        assertThat(mUserStoppedCallback.mNumInvocations).isEqualTo(1);
+    }
+
     private void waitForIdle() {
         TestableLooper.get(this).processAllMessages();
     }
 
     private class TestUserStoppedCallback implements StopUserClient.UserStoppedCallback {
-        int numInvocations;
+        int mNumInvocations;
 
         @Override
         public void onUserStopped() {
-            numInvocations++;
+            mNumInvocations++;
             mCurrentUserId = UserHandle.USER_NULL;
         }
     }
 
     private class TestUserStartedCallback implements StartUserClient.UserStartedCallback<Object> {
-        int numInvocations;
+        final List<Integer> mStartedUsers = new ArrayList<>();
+        Runnable mAfterStart = null;
 
         @Override
         public void onUserStarted(int newUserId, Object newObject, int halInterfaceVersion) {
-            numInvocations++;
+            mStartedUsers.add(newUserId);
             mCurrentUserId = newUserId;
+            if (mAfterStart != null) {
+                mAfterStart.run();
+            }
         }
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
index de0f038..6c50ca3 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
@@ -71,6 +71,7 @@
 
     private static final int USER_ID = 8;
     private static final long OP_ID = 7;
+    private static final long REQUEST_ID = 88;
     private static final int POINTER_ID = 0;
     private static final int TOUCH_X = 8;
     private static final int TOUCH_Y = 20;
@@ -259,7 +260,7 @@
 
         client.start(mCallback);
 
-        verify(mUdfpsOverlayController).showUdfpsOverlay(anyInt(), anyInt(), any());
+        verify(mUdfpsOverlayController).showUdfpsOverlay(eq(REQUEST_ID), anyInt(), anyInt(), any());
         verify(mSideFpsController).show(anyInt(), anyInt());
 
         block.accept(client);
@@ -277,7 +278,7 @@
 
         final AidlSession aidl = new AidlSession(version, mHal, USER_ID, mHalSessionCallback);
         return new FingerprintAuthenticationClient(mContext, () -> aidl, mToken,
-                2 /* requestId */, mClientMonitorCallbackConverter, 5 /* targetUserId */, OP_ID,
+                REQUEST_ID, mClientMonitorCallbackConverter, 5 /* targetUserId */, OP_ID,
         false /* restricted */, "test-owner", 4 /* cookie */, false /* requireConfirmation */,
         9 /* sensorId */, mBiometricLogger, mBiometricContext,
         true /* isStrongBiometric */,
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
index 5a96f5c..f77eb0b 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
@@ -72,6 +72,7 @@
 
     private static final byte[] HAT = new byte[69];
     private static final int USER_ID = 8;
+    private static final long REQUEST_ID = 9;
     private static final int POINTER_ID = 0;
     private static final int TOUCH_X = 8;
     private static final int TOUCH_Y = 20;
@@ -256,7 +257,7 @@
 
         client.start(mCallback);
 
-        verify(mUdfpsOverlayController).showUdfpsOverlay(anyInt(), anyInt(), any());
+        verify(mUdfpsOverlayController).showUdfpsOverlay(eq(REQUEST_ID), anyInt(), anyInt(), any());
         verify(mSideFpsController).show(anyInt(), anyInt());
 
         block.accept(client);
@@ -273,7 +274,7 @@
         when(mHal.getInterfaceVersion()).thenReturn(version);
 
         final AidlSession aidl = new AidlSession(version, mHal, USER_ID, mHalSessionCallback);
-        return new FingerprintEnrollClient(mContext, () -> aidl, mToken, 6 /* requestId */,
+        return new FingerprintEnrollClient(mContext, () -> aidl, mToken, REQUEST_ID,
         mClientMonitorCallbackConverter, 0 /* userId */,
         HAT, "owner", mBiometricUtils, 8 /* sensorId */,
         mBiometricLogger, mBiometricContext, mSensorProps, mUdfpsOverlayController,
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 61d7ede..ef9f90f 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -530,5 +530,10 @@
 
             return true;
         }
+
+        @Override
+        public Context createContextAsUser(UserHandle user) {
+            return context;
+        }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 1ebcbe1..197c21f 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -1784,10 +1784,9 @@
         final int userId = CALLER_USER_HANDLE;
         final UserHandle user = UserHandle.of(userId);
 
-        mContext.applicationInfo = new ApplicationInfo();
-        mContext.callerPermissions.add(permission.MANAGE_USERS);
-        mContext.packageName = "com.android.frameworks.servicestests";
-        getServices().addPackageContext(user, mContext);
+        mServiceContext.packageName = mRealTestContext.getPackageName();
+        mServiceContext.applicationInfo = new ApplicationInfo();
+        mServiceContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
         when(mContext.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);
 
         StringParceledListSlice oneCert = asSlice(new String[] {"1"});
@@ -4260,14 +4259,11 @@
         dpm.setPreferentialNetworkServiceConfigs(List.of(preferentialNetworkServiceConfigEnabled));
         assertThat(dpm.getPreferentialNetworkServiceConfigs().get(0)
                 .isEnabled()).isTrue();
-        List<Integer> includedList = new ArrayList<>();
-        includedList.add(1);
-        includedList.add(2);
         ProfileNetworkPreference preferenceDetails =
                 new ProfileNetworkPreference.Builder()
                         .setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK)
                         .setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1)
-                        .setIncludedUids(includedList)
+                        .setIncludedUids(new int[]{1, 2})
                         .build();
         List<ProfileNetworkPreference> preferences = new ArrayList<>();
         preferences.add(preferenceDetails);
@@ -4295,14 +4291,11 @@
         dpm.setPreferentialNetworkServiceConfigs(List.of(preferentialNetworkServiceConfigEnabled));
         assertThat(dpm.getPreferentialNetworkServiceConfigs().get(0)
                 .isEnabled()).isTrue();
-        List<Integer> excludedUids = new ArrayList<>();
-        excludedUids.add(1);
-        excludedUids.add(2);
         ProfileNetworkPreference preferenceDetails =
                 new ProfileNetworkPreference.Builder()
                         .setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK)
                         .setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1)
-                        .setExcludedUids(excludedUids)
+                        .setExcludedUids(new int[]{1, 2})
                         .build();
         List<ProfileNetworkPreference> preferences = new ArrayList<>();
         preferences.clear();
@@ -6285,6 +6278,7 @@
     @Test
     public void testGetOwnerInstalledCaCertsForDeviceOwner() throws Exception {
         mServiceContext.packageName = mRealTestContext.getPackageName();
+        mServiceContext.applicationInfo = new ApplicationInfo();
         mServiceContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
         mAdmin1Context.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setDeviceOwner();
@@ -6295,6 +6289,7 @@
     @Test
     public void testGetOwnerInstalledCaCertsForProfileOwner() throws Exception {
         mServiceContext.packageName = mRealTestContext.getPackageName();
+        mServiceContext.applicationInfo = new ApplicationInfo();
         mServiceContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
         mAdmin1Context.binder.callingUid = DpmMockContext.CALLER_UID;
         setAsProfileOwner(admin1);
@@ -6306,6 +6301,7 @@
     @Test
     public void testGetOwnerInstalledCaCertsForDelegate() throws Exception {
         mServiceContext.packageName = mRealTestContext.getPackageName();
+        mServiceContext.applicationInfo = new ApplicationInfo();
         mServiceContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
         mAdmin1Context.binder.callingUid = DpmMockContext.CALLER_UID;
         setAsProfileOwner(admin1);
@@ -6671,7 +6667,7 @@
         configureContextForAccess(mContext, false);
 
         assertExpectException(SecurityException.class, /* messageRegex= */ null,
-                () -> dpm.markProfileOwnerOnOrganizationOwnedDevice(admin2));
+                () -> dpm.setProfileOwnerOnOrganizationOwnedDevice(admin2, true));
     }
 
     @Test
@@ -6680,7 +6676,7 @@
         configureContextForAccess(mContext, false);
 
         assertExpectException(SecurityException.class, /* messageRegex= */ null,
-                () -> dpm.markProfileOwnerOnOrganizationOwnedDevice(admin1));
+                () -> dpm.setProfileOwnerOnOrganizationOwnedDevice(admin1, true));
     }
 
     @Test
@@ -6715,7 +6711,7 @@
                         DpmMockContext.CALLER_MANAGED_PROVISIONING_UID);
         try {
             runAsCaller(mServiceContext, dpms, dpm -> {
-                dpm.markProfileOwnerOnOrganizationOwnedDevice(admin1);
+                dpm.setProfileOwnerOnOrganizationOwnedDevice(admin1, true);
             });
         } finally {
             mServiceContext.binder.restoreCallingIdentity(ident);
@@ -7050,7 +7046,7 @@
 
         configureContextForAccess(mServiceContext, true);
         runAsCaller(mServiceContext, dpms, dpm -> {
-            dpm.markProfileOwnerOnOrganizationOwnedDevice(who);
+            dpm.setProfileOwnerOnOrganizationOwnedDevice(who, true);
         });
         mServiceContext.binder.restoreCallingIdentity(ident);
     }
@@ -8459,7 +8455,7 @@
 
     @Test
     public void testSendLostModeLocationUpdate_notOrganizationOwnedDevice() {
-        mContext.callerPermissions.add(permission.SEND_LOST_MODE_LOCATION_UPDATES);
+        mContext.callerPermissions.add(permission.TRIGGER_LOST_MODE);
         assertThrows(IllegalStateException.class, () -> dpm.sendLostModeLocationUpdate(
                 getServices().executor, /* empty callback */ result -> {}));
     }
@@ -8467,7 +8463,7 @@
     @Test
     public void testSendLostModeLocationUpdate_asDeviceOwner() throws Exception {
         final String TEST_PROVIDER = "network";
-        mContext.callerPermissions.add(permission.SEND_LOST_MODE_LOCATION_UPDATES);
+        mContext.callerPermissions.add(permission.TRIGGER_LOST_MODE);
         setDeviceOwner();
         when(getServices().locationManager.getAllProviders()).thenReturn(List.of(TEST_PROVIDER));
         when(getServices().locationManager.isProviderEnabled(TEST_PROVIDER)).thenReturn(true);
@@ -8484,7 +8480,7 @@
         final int MANAGED_PROFILE_ADMIN_UID =
                 UserHandle.getUid(CALLER_USER_HANDLE, DpmMockContext.SYSTEM_UID);
         mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
-        mContext.callerPermissions.add(permission.SEND_LOST_MODE_LOCATION_UPDATES);
+        mContext.callerPermissions.add(permission.TRIGGER_LOST_MODE);
         addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
         configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
         when(getServices().locationManager.getAllProviders()).thenReturn(List.of(TEST_PROVIDER));
diff --git a/services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java b/services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java
new file mode 100644
index 0000000..26a83a2
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.server.display;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.hardware.display.DisplayManagerInternal;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class ColorFadeTest {
+    private static final int DISPLAY_ID = 123;
+
+    private Context mContext;
+
+    @Mock private DisplayManagerInternal mDisplayManagerInternalMock;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        addLocalServiceMock(DisplayManagerInternal.class, mDisplayManagerInternalMock);
+        mContext = getInstrumentation().getTargetContext();
+    }
+
+    @After
+    public void tearDown() {
+        LocalServices.removeServiceForTest(DisplayManagerInternal.class);
+    }
+
+    @Test
+    public void testPrepareColorFadeForInvalidDisplay() {
+        when(mDisplayManagerInternalMock.getDisplayInfo(eq(DISPLAY_ID))).thenReturn(null);
+        ColorFade colorFade = new ColorFade(DISPLAY_ID);
+        assertFalse(colorFade.prepare(mContext, ColorFade.MODE_FADE));
+    }
+
+    private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
+        LocalServices.removeServiceForTest(clazz);
+        LocalServices.addService(clazz, mock);
+    }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index 1fb5898..bf3c7c3 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -393,7 +393,8 @@
         displayDeviceInfo.displayCutout = new DisplayCutout(
                 Insets.of(0, 10, 0, 0),
                 zeroRect, new Rect(0, 0, 10, 10), zeroRect, zeroRect);
-        displayDeviceInfo.flags = DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY;
+        displayDeviceInfo.flags = DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY;
+        displayDeviceInfo.address = new TestUtils.TestDisplayAddress();
         displayDevice.setDisplayDeviceInfo(displayDeviceInfo);
         displayManager.getDisplayDeviceRepository()
                 .onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED);
@@ -1307,7 +1308,8 @@
         displayDeviceInfo.displayCutout = new DisplayCutout(
                 Insets.of(0, 10, 0, 0),
                 zeroRect, new Rect(0, 0, 10, 10), zeroRect, zeroRect);
-        displayDeviceInfo.flags = DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY;
+        displayDeviceInfo.flags = DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY;
+        displayDeviceInfo.address = new TestUtils.TestDisplayAddress();
         displayDevice.setDisplayDeviceInfo(displayDeviceInfo);
         displayManager.getDisplayDeviceRepository()
                 .onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED);
diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
index 86b6da0..cc68ba8 100644
--- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -42,7 +42,6 @@
 import android.os.Handler;
 import android.os.IPowerManager;
 import android.os.IThermalService;
-import android.os.Parcel;
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.test.TestLooper;
@@ -146,7 +145,7 @@
     @Test
     public void testDisplayDeviceAddAndRemove_Internal() {
         DisplayDevice device = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
-                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY);
+                DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY);
 
         // add
         LogicalDisplay displayAdded = add(device);
@@ -179,7 +178,7 @@
     public void testDisplayDeviceAdd_TwoInternalOneDefault() {
         DisplayDevice device1 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, 0);
         DisplayDevice device2 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
-                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY);
+                DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY);
 
         LogicalDisplay display1 = add(device1);
         assertEquals(info(display1).address, info(device1).address);
@@ -193,9 +192,9 @@
     @Test
     public void testDisplayDeviceAdd_TwoInternalBothDefault() {
         DisplayDevice device1 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
-                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY);
+                DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY);
         DisplayDevice device2 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
-                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY);
+                DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY);
 
         LogicalDisplay display1 = add(device1);
         assertEquals(info(display1).address, info(device1).address);
@@ -208,9 +207,57 @@
     }
 
     @Test
+    public void testDisplayDeviceAddAndRemove_OneExternalDefault() {
+        DisplayDevice device = createDisplayDevice(Display.TYPE_EXTERNAL, 600, 800,
+                DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY);
+
+        // add
+        LogicalDisplay displayAdded = add(device);
+        assertEquals(info(displayAdded).address, info(device).address);
+        assertEquals(Display.DEFAULT_DISPLAY, id(displayAdded));
+
+        // remove
+        mDisplayDeviceRepo.onDisplayDeviceEvent(device, DISPLAY_DEVICE_EVENT_REMOVED);
+        verify(mListenerMock).onLogicalDisplayEventLocked(
+                mDisplayCaptor.capture(), eq(LOGICAL_DISPLAY_EVENT_REMOVED));
+        LogicalDisplay displayRemoved = mDisplayCaptor.getValue();
+        assertEquals(DEFAULT_DISPLAY, id(displayRemoved));
+        assertEquals(displayAdded, displayRemoved);
+    }
+
+    @Test
+    public void testDisplayDeviceAddAndRemove_SwitchDefault() {
+        DisplayDevice device1 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
+                DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY);
+        DisplayDevice device2 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
+                DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY);
+
+        LogicalDisplay display1 = add(device1);
+        assertEquals(info(display1).address, info(device1).address);
+        assertEquals(DEFAULT_DISPLAY, id(display1));
+
+        LogicalDisplay display2 = add(device2);
+        assertEquals(info(display2).address, info(device2).address);
+        // We can only have one default display
+        assertEquals(DEFAULT_DISPLAY, id(display1));
+
+        // remove
+        mDisplayDeviceRepo.onDisplayDeviceEvent(device1, DISPLAY_DEVICE_EVENT_REMOVED);
+
+        verify(mListenerMock).onLogicalDisplayEventLocked(
+                mDisplayCaptor.capture(), eq(LOGICAL_DISPLAY_EVENT_REMOVED));
+        LogicalDisplay displayRemoved = mDisplayCaptor.getValue();
+        // Display 1 is still the default logical display
+        assertEquals(DEFAULT_DISPLAY, id(display1));
+        // The logical displays had their devices swapped and Display 2 was removed
+        assertEquals(display2, displayRemoved);
+        assertEquals(info(display1).address, info(device2).address);
+    }
+
+    @Test
     public void testGetDisplayIdsLocked() {
         add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
-                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
+                DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY));
         add(createDisplayDevice(Display.TYPE_EXTERNAL, 600, 800, 0));
         add(createDisplayDevice(Display.TYPE_VIRTUAL, 600, 800, 0));
 
@@ -223,19 +270,19 @@
     @Test
     public void testGetDisplayInfoForStateLocked_oneDisplayGroup_internalType() {
         add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
-                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
+                DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY));
         add(createDisplayDevice(Display.TYPE_INTERNAL, 200, 800,
-                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
+                DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY));
         add(createDisplayDevice(Display.TYPE_INTERNAL, 700, 800,
-                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
+                DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY));
 
         Set<DisplayInfo> displayInfos = mLogicalDisplayMapper.getDisplayInfoForStateLocked(
                 DeviceStateToLayoutMap.STATE_DEFAULT, DEFAULT_DISPLAY, DEFAULT_DISPLAY_GROUP);
-        assertThat(displayInfos.size()).isEqualTo(3);
+        assertThat(displayInfos.size()).isEqualTo(1);
         for (DisplayInfo displayInfo : displayInfos) {
             assertThat(displayInfo.displayId).isEqualTo(DEFAULT_DISPLAY);
             assertThat(displayInfo.displayGroupId).isEqualTo(DEFAULT_DISPLAY_GROUP);
-            assertThat(displayInfo.logicalWidth).isAnyOf(600, 200, 700);
+            assertThat(displayInfo.logicalWidth).isEqualTo(600);
             assertThat(displayInfo.logicalHeight).isEqualTo(800);
         }
     }
@@ -243,19 +290,19 @@
     @Test
     public void testGetDisplayInfoForStateLocked_oneDisplayGroup_differentTypes() {
         add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
-                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
+                DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY));
         add(createDisplayDevice(Display.TYPE_INTERNAL, 200, 800,
-                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
+                DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY));
         add(createDisplayDevice(Display.TYPE_EXTERNAL, 700, 800,
-                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
+                DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY));
 
         Set<DisplayInfo> displayInfos = mLogicalDisplayMapper.getDisplayInfoForStateLocked(
                 DeviceStateToLayoutMap.STATE_DEFAULT, DEFAULT_DISPLAY, DEFAULT_DISPLAY_GROUP);
-        assertThat(displayInfos.size()).isEqualTo(2);
+        assertThat(displayInfos.size()).isEqualTo(1);
         for (DisplayInfo displayInfo : displayInfos) {
             assertThat(displayInfo.displayId).isEqualTo(DEFAULT_DISPLAY);
             assertThat(displayInfo.displayGroupId).isEqualTo(DEFAULT_DISPLAY_GROUP);
-            assertThat(displayInfo.logicalWidth).isAnyOf(600, 200);
+            assertThat(displayInfo.logicalWidth).isEqualTo(600);
             assertThat(displayInfo.logicalHeight).isEqualTo(800);
         }
     }
@@ -263,19 +310,19 @@
     @Test
     public void testGetDisplayInfoForStateLocked_multipleDisplayGroups_defaultGroup() {
         add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
-                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
+                DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY));
         add(createDisplayDevice(Display.TYPE_INTERNAL, 200, 800,
-                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
+                DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY));
         add(createDisplayDevice(Display.TYPE_VIRTUAL, 700, 800,
                 DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP));
 
         Set<DisplayInfo> displayInfos = mLogicalDisplayMapper.getDisplayInfoForStateLocked(
                 DeviceStateToLayoutMap.STATE_DEFAULT, DEFAULT_DISPLAY, DEFAULT_DISPLAY_GROUP);
-        assertThat(displayInfos.size()).isEqualTo(2);
+        assertThat(displayInfos.size()).isEqualTo(1);
         for (DisplayInfo displayInfo : displayInfos) {
             assertThat(displayInfo.displayId).isEqualTo(DEFAULT_DISPLAY);
             assertThat(displayInfo.displayGroupId).isEqualTo(DEFAULT_DISPLAY_GROUP);
-            assertThat(displayInfo.logicalWidth).isAnyOf(600, 200);
+            assertThat(displayInfo.logicalWidth).isEqualTo(600);
             assertThat(displayInfo.logicalHeight).isEqualTo(800);
         }
     }
@@ -283,7 +330,7 @@
     @Test
     public void testSingleDisplayGroup() {
         LogicalDisplay display1 = add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
-                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
+                DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY));
         LogicalDisplay display2 = add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, 0));
         LogicalDisplay display3 = add(createDisplayDevice(Display.TYPE_VIRTUAL, 600, 800, 0));
 
@@ -298,7 +345,7 @@
     @Test
     public void testMultipleDisplayGroups() {
         LogicalDisplay display1 = add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
-                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
+                DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY));
         LogicalDisplay display2 = add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, 0));
 
 
@@ -371,7 +418,7 @@
     /////////////////
 
     private TestDisplayDevice createDisplayDevice(int type, int width, int height, int flags) {
-        return createDisplayDevice(new DisplayAddressImpl(), type, width, height, flags);
+        return createDisplayDevice(new TestUtils.TestDisplayAddress(), type, width, height, flags);
     }
 
     private TestDisplayDevice createDisplayDevice(
@@ -385,7 +432,7 @@
         displayDeviceInfo.supportedModes = new Display.Mode[1];
         displayDeviceInfo.supportedModes[0] = new Display.Mode(1, width, height, 60f);
         displayDeviceInfo.modeId = 1;
-        displayDeviceInfo.address = new DisplayAddressImpl();
+        displayDeviceInfo.address = address;
         return device;
     }
 
@@ -427,18 +474,8 @@
         assertNotEquals(DEFAULT_DISPLAY, id(displayRemoved));
     }
 
-    /**
-     * Create a custom {@link DisplayAddress} to ensure we're not relying on any specific
-     * display-address implementation in our code. Intentionally uses default object (reference)
-     * equality rules.
-     */
-    class DisplayAddressImpl extends DisplayAddress {
-        @Override
-        public void writeToParcel(Parcel out, int flags) { }
-    }
-
     class TestDisplayDevice extends DisplayDevice {
-        private DisplayDeviceInfo mInfo = new DisplayDeviceInfo();
+        private DisplayDeviceInfo mInfo;
         private DisplayDeviceInfo mSentInfo;
 
         TestDisplayDevice() {
diff --git a/services/tests/servicestests/src/com/android/server/display/TestUtils.java b/services/tests/servicestests/src/com/android/server/display/TestUtils.java
index 859dfe3..0454587 100644
--- a/services/tests/servicestests/src/com/android/server/display/TestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/display/TestUtils.java
@@ -18,7 +18,9 @@
 
 import android.hardware.Sensor;
 import android.hardware.SensorEvent;
+import android.os.Parcel;
 import android.os.SystemClock;
+import android.view.DisplayAddress;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
@@ -57,4 +59,13 @@
         return sensor;
     }
 
+    /**
+     * Create a custom {@link DisplayAddress} to ensure we're not relying on any specific
+     * display-address implementation in our code. Intentionally uses default object (reference)
+     * equality rules.
+     */
+    public static class TestDisplayAddress extends DisplayAddress {
+        @Override
+        public void writeToParcel(Parcel out, int flags) { }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/GiveFeaturesActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/GiveFeaturesActionTest.java
deleted file mode 100644
index 0b31db6..0000000
--- a/services/tests/servicestests/src/com/android/server/hdmi/GiveFeaturesActionTest.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.hdmi;
-
-import static android.hardware.hdmi.DeviceFeatures.FEATURE_SUPPORTED;
-import static android.hardware.hdmi.DeviceFeatures.FEATURE_SUPPORT_UNKNOWN;
-import static android.hardware.hdmi.HdmiControlManager.HDMI_CEC_VERSION_2_0;
-import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM;
-
-import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.spy;
-
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.hardware.hdmi.DeviceFeatures;
-import android.hardware.hdmi.HdmiControlManager;
-import android.hardware.hdmi.HdmiDeviceInfo;
-import android.hardware.hdmi.IHdmiControlCallback;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.os.test.TestLooper;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-
-import com.android.server.SystemService;
-
-import com.google.android.collect.Lists;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-
-@SmallTest
-@Presubmit
-@RunWith(JUnit4.class)
-public class GiveFeaturesActionTest {
-    private HdmiControlService mHdmiControlServiceSpy;
-    private HdmiCecController mHdmiCecController;
-    private HdmiCecLocalDevicePlayback mPlaybackDevice;
-    private FakeNativeWrapper mNativeWrapper;
-    private FakePowerManagerWrapper mPowerManager;
-    private Looper mLooper;
-    private Context mContextSpy;
-    private TestLooper mTestLooper = new TestLooper();
-    private int mPhysicalAddress = 0x1100;
-    private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
-    private int mPlaybackLogicalAddress;
-
-    private TestCallback mTestCallback;
-    private GiveFeaturesAction mAction;
-
-    /**
-     * Setup: Local Playback device queries the features of a connected TV.
-     */
-    @Before
-    public void setUp() throws RemoteException {
-        mContextSpy = spy(new ContextWrapper(
-                InstrumentationRegistry.getInstrumentation().getTargetContext()));
-
-        mHdmiControlServiceSpy = spy(new HdmiControlService(mContextSpy, Collections.emptyList()));
-        doNothing().when(mHdmiControlServiceSpy)
-                .writeStringSystemProperty(anyString(), anyString());
-
-        mLooper = mTestLooper.getLooper();
-        mHdmiControlServiceSpy.setIoLooper(mLooper);
-        mHdmiControlServiceSpy.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
-
-        mNativeWrapper = new FakeNativeWrapper();
-        mNativeWrapper.setPhysicalAddress(mPhysicalAddress);
-
-        mHdmiCecController = HdmiCecController.createWithNativeWrapper(
-                mHdmiControlServiceSpy, mNativeWrapper, mHdmiControlServiceSpy.getAtomWriter());
-        mHdmiControlServiceSpy.setCecController(mHdmiCecController);
-        mHdmiControlServiceSpy.setHdmiMhlController(
-                HdmiMhlControllerStub.create(mHdmiControlServiceSpy));
-        mHdmiControlServiceSpy.initService();
-        mPowerManager = new FakePowerManagerWrapper(mContextSpy);
-        mHdmiControlServiceSpy.setPowerManager(mPowerManager);
-
-        mPlaybackDevice = new HdmiCecLocalDevicePlayback(mHdmiControlServiceSpy);
-        mPlaybackDevice.init();
-        mLocalDevices.add(mPlaybackDevice);
-
-        mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
-        mHdmiControlServiceSpy.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
-        mTestLooper.dispatchAll();
-
-        synchronized (mPlaybackDevice.mLock) {
-            mPlaybackLogicalAddress = mPlaybackDevice.getDeviceInfo().getLogicalAddress();
-        }
-
-        // Setup specific to these tests
-        mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
-                Constants.ADDR_TV, 0x0000, HdmiDeviceInfo.DEVICE_TV));
-        mTestLooper.dispatchAll();
-
-        mTestCallback = new TestCallback();
-        mAction = new GiveFeaturesAction(mPlaybackDevice, Constants.ADDR_TV, mTestCallback);
-    }
-
-    @Test
-    public void sendsGiveFeaturesMessage() {
-        mPlaybackDevice.addAndStartAction(mAction);
-        mTestLooper.dispatchAll();
-
-        HdmiCecMessage giveFeatures = HdmiCecMessageBuilder.buildGiveFeatures(
-                mPlaybackLogicalAddress, Constants.ADDR_TV);
-        assertThat(mNativeWrapper.getResultMessages()).contains(giveFeatures);
-    }
-
-    @Test
-    public void noMatchingReportFeaturesReceived_actionFailsAndNetworkIsNotUpdated() {
-        mPlaybackDevice.addAndStartAction(mAction);
-        mTestLooper.dispatchAll();
-
-        // Wrong source
-        mNativeWrapper.onCecMessage(ReportFeaturesMessage.build(
-                Constants.ADDR_AUDIO_SYSTEM, HdmiControlManager.HDMI_CEC_VERSION_2_0,
-                Arrays.asList(DEVICE_AUDIO_SYSTEM), Constants.RC_PROFILE_SOURCE,
-                Collections.emptyList(), DeviceFeatures.NO_FEATURES_SUPPORTED));
-        mTestLooper.dispatchAll();
-
-        mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
-        mTestLooper.dispatchAll();
-
-        @DeviceFeatures.FeatureSupportStatus int avcSupport =
-                mHdmiControlServiceSpy.getHdmiCecNetwork().getCecDeviceInfo(Constants.ADDR_TV)
-                        .getDeviceFeatures().getSetAudioVolumeLevelSupport();
-
-        assertThat(avcSupport).isEqualTo(FEATURE_SUPPORT_UNKNOWN);
-        assertThat(mTestCallback.getResult()).isEqualTo(
-                HdmiControlManager.RESULT_COMMUNICATION_FAILED);
-    }
-
-    @Test
-    public void matchingReportFeaturesReceived_actionSucceedsAndNetworkIsUpdated() {
-        mPlaybackDevice.addAndStartAction(mAction);
-        mTestLooper.dispatchAll();
-
-        mNativeWrapper.onCecMessage(
-                ReportFeaturesMessage.build(
-                        Constants.ADDR_TV, HDMI_CEC_VERSION_2_0, Collections.emptyList(),
-                        Constants.RC_PROFILE_TV, Lists.newArrayList(Constants.RC_PROFILE_TV_NONE),
-                        DeviceFeatures.NO_FEATURES_SUPPORTED.toBuilder()
-                                .setSetAudioVolumeLevelSupport(FEATURE_SUPPORTED)
-                                .build()
-                )
-        );
-        mTestLooper.dispatchAll();
-
-        @DeviceFeatures.FeatureSupportStatus int avcSupport =
-                mHdmiControlServiceSpy.getHdmiCecNetwork().getCecDeviceInfo(Constants.ADDR_TV)
-                        .getDeviceFeatures().getSetAudioVolumeLevelSupport();
-
-        assertThat(avcSupport).isEqualTo(FEATURE_SUPPORTED);
-        assertThat(mTestCallback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
-    }
-
-    private static class TestCallback extends IHdmiControlCallback.Stub {
-        private final ArrayList<Integer> mCallbackResult = new ArrayList<Integer>();
-
-        @Override
-        public void onComplete(int result) {
-            mCallbackResult.add(result);
-        }
-
-        private int getResult() {
-            assertThat(mCallbackResult.size()).isEqualTo(1);
-            return mCallbackResult.get(0);
-        }
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
index 4de15c8..928c76d 100644
--- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
@@ -330,11 +330,12 @@
 
     @Test
     public void testPriorityPersisted() throws Exception {
-        final JobInfo.Builder b = new Builder(92, mComponent)
+        final JobInfo job = new Builder(92, mComponent)
                 .setOverrideDeadline(5000)
                 .setPriority(JobInfo.PRIORITY_MIN)
-                .setPersisted(true);
-        final JobStatus js = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
+                .setPersisted(true)
+                .build();
+        final JobStatus js = JobStatus.createFromJobInfo(job, SOME_UID, null, -1, null);
         mTaskStoreUnderTest.add(js);
         waitForPendingIo();
 
@@ -342,7 +343,7 @@
         mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true);
         final JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
         assertEquals("Priority not correctly persisted.",
-                JobInfo.PRIORITY_MIN, loaded.getEffectivePriority());
+                JobInfo.PRIORITY_MIN, job.getPriority());
     }
 
     /**
diff --git a/services/tests/servicestests/src/com/android/server/job/PendingJobQueueTest.java b/services/tests/servicestests/src/com/android/server/job/PendingJobQueueTest.java
new file mode 100644
index 0000000..12fc958
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/job/PendingJobQueueTest.java
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.job;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.app.job.JobInfo;
+import android.content.ComponentName;
+import android.platform.test.annotations.LargeTest;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.util.SparseLongArray;
+
+import com.android.server.job.controllers.JobStatus;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+public class PendingJobQueueTest {
+    private static final String TAG = PendingJobQueueTest.class.getSimpleName();
+
+    private static final int[] sRegJobPriorities = {
+            JobInfo.PRIORITY_HIGH, JobInfo.PRIORITY_DEFAULT,
+            JobInfo.PRIORITY_LOW, JobInfo.PRIORITY_MIN
+    };
+
+    private static JobInfo.Builder createJobInfo(int jobId) {
+        return new JobInfo.Builder(jobId, new ComponentName("foo", "bar"));
+    }
+
+    private JobStatus createJobStatus(String testTag, JobInfo.Builder jobInfoBuilder,
+            int callingUid) {
+        return JobStatus.createFromJobInfo(
+                jobInfoBuilder.build(), callingUid, "com.android.test", 0, testTag);
+    }
+
+    @Test
+    public void testAdd() {
+        List<JobStatus> jobs = new ArrayList<>();
+        jobs.add(createJobStatus("testAdd", createJobInfo(1), 1));
+        jobs.add(createJobStatus("testAdd", createJobInfo(2), 2));
+        jobs.add(createJobStatus("testAdd", createJobInfo(3).setExpedited(true), 3));
+        jobs.add(createJobStatus("testAdd", createJobInfo(4), 4));
+        jobs.add(createJobStatus("testAdd", createJobInfo(5).setExpedited(true), 5));
+
+        PendingJobQueue jobQueue = new PendingJobQueue();
+        for (int i = 0; i < jobs.size(); ++i) {
+            jobQueue.add(jobs.get(i));
+            assertEquals(i + 1, jobQueue.size());
+        }
+
+        JobStatus job;
+        while ((job = jobQueue.next()) != null) {
+            jobs.remove(job);
+        }
+        assertEquals(0, jobs.size());
+    }
+
+    @Test
+    public void testAddAll() {
+        List<JobStatus> jobs = new ArrayList<>();
+        jobs.add(createJobStatus("testAddAll", createJobInfo(1), 1));
+        jobs.add(createJobStatus("testAddAll", createJobInfo(2), 2));
+        jobs.add(createJobStatus("testAddAll", createJobInfo(3).setExpedited(true), 3));
+        jobs.add(createJobStatus("testAddAll", createJobInfo(4), 4));
+        jobs.add(createJobStatus("testAddAll", createJobInfo(5).setExpedited(true), 5));
+
+        PendingJobQueue jobQueue = new PendingJobQueue();
+        jobQueue.addAll(jobs);
+        assertEquals(jobs.size(), jobQueue.size());
+
+        JobStatus job;
+        while ((job = jobQueue.next()) != null) {
+            jobs.remove(job);
+        }
+        assertEquals(0, jobs.size());
+    }
+
+    @Test
+    public void testClear() {
+        List<JobStatus> jobs = new ArrayList<>();
+        jobs.add(createJobStatus("testClear", createJobInfo(1), 1));
+        jobs.add(createJobStatus("testClear", createJobInfo(2), 2));
+        jobs.add(createJobStatus("testClear", createJobInfo(3).setExpedited(true), 3));
+        jobs.add(createJobStatus("testClear", createJobInfo(4), 4));
+        jobs.add(createJobStatus("testClear", createJobInfo(5).setExpedited(true), 5));
+
+        PendingJobQueue jobQueue = new PendingJobQueue();
+        jobQueue.addAll(jobs);
+        assertEquals(jobs.size(), jobQueue.size());
+        assertNotNull(jobQueue.next());
+
+        jobQueue.clear();
+        assertEquals(0, jobQueue.size());
+        assertNull(jobQueue.next());
+    }
+
+    @Test
+    public void testRemove() {
+        List<JobStatus> jobs = new ArrayList<>();
+        jobs.add(createJobStatus("testRemove", createJobInfo(1), 1));
+        jobs.add(createJobStatus("testRemove", createJobInfo(2), 2));
+        jobs.add(createJobStatus("testRemove", createJobInfo(3).setExpedited(true), 3));
+        jobs.add(createJobStatus("testRemove", createJobInfo(4), 4));
+        jobs.add(createJobStatus("testRemove", createJobInfo(5).setExpedited(true), 5));
+
+        PendingJobQueue jobQueue = new PendingJobQueue();
+        jobQueue.addAll(jobs);
+
+        for (int i = 0; i < jobs.size(); ++i) {
+            jobQueue.remove(jobs.get(i));
+            assertEquals(jobs.size() - i - 1, jobQueue.size());
+        }
+        assertNull(jobQueue.next());
+    }
+
+    @Test
+    public void testPendingJobSorting() {
+        PendingJobQueue jobQueue = new PendingJobQueue();
+
+        // First letter in job variable name indicate regular (r) or expedited (e).
+        // Capital letters in job variable name indicate the app/UID.
+        // Numbers in job variable name indicate the enqueue time.
+        // Expected sort order:
+        //   eA7 > rA1 > eB6 > rB2 > eC3 > rD4 > eE5 > eF9 > rF8 > eC11 > rC10 > rG12 > rG13 > eE14
+        // Intentions:
+        //   * A jobs let us test skipping both regular and expedited jobs of other apps
+        //   * B jobs let us test skipping only regular job of another app without going too far
+        //   * C jobs test that regular jobs don't skip over other app's jobs and that EJs only
+        //     skip up to level of the earliest regular job
+        //   * E jobs test that expedited jobs don't skip the line when the app has no regular jobs
+        //   * F jobs test correct expedited/regular ordering doesn't push jobs too high in list
+        //   * G jobs test correct ordering for regular jobs
+        //   * H job tests correct behavior when enqueue times are the same
+        JobStatus rA1 = createJobStatus("testPendingJobSorting", createJobInfo(1), 1);
+        JobStatus rB2 = createJobStatus("testPendingJobSorting", createJobInfo(2), 2);
+        JobStatus eC3 = createJobStatus("testPendingJobSorting",
+                createJobInfo(3).setExpedited(true), 3);
+        JobStatus rD4 = createJobStatus("testPendingJobSorting", createJobInfo(4), 4);
+        JobStatus eE5 = createJobStatus("testPendingJobSorting",
+                createJobInfo(5).setExpedited(true), 5);
+        JobStatus eB6 = createJobStatus("testPendingJobSorting",
+                createJobInfo(6).setExpedited(true), 2);
+        JobStatus eA7 = createJobStatus("testPendingJobSorting",
+                createJobInfo(7).setExpedited(true), 1);
+        JobStatus rH8 = createJobStatus("testPendingJobSorting", createJobInfo(8), 8);
+        JobStatus rF8 = createJobStatus("testPendingJobSorting", createJobInfo(8), 6);
+        JobStatus eF9 = createJobStatus("testPendingJobSorting",
+                createJobInfo(9).setExpedited(true), 6);
+        JobStatus rC10 = createJobStatus("testPendingJobSorting", createJobInfo(10), 3);
+        JobStatus eC11 = createJobStatus("testPendingJobSorting",
+                createJobInfo(11).setExpedited(true), 3);
+        JobStatus rG12 = createJobStatus("testPendingJobSorting", createJobInfo(12), 7);
+        JobStatus rG13 = createJobStatus("testPendingJobSorting", createJobInfo(13), 7);
+        JobStatus eE14 = createJobStatus("testPendingJobSorting",
+                createJobInfo(14).setExpedited(true), 5);
+
+        rA1.enqueueTime = 10;
+        rB2.enqueueTime = 20;
+        eC3.enqueueTime = 30;
+        rD4.enqueueTime = 40;
+        eE5.enqueueTime = 50;
+        eB6.enqueueTime = 60;
+        eA7.enqueueTime = 70;
+        rF8.enqueueTime = 80;
+        rH8.enqueueTime = 80;
+        eF9.enqueueTime = 90;
+        rC10.enqueueTime = 100;
+        eC11.enqueueTime = 110;
+        rG12.enqueueTime = 120;
+        rG13.enqueueTime = 130;
+        eE14.enqueueTime = 140;
+
+        // Add in random order so sorting is apparent.
+        jobQueue.add(eC3);
+        jobQueue.add(eE5);
+        jobQueue.add(rA1);
+        jobQueue.add(rG13);
+        jobQueue.add(rD4);
+        jobQueue.add(eA7);
+        jobQueue.add(rG12);
+        jobQueue.add(rH8);
+        jobQueue.add(rF8);
+        jobQueue.add(eB6);
+        jobQueue.add(eE14);
+        jobQueue.add(eF9);
+        jobQueue.add(rB2);
+        jobQueue.add(rC10);
+        jobQueue.add(eC11);
+
+        checkPendingJobInvariants(jobQueue);
+        JobStatus job;
+        final JobStatus[] expectedPureOrder = new JobStatus[]{
+                eC3, rD4, eE5, eB6, rB2, eA7, rA1, rH8, eF9, rF8, eC11, rC10, rG12, rG13, eE14};
+        int idx = 0;
+        jobQueue.setOptimizeIteration(false);
+        jobQueue.resetIterator();
+        while ((job = jobQueue.next()) != null) {
+            assertEquals("List wasn't correctly sorted @ index " + idx,
+                    expectedPureOrder[idx].getJobId(), job.getJobId());
+            idx++;
+        }
+
+        final JobStatus[] expectedOptimizedOrder = new JobStatus[]{
+                eC3, eC11, rD4, eE5, eE14, eB6, rB2, eA7, rA1, rH8, eF9, rF8,  rC10, rG12, rG13};
+        idx = 0;
+        jobQueue.setOptimizeIteration(true);
+        jobQueue.resetIterator();
+        while ((job = jobQueue.next()) != null) {
+            assertEquals("Optimized list wasn't correctly sorted @ index " + idx,
+                    expectedOptimizedOrder[idx].getJobId(), job.getJobId());
+            idx++;
+        }
+    }
+
+    @Test
+    public void testPendingJobSorting_Random() {
+        PendingJobQueue jobQueue = new PendingJobQueue();
+        Random random = new Random(1); // Always use the same series of pseudo random values.
+
+        for (int i = 0; i < 5000; ++i) {
+            JobStatus job = createJobStatus("testPendingJobSorting_Random",
+                    createJobInfo(i).setExpedited(random.nextBoolean()), random.nextInt(250));
+            job.enqueueTime = random.nextInt(1_000_000);
+            jobQueue.add(job);
+        }
+
+        checkPendingJobInvariants(jobQueue);
+    }
+
+    @Test
+    public void testPendingJobSortingTransitivity() {
+        PendingJobQueue jobQueue = new PendingJobQueue();
+        // Always use the same series of pseudo random values.
+        for (int seed : new int[]{1337, 7357, 606, 6357, 41106010, 3, 2, 1}) {
+            Random random = new Random(seed);
+
+            jobQueue.clear();
+
+            for (int i = 0; i < 300; ++i) {
+                JobStatus job = createJobStatus("testPendingJobSortingTransitivity",
+                        createJobInfo(i).setExpedited(random.nextBoolean()), random.nextInt(50));
+                job.enqueueTime = random.nextInt(1_000_000);
+                job.overrideState = random.nextInt(4);
+                jobQueue.add(job);
+            }
+
+            checkPendingJobInvariants(jobQueue);
+        }
+    }
+
+    @Test
+    @LargeTest
+    public void testPendingJobSortingTransitivity_Concentrated() {
+        PendingJobQueue jobQueue = new PendingJobQueue();
+        // Always use the same series of pseudo random values.
+        for (int seed : new int[]{1337, 6000, 637739, 6357, 1, 7, 13}) {
+            Random random = new Random(seed);
+
+            jobQueue.clear();
+
+            for (int i = 0; i < 300; ++i) {
+                JobStatus job = createJobStatus("testPendingJobSortingTransitivity_Concentrated",
+                        createJobInfo(i).setExpedited(random.nextFloat() < .03),
+                        random.nextInt(20));
+                job.enqueueTime = random.nextInt(250);
+                job.overrideState = random.nextFloat() < .01
+                        ? JobStatus.OVERRIDE_SORTING : JobStatus.OVERRIDE_NONE;
+                jobQueue.add(job);
+                Log.d(TAG, testJobToString(job));
+            }
+
+            checkPendingJobInvariants(jobQueue);
+        }
+    }
+
+    @Test
+    public void testPendingJobSorting_Random_WithPriority() {
+        PendingJobQueue jobQueue = new PendingJobQueue();
+        Random random = new Random(1); // Always use the same series of pseudo random values.
+
+        for (int i = 0; i < 5000; ++i) {
+            final boolean isEj = random.nextBoolean();
+            final int priority;
+            if (isEj) {
+                priority = random.nextBoolean() ? JobInfo.PRIORITY_MAX : JobInfo.PRIORITY_HIGH;
+            } else {
+                priority = sRegJobPriorities[random.nextInt(sRegJobPriorities.length)];
+            }
+            JobStatus job = createJobStatus("testPendingJobSorting_Random_WithPriority",
+                    createJobInfo(i).setExpedited(isEj).setPriority(priority),
+                    random.nextInt(250));
+            job.enqueueTime = random.nextInt(1_000_000);
+            jobQueue.add(job);
+        }
+
+        checkPendingJobInvariants(jobQueue);
+    }
+
+    @Test
+    public void testPendingJobSortingTransitivity_WithPriority() {
+        PendingJobQueue jobQueue = new PendingJobQueue();
+        // Always use the same series of pseudo random values.
+        for (int seed : new int[]{1337, 7357, 606, 6357, 41106010, 3, 2, 1}) {
+            Random random = new Random(seed);
+
+            jobQueue.clear();
+
+            for (int i = 0; i < 300; ++i) {
+                final boolean isEj = random.nextBoolean();
+                final int priority;
+                if (isEj) {
+                    priority = random.nextBoolean() ? JobInfo.PRIORITY_MAX : JobInfo.PRIORITY_HIGH;
+                } else {
+                    priority = sRegJobPriorities[random.nextInt(sRegJobPriorities.length)];
+                }
+                JobStatus job = createJobStatus("testPendingJobSortingTransitivity_WithPriority",
+                        createJobInfo(i).setExpedited(isEj).setPriority(priority),
+                        random.nextInt(50));
+                job.enqueueTime = random.nextInt(1_000_000);
+                job.overrideState = random.nextInt(4);
+                jobQueue.add(job);
+            }
+
+            checkPendingJobInvariants(jobQueue);
+        }
+    }
+
+    @Test
+    @LargeTest
+    public void testPendingJobSortingTransitivity_Concentrated_WithPriority() {
+        PendingJobQueue jobQueue = new PendingJobQueue();
+        // Always use the same series of pseudo random values.
+        for (int seed : new int[]{1337, 6000, 637739, 6357, 1, 7, 13}) {
+            Random random = new Random(seed);
+
+            jobQueue.clear();
+
+            for (int i = 0; i < 300; ++i) {
+                final boolean isEj = random.nextFloat() < .03;
+                final int priority;
+                if (isEj) {
+                    priority = random.nextBoolean() ? JobInfo.PRIORITY_MAX : JobInfo.PRIORITY_HIGH;
+                } else {
+                    priority = sRegJobPriorities[random.nextInt(sRegJobPriorities.length)];
+                }
+                JobStatus job = createJobStatus(
+                        "testPendingJobSortingTransitivity_Concentrated_WithPriority",
+                        createJobInfo(i).setExpedited(isEj).setPriority(priority),
+                        random.nextInt(20));
+                job.enqueueTime = random.nextInt(250);
+                job.overrideState = random.nextFloat() < .01
+                        ? JobStatus.OVERRIDE_SORTING : JobStatus.OVERRIDE_NONE;
+                jobQueue.add(job);
+                Log.d(TAG, testJobToString(job));
+            }
+
+            checkPendingJobInvariants(jobQueue);
+        }
+    }
+
+    private void checkPendingJobInvariants(PendingJobQueue jobQueue) {
+        final SparseBooleanArray regJobSeen = new SparseBooleanArray();
+        // Latest priority enqueue times seen for each priority for each app.
+        final SparseArray<SparseLongArray> latestPriorityRegEnqueueTimesPerUid =
+                new SparseArray<>();
+        final SparseArray<SparseLongArray> latestPriorityEjEnqueueTimesPerUid = new SparseArray<>();
+        final int noEntry = -1;
+        int prevOverrideState = noEntry;
+
+        JobStatus job;
+        jobQueue.resetIterator();
+        int count = 0;
+        while ((job = jobQueue.next()) != null) {
+            count++;
+            final int uid = job.getSourceUid();
+
+            // Invariant #1: All jobs are sorted by override state
+            // Invariant #2: All jobs (for a UID) are sorted by priority order
+            // Invariant #3: Jobs (for a UID) with the same priority are sorted by enqueue time.
+            // Invariant #4: EJs (for a UID) should be before regular jobs
+
+            // Invariant 1
+            if (prevOverrideState != job.overrideState) {
+                if (prevOverrideState != noEntry) {
+                    assertTrue(prevOverrideState > job.overrideState);
+                }
+                // Override state can make ordering weird. Clear the other cached states
+                // to avoid confusion in the other checks.
+                latestPriorityEjEnqueueTimesPerUid.clear();
+                latestPriorityRegEnqueueTimesPerUid.clear();
+                regJobSeen.clear();
+                prevOverrideState = job.overrideState;
+            }
+
+            final int priority = job.getEffectivePriority();
+            final SparseArray<SparseLongArray> latestPriorityEnqueueTimesPerUid =
+                    job.isRequestedExpeditedJob()
+                            ? latestPriorityEjEnqueueTimesPerUid
+                            : latestPriorityRegEnqueueTimesPerUid;
+            SparseLongArray latestPriorityEnqueueTimes = latestPriorityEnqueueTimesPerUid.get(uid);
+            if (latestPriorityEnqueueTimes != null) {
+                // Invariant 2
+                for (int p = priority - 1; p >= JobInfo.PRIORITY_MIN; --p) {
+                    // If we haven't seen the priority, there shouldn't be an entry in the array.
+                    assertEquals("Jobs not properly sorted by priority for uid " + uid,
+                            noEntry, latestPriorityEnqueueTimes.get(p, noEntry));
+                }
+
+                // Invariant 3
+                final long lastSeenPriorityEnqueueTime =
+                        latestPriorityEnqueueTimes.get(priority, noEntry);
+                if (lastSeenPriorityEnqueueTime != noEntry) {
+                    assertTrue("Jobs with same priority for uid " + uid
+                                    + " not sorted by enqueue time: "
+                                    + lastSeenPriorityEnqueueTime + " before " + job.enqueueTime,
+                            lastSeenPriorityEnqueueTime <= job.enqueueTime);
+                }
+            } else {
+                latestPriorityEnqueueTimes = new SparseLongArray();
+                latestPriorityEnqueueTimesPerUid.put(uid, latestPriorityEnqueueTimes);
+            }
+            latestPriorityEnqueueTimes.put(priority, job.enqueueTime);
+
+            // Invariant 4
+            if (!job.isRequestedExpeditedJob()) {
+                regJobSeen.put(uid, true);
+            } else if (regJobSeen.get(uid)) {
+                fail("UID " + uid + " had an EJ ordered after a regular job");
+            }
+        }
+        assertEquals("Iterator didn't go through all jobs", jobQueue.size(), count);
+    }
+
+    private static String testJobToString(JobStatus job) {
+        return "testJob " + job.getSourceUid() + "/" + job.getJobId()
+                + "/o" + job.overrideState
+                + "/p" + job.getEffectivePriority()
+                + "/b" + job.lastEvaluatedBias
+                + "/" + job.isRequestedExpeditedJob() + "@" + job.enqueueTime;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
index 21c09a0..1d10b8a 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -217,7 +217,7 @@
     }
 
     @Override
-    protected boolean isCredentialSharedWithParent(int userId) {
+    protected boolean isCredentialSharableWithParent(int userId) {
         UserInfo userInfo = mUserManager.getUserInfo(userId);
         return userInfo.isCloneProfile() || userInfo.isManagedProfile();
     }
diff --git a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java b/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java
deleted file mode 100644
index 2f77126..0000000
--- a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.net;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
-import android.net.InetAddresses;
-import android.net.IpConfiguration;
-import android.net.IpConfiguration.IpAssignment;
-import android.net.IpConfiguration.ProxySettings;
-import android.net.LinkAddress;
-import android.net.ProxyInfo;
-import android.net.StaticIpConfiguration;
-import android.util.ArrayMap;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-
-/**
- * Unit tests for {@link IpConfigStore}
- */
-@RunWith(AndroidJUnit4.class)
-public class IpConfigStoreTest {
-
-    @Test
-    public void backwardCompatibility2to3() throws IOException {
-        final int KEY_CONFIG = 17;
-        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
-        DataOutputStream outputStream = new DataOutputStream(byteStream);
-
-        final IpConfiguration expectedConfig =
-                newIpConfiguration(IpAssignment.DHCP, ProxySettings.NONE, null, null);
-
-        // Emulate writing to old format.
-        writeDhcpConfigV2(outputStream, KEY_CONFIG, expectedConfig);
-
-        InputStream in = new ByteArrayInputStream(byteStream.toByteArray());
-        ArrayMap<String, IpConfiguration> configurations = IpConfigStore.readIpConfigurations(in);
-
-        assertNotNull(configurations);
-        assertEquals(1, configurations.size());
-        IpConfiguration actualConfig = configurations.get(String.valueOf(KEY_CONFIG));
-        assertNotNull(actualConfig);
-        assertEquals(expectedConfig, actualConfig);
-    }
-
-    @Test
-    public void staticIpMultiNetworks() throws Exception {
-        final String IFACE_1 = "eth0";
-        final String IFACE_2 = "eth1";
-        final String IP_ADDR_1 = "192.168.1.10/24";
-        final String IP_ADDR_2 = "192.168.1.20/24";
-        final String DNS_IP_ADDR_1 = "1.2.3.4";
-        final String DNS_IP_ADDR_2 = "5.6.7.8";
-
-        final ArrayList<InetAddress> dnsServers = new ArrayList<>();
-        dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_1));
-        dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_2));
-        final StaticIpConfiguration staticIpConfiguration1 = new StaticIpConfiguration.Builder()
-                .setIpAddress(new LinkAddress(IP_ADDR_1))
-                .setDnsServers(dnsServers).build();
-        final StaticIpConfiguration staticIpConfiguration2 = new StaticIpConfiguration.Builder()
-                .setIpAddress(new LinkAddress(IP_ADDR_2))
-                .setDnsServers(dnsServers).build();
-
-        ProxyInfo proxyInfo =
-                ProxyInfo.buildDirectProxy("10.10.10.10", 88, Arrays.asList("host1", "host2"));
-
-        IpConfiguration expectedConfig1 = newIpConfiguration(IpAssignment.STATIC,
-                ProxySettings.STATIC, staticIpConfiguration1, proxyInfo);
-        IpConfiguration expectedConfig2 = newIpConfiguration(IpAssignment.STATIC,
-                ProxySettings.STATIC, staticIpConfiguration2, proxyInfo);
-
-        ArrayMap<String, IpConfiguration> expectedNetworks = new ArrayMap<>();
-        expectedNetworks.put(IFACE_1, expectedConfig1);
-        expectedNetworks.put(IFACE_2, expectedConfig2);
-
-        MockedDelayedDiskWrite writer = new MockedDelayedDiskWrite();
-        IpConfigStore store = new IpConfigStore(writer);
-        store.writeIpConfigurations("file/path/not/used/", expectedNetworks);
-
-        InputStream in = new ByteArrayInputStream(writer.byteStream.toByteArray());
-        ArrayMap<String, IpConfiguration> actualNetworks = IpConfigStore.readIpConfigurations(in);
-        assertNotNull(actualNetworks);
-        assertEquals(2, actualNetworks.size());
-        assertEquals(expectedNetworks.get(IFACE_1), actualNetworks.get(IFACE_1));
-        assertEquals(expectedNetworks.get(IFACE_2), actualNetworks.get(IFACE_2));
-    }
-
-    private IpConfiguration newIpConfiguration(IpAssignment ipAssignment,
-            ProxySettings proxySettings, StaticIpConfiguration staticIpConfig, ProxyInfo info) {
-        final IpConfiguration config = new IpConfiguration();
-        config.setIpAssignment(ipAssignment);
-        config.setProxySettings(proxySettings);
-        config.setStaticIpConfiguration(staticIpConfig);
-        config.setHttpProxy(info);
-        return config;
-    }
-
-    // This is simplified snapshot of code that was used to store values in V2 format (key as int).
-    private static void writeDhcpConfigV2(DataOutputStream out, int configKey,
-            IpConfiguration config) throws IOException {
-        out.writeInt(2);  // VERSION 2
-        switch (config.getIpAssignment()) {
-            case DHCP:
-                out.writeUTF("ipAssignment");
-                out.writeUTF(config.getIpAssignment().toString());
-                break;
-            default:
-                fail("Not supported in test environment");
-        }
-
-        out.writeUTF("id");
-        out.writeInt(configKey);
-        out.writeUTF("eos");
-    }
-
-    /** Synchronously writes into given byte steam */
-    private static class MockedDelayedDiskWrite extends DelayedDiskWrite {
-        final ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
-
-        @Override
-        public void write(String filePath, Writer w) {
-            DataOutputStream outputStream = new DataOutputStream(byteStream);
-
-            try {
-                w.onWriteCalled(outputStream);
-            } catch (IOException e) {
-                fail();
-            }
-        }
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index af8ac6f..7634b09 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -118,6 +118,7 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.Signature;
 import android.content.pm.UserInfo;
 import android.net.ConnectivityManager;
@@ -166,6 +167,7 @@
 import com.android.internal.util.test.FsUtil;
 import com.android.server.DeviceIdleInternal;
 import com.android.server.LocalServices;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.usage.AppStandbyInternal;
 
 import com.google.common.util.concurrent.AbstractFuture;
@@ -216,6 +218,7 @@
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
 /**
@@ -274,6 +277,7 @@
             ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
 
     private ActivityManagerInternal mActivityManagerInternal;
+    private PackageManagerInternal mPackageManagerInternal;
 
     private IUidObserver mUidObserver;
     private INetworkManagementEventObserver mNetworkObserver;
@@ -335,6 +339,7 @@
         when(usageStats.getIdleUidsForUser(anyInt())).thenReturn(new int[]{});
 
         mActivityManagerInternal = addLocalServiceMock(ActivityManagerInternal.class);
+        mPackageManagerInternal = addLocalServiceMock(PackageManagerInternal.class);
 
         final PowerSaveState state = new PowerSaveState.Builder()
                 .setBatterySaverEnabled(false).build();
@@ -483,8 +488,15 @@
                 .thenReturn(buildApplicationInfo(PKG_NAME_B, UID_B));
         when(mPackageManager.getApplicationInfo(eq(PKG_NAME_C), anyInt()))
                 .thenReturn(buildApplicationInfo(PKG_NAME_C, UID_C));
-        when(mPackageManager.getInstalledApplications(anyInt())).thenReturn(
-                buildInstalledApplicationInfoList());
+        doAnswer(arg -> {
+            final Consumer<AndroidPackage> consumer =
+                    (Consumer<AndroidPackage>) arg.getArguments()[0];
+            for (AndroidPackage androidPackage : buildInstalledPackageList()) {
+                consumer.accept(androidPackage);
+            }
+            return null;
+        }).when(mPackageManagerInternal).forEachInstalledPackage(
+                any(Consumer.class), anyInt());
         when(mUserManager.getUsers()).thenReturn(buildUserInfoList());
         when(mNetworkManager.isBandwidthControlEnabled()).thenReturn(true);
         when(mNetworkManager.setDataSaverModeEnabled(anyBoolean())).thenReturn(true);
@@ -536,6 +548,7 @@
         LocalServices.removeServiceForTest(DeviceIdleInternal.class);
         LocalServices.removeServiceForTest(AppStandbyInternal.class);
         LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
+        LocalServices.removeServiceForTest(PackageManagerInternal.class);
     }
 
     @After
@@ -2037,14 +2050,20 @@
         return ai;
     }
 
-    private List<ApplicationInfo> buildInstalledApplicationInfoList() {
-        final List<ApplicationInfo> installedApps = new ArrayList<>();
-        installedApps.add(buildApplicationInfo(PKG_NAME_A, UID_A));
-        installedApps.add(buildApplicationInfo(PKG_NAME_B, UID_B));
-        installedApps.add(buildApplicationInfo(PKG_NAME_C, UID_C));
+    private List<AndroidPackage> buildInstalledPackageList() {
+        final List<AndroidPackage> installedApps = new ArrayList<>();
+        installedApps.add(createPackageMock(UID_A));
+        installedApps.add(createPackageMock(UID_B));
+        installedApps.add(createPackageMock(UID_C));
         return installedApps;
     }
 
+    private AndroidPackage createPackageMock(int uid) {
+        final AndroidPackage androidPackage = mock(AndroidPackage.class);
+        when(androidPackage.getUid()).thenReturn(uid);
+        return androidPackage;
+    }
+
     private List<UserInfo> buildUserInfoList() {
         final List<UserInfo> users = new ArrayList<>();
         users.add(new UserInfo(USER_ID, "user1", 0));
diff --git a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
index 3cb5d5f..ce322f7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
@@ -20,6 +20,7 @@
 import android.Manifest;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions;
 import android.app.AppOpsManager;
 import android.app.IApplicationThread;
 import android.app.admin.DevicePolicyManagerInternal;
@@ -46,6 +47,7 @@
 import android.platform.test.annotations.Presubmit;
 import android.util.SparseArray;
 
+import com.android.activitycontext.ActivityContext;
 import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
 import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
 import com.android.server.LocalServices;
@@ -240,7 +242,9 @@
                                 FEATURE_ID,
                                 ACTIVITY_COMPONENT,
                                 UserHandle.of(PRIMARY_USER).getIdentifier(),
-                                true));
+                                true,
+                                /* targetTask */ null,
+                                /* options */ null));
 
         verify(mActivityTaskManagerInternal, never())
                 .startActivityAsUser(
@@ -265,7 +269,9 @@
                                 FEATURE_ID,
                                 ACTIVITY_COMPONENT,
                                 UserHandle.of(PRIMARY_USER).getIdentifier(),
-                                false));
+                                false,
+                                /* targetTask */ null,
+                                /* options */ null));
 
         verify(mActivityTaskManagerInternal, never())
                 .startActivityAsUser(
@@ -292,7 +298,9 @@
                                 FEATURE_ID,
                                 ACTIVITY_COMPONENT,
                                 UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
-                                true));
+                                true,
+                                /* targetTask */ null,
+                                /* options */ null));
 
         verify(mActivityTaskManagerInternal, never())
                 .startActivityAsUser(
@@ -319,7 +327,9 @@
                                 FEATURE_ID,
                                 ACTIVITY_COMPONENT,
                                 UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
-                                false));
+                                false,
+                                /* targetTask */ null,
+                                /* options */ null));
 
         verify(mActivityTaskManagerInternal, never())
                 .startActivityAsUser(
@@ -344,7 +354,9 @@
                                 FEATURE_ID,
                                 ACTIVITY_COMPONENT,
                                 UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
-                                true));
+                                true,
+                                /* targetTask */ null,
+                                /* options */ null));
 
         verify(mActivityTaskManagerInternal, never())
                 .startActivityAsUser(
@@ -369,7 +381,9 @@
                                 FEATURE_ID,
                                 ACTIVITY_COMPONENT,
                                 UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
-                                false));
+                                false,
+                                /* targetTask */ null,
+                                /* options */ null));
 
         verify(mActivityTaskManagerInternal, never())
                 .startActivityAsUser(
@@ -396,7 +410,9 @@
                                 FEATURE_ID,
                                 ACTIVITY_COMPONENT,
                                 UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
-                                true));
+                                true,
+                                /* targetTask */ null,
+                                /* options */ null));
 
         verify(mActivityTaskManagerInternal, never())
                 .startActivityAsUser(
@@ -440,7 +456,9 @@
                                 FEATURE_ID,
                                 ACTIVITY_COMPONENT,
                                 UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
-                                false));
+                                false,
+                                /* targetTask */ null,
+                                /* options */ null));
 
         verify(mActivityTaskManagerInternal, never())
                 .startActivityAsUser(
@@ -465,7 +483,9 @@
                                 FEATURE_ID,
                                 new ComponentName(PACKAGE_TWO, "test"),
                                 UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
-                                true));
+                                true,
+                                /* targetTask */ null,
+                                /* options */ null));
 
         verify(mActivityTaskManagerInternal, never())
                 .startActivityAsUser(
@@ -490,7 +510,9 @@
                                 FEATURE_ID,
                                 new ComponentName(PACKAGE_TWO, "test"),
                                 UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
-                                false));
+                                false,
+                                /* targetTask */ null,
+                                /* options */ null));
 
         verify(mActivityTaskManagerInternal, never())
                 .startActivityAsUser(
@@ -515,7 +537,9 @@
                                 FEATURE_ID,
                                 ACTIVITY_COMPONENT,
                                 UserHandle.of(SECONDARY_USER).getIdentifier(),
-                                true));
+                                true,
+                                /* targetTask */ null,
+                                /* options */ null));
 
         verify(mActivityTaskManagerInternal, never())
                 .startActivityAsUser(
@@ -540,7 +564,9 @@
                                 FEATURE_ID,
                                 ACTIVITY_COMPONENT,
                                 UserHandle.of(SECONDARY_USER).getIdentifier(),
-                                false));
+                                false,
+                                /* targetTask */ null,
+                                /* options */ null));
 
         verify(mActivityTaskManagerInternal, never())
                 .startActivityAsUser(
@@ -564,7 +590,9 @@
                 FEATURE_ID,
                 ACTIVITY_COMPONENT,
                 UserHandle.of(PRIMARY_USER).getIdentifier(),
-                true);
+                true,
+                /* targetTask */ null,
+                /* options */ null);
 
         verify(mActivityTaskManagerInternal)
                 .startActivityAsUser(
@@ -578,6 +606,44 @@
                         eq(PRIMARY_USER));
     }
 
+    @Test
+    public void startActivityAsUser_sameTask_fromProfile_success() throws Exception {
+        mTestInjector.setCallingUserId(PROFILE_OF_PRIMARY_USER);
+
+        Bundle options = ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle();
+        IBinder result = ActivityContext.getWithContext(activity -> {
+            try {
+                IBinder targetTask = activity.getActivityToken();
+                mCrossProfileAppsServiceImpl.startActivityAsUser(
+                        mIApplicationThread,
+                        PACKAGE_ONE,
+                        FEATURE_ID,
+                        ACTIVITY_COMPONENT,
+                        UserHandle.of(PRIMARY_USER).getIdentifier(),
+                        true,
+                        targetTask,
+                        options);
+                return targetTask;
+            } catch (Exception re) {
+                return null;
+            }
+        });
+        if (result == null) {
+            throw new Exception();
+        }
+
+        verify(mActivityTaskManagerInternal)
+                .startActivityAsUser(
+                        nullable(IApplicationThread.class),
+                        eq(PACKAGE_ONE),
+                        eq(FEATURE_ID),
+                        any(Intent.class),
+                        eq(result),
+                        anyInt(),
+                        eq(options),
+                        eq(PRIMARY_USER));
+    }
+
     private void mockAppsInstalled(String packageName, int user, boolean installed) {
         when(mPackageManagerInternal.getPackageInfo(
                 eq(packageName),
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index 050b224..946108d 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -23,11 +23,10 @@
 import static org.junit.Assert.fail;
 
 import static java.lang.reflect.Modifier.isFinal;
-import static java.lang.reflect.Modifier.isPrivate;
-import static java.lang.reflect.Modifier.isProtected;
 import static java.lang.reflect.Modifier.isPublic;
 import static java.lang.reflect.Modifier.isStatic;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AppGlobals;
 import android.content.IIntentReceiver;
@@ -63,7 +62,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
 import java.util.regex.Pattern;
 
@@ -101,7 +99,7 @@
                     @Nullable Bundle bOptions) {
             }
 
-            public void sendPackageAddedForNewUsers(String packageName,
+            public void sendPackageAddedForNewUsers(@NonNull Computer snapshot, String packageName,
                     boolean sendBootComplete, boolean includeStopped, int appId,
                     int[] userIds, int[] instantUserIds, int dataLoaderType) {
             }
@@ -456,147 +454,6 @@
         return null;
     }
 
-    // Return the boolean locked value.  A null return means the annotation was not
-    // found.  This method will fail if the annotation is found but is not one of the
-    // known constants.
-    private Boolean getOverride(Method m) {
-        final String name = "Computer." + displayName(m);
-        final Computer.LiveImplementation annotation =
-                m.getAnnotation(Computer.LiveImplementation.class);
-        if (annotation == null) {
-            return null;
-        }
-        final int override = annotation.override();
-        if (override == Computer.LiveImplementation.MANDATORY) {
-            return true;
-        } else if (override == Computer.LiveImplementation.NOT_ALLOWED) {
-            return false;
-        } else {
-            flag(name, "invalid Live value: " + override);
-            return null;
-        }
-    }
-
-    @Test
-    public void testComputerStructure() {
-        // Verify that Copmuter methods are properly annotated and that ComputerLocked is
-        // properly populated per annotations.
-        // Call PackageManagerService.validateComputer();
-        Class base = Computer.class;
-
-        HashMap<Method, Boolean> methodType = new HashMap<>();
-
-        // Verify that all Computer methods are annotated and that the annotation
-        // parameter locked() is valid.
-        for (Method m : base.getDeclaredMethods()) {
-            final String name = "Computer." + displayName(m);
-            Boolean override = getOverride(m);
-            if (override == null) {
-                flag(name, "missing required Live annotation");
-            }
-            methodType.put(m, override);
-        }
-
-        Class coreClass = ComputerEngine.class;
-        final Method[] coreMethods = coreClass.getDeclaredMethods();
-
-        // Examine every method in the core.  If it inherits from a base method it must be
-        // "public final" if the base is NOT_ALLOWED or "public" if the base is MANDATORY.
-        // If the core method does not inherit from the base then it must be either
-        // private or protected.
-        for (Method m : base.getDeclaredMethods()) {
-            String name = "Computer." + displayName(m);
-            final boolean locked = methodType.get(m);
-            final Method core = matchMethod(m, coreMethods);
-            if (core == null) {
-                flag(name, "not overridden in ComputerEngine");
-                continue;
-            }
-            name = "ComputerEngine." + displayName(m);
-            final int modifiers = core.getModifiers();
-            if (!locked) {
-                if (!isPublic(modifiers)) {
-                    flag(name, "is not public");
-                }
-                if (!isFinal(modifiers)) {
-                    flag(name, "is not final");
-                }
-            }
-        }
-        // Any methods left in the coreMethods array must be private or protected.
-        // Protected methods must be overridden (and final) in the live list.
-        Method[] coreHelpers = new Method[coreMethods.length];
-        int coreIndex = 0;
-        for (Method m : coreMethods) {
-            if (m != null) {
-                final String name = "ComputerEngine." + displayName(m);
-                if (name.contains(".lambda$static")) {
-                    // skip static lambda function
-                    continue;
-                }
-
-                final int modifiers = m.getModifiers();
-                if (isPrivate(modifiers)) {
-                    // Okay
-                } else if (isProtected(modifiers)) {
-                    coreHelpers[coreIndex++] = m;
-                } else {
-                    flag(name, "is neither private nor protected");
-                }
-            }
-        }
-
-        Class liveClass = ComputerLocked.class;
-        final Method[] liveMethods = liveClass.getDeclaredMethods();
-
-        // Examine every method in the live list.  Every method must be final and must
-        // inherit either from base or core.  If the method inherits from a base method
-        // then the base must be MANDATORY.
-        for (Method m : base.getDeclaredMethods()) {
-            String name = "Computer." + displayName(m);
-            final boolean locked = methodType.get(m);
-            final Method live = matchMethod(m, liveMethods);
-            if (live == null) {
-                if (locked) {
-                    flag(name, "not overridden in ComputerLocked");
-                }
-                continue;
-            }
-            if (!locked) {
-                flag(name, "improperly overridden in ComputerLocked");
-                continue;
-            }
-
-            name = "ComputerLocked." + displayName(m);
-            final int modifiers = live.getModifiers();
-            if (!locked) {
-                if (!isPublic(modifiers)) {
-                    flag(name, "is not public");
-                }
-                if (!isFinal(modifiers)) {
-                    flag(name, "is not final");
-                }
-            }
-        }
-        for (Method m : coreHelpers) {
-            if (m == null) {
-                continue;
-            }
-            String name = "ComputerLocked." + displayName(m);
-            final Method live = matchMethod(m, liveMethods);
-            if (live == null) {
-                flag(name, "is not overridden in ComputerLocked");
-                continue;
-            }
-        }
-        for (Method m : liveMethods) {
-            if (m != null) {
-                String name = "ComputerLocked." + displayName(m);
-                flag(name, "illegal local method");
-            }
-        }
-    }
-
     private static PerPackageReadTimeouts[] getPerPackageReadTimeouts(String knownDigestersList) {
         final String defaultTimeouts = "3600000001:3600000002:3600000003";
         List<PerPackageReadTimeouts> result = PerPackageReadTimeouts.parseDigestersList(
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 99edecf..c786784 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -16,7 +16,6 @@
 package com.android.server.pm;
 
 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertBundlesEqual;
-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertEmpty;
 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException;
 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith;
 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
@@ -37,6 +36,8 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.LocusId;
+import android.content.pm.Capability;
+import android.content.pm.CapabilityParams;
 import android.content.pm.ShortcutInfo;
 import android.content.res.Resources;
 import android.graphics.BitmapFactory;
@@ -258,10 +259,15 @@
                 .setLongLived(true)
                 .setExtras(pb)
                 .setStartingTheme(android.R.style.Theme_Black_NoTitleBar_Fullscreen)
-                .addCapabilityBinding("action.intent.START_EXERCISE",
-                        "exercise.type", list("running", "jogging"))
-                .addCapabilityBinding("action.intent.START_EXERCISE",
-                        "exercise.duration", list("10m"))
+                .addCapabilityBinding(
+                        new Capability.Builder("action.intent.START_EXERCISE").build(),
+                        new CapabilityParams.Builder("exercise.type", "running")
+                                .addAlias("jogging")
+                                .build())
+                .addCapabilityBinding(
+                        new Capability.Builder("action.intent.START_EXERCISE").build(),
+                        new CapabilityParams.Builder("exercise.duration", "10m")
+                                .build())
                 .build();
         si.addFlags(ShortcutInfo.FLAG_PINNED);
         si.setBitmapPath("abc");
@@ -299,13 +305,14 @@
         assertEquals(null, si.getDisabledMessageResName());
         assertEquals("android:style/Theme.Black.NoTitleBar.Fullscreen",
                 si.getStartingThemeResName());
-        assertTrue(si.hasCapability("action.intent.START_EXERCISE"));
-        assertFalse(si.hasCapability(""));
-        assertFalse(si.hasCapability("random"));
-        assertEquals(list("running", "jogging"), si.getCapabilityParameterValues(
-                "action.intent.START_EXERCISE", "exercise.type"));
-        assertEmpty(si.getCapabilityParameterValues("action.intent.START_EXERCISE", ""));
-        assertEmpty(si.getCapabilityParameterValues("action.intent.START_EXERCISE", "random"));
+        assertEquals(list(new Capability.Builder("action.intent.START_EXERCISE").build()),
+                si.getCapabilities());
+        assertEquals(list(
+                        new CapabilityParams.Builder("exercise.type", "running")
+                                .addAlias("jogging").build(),
+                        new CapabilityParams.Builder("exercise.duration", "10m").build()),
+                si.getCapabilityParams(
+                        new Capability.Builder("action.intent.START_EXERCISE").build()));
     }
 
     public void testShortcutInfoParcel_resId() {
@@ -959,10 +966,15 @@
                 .setRank(123)
                 .setExtras(pb)
                 .setLocusId(new LocusId("1.2.3.4.5"))
-                .addCapabilityBinding("action.intent.START_EXERCISE",
-                        "exercise.type", list("running", "jogging"))
-                .addCapabilityBinding("action.intent.START_EXERCISE",
-                        "exercise.duration", list("10m"))
+                .addCapabilityBinding(
+                        new Capability.Builder("action.intent.START_EXERCISE").build(),
+                        new CapabilityParams.Builder("exercise.type", "running")
+                                .addAlias("jogging")
+                                .build())
+                .addCapabilityBinding(
+                        new Capability.Builder("action.intent.START_EXERCISE").build(),
+                        new CapabilityParams.Builder("exercise.duration", "10m")
+                                .build())
                 .build();
         sorig.setTimestamp(mInjectedCurrentTimeMillis);
 
@@ -1024,13 +1036,14 @@
         assertNull(si.getIconUri());
         assertTrue(si.getLastChangedTimestamp() < now);
 
-        assertTrue(si.hasCapability("action.intent.START_EXERCISE"));
-        assertFalse(si.hasCapability(""));
-        assertFalse(si.hasCapability("random"));
-        assertEquals(list("running", "jogging"), si.getCapabilityParameterValues(
-                "action.intent.START_EXERCISE", "exercise.type"));
-        assertEmpty(si.getCapabilityParameterValues("action.intent.START_EXERCISE", ""));
-        assertEmpty(si.getCapabilityParameterValues("action.intent.START_EXERCISE", "random"));
+        assertEquals(list(new Capability.Builder("action.intent.START_EXERCISE").build()),
+                si.getCapabilities());
+        assertEquals(list(
+                        new CapabilityParams.Builder("exercise.type", "running")
+                                .addAlias("jogging").build(),
+                        new CapabilityParams.Builder("exercise.duration", "10m").build()),
+                si.getCapabilityParams(
+                        new Capability.Builder("action.intent.START_EXERCISE").build()));
 
         // Make sure ranks are saved too.  Because of the auto-adjusting, we need two shortcuts
         // to test it.
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index c7b5547..06b7112 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -316,7 +316,8 @@
                 asHandle(currentUser));
         try {
             assertThat(mUserManager.removeUserWhenPossible(user1.getUserHandle(),
-                    /* overrideDevicePolicy= */ false)).isEqualTo(UserManager.REMOVE_RESULT_ERROR);
+                    /* overrideDevicePolicy= */ false))
+                            .isEqualTo(UserManager.REMOVE_RESULT_ERROR_USER_RESTRICTION);
         } finally {
             mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_USER, /* value= */ false,
                     asHandle(currentUser));
@@ -353,7 +354,8 @@
     @Test
     public void testRemoveUserWhenPossible_systemUserReturnsError() throws Exception {
         assertThat(mUserManager.removeUserWhenPossible(UserHandle.SYSTEM,
-                /* overrideDevicePolicy= */ false)).isEqualTo(UserManager.REMOVE_RESULT_ERROR);
+                /* overrideDevicePolicy= */ false))
+                        .isEqualTo(UserManager.REMOVE_RESULT_ERROR_SYSTEM_USER);
 
         assertThat(hasUser(UserHandle.USER_SYSTEM)).isTrue();
     }
@@ -363,7 +365,8 @@
     public void testRemoveUserWhenPossible_invalidUserReturnsError() throws Exception {
         assertThat(hasUser(Integer.MAX_VALUE)).isFalse();
         assertThat(mUserManager.removeUserWhenPossible(UserHandle.of(Integer.MAX_VALUE),
-                /* overrideDevicePolicy= */ false)).isEqualTo(UserManager.REMOVE_RESULT_ERROR);
+                /* overrideDevicePolicy= */ false))
+                        .isEqualTo(UserManager.REMOVE_RESULT_ERROR_USER_NOT_FOUND);
     }
 
     @MediumTest
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index b2f506a..89450ff 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -210,6 +210,8 @@
 
         Settings.Global.putInt(mContextSpy.getContentResolver(),
                 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
+        Settings.Secure.putInt(mContextSpy.getContentResolver(),
+                Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 0);
 
         mClock = new OffsettableClock.Stopped();
         mTestLooper = new TestLooper(mClock::now);
@@ -709,6 +711,48 @@
         assertThat(mService.getBinderServiceInstance().forceSuspend()).isFalse();
     }
 
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testScreensaverActivateOnSleepDisabled_powered_afterTimeout_goesToDozing() {
+        when(mBatteryManagerInternalMock.isPowered(anyInt())).thenReturn(true);
+
+        doAnswer(inv -> {
+            when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
+            return null;
+        }).when(mDreamManagerInternalMock).startDream(anyBoolean());
+
+        setMinimumScreenOffTimeoutConfig(5);
+        createService();
+        startSystem();
+
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+        advanceTime(15000);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testScreensaverActivateOnSleepEnabled_powered_afterTimeout_goesToDreaming() {
+        when(mBatteryManagerInternalMock.isPowered(anyInt())).thenReturn(true);
+        Settings.Secure.putInt(mContextSpy.getContentResolver(),
+                Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1);
+
+        doAnswer(inv -> {
+            when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
+            return null;
+        }).when(mDreamManagerInternalMock).startDream(anyBoolean());
+
+        setMinimumScreenOffTimeoutConfig(5);
+        createService();
+        startSystem();
+
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+        advanceTime(15000);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
+    }
+
     @Test
     public void testSetDozeOverrideFromDreamManager_triggersSuspendBlocker() {
         final String suspendBlockerName = "PowerManagerService.Display";
@@ -1042,6 +1086,23 @@
         assertThat(mService.getGlobalWakefulnessLocked()).isNotEqualTo(WAKEFULNESS_ASLEEP);
     }
 
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testInattentiveSleep_goesToSleepFromDream() {
+        setAttentiveTimeout(20000);
+        createService();
+        startSystem();
+        setPluggedIn(true);
+        forceAwake();
+        forceDream();
+        when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
+
+        advanceTime(20500);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+    }
+
     @Test
     public void testWakeLock_affectsProperDisplayGroup() {
         final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
@@ -1136,6 +1197,11 @@
         info.displayGroupId = nonDefaultDisplayGroupId;
         when(mDisplayManagerInternalMock.getDisplayInfo(nonDefaultDisplay)).thenReturn(info);
 
+        doAnswer(inv -> {
+            when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
+            return null;
+        }).when(mDreamManagerInternalMock).startDream(anyBoolean());
+
         final String pkg = mContextSpy.getOpPackageName();
         final Binder token = new Binder();
         final String tag = "testRemovedDisplayGroupWakeLock_affectsNoDisplayGroups";
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
index 0eba6a3..0187e34 100644
--- a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
@@ -224,6 +224,11 @@
         // Stop the recognition.
         stopRecognition(module, handle, hwHandle);
 
+        ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
+                RecognitionEvent.class);
+        verify(callback).onRecognition(eq(handle), eventCaptor.capture(), eq(101));
+        assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().status);
+
         // Unload the model.
         unloadModel(module, handle, hwHandle);
         module.detach();
@@ -268,6 +273,11 @@
         // Stop the recognition.
         stopRecognition(module, handle, hwHandle);
 
+        ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
+                PhraseRecognitionEvent.class);
+        verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture(), eq(101));
+        assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().common.status);
+
         // Unload the model.
         unloadModel(module, handle, hwHandle);
         module.detach();
diff --git a/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
index 1442f1c..83139b0 100644
--- a/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
@@ -23,9 +23,11 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyLong;
 import static org.mockito.Mockito.anyString;
 import static org.mockito.Mockito.argThat;
 import static org.mockito.Mockito.eq;
@@ -37,6 +39,7 @@
 import android.Manifest;
 import android.app.ActivityManagerInternal;
 import android.app.StatusBarManager;
+import android.compat.testing.PlatformCompatChangeRule;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.om.IOverlayManager;
@@ -62,10 +65,13 @@
 import com.android.server.policy.GlobalActionsProvider;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
+import libcore.junit.util.compat.CoreCompatChangeRule;
+
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 import org.mockito.ArgumentCaptor;
@@ -73,6 +79,7 @@
 import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
 
 @RunWith(JUnit4.class)
 public class StatusBarManagerServiceTest {
@@ -88,6 +95,9 @@
     public final TestableContext mContext =
             new NoBroadcastContextWrapper(InstrumentationRegistry.getContext());
 
+    @Rule
+    public TestRule mCompatChangeRule = new PlatformCompatChangeRule();
+
     @Mock
     private ActivityTaskManagerInternal mActivityTaskManagerInternal;
     @Mock
@@ -127,6 +137,7 @@
 
         when(mMockStatusBar.asBinder()).thenReturn(mMockStatusBar);
         when(mApplicationInfo.loadLabel(any())).thenReturn(APP_NAME);
+        mockHandleIncomingUser();
 
         mStatusBarManagerService = new StatusBarManagerService(mContext);
         LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
@@ -142,6 +153,80 @@
     }
 
     @Test
+    @CoreCompatChangeRule.EnableCompatChanges(
+            {StatusBarManagerService.REQUEST_LISTENING_MUST_MATCH_PACKAGE})
+    public void testRequestActive_changeEnabled_OKCall() throws RemoteException {
+        int user = 0;
+        mockEverything(user);
+        mStatusBarManagerService.requestTileServiceListeningState(TEST_COMPONENT, user);
+
+        verify(mMockStatusBar).requestTileServiceListeningState(TEST_COMPONENT);
+    }
+
+    @Test
+    @CoreCompatChangeRule.EnableCompatChanges(
+            {StatusBarManagerService.REQUEST_LISTENING_MUST_MATCH_PACKAGE})
+    public void testRequestActive_changeEnabled_differentPackage_fail() throws RemoteException {
+        when(mPackageManagerInternal.getPackageUid(TEST_PACKAGE, 0L, mContext.getUserId()))
+                .thenReturn(Binder.getCallingUid() + 1);
+        try {
+            mStatusBarManagerService.requestTileServiceListeningState(TEST_COMPONENT, 0);
+            fail("Should cause security exception");
+        } catch (SecurityException e) { }
+        verify(mMockStatusBar, never()).requestTileServiceListeningState(TEST_COMPONENT);
+    }
+
+    @Test
+    @CoreCompatChangeRule.EnableCompatChanges(
+            {StatusBarManagerService.REQUEST_LISTENING_MUST_MATCH_PACKAGE})
+    public void testRequestActive_changeEnabled_notCurrentUser_fail() throws RemoteException {
+        mockUidCheck();
+        int user = 0;
+        mockCurrentUserCheck(user);
+        try {
+            mStatusBarManagerService.requestTileServiceListeningState(TEST_COMPONENT, user + 1);
+            fail("Should cause illegal argument exception");
+        } catch (IllegalArgumentException e) { }
+
+        // Do not call into SystemUI
+        verify(mMockStatusBar, never()).requestTileServiceListeningState(TEST_COMPONENT);
+    }
+
+    @Test
+    @CoreCompatChangeRule.DisableCompatChanges(
+            {StatusBarManagerService.REQUEST_LISTENING_MUST_MATCH_PACKAGE})
+    public void testRequestActive_changeDisabled_pass() throws RemoteException {
+        int user = 0;
+        mockEverything(user);
+        mStatusBarManagerService.requestTileServiceListeningState(TEST_COMPONENT, user);
+
+        verify(mMockStatusBar).requestTileServiceListeningState(TEST_COMPONENT);
+    }
+
+    @Test
+    @CoreCompatChangeRule.DisableCompatChanges(
+            {StatusBarManagerService.REQUEST_LISTENING_MUST_MATCH_PACKAGE})
+    public void testRequestActive_changeDisabled_differentPackage_pass() throws RemoteException {
+        when(mPackageManagerInternal.getPackageUid(TEST_PACKAGE, 0L, mContext.getUserId()))
+                .thenReturn(Binder.getCallingUid() + 1);
+        mStatusBarManagerService.requestTileServiceListeningState(TEST_COMPONENT, 0);
+
+        verify(mMockStatusBar).requestTileServiceListeningState(TEST_COMPONENT);
+    }
+
+    @Test
+    @CoreCompatChangeRule.DisableCompatChanges(
+            {StatusBarManagerService.REQUEST_LISTENING_MUST_MATCH_PACKAGE})
+    public void testRequestActive_changeDisabled_notCurrentUser_pass() throws RemoteException {
+        mockUidCheck();
+        int user = 0;
+        mockCurrentUserCheck(user);
+        mStatusBarManagerService.requestTileServiceListeningState(TEST_COMPONENT, user + 1);
+
+        verify(mMockStatusBar).requestTileServiceListeningState(TEST_COMPONENT);
+    }
+
+    @Test
     public void testHandleIncomingUserCalled() {
         int fakeUser = 17;
         try {
@@ -252,7 +337,7 @@
         mockCurrentUserCheck(user);
         IntentMatcher im = new IntentMatcher(
                 new Intent(TileService.ACTION_QS_TILE).setComponent(TEST_COMPONENT));
-        when(mPackageManagerInternal.resolveService(argThat(im), nullable(String.class), eq(0),
+        when(mPackageManagerInternal.resolveService(argThat(im), nullable(String.class), eq(0L),
                 eq(user), anyInt())).thenReturn(null);
 
         Callback callback = new Callback();
@@ -272,7 +357,7 @@
 
         IntentMatcher im = new IntentMatcher(
                 new Intent(TileService.ACTION_QS_TILE).setComponent(TEST_COMPONENT));
-        when(mPackageManagerInternal.resolveService(argThat(im), nullable(String.class), eq(0),
+        when(mPackageManagerInternal.resolveService(argThat(im), nullable(String.class), eq(0L),
                 eq(user), anyInt())).thenReturn(r);
         when(mPackageManagerInternal.getComponentEnabledSetting(TEST_COMPONENT,
                 Binder.getCallingUid(), user)).thenReturn(
@@ -294,7 +379,7 @@
 
         IntentMatcher im = new IntentMatcher(
                 new Intent(TileService.ACTION_QS_TILE).setComponent(TEST_COMPONENT));
-        when(mPackageManagerInternal.resolveService(argThat(im), nullable(String.class), eq(0),
+        when(mPackageManagerInternal.resolveService(argThat(im), nullable(String.class), eq(0L),
                 eq(user), anyInt())).thenReturn(r);
         when(mPackageManagerInternal.getComponentEnabledSetting(TEST_COMPONENT,
                 Binder.getCallingUid(), user)).thenReturn(
@@ -318,7 +403,7 @@
 
         IntentMatcher im = new IntentMatcher(
                 new Intent(TileService.ACTION_QS_TILE).setComponent(TEST_COMPONENT));
-        when(mPackageManagerInternal.resolveService(argThat(im), nullable(String.class), eq(0),
+        when(mPackageManagerInternal.resolveService(argThat(im), nullable(String.class), eq(0L),
                 eq(user), anyInt())).thenReturn(r);
         when(mPackageManagerInternal.getComponentEnabledSetting(TEST_COMPONENT,
                 Binder.getCallingUid(), user)).thenReturn(
@@ -342,7 +427,7 @@
 
         IntentMatcher im = new IntentMatcher(
                 new Intent(TileService.ACTION_QS_TILE).setComponent(TEST_COMPONENT));
-        when(mPackageManagerInternal.resolveService(argThat(im), nullable(String.class), eq(0),
+        when(mPackageManagerInternal.resolveService(argThat(im), nullable(String.class), eq(0L),
                 eq(user), anyInt())).thenReturn(r);
         when(mPackageManagerInternal.getComponentEnabledSetting(TEST_COMPONENT,
                 Binder.getCallingUid(), user)).thenReturn(
@@ -607,23 +692,12 @@
     public void testSetNavBarMode_invalidInputThrowsError() throws RemoteException {
         int navBarModeInvalid = -1;
 
-        assertThrows(UnsupportedOperationException.class,
+        assertThrows(IllegalArgumentException.class,
                 () -> mStatusBarManagerService.setNavBarMode(navBarModeInvalid));
         verify(mOverlayManager, never()).setEnabledExclusiveInCategory(anyString(), anyInt());
     }
 
     @Test
-    public void testSetNavBarMode_noOverlayManagerDoesNotEnable() throws RemoteException {
-        mOverlayManager = null;
-        int navBarModeKids = StatusBarManager.NAV_BAR_MODE_KIDS;
-
-        mStatusBarManagerService.setNavBarMode(navBarModeKids);
-
-        assertEquals(navBarModeKids, mStatusBarManagerService.getNavBarMode());
-        verify(mOverlayManager, never()).setEnabledExclusiveInCategory(anyString(), anyInt());
-    }
-
-    @Test
     public void testSetNavBarMode_noPackageDoesNotEnable() throws Exception {
         mContext.setMockPackageManager(mPackageManager);
         when(mPackageManager.getPackageInfo(anyString(),
@@ -641,7 +715,7 @@
     }
 
     private void mockUidCheck(String packageName) {
-        when(mPackageManagerInternal.getPackageUid(eq(packageName), anyInt(), anyInt()))
+        when(mPackageManagerInternal.getPackageUid(eq(packageName), anyLong(), anyInt()))
                 .thenReturn(Binder.getCallingUid());
     }
 
@@ -667,7 +741,7 @@
 
         IntentMatcher im = new IntentMatcher(
                 new Intent(TileService.ACTION_QS_TILE).setComponent(componentName));
-        when(mPackageManagerInternal.resolveService(argThat(im), nullable(String.class), eq(0),
+        when(mPackageManagerInternal.resolveService(argThat(im), nullable(String.class), eq(0L),
                 eq(user), anyInt())).thenReturn(r);
         when(mPackageManagerInternal.getComponentEnabledSetting(componentName,
                 Binder.getCallingUid(), user)).thenReturn(
@@ -679,6 +753,15 @@
                 PROCESS_STATE_TOP);
     }
 
+    private void mockHandleIncomingUser() {
+        when(mActivityManagerInternal.handleIncomingUser(anyInt(), anyInt(), anyInt(), anyBoolean(),
+                anyInt(), anyString(), anyString())).thenAnswer(
+                    (Answer<Integer>) invocation -> {
+                        return invocation.getArgument(2); // same user
+                    }
+        );
+    }
+
     private void mockEverything(int user) {
         mockUidCheck();
         mockCurrentUserCheck(user);
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 18d3f3d..17464a6 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -62,7 +62,10 @@
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.intThat;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
@@ -76,11 +79,13 @@
 import android.appwidget.AppWidgetManager;
 import android.content.Context;
 import android.content.ContextWrapper;
+import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
+import android.content.pm.ResolveInfo;
 import android.hardware.display.DisplayManager;
 import android.os.Handler;
 import android.os.Looper;
@@ -118,6 +123,7 @@
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 /**
  * Unit test for AppStandbyController.
@@ -421,8 +427,31 @@
         pib.packageName = PACKAGE_BACKGROUND_LOCATION;
         packages.add(pib);
 
-        doReturn(packages).when(mockPm).getInstalledPackagesAsUser(anyInt(), anyInt());
 
+        // Set up getInstalledPackagesAsUser().
+        doReturn(packages).when(mockPm).getInstalledPackagesAsUser(anyInt(),
+                anyInt());
+
+        // Set up getInstalledPackagesAsUser() for "MATCH_ONLY_SYSTEM"
+        doReturn(
+                packages.stream().filter(pinfo -> pinfo.applicationInfo.isSystemApp())
+                .collect(Collectors.toList())
+        ).when(mockPm).getInstalledPackagesAsUser(
+                intThat(i -> (i & PackageManager.MATCH_SYSTEM_ONLY) != 0),
+                anyInt());
+
+        // Set up queryIntentActivitiesAsUser()
+        final ArrayList<ResolveInfo> systemFrontDoorActivities = new ArrayList<>();
+        final ResolveInfo frontDoorActivity = new ResolveInfo();
+        frontDoorActivity.activityInfo = new ActivityInfo();
+        frontDoorActivity.activityInfo.packageName = pis.packageName;
+        systemFrontDoorActivities.add(frontDoorActivity);
+        doReturn(systemFrontDoorActivities).when(mockPm)
+                .queryIntentActivitiesAsUser(any(Intent.class),
+                intThat(i -> (i & PackageManager.MATCH_SYSTEM_ONLY) != 0),
+                anyInt());
+
+        // Set up other APIs.
         try {
             for (int i = 0; i < packages.size(); ++i) {
                 PackageInfo pkg = packages.get(i);
@@ -483,17 +512,41 @@
         return controller;
     }
 
-    private long getCurrentTime() {
-        return TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
+    private void setupInitialUsageHistory() throws Exception {
+        final int[] userIds = new int[] { USER_ID, USER_ID2, USER_ID3 };
+        final String[] packages = new String[] {
+                PACKAGE_1,
+                PACKAGE_2,
+                PACKAGE_EXEMPTED_1,
+                PACKAGE_SYSTEM_HEADFULL,
+                PACKAGE_SYSTEM_HEADLESS,
+                PACKAGE_WELLBEING,
+                PACKAGE_BACKGROUND_LOCATION,
+                ADMIN_PKG,
+                ADMIN_PKG2,
+                ADMIN_PKG3
+        };
+        for (int userId : userIds) {
+            for (String pkg : packages) {
+                final AppIdleHistory.AppUsageHistory usageHistory = mController
+                        .getAppIdleHistoryForTest().getAppUsageHistory(
+                                pkg, userId, mInjector.mElapsedRealtime);
+                usageHistory.lastUsedElapsedTime = 0;
+                usageHistory.lastUsedByUserElapsedTime = 0;
+                usageHistory.lastUsedScreenTime = 0;
+            }
+        }
     }
 
     @Before
     public void setUp() throws Exception {
+        LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
         LocalServices.addService(
                 UsageStatsManagerInternal.class, mock(UsageStatsManagerInternal.class));
         MyContextWrapper myContext = new MyContextWrapper(InstrumentationRegistry.getContext());
         mInjector = new MyInjector(myContext, Looper.getMainLooper());
         mController = setupController();
+        setupInitialUsageHistory();
     }
 
     @After
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java
index 0301e94..b907c62 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java
@@ -277,6 +277,6 @@
         Settings.System.putIntForUser(
                 mContextSpy.getContentResolver(), settingName, value, UserHandle.USER_CURRENT);
         // FakeSettingsProvider don't support testing triggering ContentObserver yet.
-        mVibrationSettings.updateSettings();
+        mVibrationSettings.update();
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
index ec16188..0c28d8c 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
@@ -476,6 +476,24 @@
     }
 
     @Test
+    public void shouldIgnoreVibration_updateTriggeredAfterInternalRingerModeChanged() {
+        // Vibrating settings on are overruled by ringer mode.
+        setUserSetting(Settings.System.HAPTIC_FEEDBACK_ENABLED, 1);
+        setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
+        setUserSetting(Settings.System.APPLY_RAMPING_RINGER, 1);
+        setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+
+        assertVibrationNotIgnoredForUsage(USAGE_RINGTONE);
+
+        // Testing the broadcast flow manually.
+        mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_SILENT);
+        mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy,
+                new Intent(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
+
+        assertVibrationIgnoredForUsage(USAGE_RINGTONE, Vibration.Status.IGNORED_FOR_RINGER_MODE);
+    }
+
+    @Test
     public void shouldVibrateInputDevices_returnsSettingsValue() {
         setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1);
         assertTrue(mVibrationSettings.shouldVibrateInputDevices());
@@ -577,7 +595,7 @@
         Settings.System.putIntForUser(mContextSpy.getContentResolver(),
                 Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW,
                 UserHandle.USER_CURRENT);
-        mVibrationSettings.mUserReceiver.onReceive(mContextSpy,
+        mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy,
                 new Intent(Intent.ACTION_USER_SWITCHED));
         assertEquals(VIBRATION_INTENSITY_LOW,
                 mVibrationSettings.getCurrentIntensity(USAGE_RINGTONE));
@@ -587,7 +605,7 @@
     public void getCurrentIntensity_noHardwareFeedbackValueUsesHapticFeedbackValue() {
         setDefaultIntensity(USAGE_HARDWARE_FEEDBACK, VIBRATION_INTENSITY_MEDIUM);
         setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF);
-        mVibrationSettings.updateSettings();
+        mVibrationSettings.update();
         assertEquals(VIBRATION_INTENSITY_OFF, mVibrationSettings.getCurrentIntensity(USAGE_TOUCH));
         // If haptic feedback is off, fallback to default value.
         assertEquals(VIBRATION_INTENSITY_MEDIUM,
@@ -596,7 +614,7 @@
                 mVibrationSettings.getCurrentIntensity(USAGE_PHYSICAL_EMULATION));
 
         setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_HIGH);
-        mVibrationSettings.updateSettings();
+        mVibrationSettings.update();
         assertEquals(VIBRATION_INTENSITY_HIGH,
                 mVibrationSettings.getCurrentIntensity(USAGE_TOUCH));
         // If haptic feedback is on, fallback to that value.
@@ -633,7 +651,7 @@
                 mVibrationSettings.shouldIgnoreVibration(UID,
                         new VibrationAttributes.Builder()
                                 .setUsage(usage)
-                                .setFlags(flags, VibrationAttributes.FLAG_ALL_SUPPORTED)
+                                .setFlags(flags)
                                 .build()));
     }
 
@@ -654,18 +672,19 @@
         Settings.System.putStringForUser(
                 mContextSpy.getContentResolver(), settingName, null, UserHandle.USER_CURRENT);
         // FakeSettingsProvider doesn't support testing triggering ContentObserver yet.
-        mVibrationSettings.updateSettings();
+        mVibrationSettings.update();
     }
 
     private void setUserSetting(String settingName, int value) {
         Settings.System.putIntForUser(
                 mContextSpy.getContentResolver(), settingName, value, UserHandle.USER_CURRENT);
         // FakeSettingsProvider doesn't support testing triggering ContentObserver yet.
-        mVibrationSettings.updateSettings();
+        mVibrationSettings.update();
     }
 
     private void setRingerMode(int ringerMode) {
         mAudioManager.setRingerModeInternal(ringerMode);
         assertEquals(ringerMode, mAudioManager.getRingerModeInternal());
+        mVibrationSettings.update();
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
index 704729e..9f13591 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -257,13 +257,13 @@
         assertTrue(mThread.isRunningVibrationId(vibrationId));
         assertTrue(mControllers.get(VIBRATOR_ID).isVibrating());
 
-        conductor.notifyCancelled(/* immediate= */ false);
+        conductor.notifyCancelled(Vibration.Status.CANCELLED_SUPERSEDED, /* immediate= */ false);
         waitForCompletion();
         assertFalse(mThread.isRunningVibrationId(vibrationId));
 
         verify(mManagerHooks).noteVibratorOn(eq(UID), anyLong());
         verify(mManagerHooks).noteVibratorOff(eq(UID));
-        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
+        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_SUPERSEDED);
         assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
 
         List<Float> playedAmplitudes = fakeVibrator.getAmplitudes();
@@ -288,10 +288,10 @@
         VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, effect);
 
         assertTrue(waitUntil(() -> !fakeVibrator.getAmplitudes().isEmpty(), TEST_TIMEOUT_MILLIS));
-        conductor.notifyCancelled(/* immediate= */ false);
+        conductor.notifyCancelled(Vibration.Status.CANCELLED_BY_USER, /* immediate= */ false);
         waitForCompletion();
 
-        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
+        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_USER);
         assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
         assertEquals(Arrays.asList(expectedOneShot(1000)),
                 fakeVibrator.getEffectSegments(vibrationId));
@@ -310,10 +310,10 @@
         VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, effect);
 
         assertTrue(waitUntil(() -> !fakeVibrator.getAmplitudes().isEmpty(), TEST_TIMEOUT_MILLIS));
-        conductor.notifyCancelled(/* immediate= */ false);
+        conductor.notifyCancelled(Vibration.Status.CANCELLED_BY_USER, /* immediate= */ false);
         waitForCompletion();
 
-        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
+        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_USER);
         assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
         assertEquals(Arrays.asList(expectedOneShot(5550)),
                 fakeVibrator.getEffectSegments(vibrationId));
@@ -334,10 +334,10 @@
 
         assertTrue(waitUntil(() -> fakeVibrator.getAmplitudes().size() > 2 * amplitudes.length,
                 1000 + TEST_TIMEOUT_MILLIS));
-        conductor.notifyCancelled(/* immediate= */ false);
+        conductor.notifyCancelled(Vibration.Status.CANCELLED_BY_USER, /* immediate= */ false);
         waitForCompletion();
 
-        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
+        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_USER);
         assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
         assertEquals(2, fakeVibrator.getEffectSegments(vibrationId).size());
         // First time turn vibrator ON for minimum of 1s.
@@ -371,13 +371,14 @@
         // Run cancel in a separate thread so if VibrationThread.cancel blocks then this test should
         // fail at waitForCompletion(vibrationThread) if the vibration not cancelled immediately.
         Thread cancellingThread =
-                new Thread(() -> conductor.notifyCancelled(/* immediate= */ false));
+                new Thread(() -> conductor.notifyCancelled(
+                        Vibration.Status.CANCELLED_BY_SETTINGS_UPDATE, /* immediate= */ false));
         cancellingThread.start();
 
         waitForCompletion(/* timeout= */ 50);
         cancellingThread.join();
 
-        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
+        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_SETTINGS_UPDATE);
         assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
     }
 
@@ -397,13 +398,14 @@
         // Run cancel in a separate thread so if VibrationThread.cancel blocks then this test should
         // fail at waitForCompletion(vibrationThread) if the vibration not cancelled immediately.
         Thread cancellingThread =
-                new Thread(() -> conductor.notifyCancelled(/* immediate= */ false));
+                new Thread(() -> conductor.notifyCancelled(
+                        Vibration.Status.CANCELLED_BY_SCREEN_OFF, /* immediate= */ false));
         cancellingThread.start();
 
         waitForCompletion(/* timeout= */ 50);
         cancellingThread.join();
 
-        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
+        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_SCREEN_OFF);
         assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
     }
 
@@ -647,7 +649,7 @@
         waitForCompletion();
         assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
 
-        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
+        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BINDER_DIED);
     }
 
     @Test
@@ -1043,7 +1045,8 @@
         // Run cancel in a separate thread so if VibrationThread.cancel blocks then this test should
         // fail at waitForCompletion(cancellingThread).
         Thread cancellingThread = new Thread(
-                () -> conductor.notifyCancelled(/* immediate= */ false));
+                () -> conductor.notifyCancelled(
+                        Vibration.Status.CANCELLED_BY_USER, /* immediate= */ false));
         cancellingThread.start();
 
         // Cancelling the vibration should be fast and return right away, even if the thread is
@@ -1052,7 +1055,7 @@
 
         // After the vibrator call ends the vibration is cancelled and the vibrator is turned off.
         waitForCompletion(/* timeout= */ latency + TEST_TIMEOUT_MILLIS);
-        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
+        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_USER);
         assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
     }
 
@@ -1080,13 +1083,14 @@
         // Run cancel in a separate thread so if VibrationThread.cancel blocks then this test should
         // fail at waitForCompletion(vibrationThread) if the vibration not cancelled immediately.
         Thread cancellingThread = new Thread(
-                () -> conductor.notifyCancelled(/* immediate= */ false));
+                () -> conductor.notifyCancelled(
+                        Vibration.Status.CANCELLED_SUPERSEDED, /* immediate= */ false));
         cancellingThread.start();
 
         waitForCompletion(/* timeout= */ 50);
         cancellingThread.join();
 
-        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
+        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_SUPERSEDED);
         assertFalse(mControllers.get(1).isVibrating());
         assertFalse(mControllers.get(2).isVibrating());
     }
@@ -1113,13 +1117,14 @@
         // Run cancel in a separate thread so if VibrationThread.cancel blocks then this test should
         // fail at waitForCompletion(vibrationThread) if the vibration not cancelled immediately.
         Thread cancellingThread =
-                new Thread(() -> conductor.notifyCancelled(/* immediate= */ false));
+                new Thread(() -> conductor.notifyCancelled(
+                        Vibration.Status.CANCELLED_BY_SCREEN_OFF, /* immediate= */ false));
         cancellingThread.start();
 
         waitForCompletion(/* timeout= */ 50);
         cancellingThread.join();
 
-        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
+        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_SCREEN_OFF);
         assertFalse(mControllers.get(1).isVibrating());
         assertFalse(mControllers.get(2).isVibrating());
     }
@@ -1139,7 +1144,7 @@
 
         verify(mVibrationToken).linkToDeath(same(conductor), eq(0));
         verify(mVibrationToken).unlinkToDeath(same(conductor), eq(0));
-        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
+        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BINDER_DIED);
         assertFalse(mVibratorProviders.get(VIBRATOR_ID).getEffectSegments(vibrationId).isEmpty());
         assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
     }
@@ -1193,12 +1198,13 @@
                 mVibratorProviders.get(VIBRATOR_ID).getEffectSegments(vibrationId));
 
         // Will stop the ramp down right away.
-        conductor.notifyCancelled(/* immediate= */ true);
+        conductor.notifyCancelled(
+                Vibration.Status.CANCELLED_BY_SETTINGS_UPDATE, /* immediate= */ true);
         waitForCompletion();
 
         // Does not cancel already finished vibration, but releases vibrator.
         verify(mManagerHooks, never()).onVibrationCompleted(eq(vibrationId),
-                eq(Vibration.Status.CANCELLED));
+                eq(Vibration.Status.CANCELLED_BY_SETTINGS_UPDATE));
         verify(mManagerHooks).onVibrationThreadReleased(vibrationId);
     }
 
@@ -1214,10 +1220,10 @@
         VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, effect);
         assertTrue(waitUntil(() -> mControllers.get(VIBRATOR_ID).isVibrating(),
                 TEST_TIMEOUT_MILLIS));
-        conductor.notifyCancelled(/* immediate= */ false);
+        conductor.notifyCancelled(Vibration.Status.CANCELLED_BY_USER, /* immediate= */ false);
         waitForCompletion();
 
-        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED);
+        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_USER);
 
         // Duration extended for 10000 + 15.
         assertEquals(Arrays.asList(expectedOneShot(10_015)),
@@ -1337,7 +1343,7 @@
         VibrationStepConductor conductor2 = startThreadAndDispatcher(vibrationId2, effect2);
         // Effect2 won't complete on its own. Cancel it after a couple of repeats.
         Thread.sleep(150);  // More than two TICKs.
-        conductor2.notifyCancelled(/* immediate= */ false);
+        conductor2.notifyCancelled(Vibration.Status.CANCELLED_BY_USER, /* immediate= */ false);
         waitForCompletion();
 
         startThreadAndDispatcher(vibrationId3, effect3);
@@ -1346,7 +1352,7 @@
         // Effect4 is a long oneshot, but it gets cancelled as fast as possible.
         long start4 = System.currentTimeMillis();
         VibrationStepConductor conductor4 = startThreadAndDispatcher(vibrationId4, effect4);
-        conductor4.notifyCancelled(/* immediate= */ true);
+        conductor4.notifyCancelled(Vibration.Status.CANCELLED_SUPERSEDED, /* immediate= */ true);
         waitForCompletion();
         long duration4 = System.currentTimeMillis() - start4;
 
@@ -1366,7 +1372,7 @@
 
         // Effect2: repeating, cancelled.
         verify(mControllerCallbacks, atLeast(2)).onComplete(VIBRATOR_ID, vibrationId2);
-        verifyCallbacksTriggered(vibrationId2, Vibration.Status.CANCELLED);
+        verifyCallbacksTriggered(vibrationId2, Vibration.Status.CANCELLED_BY_USER);
 
         // The exact count of segments might vary, so just check that there's more than 2 and
         // all elements are the same segment.
@@ -1384,7 +1390,7 @@
                 fakeVibrator.getEffectSegments(vibrationId3));
 
         // Effect4: cancelled quickly.
-        verifyCallbacksTriggered(vibrationId4, Vibration.Status.CANCELLED);
+        verifyCallbacksTriggered(vibrationId4, Vibration.Status.CANCELLED_SUPERSEDED);
         assertTrue("Tested duration=" + duration4, duration4 < 2000);
 
         // Effect5: normal oneshot. Don't worry about amplitude, as effect4 may or may not have
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index 92736c5..9c72ce2 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -673,6 +673,42 @@
     }
 
     @Test
+    public void vibrate_withVibrationAttributesEnforceFreshSettings_refreshesVibrationSettings()
+            throws Exception {
+        mockVibrators(0);
+        mVibratorProviders.get(0).setSupportedEffects(VibrationEffect.EFFECT_CLICK,
+                VibrationEffect.EFFECT_TICK);
+        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_HIGH);
+        VibratorManagerService service = createSystemReadyService();
+
+        VibrationAttributes enforceFreshAttrs = new VibrationAttributes.Builder()
+                .setUsage(VibrationAttributes.USAGE_NOTIFICATION)
+                .setFlags(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)
+                .build();
+
+        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_LOW);
+        vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), NOTIFICATION_ATTRS);
+        // VibrationThread will start this vibration async, so wait before vibrating a second time.
+        assertTrue(waitUntil(s -> mVibratorProviders.get(0).getAllEffectSegments().size() > 0,
+                service, TEST_TIMEOUT_MILLIS));
+
+        vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_TICK), enforceFreshAttrs);
+        // VibrationThread will start this vibration async, so wait before checking.
+        assertTrue(waitUntil(s -> mVibratorProviders.get(0).getAllEffectSegments().size() > 1,
+                service, TEST_TIMEOUT_MILLIS));
+
+        assertEquals(
+                Arrays.asList(
+                        expectedPrebaked(VibrationEffect.EFFECT_CLICK,
+                                VibrationEffect.EFFECT_STRENGTH_STRONG),
+                        expectedPrebaked(VibrationEffect.EFFECT_TICK,
+                                VibrationEffect.EFFECT_STRENGTH_LIGHT)),
+                mVibratorProviders.get(0).getAllEffectSegments());
+    }
+
+    @Test
     public void vibrate_withAttributesUnknownUsage_usesEffectToIdentifyTouchUsage() {
         VibratorManagerService service = createSystemReadyService();
 
@@ -1280,7 +1316,11 @@
     }
 
     private VibrationEffectSegment expectedPrebaked(int effectId) {
-        return new PrebakedSegment(effectId, false, VibrationEffect.EFFECT_STRENGTH_MEDIUM);
+        return expectedPrebaked(effectId, VibrationEffect.EFFECT_STRENGTH_MEDIUM);
+    }
+
+    private VibrationEffectSegment expectedPrebaked(int effectId, int effectStrength) {
+        return new PrebakedSegment(effectId, false, effectStrength);
     }
 
     private void mockCapabilities(long... capabilities) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
index 5458a5b..ff6c976 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
@@ -20,6 +20,7 @@
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertNotNull;
 
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
@@ -53,7 +54,7 @@
 public class GroupHelperTest extends UiServiceTestCase {
     private @Mock GroupHelper.Callback mCallback;
 
-    private final static int AUTOGROUP_AT_COUNT = 4;
+    private final static int AUTOGROUP_AT_COUNT = 7;
     private GroupHelper mGroupHelper;
 
     @Before
@@ -88,7 +89,7 @@
                     false);
         }
         verify(mCallback, never()).addAutoGroupSummary(
-                eq(UserHandle.USER_SYSTEM), eq(pkg), anyString());
+                eq(UserHandle.USER_SYSTEM), eq(pkg), anyString(), anyBoolean());
         verify(mCallback, never()).addAutoGroup(anyString());
         verify(mCallback, never()).removeAutoGroup(anyString());
         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
@@ -105,7 +106,7 @@
         mGroupHelper.onNotificationPosted(
                 getSbn(pkg2, AUTOGROUP_AT_COUNT, "four", UserHandle.SYSTEM), false);
         verify(mCallback, never()).addAutoGroupSummary(
-                eq(UserHandle.USER_SYSTEM), eq(pkg), anyString());
+                eq(UserHandle.USER_SYSTEM), eq(pkg), anyString(), anyBoolean());
         verify(mCallback, never()).addAutoGroup(anyString());
         verify(mCallback, never()).removeAutoGroup(anyString());
         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
@@ -120,7 +121,8 @@
         }
         mGroupHelper.onNotificationPosted(
                 getSbn(pkg, AUTOGROUP_AT_COUNT, "four", UserHandle.ALL), false);
-        verify(mCallback, never()).addAutoGroupSummary(anyInt(), eq(pkg), anyString());
+        verify(mCallback, never()).addAutoGroupSummary(
+                anyInt(), eq(pkg), anyString(), anyBoolean());
         verify(mCallback, never()).addAutoGroup(anyString());
         verify(mCallback, never()).removeAutoGroup(anyString());
         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
@@ -136,13 +138,12 @@
         mGroupHelper.onNotificationPosted(
                 getSbn(pkg, AUTOGROUP_AT_COUNT, "four", UserHandle.SYSTEM, "a"), false);
         verify(mCallback, never()).addAutoGroupSummary(
-                eq(UserHandle.USER_SYSTEM), eq(pkg), anyString());
+                eq(UserHandle.USER_SYSTEM), eq(pkg), anyString(), anyBoolean());
         verify(mCallback, never()).addAutoGroup(anyString());
         verify(mCallback, never()).removeAutoGroup(anyString());
         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
     }
 
-
     @Test
     public void testPostingOverLimit() throws Exception {
         final String pkg = "package";
@@ -150,7 +151,23 @@
             mGroupHelper.onNotificationPosted(
                     getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM), false);
         }
-        verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString());
+        verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(false));
+        verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
+        verify(mCallback, never()).removeAutoGroup(anyString());
+        verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
+    }
+
+    @Test
+    public void testPostingOverLimit_addsOngoingFlag() throws Exception {
+        final String pkg = "package";
+        for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
+            StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM);
+            if (i == 0) {
+                sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
+            }
+            mGroupHelper.onNotificationPosted(sbn, false);
+        }
+        verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(true));
         verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
         verify(mCallback, never()).removeAutoGroup(anyString());
         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
@@ -178,7 +195,7 @@
 
         int userId = UserHandle.SYSTEM.getIdentifier();
         assertEquals(mGroupHelper.getOngoingGroupCount(
-                userId, pkg, AUTOGROUP_KEY), AUTOGROUP_AT_COUNT + 1);
+                userId, pkg), AUTOGROUP_AT_COUNT + 1);
     }
 
     @Test
@@ -199,15 +216,14 @@
         }
 
         notifications.get(0).getNotification().flags &= ~Notification.FLAG_ONGOING_EVENT;
-
-        mGroupHelper.onNotificationUpdated(notifications.get(0), true);
+        mGroupHelper.onNotificationUpdated(notifications.get(0));
 
         verify(mCallback, times(AUTOGROUP_AT_COUNT + 2))
                 .updateAutogroupSummary(anyInt(), anyString(), eq(true));
 
         int userId = UserHandle.SYSTEM.getIdentifier();
         assertEquals(mGroupHelper.getOngoingGroupCount(
-                userId, pkg, AUTOGROUP_KEY), AUTOGROUP_AT_COUNT);
+                userId, pkg), AUTOGROUP_AT_COUNT);
     }
 
     @Test
@@ -229,18 +245,18 @@
 
         notifications.get(0).getNotification().flags &= ~Notification.FLAG_ONGOING_EVENT;
 
-        mGroupHelper.onNotificationUpdated(notifications.get(0), true);
+        mGroupHelper.onNotificationUpdated(notifications.get(0));
 
         notifications.get(0).getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
 
-        mGroupHelper.onNotificationUpdated(notifications.get(0), true);
+        mGroupHelper.onNotificationUpdated(notifications.get(0));
 
         verify(mCallback, times(AUTOGROUP_AT_COUNT + 3))
                 .updateAutogroupSummary(anyInt(), anyString(), eq(true));
 
         int userId = UserHandle.SYSTEM.getIdentifier();
         assertEquals(mGroupHelper.getOngoingGroupCount(
-                userId, pkg, AUTOGROUP_KEY), AUTOGROUP_AT_COUNT + 1);
+                userId, pkg), AUTOGROUP_AT_COUNT + 1);
     }
 
     @Test
@@ -267,7 +283,7 @@
 
         int userId = UserHandle.SYSTEM.getIdentifier();
         assertEquals(mGroupHelper.getOngoingGroupCount(
-                userId, pkg, AUTOGROUP_KEY), AUTOGROUP_AT_COUNT);
+                userId, pkg), AUTOGROUP_AT_COUNT);
     }
 
 
@@ -288,14 +304,14 @@
         }
 
         notifications.get(0).getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
-        mGroupHelper.onNotificationUpdated(notifications.get(0), true);
+        mGroupHelper.onNotificationUpdated(notifications.get(0));
 
         verify(mCallback, times(1))
                 .updateAutogroupSummary(anyInt(), anyString(), eq(true));
 
         int userId = UserHandle.SYSTEM.getIdentifier();
         assertEquals(mGroupHelper.getOngoingGroupCount(
-                userId, pkg, AUTOGROUP_KEY), 1);
+                userId, pkg), 1);
     }
 
     @Test
@@ -305,7 +321,7 @@
         for (int i = 0; i < AUTOGROUP_AT_COUNT + 1; i++) {
             notifications.add(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM));
         }
-        StatusBarNotification sbn = notifications.get(0);
+        StatusBarNotification sbn = notifications.get(AUTOGROUP_AT_COUNT);
         sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
         sbn.setOverrideGroupKey(AUTOGROUP_KEY);
 
@@ -319,7 +335,7 @@
 
         int userId = UserHandle.SYSTEM.getIdentifier();
         assertEquals(mGroupHelper.getOngoingGroupCount(
-                userId, pkg, AUTOGROUP_KEY), 1);
+                userId, pkg), 1);
     }
 
     @Test
@@ -342,7 +358,7 @@
                 .updateAutogroupSummary(anyInt(), anyString(), eq(true));
 
         int userId = UserHandle.SYSTEM.getIdentifier();
-        assertEquals(mGroupHelper.getOngoingGroupCount(userId, pkg, AUTOGROUP_KEY), 0);
+        assertEquals(mGroupHelper.getOngoingGroupCount(userId, pkg), 0);
     }
 
 
@@ -355,7 +371,7 @@
             posted.add(sbn);
             mGroupHelper.onNotificationPosted(sbn, false);
         }
-        verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString());
+        verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(false));
         verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
         verify(mCallback, never()).removeAutoGroup(anyString());
         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
@@ -382,28 +398,22 @@
             posted.add(sbn);
             mGroupHelper.onNotificationPosted(sbn, false);
         }
-        verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString());
+        verify(mCallback, times(1)).addAutoGroupSummary(
+                anyInt(), eq(pkg), anyString(), anyBoolean());
         verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
         verify(mCallback, never()).removeAutoGroup(anyString());
         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
         Mockito.reset(mCallback);
 
-        int i = 0;
-        for (i = 0; i < AUTOGROUP_AT_COUNT - 2; i++) {
+        for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
             final StatusBarNotification sbn =
                     getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM, "app group");
             mGroupHelper.onNotificationPosted(sbn, false);
+            verify(mCallback, times(1)).removeAutoGroup(sbn.getKey());
+            if (i < AUTOGROUP_AT_COUNT -1) {
+                verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
+            }
         }
-        verify(mCallback, times(AUTOGROUP_AT_COUNT - 2)).removeAutoGroup(anyString());
-        verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
-        Mockito.reset(mCallback);
-
-        for (; i < AUTOGROUP_AT_COUNT; i++) {
-            final StatusBarNotification sbn =
-                    getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM, "app group");
-            mGroupHelper.onNotificationPosted(sbn, false);
-        }
-        verify(mCallback, times(2)).removeAutoGroup(anyString());
         verify(mCallback, times(1)).removeAutoGroupSummary(anyInt(), anyString());
     }
 
@@ -417,7 +427,7 @@
             posted.add(sbn);
             mGroupHelper.onNotificationPosted(sbn, false);
         }
-        verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString());
+        verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(false));
         verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
         verify(mCallback, never()).removeAutoGroup(anyString());
         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
@@ -441,7 +451,7 @@
         final StatusBarNotification sbn = getSbn(pkg, 5, String.valueOf(5), UserHandle.SYSTEM);
         posted.add(sbn);
         mGroupHelper.onNotificationPosted(sbn, true);
-        verify(mCallback, times(posted.size())).addAutoGroup(anyString());
+        verify(mCallback, times(1)).addAutoGroup(sbn.getKey());
         verify(mCallback, never()).removeAutoGroup(anyString());
         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
     }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
index d4420bd..f4b9e25 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
@@ -27,8 +27,13 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.INotificationManager;
@@ -38,8 +43,10 @@
 import android.content.pm.ServiceInfo;
 import android.content.pm.VersionedPackage;
 import android.os.Bundle;
+import android.os.UserHandle;
 import android.service.notification.NotificationListenerFilter;
 import android.service.notification.NotificationListenerService;
+import android.testing.TestableContext;
 import android.util.ArraySet;
 import android.util.Pair;
 import android.util.TypedXmlPullParser;
@@ -69,6 +76,7 @@
     NotificationManagerService mNm;
     @Mock
     private INotificationManager mINm;
+    private TestableContext mContext = spy(getContext());
 
     NotificationManagerService.NotificationListeners mListeners;
 
@@ -80,6 +88,7 @@
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         getContext().setMockPackageManager(mPm);
+        doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any());
 
         mListeners = spy(mNm.new NotificationListeners(
                 mContext, new Object(), mock(ManagedServices.UserProfiles.class), miPm));
@@ -370,4 +379,13 @@
         assertFalse(mListeners.hasAllowedListener(mCn2.getPackageName(), uid1));
         assertFalse(mListeners.hasAllowedListener(mCn2.getPackageName(), uid2));
     }
+
+    @Test
+    public void testBroadcastUsers() {
+        int userId = 0;
+        mListeners.setPackageOrComponentEnabled(mCn1.flattenToString(), userId, true, false, true);
+
+        verify(mContext).sendBroadcastAsUser(
+                any(), eq(UserHandle.of(userId)), nullable(String.class));
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
index 2ba587d..0f6d5a5 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
@@ -722,7 +722,7 @@
         when(mPermissionHelper.isPermissionFixed(PKG, temp.getUserId())).thenReturn(true);
 
         NotificationRecord r = mService.createAutoGroupSummary(
-                temp.getUserId(), temp.getSbn().getPackageName(), temp.getKey());
+                temp.getUserId(), temp.getSbn().getPackageName(), temp.getKey(), false);
 
         assertThat(r.isImportanceFixed()).isTrue();
     }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
index 50151bf..46b47f4 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
@@ -88,7 +88,7 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mPermissionHelper = new PermissionHelper(mPmi, mPackageManager, mPermManager, true);
+        mPermissionHelper = new PermissionHelper(mPmi, mPackageManager, mPermManager, true, false);
         PackageInfo testPkgInfo = new PackageInfo();
         testPkgInfo.requestedPermissions = new String[]{ Manifest.permission.POST_NOTIFICATIONS };
         when(mPackageManager.getPackageInfo(anyString(), anyLong(), anyInt()))
@@ -100,7 +100,7 @@
     public void testMethodsThrowIfMigrationDisabled() throws IllegalAccessException,
             InvocationTargetException {
         PermissionHelper permHelper =
-                new PermissionHelper(mPmi, mPackageManager, mPermManager, false);
+                new PermissionHelper(mPmi, mPackageManager, mPermManager, false, false);
 
         Method[] allMethods = PermissionHelper.class.getDeclaredMethods();
         for (Method method : allMethods) {
@@ -302,6 +302,26 @@
     }
 
     @Test
+    public void testSetNotificationPermission_pkgPerm_grantedByDefaultPermSet_allUserSet()
+            throws Exception {
+        mPermissionHelper = new PermissionHelper(mPmi, mPackageManager, mPermManager, true, true);
+        when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+                .thenReturn(PERMISSION_DENIED);
+        when(mPermManager.getPermissionFlags(anyString(),
+                eq(Manifest.permission.POST_NOTIFICATIONS),
+                anyInt())).thenReturn(FLAG_PERMISSION_GRANTED_BY_DEFAULT);
+        PermissionHelper.PackagePermission pkgPerm = new PermissionHelper.PackagePermission(
+                "pkg", 10, true, false);
+
+        mPermissionHelper.setNotificationPermission(pkgPerm);
+        verify(mPermManager).grantRuntimePermission(
+                "pkg", Manifest.permission.POST_NOTIFICATIONS, 10);
+        verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
+                FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_REVIEW_REQUIRED,
+                FLAG_PERMISSION_USER_SET, true, 10);
+    }
+
+    @Test
     public void testSetNotificationPermission_revokeUserSet() throws Exception {
         when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
                 .thenReturn(PERMISSION_GRANTED);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 31be33e..fd1536c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -43,6 +43,7 @@
 import static com.android.os.AtomsProto.DNDModeProto.ID_FIELD_NUMBER;
 import static com.android.os.AtomsProto.DNDModeProto.UID_FIELD_NUMBER;
 import static com.android.os.AtomsProto.DNDModeProto.ZEN_MODE_FIELD_NUMBER;
+import static com.android.server.notification.ZenModeHelper.RULE_LIMIT_PER_PACKAGE;
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
@@ -1611,6 +1612,35 @@
     }
 
     @Test
+    public void testAddAutomaticZenRule_beyondSystemLimit() {
+        for (int i = 0; i < RULE_LIMIT_PER_PACKAGE; i++) {
+            ScheduleInfo si = new ScheduleInfo();
+            si.startHour = i;
+            AutomaticZenRule zenRule = new AutomaticZenRule("name" + i,
+                    null,
+                    new ComponentName("android", "ScheduleConditionProvider"),
+                    ZenModeConfig.toScheduleConditionId(si),
+                    new ZenPolicy.Builder().build(),
+                    NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+            String id = mZenModeHelperSpy.addAutomaticZenRule("android", zenRule, "test");
+            assertNotNull(id);
+        }
+        try {
+            AutomaticZenRule zenRule = new AutomaticZenRule("name",
+                    null,
+                    new ComponentName("android", "ScheduleConditionProvider"),
+                    ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
+                    new ZenPolicy.Builder().build(),
+                    NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+            String id = mZenModeHelperSpy.addAutomaticZenRule("android", zenRule, "test");
+            fail("allowed too many rules to be created");
+        } catch (IllegalArgumentException e) {
+            // yay
+        }
+
+    }
+
+    @Test
     public void testAddAutomaticZenRule_CA() {
         AutomaticZenRule zenRule = new AutomaticZenRule("name",
                 null,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index d4d8b868..7689e08 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -256,6 +256,14 @@
         mActivityMetricsLogger.notifyVisibilityChanged(noDrawnActivity);
 
         verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(noDrawnActivity));
+
+        // If an activity is removed immediately before visibility update, it should cancel too.
+        final ActivityRecord removedImm = new ActivityBuilder(mAtm).setCreateTask(true).build();
+        clearInvocations(mLaunchObserver);
+        onActivityLaunched(removedImm);
+        removedImm.removeImmediately();
+        // Verify any() instead of proto because the field of record may be changed.
+        verifyAsync(mLaunchObserver).onActivityLaunchCancelled(any());
     }
 
     @Test
@@ -299,15 +307,16 @@
     @Test
     public void testOnReportFullyDrawn() {
         // Create an invisible event that should be cancelled after the next event starts.
-        onActivityLaunched(mTrampolineActivity);
-        mTrampolineActivity.mVisibleRequested = false;
+        final ActivityRecord prev = new ActivityBuilder(mAtm).setCreateTask(true).build();
+        onActivityLaunched(prev);
+        prev.mVisibleRequested = false;
 
         mActivityOptions = ActivityOptions.makeBasic();
         mActivityOptions.setSourceInfo(SourceInfo.TYPE_LAUNCHER, SystemClock.uptimeMillis() - 10);
         onIntentStarted(mTopActivity.intent);
         notifyActivityLaunched(START_SUCCESS, mTopActivity);
         verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTopActivity), anyInt());
-        verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTrampolineActivity));
+        verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(prev));
 
         // The activity reports fully drawn before windows drawn, then the fully drawn event will
         // be pending (see {@link WindowingModeTransitionInfo#pendingFullyDrawn}).
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 40ab8eb..f9d4dff 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wm;
 
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.OP_PICTURE_IN_PICTURE;
 import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED;
 import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
 import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
@@ -110,6 +112,7 @@
 import static org.mockito.Mockito.never;
 
 import android.app.ActivityOptions;
+import android.app.AppOpsManager;
 import android.app.ICompatCameraControlCallback;
 import android.app.PictureInPictureParams;
 import android.app.servertransaction.ActivityConfigurationChangeItem;
@@ -2204,6 +2207,28 @@
     }
 
     @Test
+    public void testCheckEnterPictureInPictureState_displayNotSupportedPip() {
+        final Task task = new TaskBuilder(mSupervisor)
+                .setDisplay(mDisplayContent).build();
+        final ActivityRecord activity = new ActivityBuilder(mAtm)
+                .setTask(task)
+                .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE)
+                .setActivityFlags(FLAG_SUPPORTS_PICTURE_IN_PICTURE)
+                .build();
+        mAtm.mSupportsPictureInPicture = true;
+        AppOpsManager appOpsManager = mAtm.getAppOpsManager();
+        doReturn(MODE_ALLOWED).when(appOpsManager).checkOpNoThrow(eq(OP_PICTURE_IN_PICTURE),
+                anyInt(), any());
+        doReturn(false).when(mAtm).shouldDisableNonVrUiLocked();
+
+        spyOn(mDisplayContent.mDwpcHelper);
+        doReturn(false).when(mDisplayContent.mDwpcHelper).isWindowingModeSupported(
+                WINDOWING_MODE_PINNED);
+
+        assertFalse(activity.checkEnterPictureInPictureState("TEST", false /* beforeStopping */));
+    }
+
+    @Test
     public void testLaunchIntoPip() {
         final PictureInPictureParams params = new PictureInPictureParams.Builder()
                 .build();
@@ -3086,11 +3111,11 @@
 
         // Simulate app re-start input or turning screen off/on then unlocked by un-secure
         // keyguard to back to the app, expect IME insets is not frozen
+        mDisplayContent.updateImeInputAndControlTarget(app);
+        assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
         imeSource.setFrame(new Rect(100, 400, 500, 500));
         app.getInsetsState().addSource(imeSource);
         app.getInsetsState().setSourceVisible(ITYPE_IME, true);
-        mDisplayContent.updateImeInputAndControlTarget(app);
-        assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
 
         // Verify when IME is visible and the app can receive the right IME insets from policy.
         makeWindowVisibleAndDrawn(app, mImeWindow);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index f9aa4b1..9902e83 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -500,6 +500,23 @@
         return Pair.create(splitPrimaryActivity, splitSecondActivity);
     }
 
+    @Test
+    public void testMoveVisibleTaskToFront() {
+        final ActivityRecord activity = new TaskBuilder(mSupervisor)
+                .setCreateActivity(true).build().getTopMostActivity();
+        final ActivityRecord translucentActivity = new TaskBuilder(mSupervisor)
+                .setCreateActivity(true).build().getTopMostActivity();
+        assertTrue(activity.mVisibleRequested);
+
+        final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
+                false /* mockGetRootTask */);
+        starter.getIntent().setComponent(activity.mActivityComponent);
+        final int result = starter.setReason("testMoveVisibleTaskToFront").execute();
+
+        assertEquals(START_TASK_TO_FRONT, result);
+        assertEquals(1, activity.compareTo(translucentActivity));
+    }
+
     /**
      * Tests activity is cleaned up properly in a task mode violation.
      */
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
index 66da2a6..716612c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
@@ -284,7 +284,7 @@
                 .setCreateActivity(true).build().getTopMostActivity();
         activity2.getTask().setResumedActivity(activity2, "test");
 
-        mAtm.mAmInternal.deletePendingTopUid(activity1.getUid());
+        mAtm.mAmInternal.deletePendingTopUid(activity1.getUid(), Long.MAX_VALUE);
         clearInvocations(mAtm);
         activity1.moveFocusableActivityToTop("test");
         assertTrue(mAtm.mAmInternal.isPendingTopUid(activity1.getUid()));
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 72521fd..97d477f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -33,21 +33,26 @@
 import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doCallRealMethod;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
 import android.annotation.Nullable;
+import android.gui.DropInputMode;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -739,20 +744,36 @@
     }
 
     static class TestRemoteAnimationRunner implements IRemoteAnimationRunner {
+        private IRemoteAnimationFinishedCallback mFinishedCallback;
+
         @Override
         public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
                 RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
                 IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
+            mFinishedCallback = finishedCallback;
         }
 
         @Override
         public void onAnimationCancelled() throws RemoteException {
+            mFinishedCallback = null;
         }
 
         @Override
         public IBinder asBinder() {
             return new Binder();
         }
+
+        boolean isAnimationStarted() {
+            return mFinishedCallback != null;
+        }
+
+        void finishAnimation() {
+            try {
+                mFinishedCallback.onAnimationFinished();
+            } catch (RemoteException e) {
+                fail();
+            }
+        }
     }
 
     @Test
@@ -841,144 +862,139 @@
     @Test
     public void testOverrideTaskFragmentAdapter_overrideWithEmbeddedActivity() {
         final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
-        final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
-                new TestRemoteAnimationRunner(), 10, 1);
-        setupTaskFragmentRemoteAnimation(organizer, adapter);
+        final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
+        setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
 
         // Create a TaskFragment with embedded activity.
         final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(
                 createTask(mDisplayContent), organizer);
         final ActivityRecord activity = taskFragment.getTopMostActivity();
-        activity.allDrawn = true;
+        prepareActivityForAppTransition(activity);
         spyOn(mDisplayContent.mAppTransition);
 
-        // Prepare a transition.
+        // Prepare and start transition.
         prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
+        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
 
-        // Should be overridden.
-        verify(mDisplayContent.mAppTransition)
-                .overridePendingAppTransitionRemote(adapter, false /* sync */);
+        // Animation run by the remote handler.
+        assertTrue(remoteAnimationRunner.isAnimationStarted());
     }
 
     @Test
     public void testOverrideTaskFragmentAdapter_overrideWithNonEmbeddedActivity() {
         final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
-        final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
-                new TestRemoteAnimationRunner(), 10, 1);
-        setupTaskFragmentRemoteAnimation(organizer, adapter);
+        final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
+        setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
 
         final Task task = createTask(mDisplayContent);
         // Closing non-embedded activity.
         final ActivityRecord closingActivity = createActivityRecord(task);
-        closingActivity.allDrawn = true;
+        prepareActivityForAppTransition(closingActivity);
         // Opening TaskFragment with embedded activity.
         final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
         final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
-        openingActivity.allDrawn = true;
+        prepareActivityForAppTransition(openingActivity);
         task.effectiveUid = openingActivity.getUid();
         spyOn(mDisplayContent.mAppTransition);
 
-        // Prepare a transition.
+        // Prepare and start transition.
         prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment);
+        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
 
-        // Should be overridden.
-        verify(mDisplayContent.mAppTransition)
-                .overridePendingAppTransitionRemote(adapter, false /* sync */);
+        // Animation run by the remote handler.
+        assertTrue(remoteAnimationRunner.isAnimationStarted());
     }
 
     @Test
     public void testOverrideTaskFragmentAdapter_overrideEmbeddedActivityWithDiffUid() {
         final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
-        final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
-                new TestRemoteAnimationRunner(), 10, 1);
-        setupTaskFragmentRemoteAnimation(organizer, adapter);
+        final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
+        setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
 
         final Task task = createTask(mDisplayContent);
         // Closing TaskFragment with embedded activity.
         final TaskFragment taskFragment1 = createTaskFragmentWithEmbeddedActivity(task, organizer);
         final ActivityRecord closingActivity = taskFragment1.getTopMostActivity();
-        closingActivity.allDrawn = true;
+        prepareActivityForAppTransition(closingActivity);
         closingActivity.info.applicationInfo.uid = 12345;
         // Opening TaskFragment with embedded activity with different UID.
         final TaskFragment taskFragment2 = createTaskFragmentWithEmbeddedActivity(task, organizer);
         final ActivityRecord openingActivity = taskFragment2.getTopMostActivity();
+        prepareActivityForAppTransition(openingActivity);
         openingActivity.info.applicationInfo.uid = 54321;
-        openingActivity.allDrawn = true;
         spyOn(mDisplayContent.mAppTransition);
 
-        // Prepare a transition.
+        // Prepare and start transition.
         prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment1);
+        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
 
-        // Should be overridden.
-        verify(mDisplayContent.mAppTransition)
-                .overridePendingAppTransitionRemote(adapter, false /* sync */);
+        // Animation run by the remote handler.
+        assertTrue(remoteAnimationRunner.isAnimationStarted());
     }
 
     @Test
     public void testOverrideTaskFragmentAdapter_noOverrideWithTwoApps() {
         final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
-        final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
-                new TestRemoteAnimationRunner(), 10, 1);
-        setupTaskFragmentRemoteAnimation(organizer, adapter);
+        final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
+        setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
 
         // Closing activity in Task1.
         final ActivityRecord closingActivity = createActivityRecord(mDisplayContent);
-        closingActivity.allDrawn = true;
+        prepareActivityForAppTransition(closingActivity);
         // Opening TaskFragment with embedded activity in Task2.
         final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(
                 createTask(mDisplayContent), organizer);
         final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
-        openingActivity.allDrawn = true;
+        prepareActivityForAppTransition(openingActivity);
         spyOn(mDisplayContent.mAppTransition);
 
-        // Prepare a transition for TaskFragment.
+        // Prepare and start transition.
         prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment);
+        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
 
-        // Should not be overridden.
-        verify(mDisplayContent.mAppTransition, never())
-                .overridePendingAppTransitionRemote(adapter, false /* sync */);
+        // Animation not run by the remote handler.
+        assertFalse(remoteAnimationRunner.isAnimationStarted());
     }
 
     @Test
     public void testOverrideTaskFragmentAdapter_noOverrideNonEmbeddedActivityWithDiffUid() {
         final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
-        final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
-                new TestRemoteAnimationRunner(), 10, 1);
-        setupTaskFragmentRemoteAnimation(organizer, adapter);
+        final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
+        setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
 
         final Task task = createTask(mDisplayContent);
         // Closing TaskFragment with embedded activity.
         final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
         final ActivityRecord closingActivity = taskFragment.getTopMostActivity();
-        closingActivity.allDrawn = true;
+        prepareActivityForAppTransition(closingActivity);
         closingActivity.info.applicationInfo.uid = 12345;
         task.effectiveUid = closingActivity.getUid();
         // Opening non-embedded activity with different UID.
         final ActivityRecord openingActivity = createActivityRecord(task);
+        prepareActivityForAppTransition(openingActivity);
         openingActivity.info.applicationInfo.uid = 54321;
-        openingActivity.allDrawn = true;
         spyOn(mDisplayContent.mAppTransition);
 
-        // Prepare a transition.
+        // Prepare and start transition.
         prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment);
+        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
 
-        // Should not be overridden
-        verify(mDisplayContent.mAppTransition, never())
-                .overridePendingAppTransitionRemote(adapter, false /* sync */);
+        // Animation should not run by the remote handler when there are non-embedded activities of
+        // different UID.
+        assertFalse(remoteAnimationRunner.isAnimationStarted());
     }
 
     @Test
     public void testOverrideTaskFragmentAdapter_noOverrideWithWallpaper() {
         final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
-        final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
-                new TestRemoteAnimationRunner(), 10, 1);
-        setupTaskFragmentRemoteAnimation(organizer, adapter);
+        final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
+        setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
 
         // Create a TaskFragment with embedded activity.
         final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(
                 createTask(mDisplayContent), organizer);
         final ActivityRecord activity = taskFragment.getTopMostActivity();
-        activity.allDrawn = true;
+        prepareActivityForAppTransition(activity);
         // Set wallpaper as visible.
         final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
                 mock(IBinder.class), true, mDisplayContent, true /* ownerCanManageAppTokens */);
@@ -986,12 +1002,107 @@
         doReturn(true).when(mDisplayContent.mWallpaperController).isWallpaperVisible();
         spyOn(mDisplayContent.mAppTransition);
 
-        // Prepare a transition.
+        // Prepare and start transition.
         prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
+        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
 
-        // Should not be overridden when there is wallpaper in the transition.
-        verify(mDisplayContent.mAppTransition, never())
-                .overridePendingAppTransitionRemote(adapter, false /* sync */);
+        // Animation should not run by the remote handler when there is wallpaper in the transition.
+        assertFalse(remoteAnimationRunner.isAnimationStarted());
+    }
+
+    @Test
+    public void testOverrideTaskFragmentAdapter_inputProtectedForUntrustedAnimation() {
+        final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+        final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
+        setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
+
+        // Create a TaskFragment with embedded activities, one is trusted embedded, and the other
+        // one is untrusted embedded.
+        final Task task = createTask(mDisplayContent);
+        final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
+                .setParentTask(task)
+                .createActivityCount(2)
+                .setOrganizer(organizer)
+                .build();
+        final ActivityRecord activity0 = taskFragment.getChildAt(0).asActivityRecord();
+        final ActivityRecord activity1 = taskFragment.getChildAt(1).asActivityRecord();
+        // Also create a non-embedded activity in the Task.
+        final ActivityRecord activity2 = new ActivityBuilder(mAtm).build();
+        task.addChild(activity2, POSITION_BOTTOM);
+        prepareActivityForAppTransition(activity0);
+        prepareActivityForAppTransition(activity1);
+        prepareActivityForAppTransition(activity2);
+        doReturn(false).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity0);
+        doReturn(true).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity1);
+        spyOn(mDisplayContent.mAppTransition);
+
+        // Prepare and start transition.
+        prepareAndTriggerAppTransition(activity1, null /* closingActivity */, taskFragment);
+        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+
+        // The animation will be animated remotely by client and all activities are input disabled
+        // for untrusted animation.
+        assertTrue(remoteAnimationRunner.isAnimationStarted());
+        verify(activity0).setDropInputForAnimation(true);
+        verify(activity1).setDropInputForAnimation(true);
+        verify(activity2).setDropInputForAnimation(true);
+        verify(activity0).setDropInputMode(DropInputMode.ALL);
+        verify(activity1).setDropInputMode(DropInputMode.ALL);
+        verify(activity2).setDropInputMode(DropInputMode.ALL);
+
+        // Reset input after animation is finished.
+        clearInvocations(activity0);
+        clearInvocations(activity1);
+        clearInvocations(activity2);
+        remoteAnimationRunner.finishAnimation();
+
+        verify(activity0).setDropInputForAnimation(false);
+        verify(activity1).setDropInputForAnimation(false);
+        verify(activity2).setDropInputForAnimation(false);
+        verify(activity0).setDropInputMode(DropInputMode.OBSCURED);
+        verify(activity1).setDropInputMode(DropInputMode.NONE);
+        verify(activity2).setDropInputMode(DropInputMode.NONE);
+    }
+
+    /**
+     * Since we don't have any use case to rely on handling input during animation, disable it even
+     * if it is trusted embedding so that it could cover some edge-cases when a previously trusted
+     * host starts doing something bad.
+     */
+    @Test
+    public void testOverrideTaskFragmentAdapter_inputProtectedForTrustedAnimation() {
+        final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+        final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
+        setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
+
+        // Create a TaskFragment with only trusted embedded activity
+        final Task task = createTask(mDisplayContent);
+        final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
+                .setParentTask(task)
+                .createActivityCount(1)
+                .setOrganizer(organizer)
+                .build();
+        final ActivityRecord activity = taskFragment.getChildAt(0).asActivityRecord();
+        prepareActivityForAppTransition(activity);
+        doReturn(true).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity);
+        spyOn(mDisplayContent.mAppTransition);
+
+        // Prepare and start transition.
+        prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
+        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+
+        // The animation will be animated remotely by client and all activities are input disabled
+        // for untrusted animation.
+        assertTrue(remoteAnimationRunner.isAnimationStarted());
+        verify(activity).setDropInputForAnimation(true);
+        verify(activity).setDropInputMode(DropInputMode.ALL);
+
+        // Reset input after animation is finished.
+        clearInvocations(activity);
+        remoteAnimationRunner.finishAnimation();
+
+        verify(activity).setDropInputForAnimation(false);
+        verify(activity).setDropInputMode(DropInputMode.NONE);
     }
 
     @Test
@@ -1004,7 +1115,7 @@
                 .setParentTask(task)
                 .setOrganizer(organizer)
                 .build();
-        changeTaskFragment.getTopMostActivity().allDrawn = true;
+        prepareActivityForAppTransition(changeTaskFragment.getTopMostActivity());
         spyOn(mDisplayContent.mAppTransition);
         spyOn(emptyTaskFragment);
 
@@ -1034,7 +1145,7 @@
                 .setParentTask(task)
                 .setOrganizer(organizer)
                 .build();
-        changeTaskFragment.getTopMostActivity().allDrawn = true;
+        prepareActivityForAppTransition(changeTaskFragment.getTopMostActivity());
         // To make sure that having a detached activity won't cause any issue.
         final ActivityRecord detachedActivity = createActivityRecord(task);
         detachedActivity.removeImmediately();
@@ -1060,7 +1171,9 @@
 
     /** Registers remote animation for the organizer. */
     private void setupTaskFragmentRemoteAnimation(TaskFragmentOrganizer organizer,
-            RemoteAnimationAdapter adapter) {
+            TestRemoteAnimationRunner remoteAnimationRunner) {
+        final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
+                remoteAnimationRunner, 10, 1);
         final ITaskFragmentOrganizer iOrganizer =
                 ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder());
         final RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
@@ -1087,4 +1200,14 @@
         }
         mDisplayContent.mAppTransitionController.handleAppTransitionReady();
     }
+
+    private static void prepareActivityForAppTransition(ActivityRecord activity) {
+        // Transition will wait until all participated activities to be drawn.
+        activity.allDrawn = true;
+        // Skip manipulate the SurfaceControl.
+        doNothing().when(activity).setDropInputMode(anyInt());
+        // Make sure activity can create remote animation target.
+        doReturn(mock(RemoteAnimationTarget.class)).when(activity).createRemoteAnimationTarget(
+                any());
+    }
 }
\ No newline at end of file
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index c21a5b6..92550a3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -30,7 +30,10 @@
 import android.annotation.NonNull;
 import android.hardware.HardwareBuffer;
 import android.platform.test.annotations.Presubmit;
+import android.window.BackEvent;
 import android.window.BackNavigationInfo;
+import android.window.IOnBackInvokedCallback;
+import android.window.OnBackInvokedDispatcher;
 import android.window.TaskSnapshot;
 
 import org.junit.Before;
@@ -42,15 +45,19 @@
 public class BackNavigationControllerTests extends WindowTestsBase {
 
     private BackNavigationController mBackNavigationController;
+    private IOnBackInvokedCallback mOnBackInvokedCallback;
 
     @Before
     public void setUp() throws Exception {
         mBackNavigationController = new BackNavigationController();
+        mOnBackInvokedCallback = createBackCallback();
     }
 
     @Test
     public void backTypeHomeWhenBackToLauncher() {
         Task task = createTopTaskWithActivity();
+        registerSystemOnBackInvokedCallback();
+
         BackNavigationInfo backNavigationInfo =
                 mBackNavigationController.startBackNavigation(task, new StubTransaction());
         assertThat(backNavigationInfo).isNotNull();
@@ -63,6 +70,8 @@
         Task taskA = createTask(mDefaultDisplay);
         createActivityRecord(taskA);
         Task task = createTopTaskWithActivity();
+        registerSystemOnBackInvokedCallback();
+
         BackNavigationInfo backNavigationInfo =
                 mBackNavigationController.startBackNavigation(task, new StubTransaction());
         assertThat(backNavigationInfo).isNotNull();
@@ -75,6 +84,8 @@
         Task task = createTopTaskWithActivity();
         mAtm.setFocusedTask(task.mTaskId,
                 createAppWindow(task, FIRST_APPLICATION_WINDOW, "window").mActivityRecord);
+        registerSystemOnBackInvokedCallback();
+
         BackNavigationInfo backNavigationInfo =
                 mBackNavigationController.startBackNavigation(task, new StubTransaction());
         assertThat(backNavigationInfo).isNotNull();
@@ -89,6 +100,7 @@
     public void backNavInfoFullyPopulated() {
         Task task = createTopTaskWithActivity();
         createAppWindow(task, FIRST_APPLICATION_WINDOW, "window");
+        registerSystemOnBackInvokedCallback();
 
         // We need a mock screenshot so
         TaskSnapshotController taskSnapshotController = createMockTaskSnapshotController();
@@ -104,6 +116,30 @@
         assertThat(backNavigationInfo.getTaskWindowConfiguration()).isNotNull();
     }
 
+    @Test
+    public void preparesForBackToHome() {
+        Task task = createTopTaskWithActivity();
+        ActivityRecord activity = task.getTopActivity(false, false);
+        registerSystemOnBackInvokedCallback();
+
+        BackNavigationInfo backNavigationInfo =
+                mBackNavigationController.startBackNavigation(task, new StubTransaction());
+        assertThat(typeToString(backNavigationInfo.getType()))
+                .isEqualTo(typeToString(BackNavigationInfo.TYPE_RETURN_TO_HOME));
+    }
+
+    @Test
+    public void backTypeCallback() {
+        Task task = createTopTaskWithActivity();
+        ActivityRecord activity = task.getTopActivity(false, false);
+        registerApplicationOnBackInvokedCallback();
+
+        BackNavigationInfo backNavigationInfo =
+                mBackNavigationController.startBackNavigation(task, new StubTransaction());
+        assertThat(typeToString(backNavigationInfo.getType()))
+                .isEqualTo(typeToString(BackNavigationInfo.TYPE_CALLBACK));
+    }
+
     @NonNull
     private TaskSnapshotController createMockTaskSnapshotController() {
         TaskSnapshotController taskSnapshotController = mock(TaskSnapshotController.class);
@@ -126,4 +162,30 @@
         mAtm.setFocusedTask(task.mTaskId, record);
         return task;
     }
+
+    private void registerSystemOnBackInvokedCallback() {
+        mWm.getFocusedWindowLocked().setOnBackInvokedCallback(
+                mOnBackInvokedCallback, OnBackInvokedDispatcher.PRIORITY_SYSTEM);
+    }
+
+    private void registerApplicationOnBackInvokedCallback() {
+        mWm.getFocusedWindowLocked().setOnBackInvokedCallback(
+                mOnBackInvokedCallback, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+    }
+
+    private IOnBackInvokedCallback createBackCallback() {
+        return new IOnBackInvokedCallback.Stub() {
+            @Override
+            public void onBackStarted() { }
+
+            @Override
+            public void onBackProgressed(BackEvent backEvent) { }
+
+            @Override
+            public void onBackCancelled() { }
+
+            @Override
+            public void onBackInvoked() { }
+        };
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
index 50eefa0..c5117bb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
@@ -19,12 +19,12 @@
 
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
-import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.ContentRecorder.KEY_RECORD_TASK_FEATURE;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -40,17 +40,22 @@
 import android.os.Binder;
 import android.os.IBinder;
 import android.platform.test.annotations.Presubmit;
+import android.provider.DeviceConfig;
 import android.util.DisplayMetrics;
 import android.view.ContentRecordingSession;
 import android.view.Surface;
 import android.view.SurfaceControl;
 
+import androidx.annotation.NonNull;
 import androidx.test.filters.SmallTest;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.concurrent.CountDownLatch;
+
 /**
  * Tests for the {@link ContentRecorder} class.
  *
@@ -62,17 +67,18 @@
 @RunWith(WindowTestRunner.class)
 public class ContentRecorderTests extends WindowTestsBase {
     private static final IBinder TEST_TOKEN = new RecordingTestToken();
-    private final ContentRecordingSession mDefaultSession =
+    private static IBinder sTaskWindowContainerToken;
+    private final ContentRecordingSession mDisplaySession =
             ContentRecordingSession.createDisplaySession(TEST_TOKEN);
+    private ContentRecordingSession mTaskSession;
     private static Point sSurfaceSize;
     private ContentRecorder mContentRecorder;
     private SurfaceControl mRecordedSurface;
+    // Handle feature flag.
+    private ConfigListener mConfigListener;
+    private CountDownLatch mLatch;
 
     @Before public void setUp() {
-        // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
-        // mirror.
-        setUpDefaultTaskDisplayAreaWindowToken();
-
         // GIVEN SurfaceControl can successfully mirror the provided surface.
         sSurfaceSize = new Point(
                 mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
@@ -84,12 +90,32 @@
                 sSurfaceSize.x, sSurfaceSize.y,
                 DisplayMetrics.DENSITY_140, new Surface(), VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR);
         final int displayId = virtualDisplay.getDisplay().getDisplayId();
-        mDefaultSession.setDisplayId(displayId);
-
         mWm.mRoot.onDisplayAdded(displayId);
-        final DisplayContent mVirtualDisplayContent = mWm.mRoot.getDisplayContent(displayId);
-        mContentRecorder = new ContentRecorder(mVirtualDisplayContent);
-        spyOn(mVirtualDisplayContent);
+        final DisplayContent virtualDisplayContent = mWm.mRoot.getDisplayContent(displayId);
+        mContentRecorder = new ContentRecorder(virtualDisplayContent);
+        spyOn(virtualDisplayContent);
+
+        // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
+        // record.
+        setUpDefaultTaskDisplayAreaWindowToken();
+        mDisplaySession.setDisplayId(displayId);
+
+        // GIVEN there is a window token associated with a task to record.
+        sTaskWindowContainerToken = setUpTaskWindowContainerToken(virtualDisplayContent);
+        mTaskSession = ContentRecordingSession.createTaskSession(sTaskWindowContainerToken);
+        mTaskSession.setDisplayId(displayId);
+
+        mConfigListener = new ConfigListener();
+        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+                mContext.getMainExecutor(), mConfigListener);
+        mLatch = new CountDownLatch(1);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_RECORD_TASK_FEATURE,
+                "true", true);
+    }
+
+    @After
+    public void teardown() {
+        DeviceConfig.removeOnPropertiesChangedListener(mConfigListener);
     }
 
     @Test
@@ -102,22 +128,74 @@
 
     @Test
     public void testUpdateRecording_display() {
-        mContentRecorder.setContentRecordingSession(mDefaultSession);
+        mContentRecorder.setContentRecordingSession(mDisplaySession);
         mContentRecorder.updateRecording();
         assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
     }
 
     @Test
-    public void testUpdateRecording_task() {
-        mDefaultSession.setContentToRecord(RECORD_CONTENT_TASK);
-        mContentRecorder.setContentRecordingSession(mDefaultSession);
+    public void testUpdateRecording_display_nullToken() {
+        ContentRecordingSession session = ContentRecordingSession.createDisplaySession(TEST_TOKEN);
+        session.setDisplayId(mDisplaySession.getDisplayId());
+        session.setTokenToRecord(null);
+        mContentRecorder.setContentRecordingSession(session);
         mContentRecorder.updateRecording();
         assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
     }
 
     @Test
+    public void testUpdateRecording_display_noWindowContainer() {
+        doReturn(null).when(
+                mWm.mWindowContextListenerController).getContainer(any());
+        mContentRecorder.setContentRecordingSession(mDisplaySession);
+        mContentRecorder.updateRecording();
+        assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+    }
+
+    @Test
+    public void testUpdateRecording_task_featureDisabled() {
+        mLatch = new CountDownLatch(1);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_RECORD_TASK_FEATURE,
+                "false", false);
+        mContentRecorder.setContentRecordingSession(mTaskSession);
+        mContentRecorder.updateRecording();
+        assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+    }
+
+    @Test
+    public void testUpdateRecording_task_featureEnabled() {
+        // Feature already enabled; don't need to again.
+        mContentRecorder.setContentRecordingSession(mTaskSession);
+        mContentRecorder.updateRecording();
+        assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
+    }
+
+    @Test
+    public void testUpdateRecording_task_nullToken() {
+        ContentRecordingSession session = ContentRecordingSession.createTaskSession(
+                sTaskWindowContainerToken);
+        session.setDisplayId(mDisplaySession.getDisplayId());
+        session.setTokenToRecord(null);
+        mContentRecorder.setContentRecordingSession(session);
+        mContentRecorder.updateRecording();
+        assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+        // TODO(b/219761722) validate VirtualDisplay is torn down when can't set up task recording.
+    }
+
+    @Test
+    public void testUpdateRecording_task_noWindowContainer() {
+        // Use the window container token of the DisplayContent, rather than task.
+        ContentRecordingSession invalidTaskSession = ContentRecordingSession.createTaskSession(
+                new WindowContainer.RemoteToken(mDisplayContent));
+        mContentRecorder.setContentRecordingSession(invalidTaskSession);
+        mContentRecorder.updateRecording();
+        assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+        // TODO(b/219761722) validate VirtualDisplay is torn down when can't set up task recording.
+    }
+
+    @Test
     public void testUpdateRecording_wasPaused() {
-        mContentRecorder.setContentRecordingSession(mDefaultSession);
+        mContentRecorder.setContentRecordingSession(mDisplaySession);
         mContentRecorder.updateRecording();
 
         mContentRecorder.pauseRecording();
@@ -126,16 +204,6 @@
     }
 
     @Test
-    public void testUpdateRecording_wasStopped() {
-        mContentRecorder.setContentRecordingSession(mDefaultSession);
-        mContentRecorder.updateRecording();
-
-        mContentRecorder.remove();
-        mContentRecorder.updateRecording();
-        assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
-    }
-
-    @Test
     public void testOnConfigurationChanged_neverRecording() {
         mContentRecorder.onConfigurationChanged(ORIENTATION_PORTRAIT);
 
@@ -146,7 +214,7 @@
 
     @Test
     public void testOnConfigurationChanged_resizesSurface() {
-        mContentRecorder.setContentRecordingSession(mDefaultSession);
+        mContentRecorder.setContentRecordingSession(mDisplaySession);
         mContentRecorder.updateRecording();
         mContentRecorder.onConfigurationChanged(ORIENTATION_PORTRAIT);
 
@@ -158,7 +226,7 @@
 
     @Test
     public void testPauseRecording_pausesRecording() {
-        mContentRecorder.setContentRecordingSession(mDefaultSession);
+        mContentRecorder.setContentRecordingSession(mDisplaySession);
         mContentRecorder.updateRecording();
 
         mContentRecorder.pauseRecording();
@@ -173,7 +241,7 @@
 
     @Test
     public void testRemove_stopsRecording() {
-        mContentRecorder.setContentRecordingSession(mDefaultSession);
+        mContentRecorder.setContentRecordingSession(mDisplaySession);
         mContentRecorder.updateRecording();
 
         mContentRecorder.remove();
@@ -188,8 +256,9 @@
 
     @Test
     public void testUpdateMirroredSurface_capturedAreaResized() {
-        mContentRecorder.setContentRecordingSession(mDefaultSession);
+        mContentRecorder.setContentRecordingSession(mDisplaySession);
         mContentRecorder.updateRecording();
+        assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
 
         // WHEN attempting to mirror on the virtual display, and the captured content is resized.
         float xScale = 0.7f;
@@ -197,13 +266,14 @@
         Rect displayAreaBounds = new Rect(0, 0, Math.round(sSurfaceSize.x * xScale),
                 Math.round(sSurfaceSize.y * yScale));
         mContentRecorder.updateMirroredSurface(mTransaction, displayAreaBounds, sSurfaceSize);
+        assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
 
         // THEN content in the captured DisplayArea is scaled to fit the surface size.
         verify(mTransaction, atLeastOnce()).setMatrix(mRecordedSurface, 1.0f / yScale, 0, 0,
                 1.0f / yScale);
         // THEN captured content is positioned in the centre of the output surface.
-        float scaledWidth = displayAreaBounds.width() / xScale;
-        float xInset = (sSurfaceSize.x - scaledWidth) / 2;
+        int scaledWidth = Math.round((float) displayAreaBounds.width() / xScale);
+        int xInset = (sSurfaceSize.x - scaledWidth) / 2;
         verify(mTransaction, atLeastOnce()).setPosition(mRecordedSurface, xInset, 0);
     }
 
@@ -222,6 +292,18 @@
     }
 
     /**
+     * Creates a {@link android.window.WindowContainerToken} associated with a task, in order for
+     * that task to be recorded.
+     */
+    private IBinder setUpTaskWindowContainerToken(DisplayContent displayContent) {
+        final Task rootTask = createTask(displayContent);
+        final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
+        // Ensure the task is not empty.
+        createActivityRecord(displayContent, task);
+        return task.getTaskInfo().token.asBinder();
+    }
+
+    /**
      * SurfaceControl successfully creates a mirrored surface of the given size.
      */
     private SurfaceControl surfaceControlMirrors(Point surfaceSize) {
@@ -236,4 +318,13 @@
                 anyInt());
         return mirroredSurface;
     }
+
+    private class ConfigListener implements DeviceConfig.OnPropertiesChangedListener {
+        @Override
+        public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
+            if (mLatch != null && properties.getKeyset().contains(KEY_RECORD_TASK_FEATURE)) {
+                mLatch.countDown();
+            }
+        }
+    }
 }
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 8e990f7..9169267 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -414,6 +414,33 @@
         imeContainer.setOrganizer(null);
     }
 
+    @Test
+    public void testImeContainerIsReparentedUnderParentWhenOrganized() {
+        final DisplayArea.Tokens imeContainer = mDisplayContent.getImeContainer();
+        final ActivityRecord activity = createActivityRecord(mDisplayContent);
+
+        final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, activity,
+                "startingWin");
+        startingWin.setHasSurface(true);
+        assertTrue(startingWin.canBeImeTarget());
+
+        final Transaction transaction = mDisplayContent.getPendingTransaction();
+        spyOn(transaction);
+
+        // Organized the ime container.
+        final IDisplayAreaOrganizer mockImeOrganizer = mock(IDisplayAreaOrganizer.class);
+        when(mockImeOrganizer.asBinder()).thenReturn(new Binder());
+        imeContainer.setOrganizer(mockImeOrganizer);
+
+        // Verify that the ime container surface is reparented under
+        // its parent surface as a consequence of the setOrganizer call.
+        SurfaceControl imeParentSurfaceControl = imeContainer.getParentSurfaceControl();
+        verify(transaction).reparent(imeContainer.getSurfaceControl(), imeParentSurfaceControl);
+
+        // Clean up organizer.
+        imeContainer.setOrganizer(null);
+    }
+
     /**
      * This tests root task movement between displays and proper root task's, task's and app token's
      * display container references updates.
@@ -1102,6 +1129,21 @@
         assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent());
     }
 
+    @UseTestDisplay(addWindows = W_ACTIVITY)
+    @Test
+    public void testComputeImeParent_inputTargetNotUpdate() throws Exception {
+        WindowState app1 = createWindow(null, TYPE_BASE_APPLICATION, "app1");
+        WindowState app2 = createWindow(null, TYPE_BASE_APPLICATION, "app2");
+        doReturn(true).when(mDisplayContent).shouldImeAttachedToApp();
+        mDisplayContent.setImeLayeringTarget(app1);
+        mDisplayContent.setImeInputTarget(app1);
+        assertEquals(app1.mActivityRecord.getSurfaceControl(), mDisplayContent.computeImeParent());
+        mDisplayContent.setImeLayeringTarget(app2);
+        // Expect null means no change IME parent when the IME layering target not yet
+        // request IME to be the input target.
+        assertNull(mDisplayContent.computeImeParent());
+    }
+
     @Test
     public void testInputMethodInputTarget_isClearedWhenWindowStateIsRemoved() throws Exception {
         final DisplayContent dc = createNewDisplay();
@@ -1969,7 +2011,7 @@
         appWin2.setHasSurface(true);
         assertTrue(appWin2.canBeImeTarget());
         doReturn(true).when(appWin1).isClosing();
-        doReturn(true).when(appWin1).inAppOrRecentsTransition();
+        doReturn(true).when(appWin1).inTransitionSelfOrParent();
 
         // Test step 3: Verify appWin2 will be the next IME target and the IME snapshot surface will
         // be attached and shown on the display at this time.
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index db22757..45ae81a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -157,6 +157,7 @@
         win.getFrame().set(0, 0, 500, 100);
 
         addWindow(win);
+        win.updateSourceFrame(win.getFrame());
         InsetsStateController controller = mDisplayContent.getInsetsStateController();
         controller.onPostLayout();
 
@@ -185,6 +186,7 @@
         win.getFrame().set(0, 0, 500, 100);
 
         addWindow(win);
+        win.updateSourceFrame(win.getFrame());
         mDisplayContent.getInsetsStateController().onPostLayout();
 
         InsetsSourceProvider provider =
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerHelperTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerHelperTests.java
index 6e11d8c..f968999 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerHelperTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerHelperTests.java
@@ -16,13 +16,18 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
 
+import android.app.WindowConfiguration;
 import android.content.ComponentName;
 import android.content.pm.ActivityInfo;
 import android.os.UserHandle;
@@ -37,6 +42,7 @@
 import org.junit.runner.RunWith;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * Tests for the {@link DisplayWindowPolicyControllerHelper} class.
@@ -113,6 +119,39 @@
         return activity;
     }
 
+    @Test
+    public void testIsWindowingModeSupported_noController_returnTrueForAnyWindowingMode() {
+        doReturn(null).when(mWm.mDisplayManagerInternal)
+                .getDisplayWindowPolicyController(anyInt());
+        mSecondaryDisplay = createNewDisplay();
+        assertFalse(mSecondaryDisplay.mDwpcHelper.hasController());
+
+        assertTrue(mSecondaryDisplay.mDwpcHelper.isWindowingModeSupported(WINDOWING_MODE_PINNED));
+        assertTrue(
+                mSecondaryDisplay.mDwpcHelper.isWindowingModeSupported(WINDOWING_MODE_FULLSCREEN));
+    }
+
+    @Test
+    public void testIsWindowingModeSupported_withoutSettingSupportedMode_returnFalse() {
+        assertFalse(mSecondaryDisplay.mDwpcHelper.isWindowingModeSupported(WINDOWING_MODE_PINNED));
+    }
+
+    @Test
+    public void testIsWindowingModeSupported_withoutSupportedMode_defaultSupportFullScreen() {
+        assertTrue(
+                mSecondaryDisplay.mDwpcHelper.isWindowingModeSupported(WINDOWING_MODE_FULLSCREEN));
+    }
+
+    @Test
+    public void testIsWindowingModeSupported_setPinnedMode_returnTrue() {
+        Set<Integer> supportedWindowingMode = new ArraySet<>();
+        supportedWindowingMode.add(WINDOWING_MODE_PINNED);
+
+        mDwpc.setSupportedWindowingModes(supportedWindowingMode);
+
+        assertTrue(mSecondaryDisplay.mDwpcHelper.isWindowingModeSupported(WINDOWING_MODE_PINNED));
+    }
+
     private class TestDisplayWindowPolicyController extends DisplayWindowPolicyController {
 
         ComponentName mTopActivity = null;
@@ -120,7 +159,8 @@
         ArraySet<Integer> mRunningUids = new ArraySet<>();
 
         @Override
-        public boolean canContainActivities(@NonNull List<ActivityInfo> activities) {
+        public boolean canContainActivities(@NonNull List<ActivityInfo> activities,
+                @WindowConfiguration.WindowingMode int windowingMode) {
             return false;
         }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateDenylistTest.java b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateDenylistTest.java
index dfc2e35..38ab683 100644
--- a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateDenylistTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateDenylistTest.java
@@ -33,7 +33,6 @@
 import com.android.internal.util.Preconditions;
 import com.android.server.testutils.FakeDeviceConfigInterface;
 
-import org.junit.After;
 import org.junit.Test;
 
 import java.util.concurrent.Executor;
@@ -51,11 +50,6 @@
 
     private HighRefreshRateDenylist mDenylist;
 
-    @After
-    public void tearDown() {
-        mDenylist.dispose();
-    }
-
     @Test
     public void testDefaultDenylist() {
         final Resources r = createResources(APP1, APP2);
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index 90a6918..6d02226 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -280,6 +280,7 @@
                 rect.set(0, 1, 2, 3)));
         getController().getSourceProvider(ITYPE_IME).setWindowContainer(ime, null, null);
         statusBar.setControllableInsetProvider(statusBarProvider);
+        statusBar.updateSourceFrame(statusBar.getFrame());
 
         statusBarProvider.onPostLayout();
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
index 0c2de5c..5265b44 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
@@ -23,9 +23,7 @@
 import static android.view.Display.INVALID_DISPLAY;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
@@ -279,51 +277,6 @@
     }
 
     /**
-     * Ensures that {@link LaunchParamsModifier} requests specifying display id during
-     * layout are honored.
-     */
-    @Test
-    public void testLayoutTaskPreferredDisplayChange() {
-        final LaunchParams params = new LaunchParams();
-        final TestDisplayContent display = createNewDisplayContent();
-        final TaskDisplayArea preferredTaskDisplayArea = display.getDefaultTaskDisplayArea();
-        params.mPreferredTaskDisplayArea = preferredTaskDisplayArea;
-        final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
-        final Task task = new TaskBuilder(mAtm.mTaskSupervisor).build();
-
-        mController.registerModifier(positioner);
-
-        doNothing().when(mRootWindowContainer).moveRootTaskToTaskDisplayArea(anyInt(), any(),
-                anyBoolean());
-        mController.layoutTask(task, null /* windowLayout */);
-        verify(mRootWindowContainer, times(1)).moveRootTaskToTaskDisplayArea(
-                eq(task.getRootTaskId()), eq(preferredTaskDisplayArea), anyBoolean());
-    }
-
-    /**
-     * Ensures that {@link LaunchParamsModifier} requests specifying windowingMode during
-     * layout are honored.
-     */
-    @Test
-    public void testLayoutTaskWindowingModeChange() {
-        final LaunchParams params = new LaunchParams();
-        final int windowingMode = WINDOWING_MODE_FREEFORM;
-        params.mWindowingMode = windowingMode;
-        final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
-        final Task task = new TaskBuilder(mAtm.mTaskSupervisor).build();
-
-        mController.registerModifier(positioner);
-
-        final int beforeWindowMode = task.getRootTask().getWindowingMode();
-        assertNotEquals(windowingMode, beforeWindowMode);
-
-        mController.layoutTask(task, null /* windowLayout */);
-
-        final int afterWindowMode = task.getRootTask().getWindowingMode();
-        assertEquals(windowingMode, afterWindowMode);
-    }
-
-    /**
      * Ensures that {@link LaunchParamsModifier} doesn't alter non-root tasks' windowingMode.
      */
     @Test
@@ -355,10 +308,10 @@
         final Rect expected = new Rect(10, 20, 30, 40);
 
         final LaunchParams params = new LaunchParams();
-        params.mWindowingMode = WINDOWING_MODE_FREEFORM;
         params.mBounds.set(expected);
         final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
-        final Task task = new TaskBuilder(mAtm.mTaskSupervisor).build();
+        final Task task = new TaskBuilder(mAtm.mTaskSupervisor)
+                .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
 
         mController.registerModifier(positioner);
 
@@ -380,10 +333,10 @@
         final Rect expected = new Rect(10, 20, 30, 40);
 
         final LaunchParams params = new LaunchParams();
-        params.mWindowingMode = WINDOWING_MODE_MULTI_WINDOW;
         params.mBounds.set(expected);
         final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
-        final Task task = new TaskBuilder(mAtm.mTaskSupervisor).build();
+        final Task task = new TaskBuilder(mAtm.mTaskSupervisor)
+                .setWindowingMode(WINDOWING_MODE_MULTI_WINDOW).build();
 
         mController.registerModifier(positioner);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 99ba3b8..762c08f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -20,6 +20,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+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_PINNED;
@@ -945,14 +946,16 @@
                 mWm, "TDA", FEATURE_VENDOR_FIRST);
         display.addChild(taskDisplayArea, POSITION_BOTTOM);
 
-        // Making sure getting the root task from the preferred TDA
+        // Making sure getting the root task from the preferred TDA and the preferred windowing mode
         LaunchParamsController.LaunchParams launchParams =
                 new LaunchParamsController.LaunchParams();
         launchParams.mPreferredTaskDisplayArea = taskDisplayArea;
+        launchParams.mWindowingMode = WINDOWING_MODE_FREEFORM;
         Task root = mRootWindowContainer.getOrCreateRootTask(null /* r */, null /* options */,
                 null /* candidateTask */, null /* sourceTask */, true /* onTop */, launchParams,
                 0 /* launchParams */);
         assertEquals(taskDisplayArea, root.getTaskDisplayArea());
+        assertEquals(WINDOWING_MODE_FREEFORM, root.getWindowingMode());
 
         // Making sure still getting the root task from the preferred TDA when passing in a
         // launching activity.
@@ -961,6 +964,7 @@
                 null /* candidateTask */, null /* sourceTask */, true /* onTop */, launchParams,
                 0 /* launchParams */);
         assertEquals(taskDisplayArea, root.getTaskDisplayArea());
+        assertEquals(WINDOWING_MODE_FREEFORM, root.getWindowingMode());
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index f999e49..ce86159 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -18,6 +18,7 @@
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.provider.DeviceConfig.NAMESPACE_CONSTRAIN_DISPLAY_APIS;
 import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;
 import static android.view.Display.DEFAULT_DISPLAY;
 
@@ -27,6 +28,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
@@ -36,6 +38,9 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 
+import static org.mockito.Mockito.CALLS_REAL_METHODS;
+import static org.mockito.Mockito.withSettings;
+
 import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
 import android.app.usage.UsageStatsManagerInternal;
@@ -57,6 +62,7 @@
 import android.os.PowerSaveState;
 import android.os.StrictMode;
 import android.os.UserHandle;
+import android.provider.DeviceConfig;
 import android.util.Log;
 import android.view.InputChannel;
 import android.view.Surface;
@@ -83,10 +89,12 @@
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
+import org.mockito.MockSettings;
 import org.mockito.Mockito;
 import org.mockito.quality.Strictness;
 
 import java.io.File;
+import java.util.ArrayList;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Supplier;
 
@@ -106,6 +114,13 @@
             .getSystemService(PowerManager.class).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
     private PowerManager.WakeLock mStubbedWakeLock;
 
+    /**
+     * The captured listeners will be unregistered in {@link #tearDown()} to avoid keeping static
+     * references of test instances from DeviceConfig.
+     */
+    private final ArrayList<DeviceConfig.OnPropertiesChangedListener> mDeviceConfigListeners =
+            new ArrayList<>();
+
     private Description mDescription;
     private Context mContext;
     private StaticMockitoSession mMockitoSession;
@@ -141,20 +156,29 @@
                             Log.e("SystemServicesTestRule", "Suppressed: ", throwable);
                             t.addSuppressed(throwable);
                         }
-                        throw t;
+                        throwable = t;
                     }
-                    if (throwable != null) throw throwable;
                 }
+                if (throwable != null) throw throwable;
             }
         };
     }
 
     private void setUp() {
+        // Use stubOnly() to reduce memory usage if it doesn't need verification.
+        final MockSettings spyStubOnly = withSettings().stubOnly()
+                .defaultAnswer(CALLS_REAL_METHODS);
+        final MockSettings mockStubOnly = withSettings().stubOnly();
+        // Return mocked services: LocalServices.getService
+        // Avoid real operation: SurfaceControl.mirrorSurface
+        // Avoid leakage: DeviceConfig.addOnPropertiesChangedListener, LockGuard.installLock
+        //                Watchdog.getInstance/addMonitor
         mMockitoSession = mockitoSession()
-                .spyStatic(LocalServices.class)
-                .spyStatic(SurfaceControl.class)
-                .mockStatic(LockGuard.class)
-                .mockStatic(Watchdog.class)
+                .mockStatic(LocalServices.class, spyStubOnly)
+                .mockStatic(DeviceConfig.class, spyStubOnly)
+                .mockStatic(SurfaceControl.class, mockStubOnly)
+                .mockStatic(LockGuard.class, mockStubOnly)
+                .mockStatic(Watchdog.class, mockStubOnly)
                 .strictness(Strictness.LENIENT)
                 .startMocking();
 
@@ -166,6 +190,16 @@
 
     private void setUpSystemCore() {
         doReturn(mock(Watchdog.class)).when(Watchdog::getInstance);
+        doAnswer(invocation -> {
+            // Exclude CONSTRAIN_DISPLAY_APIS because ActivityRecord#sConstrainDisplayApisConfig
+            // only registers once and it doesn't reference to outside.
+            if (!NAMESPACE_CONSTRAIN_DISPLAY_APIS.equals(invocation.getArgument(0))) {
+                mDeviceConfigListeners.add(invocation.getArgument(2));
+            }
+            // SizeCompatTests uses setNeverConstrainDisplayApisFlag, and ActivityRecordTests
+            // uses splash_screen_exception_list. So still execute real registration.
+            return invocation.callRealMethod();
+        }).when(() -> DeviceConfig.addOnPropertiesChangedListener(anyString(), any(), any()));
 
         mContext = getInstrumentation().getTargetContext();
         spyOn(mContext);
@@ -345,11 +379,10 @@
         // Unregister display listener from root to avoid issues with subsequent tests.
         mContext.getSystemService(DisplayManager.class)
                 .unregisterDisplayListener(mAtmService.mRootWindowContainer);
-        // The constructor of WindowManagerService registers WindowManagerConstants and
-        // HighRefreshRateBlacklist with DeviceConfig. We need to undo that here to avoid
-        // leaking mWmService.
-        mWmService.mConstants.dispose();
-        mWmService.mHighRefreshRateDenylist.dispose();
+
+        for (int i = mDeviceConfigListeners.size() - 1; i >= 0; i--) {
+            DeviceConfig.removeOnPropertiesChangedListener(mDeviceConfigListeners.get(i));
+        }
 
         // This makes sure the posted messages without delay are processed, e.g.
         // DisplayPolicy#release, WindowManagerService#setAnimationScale.
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRuleTest.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRuleTest.java
index 4056c71..2e7cc27 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRuleTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRuleTest.java
@@ -16,59 +16,64 @@
 
 package com.android.server.wm;
 
-import static junit.framework.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.fail;
 
 import android.platform.test.annotations.Presubmit;
 
-import org.junit.Rule;
+import com.android.internal.util.GcUtils;
+
 import org.junit.Test;
-import org.junit.rules.ExpectedException;
 import org.junit.runners.model.Statement;
 
-import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.function.Predicate;
 
 @Presubmit
 public class SystemServicesTestRuleTest {
-    @Rule
-    public ExpectedException mExpectedException = ExpectedException.none();
 
     @Test
-    public void testRule_rethrows_unchecked_exceptions() throws Throwable {
-        final SystemServicesTestRule mWmsRule = new SystemServicesTestRule();
-        Statement statement = new Statement() {
-            @Override
-            public void evaluate() throws Throwable {
-                throw new RuntimeException("A failing test!");
-            }
-        };
-        mExpectedException.expect(RuntimeException.class);
-        mWmsRule.apply(statement, null /* Description*/).evaluate();
-    }
-
-    @Test
-    public void testRule_rethrows_checked_exceptions() throws Throwable {
-        final SystemServicesTestRule mWmsRule = new SystemServicesTestRule();
-        Statement statement = new Statement() {
-            @Override
-            public void evaluate() throws Throwable {
-                throw new IOException("A failing test!");
-            }
-        };
-        mExpectedException.expect(IOException.class);
-        mWmsRule.apply(statement, null /* Description*/).evaluate();
+    public void testRule_rethrows_throwable() {
+        assertThrows(Throwable.class, () -> applyRule(rule -> false));
     }
 
     @Test
     public void testRule_ranSuccessfully() throws Throwable {
-        final boolean[] testRan = {false};
-        final SystemServicesTestRule mWmsRule = new SystemServicesTestRule();
-        Statement statement = new Statement() {
+        final int iterations = 5;
+        final ArrayList<WeakReference<WindowManagerService>> wmsRefs = new ArrayList<>();
+        for (int i = 0; i < iterations; i++) {
+            applyRule(rule -> {
+                final WindowManagerService wms = rule.getWindowManagerService();
+                assertNotNull(wms);
+                wmsRefs.add(new WeakReference<>(wms));
+                return true;
+            });
+        }
+        assertEquals(iterations, wmsRefs.size());
+
+        GcUtils.runGcAndFinalizersSync();
+        // Only ensure that at least one instance is released because some references may be kept
+        // temporally by the message of other thread or single static reference.
+        for (int i = wmsRefs.size() - 1; i >= 0; i--) {
+            if (wmsRefs.get(i).get() == null) {
+                return;
+            }
+        }
+        fail("WMS instance is leaked");
+    }
+
+    private static void applyRule(Predicate<SystemServicesTestRule> action) throws Throwable {
+        final SystemServicesTestRule wmsRule = new SystemServicesTestRule();
+        wmsRule.apply(new Statement() {
             @Override
             public void evaluate() throws Throwable {
-                testRan[0] = true;
+                if (!action.test(wmsRule)) {
+                    throw new Throwable("A failing test!");
+                }
             }
-        };
-        mWmsRule.apply(statement, null /* Description*/).evaluate();
-        assertTrue(testRan[0]);
+        }, null /* description */).evaluate();
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index 0debdfa..b1c9d3d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -18,6 +18,7 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
 import static com.android.server.wm.testing.Assert.assertThrows;
 
 import static org.junit.Assert.assertEquals;
@@ -249,19 +250,13 @@
         // the organizer.
         mTransaction.setBounds(mFragmentWindowToken, new Rect(0, 0, 100, 100));
 
-        assertThrows(SecurityException.class, () -> {
-            try {
-                mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
-            } catch (RemoteException e) {
-                fail();
-            }
-        });
+        assertApplyTransactionDisallowed(mTransaction);
 
         // Allow transaction to change a TaskFragment created by the organizer.
         mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
                 "Test:TaskFragmentOrganizer" /* processName */);
 
-        mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
     }
 
     @Test
@@ -272,19 +267,13 @@
         // the organizer.
         mTransaction.reorder(mFragmentWindowToken, true /* onTop */);
 
-        assertThrows(SecurityException.class, () -> {
-            try {
-                mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
-            } catch (RemoteException e) {
-                fail();
-            }
-        });
+        assertApplyTransactionDisallowed(mTransaction);
 
         // Allow transaction to change a TaskFragment created by the organizer.
         mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
                 "Test:TaskFragmentOrganizer" /* processName */);
 
-        mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
     }
 
     @Test
@@ -298,27 +287,21 @@
         // the organizer.
         mTransaction.deleteTaskFragment(mFragmentWindowToken);
 
-        assertThrows(SecurityException.class, () -> {
-            try {
-                mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
-            } catch (RemoteException e) {
-                fail();
-            }
-        });
+        assertApplyTransactionDisallowed(mTransaction);
 
         // Allow transaction to change a TaskFragment created by the organizer.
         mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
                 "Test:TaskFragmentOrganizer" /* processName */);
         clearInvocations(mAtm.mRootWindowContainer);
 
-        mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
 
         // No lifecycle update when the TaskFragment is not recorded.
         verify(mAtm.mRootWindowContainer, never()).resumeFocusedTasksTopActivities();
 
         mAtm.mWindowOrganizerController.mLaunchTaskFragments
                 .put(mFragmentToken, mTaskFragment);
-        mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
 
         verify(mAtm.mRootWindowContainer).resumeFocusedTasksTopActivities();
     }
@@ -335,13 +318,7 @@
         // the organizer.
         mTransaction.setAdjacentRoots(mFragmentWindowToken, token2, false /* moveTogether */);
 
-        assertThrows(SecurityException.class, () -> {
-            try {
-                mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
-            } catch (RemoteException e) {
-                fail();
-            }
-        });
+        assertApplyTransactionDisallowed(mTransaction);
 
         // Allow transaction to change a TaskFragment created by the organizer.
         mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
@@ -350,7 +327,7 @@
                 "Test:TaskFragmentOrganizer" /* processName */);
         clearInvocations(mAtm.mRootWindowContainer);
 
-        mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
 
         verify(mAtm.mRootWindowContainer).resumeFocusedTasksTopActivities();
     }
@@ -359,17 +336,11 @@
     public void testApplyTransaction_enforceHierarchyChange_createTaskFragment()
             throws RemoteException {
         mController.registerOrganizer(mIOrganizer);
-        final ActivityRecord activity = createActivityRecord(mDisplayContent);
-        final int uid = Binder.getCallingUid();
-        activity.info.applicationInfo.uid = uid;
-        activity.getTask().effectiveUid = uid;
+        final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent);
         final IBinder fragmentToken = new Binder();
-        final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
-                mOrganizerToken, fragmentToken, activity.token).build();
-        mOrganizer.applyTransaction(mTransaction);
 
         // Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
-        mTransaction.createTaskFragment(params);
+        createTaskFragmentFromOrganizer(mTransaction, ownerActivity, fragmentToken);
         mTransaction.startActivityInTaskFragment(
                 mFragmentToken, null /* callerToken */, new Intent(), null /* activityOptions */);
         mTransaction.reparentActivityToTaskFragment(mFragmentToken, mock(IBinder.class));
@@ -381,7 +352,7 @@
         final TaskFragment taskFragment = mAtm.mWindowOrganizerController
                 .getTaskFragment(fragmentToken);
         assertNotNull(taskFragment);
-        assertEquals(activity.getTask(), taskFragment.getTask());
+        assertEquals(ownerActivity.getTask(), taskFragment.getTask());
     }
 
     @Test
@@ -429,20 +400,14 @@
         // the organizer.
         mTransaction.reparentChildren(mFragmentWindowToken, null /* newParent */);
 
-        assertThrows(SecurityException.class, () -> {
-            try {
-                mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
-            } catch (RemoteException e) {
-                fail();
-            }
-        });
+        assertApplyTransactionDisallowed(mTransaction);
 
         // Allow transaction to change a TaskFragment created by the organizer.
         mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
                 "Test:TaskFragmentOrganizer" /* processName */);
         clearInvocations(mAtm.mRootWindowContainer);
 
-        mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
 
         verify(mAtm.mRootWindowContainer).resumeFocusedTasksTopActivities();
     }
@@ -460,6 +425,7 @@
         mAtm.mWindowOrganizerController.mLaunchTaskFragments
                 .put(mFragmentToken, mTaskFragment);
         mTransaction.reparentActivityToTaskFragment(mFragmentToken, activity.token);
+        doReturn(true).when(mTaskFragment).isAllowedToEmbedActivity(activity);
         clearInvocations(mAtm.mRootWindowContainer);
 
         mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
@@ -490,6 +456,40 @@
         verify(mOrganizer, never()).onTaskFragmentInfoChanged(any());
     }
 
+    @Test
+    public void testCanSendPendingTaskFragmentEventsAfterActivityResumed() {
+        // Task - TaskFragment - Activity.
+        final Task task = createTask(mDisplayContent);
+        final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
+                .setParentTask(task)
+                .setOrganizer(mOrganizer)
+                .setFragmentToken(mFragmentToken)
+                .createActivityCount(1)
+                .build();
+        final ActivityRecord activity = taskFragment.getTopMostActivity();
+
+        // Mock the task to invisible
+        doReturn(false).when(task).shouldBeVisible(any());
+        taskFragment.setResumedActivity(null, "test");
+
+        // Sending events
+        mController.registerOrganizer(mIOrganizer);
+        taskFragment.mTaskFragmentAppearedSent = true;
+        mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
+        mController.dispatchPendingEvents();
+
+        // Verifies that event was not sent
+        verify(mOrganizer, never()).onTaskFragmentInfoChanged(any());
+
+        // Mock the task becomes visible, and activity resumed
+        doReturn(true).when(task).shouldBeVisible(any());
+        taskFragment.setResumedActivity(activity, "test");
+
+        // Verifies that event is sent.
+        mController.dispatchPendingEvents();
+        verify(mOrganizer).onTaskFragmentInfoChanged(any());
+    }
+
     /**
      * Tests that a task fragment info changed event is still sent if the task is invisible only
      * when the info changed event is because of the last activity in a task finishing.
@@ -523,4 +523,123 @@
         mController.dispatchPendingEvents();
         verify(mOrganizer).onTaskFragmentInfoChanged(any());
     }
+
+    /**
+     * When an embedded {@link TaskFragment} is removed, we should clean up the reference in the
+     * {@link WindowOrganizerController}.
+     */
+    @Test
+    public void testTaskFragmentRemoved_cleanUpEmbeddedTaskFragment()
+            throws RemoteException {
+        mController.registerOrganizer(mIOrganizer);
+        final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent);
+        final IBinder fragmentToken = new Binder();
+        createTaskFragmentFromOrganizer(mTransaction, ownerActivity, fragmentToken);
+        mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+        final TaskFragment taskFragment = mAtm.mWindowOrganizerController
+                .getTaskFragment(fragmentToken);
+
+        assertNotNull(taskFragment);
+
+        taskFragment.removeImmediately();
+
+        assertNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
+    }
+
+    /**
+     * For config change to untrusted embedded TaskFragment, we only allow bounds change within
+     * its parent bounds.
+     */
+    @Test
+    public void testUntrustedEmbedding_configChange() throws RemoteException  {
+        mController.registerOrganizer(mIOrganizer);
+        mOrganizer.applyTransaction(mTransaction);
+        mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
+                "Test:TaskFragmentOrganizer" /* processName */);
+        doReturn(false).when(mTaskFragment).isAllowedToBeEmbeddedInTrustedMode();
+        final Task task = createTask(mDisplayContent);
+        final Rect taskBounds = new Rect(task.getBounds());
+        final Rect taskAppBounds = new Rect(task.getWindowConfiguration().getAppBounds());
+        final int taskScreenWidthDp = task.getConfiguration().screenWidthDp;
+        final int taskScreenHeightDp = task.getConfiguration().screenHeightDp;
+        final int taskSmallestScreenWidthDp = task.getConfiguration().smallestScreenWidthDp;
+        task.addChild(mTaskFragment, POSITION_TOP);
+
+        // Throw exception if the transaction is trying to change bounds of an untrusted outside of
+        // its parent's.
+
+        // setBounds
+        final Rect tfBounds = new Rect(taskBounds);
+        tfBounds.right++;
+        mTransaction.setBounds(mFragmentWindowToken, tfBounds);
+        assertApplyTransactionDisallowed(mTransaction);
+
+        mTransaction.setBounds(mFragmentWindowToken, taskBounds);
+        assertApplyTransactionAllowed(mTransaction);
+
+        // setAppBounds
+        final Rect tfAppBounds = new Rect(taskAppBounds);
+        tfAppBounds.right++;
+        mTransaction.setAppBounds(mFragmentWindowToken, tfAppBounds);
+        assertApplyTransactionDisallowed(mTransaction);
+
+        mTransaction.setAppBounds(mFragmentWindowToken, taskAppBounds);
+        assertApplyTransactionAllowed(mTransaction);
+
+        // setScreenSizeDp
+        mTransaction.setScreenSizeDp(mFragmentWindowToken, taskScreenWidthDp + 1,
+                taskScreenHeightDp + 1);
+        assertApplyTransactionDisallowed(mTransaction);
+
+        mTransaction.setScreenSizeDp(mFragmentWindowToken, taskScreenWidthDp, taskScreenHeightDp);
+        assertApplyTransactionAllowed(mTransaction);
+
+        // setSmallestScreenWidthDp
+        mTransaction.setSmallestScreenWidthDp(mFragmentWindowToken, taskSmallestScreenWidthDp + 1);
+        assertApplyTransactionDisallowed(mTransaction);
+
+        mTransaction.setSmallestScreenWidthDp(mFragmentWindowToken, taskSmallestScreenWidthDp);
+        assertApplyTransactionAllowed(mTransaction);
+
+        // Any of the change mask is not allowed.
+        mTransaction.setFocusable(mFragmentWindowToken, false);
+        assertApplyTransactionDisallowed(mTransaction);
+    }
+
+    /**
+     * Creates a {@link TaskFragment} with the {@link WindowContainerTransaction}. Calls
+     * {@link WindowOrganizerController#applyTransaction} to apply the transaction,
+     */
+    private void createTaskFragmentFromOrganizer(WindowContainerTransaction wct,
+            ActivityRecord ownerActivity, IBinder fragmentToken) {
+        final int uid = Binder.getCallingUid();
+        ownerActivity.info.applicationInfo.uid = uid;
+        ownerActivity.getTask().effectiveUid = uid;
+        final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
+                mOrganizerToken, fragmentToken, ownerActivity.token).build();
+        mOrganizer.applyTransaction(wct);
+
+        // Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
+        wct.createTaskFragment(params);
+    }
+
+    /** Asserts that applying the given transaction will throw a {@link SecurityException}. */
+    private void assertApplyTransactionDisallowed(WindowContainerTransaction t) {
+        assertThrows(SecurityException.class, () -> {
+            try {
+                mAtm.getWindowOrganizerController().applyTransaction(t);
+            } catch (RemoteException e) {
+                fail();
+            }
+        });
+    }
+
+    /** Asserts that applying the given transaction will not throw any exception. */
+    private void assertApplyTransactionAllowed(WindowContainerTransaction t) {
+        try {
+            mAtm.getWindowOrganizerController().applyTransaction(t);
+        } catch (RemoteException e) {
+            fail();
+        }
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index 730275c..189a1da 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -149,4 +149,25 @@
         assertEquals(false, info.isEmpty());
         assertEquals(activity.token, info.getActivities().get(0));
     }
+
+    @Test
+    public void testActivityVisibilityBehindTranslucentTaskFragment() {
+        // Having an activity covered by a translucent TaskFragment:
+        // Task
+        //   - TaskFragment
+        //      - Activity (Translucent)
+        //   - Activity
+        ActivityRecord translucentActivity = new ActivityBuilder(mAtm)
+                .setUid(DEFAULT_TASK_FRAGMENT_ORGANIZER_UID).build();
+        mTaskFragment.addChild(translucentActivity);
+        doReturn(true).when(mTaskFragment).isTranslucent(any());
+
+        ActivityRecord activityBelow = new ActivityBuilder(mAtm).build();
+        mTaskFragment.getTask().addChild(activityBelow, 0);
+
+        // Ensure the activity below is visible
+        mTaskFragment.getTask().ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
+                false /* preserveWindows */);
+        assertEquals(true, activityBelow.isVisibleRequested());
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
index 70d71bc..7409d62 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
@@ -31,13 +31,13 @@
 import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
-import android.window.TaskSnapshot;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
 import android.util.ArraySet;
 import android.view.Surface;
+import android.window.TaskSnapshot;
 
 import androidx.test.filters.MediumTest;
 
@@ -83,6 +83,12 @@
         assertEquals(TEST_INSETS, snapshot.getContentInsets());
         assertNotNull(snapshot.getSnapshot());
         assertEquals(Configuration.ORIENTATION_PORTRAIT, snapshot.getOrientation());
+
+        snapshot.getHardwareBuffer().close();
+        mPersister.persistSnapshot(1, mTestUserId, snapshot);
+        mPersister.waitForQueueEmpty();
+        assertTrueForFiles(files, file -> !file.exists(),
+                " snapshot files must be removed by invalid buffer");
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
index 437d418..f71ed2f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
@@ -131,8 +131,7 @@
     }
 
     TaskSnapshot createSnapshot() {
-        return new TaskSnapshotBuilder()
-                .build();
+        return new TaskSnapshotBuilder().setTopActivityComponent(getUniqueComponentName()).build();
     }
 
     protected static void assertTrueForFiles(File[] files, Predicate<File> predicate,
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 636c6bc..9304761 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -259,6 +259,20 @@
     }
 
     @Test
+    public void testPerformClearTop() {
+        final Task task = createTask(mDisplayContent);
+        final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
+        final ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(task).build();
+        // Detach from process so the activities can be removed from hierarchy when finishing.
+        activity1.detachFromProcess();
+        activity2.detachFromProcess();
+        assertNull(task.performClearTop(activity1, 0 /* launchFlags */));
+        assertFalse(task.hasChild());
+        // In real case, the task should be preserved for adding new activity.
+        assertTrue(task.isAttached());
+    }
+
+    @Test
     public void testRemoveChildForOverlayTask() {
         final Task task = createTask(mDisplayContent);
         final int taskId = task.mTaskId;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
index 7dfb5ae..7cf4b2e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
@@ -44,7 +44,7 @@
     @Override
     public void resized(ClientWindowFrames frames, boolean reportDraw,
             MergedConfiguration mergedConfig, boolean forceLayout, boolean alwaysConsumeSystemBars,
-            int displayId) throws RemoteException {
+            int displayId, int seqId, int resizeMode) throws RemoteException {
     }
 
     @Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index c4547f6..3330ca9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -617,8 +617,8 @@
         }
         player.startTransition();
 
-        assertFalse(statusBar.mToken.inTransition());
-        assertFalse(decorToken.inTransition());
+        assertFalse(mDisplayContent.mTransitionController.isCollecting(statusBar.mToken));
+        assertFalse(mDisplayContent.mTransitionController.isCollecting(decorToken));
         assertTrue(ime.mToken.inTransition());
         assertTrue(task.inTransition());
         assertTrue(asyncRotationController.isTargetToken(decorToken));
@@ -692,7 +692,8 @@
         statusBar.mWinAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
         final SurfaceControl.Transaction postDrawTransaction =
                 mock(SurfaceControl.Transaction.class);
-        final boolean layoutNeeded = statusBar.finishDrawing(postDrawTransaction);
+        final boolean layoutNeeded = statusBar.finishDrawing(postDrawTransaction,
+                Integer.MAX_VALUE);
         assertFalse(layoutNeeded);
 
         transactionCommittedListener.onTransactionCommitted();
@@ -734,7 +735,7 @@
         statusBar.setOrientationChanging(true);
         player.startTransition();
         // Non-app windows should not be collected.
-        assertFalse(statusBar.mToken.inTransition());
+        assertFalse(mDisplayContent.mTransitionController.isCollecting(statusBar.mToken));
 
         onRotationTransactionReady(player, mWm.mTransactionFactory.get()).onTransactionCommitted();
         assertEquals(ROTATION_ANIMATION_SEAMLESS, player.mLastReady.getChange(
@@ -742,7 +743,7 @@
         player.finish();
 
         // The controller should be cleared if the target windows are drawn.
-        statusBar.finishDrawing(mWm.mTransactionFactory.get());
+        statusBar.finishDrawing(mWm.mTransactionFactory.get(), Integer.MAX_VALUE);
         statusBar.setOrientationChanging(false);
         assertNull(mDisplayContent.getAsyncRotationController());
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerInsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerInsetsSourceProviderTest.java
index 10e4292..e824f3d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerInsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerInsetsSourceProviderTest.java
@@ -64,6 +64,7 @@
         statusBar.getFrame().set(0, 0, 500, 100);
         statusBar.mHasSurface = true;
         mProvider.setWindowContainer(statusBar, null, null);
+        mProvider.updateSourceFrame(statusBar.getFrame());
         mProvider.onPostLayout();
         assertEquals(new Rect(0, 0, 500, 100), mProvider.getSource().getFrame());
         assertEquals(Insets.of(0, 100, 0, 0),
@@ -81,6 +82,7 @@
         ime.mGivenVisibleInsets.set(0, 0, 0, 75);
         ime.mHasSurface = true;
         mProvider.setWindowContainer(ime, null, null);
+        mProvider.updateSourceFrame(ime.getFrame());
         mProvider.onPostLayout();
         assertEquals(new Rect(0, 0, 500, 40), mProvider.getSource().getFrame());
         assertEquals(new Rect(0, 0, 500, 25), mProvider.getSource().getVisibleFrame());
@@ -96,6 +98,7 @@
         final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
         statusBar.getFrame().set(0, 0, 500, 100);
         mProvider.setWindowContainer(statusBar, null, null);
+        mProvider.updateSourceFrame(statusBar.getFrame());
         mProvider.onPostLayout();
         assertEquals(Insets.NONE, mProvider.getSource().calculateInsets(new Rect(0, 0, 500, 500),
                 false /* ignoreVisibility */));
@@ -110,6 +113,7 @@
                 (displayFrames, windowState, rect) -> {
                     rect.set(10, 10, 20, 20);
                 }, null);
+        mProvider.updateSourceFrame(statusBar.getFrame());
         mProvider.onPostLayout();
         assertEquals(new Rect(10, 10, 20, 20), mProvider.getSource().getFrame());
     }
@@ -181,7 +185,7 @@
         mImeProvider.setWindowContainer(inputMethod, null, null);
         mImeProvider.setServerVisible(false);
         mImeSource.setVisible(true);
-        mImeProvider.updateSourceFrame();
+        mImeProvider.updateSourceFrame(inputMethod.getFrame());
         assertEquals(new Rect(0, 0, 0, 0), mImeSource.getFrame());
         Insets insets = mImeSource.calculateInsets(new Rect(0, 0, 500, 500),
                 false /* ignoreVisibility */);
@@ -189,7 +193,7 @@
 
         mImeProvider.setServerVisible(true);
         mImeSource.setVisible(true);
-        mImeProvider.updateSourceFrame();
+        mImeProvider.updateSourceFrame(inputMethod.getFrame());
         assertEquals(inputMethod.getFrame(), mImeSource.getFrame());
         insets = mImeSource.calculateInsets(new Rect(0, 0, 500, 500),
                 false /* ignoreVisibility */);
@@ -229,6 +233,7 @@
         statusBar.getFrame().set(0, 0, 500, 100);
         statusBar.mHasSurface = true;
         mProvider.setWindowContainer(statusBar, null, null);
+        mProvider.updateSourceFrame(statusBar.getFrame());
         mProvider.onPostLayout();
         assertEquals(new Rect(0, 0, 500, 100), mProvider.getSource().getFrame());
         // Still apply top insets if window overlaps even if it's top doesn't exactly match
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowLayoutTests.java
index 7d2e9bf..ea18e58 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowLayoutTests.java
@@ -45,6 +45,7 @@
 import android.view.WindowInsets;
 import android.view.WindowLayout;
 import android.view.WindowManager;
+import android.window.ClientWindowFrames;
 
 import androidx.test.filters.SmallTest;
 
@@ -71,9 +72,7 @@
     private static final Insets WATERFALL_INSETS = Insets.of(6, 0, 12, 0);
 
     private final WindowLayout mWindowLayout = new WindowLayout();
-    private final Rect mDisplayFrame = new Rect();
-    private final Rect mParentFrame = new Rect();
-    private final Rect mFrame = new Rect();
+    private final ClientWindowFrames mOutFrames = new ClientWindowFrames();
 
     private WindowManager.LayoutParams mAttrs;
     private InsetsState mState;
@@ -108,7 +107,7 @@
     private void computeFrames() {
         mWindowLayout.computeFrames(mAttrs, mState, mDisplayCutoutSafe, mWindowBounds,
                 mWindowingMode, mRequestedWidth, mRequestedHeight, mRequestedVisibilities,
-                mAttachedWindowFrame, mCompatScale, mDisplayFrame, mParentFrame, mFrame);
+                mAttachedWindowFrame, mCompatScale, mOutFrames);
     }
 
     private void addDisplayCutout() {
@@ -146,9 +145,9 @@
     public void defaultParams() {
         computeFrames();
 
-        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
-        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
-        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.displayFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.parentFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.frame);
     }
 
     @Test
@@ -157,9 +156,9 @@
         mRequestedHeight = UNSPECIFIED_LENGTH;
         computeFrames();
 
-        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
-        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
-        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.displayFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.parentFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.frame);
     }
 
     @Test
@@ -173,9 +172,9 @@
         mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
         computeFrames();
 
-        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
-        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
-        assertRect(0, STATUS_BAR_HEIGHT, width, STATUS_BAR_HEIGHT + height, mFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.displayFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.parentFrame);
+        assertRect(0, STATUS_BAR_HEIGHT, width, STATUS_BAR_HEIGHT + height, mOutFrames.frame);
     }
 
     @Test
@@ -186,9 +185,12 @@
         mRequestedHeight = UNSPECIFIED_LENGTH;
         computeFrames();
 
-        assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, mDisplayFrame);
-        assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, mParentFrame);
-        assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, mFrame);
+        assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
+                mOutFrames.displayFrame);
+        assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
+                mOutFrames.parentFrame);
+        assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
+                mOutFrames.frame);
     }
 
     @Test
@@ -196,9 +198,9 @@
         mAttrs.setFitInsetsTypes(WindowInsets.Type.statusBars());
         computeFrames();
 
-        assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mDisplayFrame);
-        assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mParentFrame);
-        assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mOutFrames.displayFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mOutFrames.parentFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mOutFrames.frame);
     }
 
     @Test
@@ -206,9 +208,9 @@
         mAttrs.setFitInsetsTypes(WindowInsets.Type.navigationBars());
         computeFrames();
 
-        assertInsetByTopBottom(0, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
-        assertInsetByTopBottom(0, NAVIGATION_BAR_HEIGHT, mParentFrame);
-        assertInsetByTopBottom(0, NAVIGATION_BAR_HEIGHT, mFrame);
+        assertInsetByTopBottom(0, NAVIGATION_BAR_HEIGHT, mOutFrames.displayFrame);
+        assertInsetByTopBottom(0, NAVIGATION_BAR_HEIGHT, mOutFrames.parentFrame);
+        assertInsetByTopBottom(0, NAVIGATION_BAR_HEIGHT, mOutFrames.frame);
     }
 
     @Test
@@ -216,9 +218,9 @@
         mAttrs.setFitInsetsTypes(0);
         computeFrames();
 
-        assertInsetByTopBottom(0, 0, mDisplayFrame);
-        assertInsetByTopBottom(0, 0, mParentFrame);
-        assertInsetByTopBottom(0, 0, mFrame);
+        assertInsetByTopBottom(0, 0, mOutFrames.displayFrame);
+        assertInsetByTopBottom(0, 0, mOutFrames.parentFrame);
+        assertInsetByTopBottom(0, 0, mOutFrames.frame);
     }
 
     @Test
@@ -226,9 +228,9 @@
         mAttrs.setFitInsetsSides(WindowInsets.Side.all());
         computeFrames();
 
-        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
-        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
-        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.displayFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.parentFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.frame);
     }
 
     @Test
@@ -236,9 +238,9 @@
         mAttrs.setFitInsetsSides(WindowInsets.Side.TOP);
         computeFrames();
 
-        assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mDisplayFrame);
-        assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mParentFrame);
-        assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mOutFrames.displayFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mOutFrames.parentFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mOutFrames.frame);
     }
 
     @Test
@@ -246,9 +248,9 @@
         mAttrs.setFitInsetsSides(0);
         computeFrames();
 
-        assertInsetByTopBottom(0, 0, mDisplayFrame);
-        assertInsetByTopBottom(0, 0, mParentFrame);
-        assertInsetByTopBottom(0, 0, mFrame);
+        assertInsetByTopBottom(0, 0, mOutFrames.displayFrame);
+        assertInsetByTopBottom(0, 0, mOutFrames.parentFrame);
+        assertInsetByTopBottom(0, 0, mOutFrames.frame);
     }
 
     @Test
@@ -257,9 +259,9 @@
         mState.getSource(ITYPE_NAVIGATION_BAR).setVisible(false);
         computeFrames();
 
-        assertInsetByTopBottom(0, 0, mDisplayFrame);
-        assertInsetByTopBottom(0, 0, mParentFrame);
-        assertInsetByTopBottom(0, 0, mFrame);
+        assertInsetByTopBottom(0, 0, mOutFrames.displayFrame);
+        assertInsetByTopBottom(0, 0, mOutFrames.parentFrame);
+        assertInsetByTopBottom(0, 0, mOutFrames.frame);
     }
 
     @Test
@@ -269,9 +271,9 @@
         mAttrs.setFitInsetsIgnoringVisibility(true);
         computeFrames();
 
-        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
-        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
-        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.displayFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.parentFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.frame);
     }
 
     @Test
@@ -282,9 +284,9 @@
         mAttrs.privateFlags |= PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
         computeFrames();
 
-        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
-        assertInsetByTopBottom(STATUS_BAR_HEIGHT, IME_HEIGHT, mParentFrame);
-        assertInsetByTopBottom(STATUS_BAR_HEIGHT, IME_HEIGHT, mFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.displayFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, IME_HEIGHT, mOutFrames.parentFrame);
+        assertInsetByTopBottom(STATUS_BAR_HEIGHT, IME_HEIGHT, mOutFrames.frame);
     }
 
     @Test
@@ -295,11 +297,11 @@
         computeFrames();
 
         assertInsetBy(WATERFALL_INSETS.left, DISPLAY_CUTOUT_HEIGHT, WATERFALL_INSETS.right, 0,
-                mDisplayFrame);
+                mOutFrames.displayFrame);
         assertInsetBy(WATERFALL_INSETS.left, DISPLAY_CUTOUT_HEIGHT, WATERFALL_INSETS.right, 0,
-                mParentFrame);
+                mOutFrames.parentFrame);
         assertInsetBy(WATERFALL_INSETS.left, DISPLAY_CUTOUT_HEIGHT, WATERFALL_INSETS.right, 0,
-                mFrame);
+                mOutFrames.frame);
     }
 
     @Test
@@ -310,11 +312,11 @@
         computeFrames();
 
         assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
-                mDisplayFrame);
+                mOutFrames.displayFrame);
         assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
-                mParentFrame);
+                mOutFrames.parentFrame);
         assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
-                mFrame);
+                mOutFrames.frame);
     }
 
     @Test
@@ -325,9 +327,9 @@
         mAttrs.setFitInsetsTypes(0);
         computeFrames();
 
-        assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mDisplayFrame);
-        assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mParentFrame);
-        assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mFrame);
+        assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mOutFrames.displayFrame);
+        assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mOutFrames.parentFrame);
+        assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mOutFrames.frame);
     }
 
     @Test
@@ -342,9 +344,9 @@
         mAttrs.privateFlags |= PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT;
         computeFrames();
 
-        assertRect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayFrame);
-        assertRect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, mParentFrame);
-        assertRect(0, 0, DISPLAY_WIDTH, height + DISPLAY_CUTOUT_HEIGHT, mFrame);
+        assertRect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, mOutFrames.displayFrame);
+        assertRect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, mOutFrames.parentFrame);
+        assertRect(0, 0, DISPLAY_WIDTH, height + DISPLAY_CUTOUT_HEIGHT, mOutFrames.frame);
     }
 
     @Test
@@ -357,11 +359,11 @@
         computeFrames();
 
         assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
-                mDisplayFrame);
+                mOutFrames.displayFrame);
         assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
-                mParentFrame);
+                mOutFrames.parentFrame);
         assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
-                mFrame);
+                mOutFrames.frame);
     }
 
     @Test
@@ -371,9 +373,9 @@
         mAttrs.setFitInsetsTypes(0);
         computeFrames();
 
-        assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mDisplayFrame);
-        assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mParentFrame);
-        assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mFrame);
+        assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mOutFrames.displayFrame);
+        assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mOutFrames.parentFrame);
+        assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mOutFrames.frame);
     }
 
     @Test
@@ -384,11 +386,11 @@
         computeFrames();
 
         assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
-                mDisplayFrame);
+                mOutFrames.displayFrame);
         assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
-                mParentFrame);
+                mOutFrames.parentFrame);
         assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
-                mFrame);
+                mOutFrames.frame);
     }
 
     @Test
@@ -398,8 +400,8 @@
         mAttrs.setFitInsetsTypes(0);
         computeFrames();
 
-        assertInsetByTopBottom(0, 0, mDisplayFrame);
-        assertInsetByTopBottom(0, 0, mParentFrame);
-        assertInsetByTopBottom(0, 0, mFrame);
+        assertInsetByTopBottom(0, 0, mOutFrames.displayFrame);
+        assertInsetByTopBottom(0, 0, mOutFrames.parentFrame);
+        assertInsetByTopBottom(0, 0, mOutFrames.frame);
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 08320f8..a0c20c2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -70,7 +70,7 @@
 
 /**
  * Build/Install/Run:
- *  atest WmTests:WindowManagerServiceTests
+ * atest WmTests:WindowManagerServiceTests
  */
 @SmallTest
 @Presubmit
@@ -266,7 +266,8 @@
         final WindowToken windowToken = createTestWindowToken(TYPE_INPUT_METHOD, mDefaultDisplay);
         final Session session = new Session(mWm, new IWindowSessionCallback.Stub() {
             @Override
-            public void onAnimatorScaleChanged(float v) throws RemoteException {}
+            public void onAnimatorScaleChanged(float v) throws RemoteException {
+            }
         });
         final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                 TYPE_APPLICATION_ATTACHED_DIALOG);
@@ -291,8 +292,9 @@
         boolean currentTouchMode = mWm.getInTouchMode();
         int callingPid = Binder.getCallingPid();
         int callingUid = Binder.getCallingUid();
-        doReturn(false).when(mWm).checkCallingPermission(anyString(), anyString());
-        when(mWm.mAtmService.isInstrumenting(callingPid)).thenReturn(true);
+        doReturn(false).when(mWm).checkCallingPermission(anyString(), anyString(), anyBoolean());
+        when(mWm.mAtmService.instrumentationSourceHasPermission(callingPid,
+                android.Manifest.permission.MODIFY_TOUCH_MODE_STATE)).thenReturn(true);
 
         mWm.setInTouchMode(!currentTouchMode);
 
@@ -305,8 +307,9 @@
         boolean currentTouchMode = mWm.getInTouchMode();
         int callingPid = Binder.getCallingPid();
         int callingUid = Binder.getCallingUid();
-        doReturn(false).when(mWm).checkCallingPermission(anyString(), anyString());
-        when(mWm.mAtmService.isInstrumenting(callingPid)).thenReturn(false);
+        doReturn(false).when(mWm).checkCallingPermission(anyString(), anyString(), anyBoolean());
+        when(mWm.mAtmService.instrumentationSourceHasPermission(callingPid,
+                android.Manifest.permission.MODIFY_TOUCH_MODE_STATE)).thenReturn(false);
 
         mWm.setInTouchMode(!currentTouchMode);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 25d7334..9faf499 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -309,6 +309,51 @@
     }
 
     @Test
+    public void testOrganizerDeathReturnsRegistrationToPrevious() throws RemoteException {
+        final Task rootTask = createRootTask();
+        final Task task = createTask(rootTask);
+        final Task rootTask2 = createRootTask();
+        final Task task2 = createTask(rootTask2);
+        final Task rootTask3 = createRootTask();
+        final Task task3 = createTask(rootTask3);
+        final ArrayList<TaskAppearedInfo> existingTasks = new ArrayList<>();
+        final ITaskOrganizer organizer = registerMockOrganizer(existingTasks);
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
+
+        // verify that tasks are returned and taskAppeared is not called
+        assertContainsTasks(existingTasks, rootTask, rootTask2, rootTask3);
+        verify(organizer, times(0)).onTaskAppeared(any(RunningTaskInfo.class),
+                any(SurfaceControl.class));
+        verify(organizer, times(0)).onTaskVanished(any());
+        assertTrue(rootTask.isOrganized());
+
+        // Now we replace the registration and verify the new organizer receives existing tasks
+        final ArrayList<TaskAppearedInfo> existingTasks2 = new ArrayList<>();
+        final ITaskOrganizer organizer2 = registerMockOrganizer(existingTasks2);
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
+        assertContainsTasks(existingTasks2, rootTask, rootTask2, rootTask3);
+        verify(organizer2, times(0)).onTaskAppeared(any(RunningTaskInfo.class),
+                any(SurfaceControl.class));
+        verify(organizer2, times(0)).onTaskVanished(any());
+        // Removed tasks from the original organizer
+        assertTaskVanished(organizer, true /* expectVanished */, rootTask, rootTask2, rootTask3);
+        assertTrue(rootTask2.isOrganized());
+
+        // Trigger binderDied for second one, the first one should automatically be reregistered
+        // so we verify that it's now seeing changes.
+        mWm.mAtmService.mTaskOrganizerController.getTaskOrganizerState(organizer2.asBinder())
+                .getDeathRecipient().binderDied();
+
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
+        verify(organizer, times(3))
+                .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
+        assertTaskVanished(organizer2, true /* expectVanished */, rootTask, rootTask2, rootTask3);
+    }
+
+    @Test
     public void testRegisterTaskOrganizerWithExistingTasks() throws RemoteException {
         final Task rootTask = createRootTask();
         final Task task = createTask(rootTask);
@@ -932,7 +977,7 @@
         mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         assertNotNull(o.mChangedInfo);
         assertNotNull(o.mChangedInfo.pictureInPictureParams);
-        final Rational ratio = o.mChangedInfo.pictureInPictureParams.getAspectRatioRational();
+        final Rational ratio = o.mChangedInfo.pictureInPictureParams.getAspectRatio();
         assertEquals(3, ratio.getNumerator());
         assertEquals(4, ratio.getDenominator());
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index e4f691b..91bde7b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -504,7 +504,7 @@
         assertTrue(win.useBLASTSync());
         final SurfaceControl.Transaction drawT = new StubTransaction();
         win.prepareDrawHandlers();
-        assertTrue(win.finishDrawing(drawT));
+        assertTrue(win.finishDrawing(drawT, Integer.MAX_VALUE));
         assertEquals(drawT, handledT[0]);
         assertFalse(win.useBLASTSync());
 
@@ -693,7 +693,7 @@
             doThrow(new RemoteException("test")).when(win.mClient).resized(any() /* frames */,
                     anyBoolean() /* reportDraw */, any() /* mergedConfig */,
                     anyBoolean() /* forceLayout */, anyBoolean() /* alwaysConsumeSystemBars */,
-                    anyInt() /* displayId */);
+                    anyInt() /* displayId */, anyInt() /* seqId */, anyInt() /* resizeMode */);
         } catch (RemoteException ignored) {
         }
         win.reportResized();
@@ -820,7 +820,6 @@
     @Test
     public void testHasActiveVisibleWindow() {
         final int uid = ActivityBuilder.DEFAULT_FAKE_UID;
-        mAtm.mActiveUids.onUidActive(uid, 0 /* any proc state */);
 
         final WindowState app = createWindow(null, TYPE_APPLICATION, "app", uid);
         app.mActivityRecord.setVisible(false);
@@ -848,6 +847,11 @@
         // Make the application overlay window visible. It should be a valid active visible window.
         overlay.onSurfaceShownChanged(true);
         assertTrue(mAtm.hasActiveVisibleWindow(uid));
+
+        // The number of windows should be independent of the existence of uid state.
+        mAtm.mActiveUids.onUidInactive(uid);
+        mAtm.mActiveUids.onUidActive(uid, 0 /* any proc state */);
+        assertTrue(mAtm.mActiveUids.hasNonAppVisibleWindow(uid));
     }
 
     @UseTestDisplay(addWindows = W_ACTIVITY)
@@ -945,6 +949,46 @@
         assertFalse(app2.getInsetsState().getSource(ITYPE_IME).isVisible());
     }
 
+    @Test
+    public void testAdjustImeInsetsVisibilityWhenSwitchingApps_toAppInMultiWindowMode() {
+        final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+        final WindowState app2 = createWindow(null, WINDOWING_MODE_MULTI_WINDOW,
+                ACTIVITY_TYPE_STANDARD, TYPE_APPLICATION, mDisplayContent, "app2");
+        final WindowState imeWindow = createWindow(null, TYPE_APPLICATION, "imeWindow");
+        spyOn(imeWindow);
+        doReturn(true).when(imeWindow).isVisible();
+        mDisplayContent.mInputMethodWindow = imeWindow;
+
+        final InsetsStateController controller = mDisplayContent.getInsetsStateController();
+        controller.getImeSourceProvider().setWindowContainer(imeWindow, null, null);
+
+        // Simulate app2 in multi-window mode is going to background to switch to the fullscreen
+        // app which requests IME with updating all windows Insets State when IME is above app.
+        app2.mActivityRecord.mImeInsetsFrozenUntilStartInput = true;
+        mDisplayContent.setImeLayeringTarget(app);
+        mDisplayContent.setImeInputTarget(app);
+        assertTrue(mDisplayContent.shouldImeAttachedToApp());
+        controller.getImeSourceProvider().scheduleShowImePostLayout(app);
+        controller.getImeSourceProvider().getSource().setVisible(true);
+        controller.updateAboveInsetsState(false);
+
+        // Expect app windows behind IME can receive IME insets visible,
+        // but not for app2 in background.
+        assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible());
+        assertFalse(app2.getInsetsState().getSource(ITYPE_IME).isVisible());
+
+        // Simulate app plays closing transition to app2.
+        // And app2 is now IME layering target but not yet to be the IME input target.
+        mDisplayContent.setImeLayeringTarget(app2);
+        app.mActivityRecord.commitVisibility(false, false);
+        assertTrue(app.mActivityRecord.mLastImeShown);
+        assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+        // Verify the IME insets is still visible on app, but not for app2 during task switching.
+        assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible());
+        assertFalse(app2.getInsetsState().getSource(ITYPE_IME).isVisible());
+    }
+
     @UseTestDisplay(addWindows = {W_ACTIVITY})
     @Test
     public void testUpdateImeControlTargetWhenLeavingMultiWindow() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index bd1f9d5..bcab4a5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -903,7 +903,7 @@
         doReturn(100).when(hardwareBuffer).getHeight();
     }
 
-    private static ComponentName getUniqueComponentName() {
+    static ComponentName getUniqueComponentName() {
         return ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
                 DEFAULT_COMPONENT_CLASS_NAME + sCurrentActivityId++);
     }
@@ -1264,6 +1264,7 @@
                         mOrganizer.getOrganizerToken(), DEFAULT_TASK_FRAGMENT_ORGANIZER_UID,
                         DEFAULT_TASK_FRAGMENT_ORGANIZER_PROCESS_NAME);
             }
+            spyOn(taskFragment);
             return taskFragment;
         }
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index eea3f84..0f223ca 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -293,8 +293,7 @@
     public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() {
         final WindowState appBelowImeTarget = createWindow("appBelowImeTarget");
         final WindowState imeAppTarget = createWindow("imeAppTarget");
-        final WindowState appAboveImeTarget = createWindow(imeAppTarget, TYPE_APPLICATION,
-                "appAboveImeTarget");
+        final WindowState appAboveImeTarget = createWindow("appAboveImeTarget");
 
         mDisplayContent.setImeLayeringTarget(imeAppTarget);
         mDisplayContent.setImeControlTarget(imeAppTarget);
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
index 364d592..3833ceb 100644
--- a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
+++ b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
@@ -17,6 +17,7 @@
 package com.android.server.translation;
 
 import static android.view.translation.TranslationManager.EXTRA_CAPABILITIES;
+import static android.view.translation.UiTranslationManager.EXTRA_PACKAGE_NAME;
 import static android.view.translation.UiTranslationManager.EXTRA_SOURCE_LOCALE;
 import static android.view.translation.UiTranslationManager.EXTRA_STATE;
 import static android.view.translation.UiTranslationManager.EXTRA_TARGET_LOCALE;
@@ -184,7 +185,7 @@
                         componentName.getPackageName(), 0, userId).uid;
             }
         } catch (PackageManager.NameNotFoundException e) {
-            Slog.d(TAG, "Cannot find packageManager for" +  componentName);
+            Slog.d(TAG, "Cannot find packageManager for" + componentName);
         }
         return translationActivityUid;
     }
@@ -192,19 +193,22 @@
     @GuardedBy("mLock")
     public void onTranslationFinishedLocked(boolean activityDestroyed, IBinder token,
             ComponentName componentName) {
-        int translationActivityUid =
+        final int translationActivityUid =
                 getActivityUidByComponentName(getContext(), componentName, getUserId());
+        final String packageName = componentName.getPackageName();
         if (activityDestroyed) {
             // In the Activity destroy case, we only calls onTranslationFinished() in
             // non-finisTranslation() state. If there is a finisTranslation() calls by apps, we
             // should remove the waiting callback to avoid callback twice.
-            invokeCallbacks(STATE_UI_TRANSLATION_FINISHED, /* sourceSpec= */
-                    null, /* targetSpec= */null, translationActivityUid);
+            invokeCallbacks(STATE_UI_TRANSLATION_FINISHED,
+                    /* sourceSpec= */ null, /* targetSpec= */ null,
+                    packageName, translationActivityUid);
             mWaitingFinishedCallbackActivities.remove(token);
         } else {
             if (mWaitingFinishedCallbackActivities.contains(token)) {
-                invokeCallbacks(STATE_UI_TRANSLATION_FINISHED, /* sourceSpec= */
-                        null, /* targetSpec= */null, translationActivityUid);
+                invokeCallbacks(STATE_UI_TRANSLATION_FINISHED,
+                        /* sourceSpec= */ null, /* targetSpec= */ null,
+                        packageName, translationActivityUid);
                 mWaitingFinishedCallbackActivities.remove(token);
             }
         }
@@ -223,25 +227,25 @@
                     + "state for token=" + token + " taskId=" + taskId + " for state= " + state);
             return;
         }
+        mLastActivityTokens = new WeakReference<>(taskTopActivityTokens);
         if (state == STATE_UI_TRANSLATION_FINISHED) {
             mWaitingFinishedCallbackActivities.add(token);
         }
-        int translationActivityUid = -1;
+        IBinder activityToken = taskTopActivityTokens.getActivityToken();
         try {
-            IBinder activityToken = taskTopActivityTokens.getActivityToken();
             taskTopActivityTokens.getApplicationThread().updateUiTranslationState(
                     activityToken, state, sourceSpec, targetSpec,
                     viewIds, uiTranslationSpec);
-            mLastActivityTokens = new WeakReference<>(taskTopActivityTokens);
-            ComponentName componentName =
-                    mActivityTaskManagerInternal.getActivityName(activityToken);
-            translationActivityUid =
-                    getActivityUidByComponentName(getContext(), componentName, getUserId());
         } catch (RemoteException e) {
             Slog.w(TAG, "Update UiTranslationState fail: " + e);
         }
+
+        ComponentName componentName = mActivityTaskManagerInternal.getActivityName(activityToken);
+        int translationActivityUid =
+                getActivityUidByComponentName(getContext(), componentName, getUserId());
         if (state != STATE_UI_TRANSLATION_FINISHED) {
-            invokeCallbacks(state, sourceSpec, targetSpec, translationActivityUid);
+            invokeCallbacks(state, sourceSpec, targetSpec, componentName.getPackageName(),
+                    translationActivityUid);
         }
     }
 
@@ -255,7 +259,7 @@
             try (TransferPipe tp = new TransferPipe()) {
                 activityTokens.getApplicationThread().dumpActivity(tp.getWriteFd(),
                         activityTokens.getActivityToken(), prefix,
-                        new String[] {
+                        new String[]{
                                 Activity.DUMP_ARG_DUMP_DUMPABLE,
                                 UiTranslationController.DUMPABLE_NAME
                         });
@@ -266,20 +270,24 @@
                 pw.println(prefix + "Got a RemoteException while dumping the activity");
             }
         } else {
-            pw.print(prefix); pw.println("No requested UiTranslation Activity.");
+            pw.print(prefix);
+            pw.println("No requested UiTranslation Activity.");
         }
         final int waitingFinishCallbackSize = mWaitingFinishedCallbackActivities.size();
         if (waitingFinishCallbackSize > 0) {
-            pw.print(prefix); pw.print("number waiting finish callback activities: ");
+            pw.print(prefix);
+            pw.print("number waiting finish callback activities: ");
             pw.println(waitingFinishCallbackSize);
             for (IBinder activityToken : mWaitingFinishedCallbackActivities) {
-                pw.print(prefix); pw.print("activityToken: "); pw.println(activityToken);
+                pw.print(prefix);
+                pw.print("activityToken: ");
+                pw.println(activityToken);
             }
         }
     }
 
     private void invokeCallbacks(
-            int state, TranslationSpec sourceSpec, TranslationSpec targetSpec,
+            int state, TranslationSpec sourceSpec, TranslationSpec targetSpec, String packageName,
             int translationActivityUid) {
         Bundle res = new Bundle();
         res.putInt(EXTRA_STATE, state);
@@ -288,6 +296,7 @@
             res.putSerializable(EXTRA_SOURCE_LOCALE, sourceSpec.getLocale());
             res.putSerializable(EXTRA_TARGET_LOCALE, targetSpec.getLocale());
         }
+        res.putString(EXTRA_PACKAGE_NAME, packageName);
         // TODO(177500482): Only support the *current* Input Method.
         List<InputMethodInfo> enabledInputMethods =
                 LocalServices.getService(InputMethodManagerInternal.class)
@@ -299,6 +308,7 @@
                 } catch (RemoteException e) {
                     Slog.w(TAG, "Failed to invoke UiTranslationStateCallback: " + e);
                 }
+                return;
             }
             // Code here is non-optimal since it's temporary..
             boolean isIme = false;
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index b9abbf0..da54c32 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -79,6 +79,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -1982,6 +1983,10 @@
         }
     }
 
+    void clearLastUsedTimestamps(@NonNull String packageName, @UserIdInt int userId) {
+        mAppStandby.clearLastUsedTimestampsForTest(packageName, userId);
+    }
+
     private final class BinderService extends IUsageStatsManager.Stub {
 
         private boolean hasPermission(String callingPackage) {
@@ -2015,7 +2020,7 @@
                     == PackageManager.PERMISSION_GRANTED;
         }
 
-        private boolean hasPermissions(String callingPackage, String... permissions) {
+        private boolean hasPermissions(String... permissions) {
             final int callingUid = Binder.getCallingUid();
             if (callingUid == Process.SYSTEM_UID) {
                 // Caller is the system, so proceed.
@@ -2578,7 +2583,7 @@
                 String callingPackage) {
             final int callingUid = Binder.getCallingUid();
             final DevicePolicyManagerInternal dpmInternal = getDpmInternal();
-            if (!hasPermissions(callingPackage,
+            if (!hasPermissions(
                     Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)
                     && (dpmInternal == null || !dpmInternal.isActiveSupervisionApp(callingUid))) {
                 throw new SecurityException("Caller must be the active supervision app or "
@@ -2605,7 +2610,7 @@
         public void unregisterAppUsageLimitObserver(int observerId, String callingPackage) {
             final int callingUid = Binder.getCallingUid();
             final DevicePolicyManagerInternal dpmInternal = getDpmInternal();
-            if (!hasPermissions(callingPackage,
+            if (!hasPermissions(
                     Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)
                     && (dpmInternal == null || !dpmInternal.isActiveSupervisionApp(callingUid))) {
                 throw new SecurityException("Caller must be the active supervision app or "
@@ -2703,8 +2708,7 @@
 
         @Override
         public long getLastTimeAnyComponentUsed(String packageName, String callingPackage) {
-            if (!hasPermissions(
-                    callingPackage, android.Manifest.permission.INTERACT_ACROSS_USERS)) {
+            if (!hasPermissions(android.Manifest.permission.INTERACT_ACROSS_USERS)) {
                 throw new SecurityException("Caller doesn't have INTERACT_ACROSS_USERS permission");
             }
             if (!hasPermission(callingPackage)) {
@@ -2731,13 +2735,19 @@
                 throw new IllegalArgumentException("id needs to be >=0");
             }
 
-            final int callingUid = Binder.getCallingUid();
-            if (!hasPermission(callingPackage)) {
-                throw new SecurityException(
-                        "Caller does not have the permission needed to call this API; "
-                                + "callingPackage=" + callingPackage
-                                + ", callingUid=" + callingUid);
+            final int result = getContext().checkCallingOrSelfPermission(
+                    android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS);
+            // STOPSHIP (206518114): Temporarily check for PACKAGE_USAGE_STATS permission as well
+            // until the clients switch to using the new permission.
+            if (result != PackageManager.PERMISSION_GRANTED) {
+                if (!hasPermission(callingPackage)) {
+                    throw new SecurityException(
+                            "Caller does not have the permission needed to call this API; "
+                                    + "callingPackage=" + callingPackage
+                                    + ", callingUid=" + Binder.getCallingUid());
+                }
             }
+            final int callingUid = Binder.getCallingUid();
             userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), callingUid,
                     userId, false /* allowAll */, false /* requireFull */,
                     "queryBroadcastResponseStats" /* name */, callingPackage);
@@ -2757,13 +2767,20 @@
                 throw new IllegalArgumentException("id needs to be >=0");
             }
 
-            final int callingUid = Binder.getCallingUid();
-            if (!hasPermission(callingPackage)) {
-                throw new SecurityException(
-                        "Caller does not have the permission needed to call this API; "
-                                + "callingPackage=" + callingPackage
-                                + ", callingUid=" + callingUid);
+
+            final int result = getContext().checkCallingOrSelfPermission(
+                    android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS);
+            // STOPSHIP (206518114): Temporarily check for PACKAGE_USAGE_STATS permission as well
+            // until the clients switch to using the new permission.
+            if (result != PackageManager.PERMISSION_GRANTED) {
+                if (!hasPermission(callingPackage)) {
+                    throw new SecurityException(
+                            "Caller does not have the permission needed to call this API; "
+                                    + "callingPackage=" + callingPackage
+                                    + ", callingUid=" + Binder.getCallingUid());
+                }
             }
+            final int callingUid = Binder.getCallingUid();
             userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), callingUid,
                     userId, false /* allowAll */, false /* requireFull */,
                     "clearBroadcastResponseStats" /* name */, callingPackage);
@@ -2775,18 +2792,43 @@
         public void clearBroadcastEvents(@NonNull String callingPackage, @UserIdInt int userId) {
             Objects.requireNonNull(callingPackage);
 
-            final int callingUid = Binder.getCallingUid();
-            if (!hasPermission(callingPackage)) {
-                throw new SecurityException(
-                        "Caller does not have the permission needed to call this API; "
-                                + "callingPackage=" + callingPackage
-                                + ", callingUid=" + callingUid);
+            final int result = getContext().checkCallingOrSelfPermission(
+                    android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS);
+            // STOPSHIP (206518114): Temporarily check for PACKAGE_USAGE_STATS permission as well
+            // until the clients switch to using the new permission.
+            if (result != PackageManager.PERMISSION_GRANTED) {
+                if (!hasPermission(callingPackage)) {
+                    throw new SecurityException(
+                            "Caller does not have the permission needed to call this API; "
+                                    + "callingPackage=" + callingPackage
+                                    + ", callingUid=" + Binder.getCallingUid());
+                }
             }
+            final int callingUid = Binder.getCallingUid();
             userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), callingUid,
                     userId, false /* allowAll */, false /* requireFull */,
                     "clearBroadcastResponseStats" /* name */, callingPackage);
             mResponseStatsTracker.clearBroadcastEvents(callingUid, userId);
         }
+
+        @Override
+        @Nullable
+        public String getAppStandbyConstant(@NonNull String key) {
+            Objects.requireNonNull(key);
+
+            if (!hasPermissions(Manifest.permission.READ_DEVICE_CONFIG)) {
+                throw new SecurityException("Caller doesn't have READ_DEVICE_CONFIG permission");
+            }
+            return mAppStandby.getAppStandbyConstant(key);
+        }
+
+        @Override
+        public int handleShellCommand(@NonNull ParcelFileDescriptor in,
+                @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
+                @NonNull String[] args) {
+            return new UsageStatsShellCommand(UsageStatsService.this).exec(this,
+                    in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(), args);
+        }
     }
 
     void registerAppUsageObserver(int callingUid, int observerId, String[] packages,
diff --git a/services/usage/java/com/android/server/usage/UsageStatsShellCommand.java b/services/usage/java/com/android/server/usage/UsageStatsShellCommand.java
new file mode 100644
index 0000000..772b22a
--- /dev/null
+++ b/services/usage/java/com/android/server/usage/UsageStatsShellCommand.java
@@ -0,0 +1,79 @@
+/*
+ * 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.server.usage;
+
+import android.annotation.SuppressLint;
+import android.app.ActivityManager;
+import android.os.ShellCommand;
+import android.os.UserHandle;
+
+import java.io.PrintWriter;
+
+class UsageStatsShellCommand extends ShellCommand {
+    private final UsageStatsService mService;
+
+    UsageStatsShellCommand(UsageStatsService usageStatsService) {
+        mService = usageStatsService;
+    }
+
+    @Override
+    public int onCommand(String cmd) {
+        if (cmd == null) {
+            return handleDefaultCommands(null);
+        }
+        switch (cmd) {
+            case "clear-last-used-timestamps":
+                return runClearLastUsedTimestamps();
+            default:
+                return handleDefaultCommands(cmd);
+        }
+    }
+
+    @Override
+    public void onHelp() {
+        final PrintWriter pw = getOutPrintWriter();
+        pw.println("UsageStats service (usagestats) commands:");
+        pw.println("help");
+        pw.println("    Print this help text.");
+        pw.println();
+        pw.println("clear-last-used-timestamps PACKAGE_NAME [-u | --user USER_ID]");
+        pw.println("    Clears any existing usage data for the given package.");
+        pw.println();
+    }
+
+    @SuppressLint("AndroidFrameworkRequiresPermission")
+    private int runClearLastUsedTimestamps() {
+        final String packageName = getNextArgRequired();
+
+        int userId = UserHandle.USER_CURRENT;
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            if ("-u".equals(opt) || "--user".equals(opt)) {
+                userId = UserHandle.parseUserArg(getNextArgRequired());
+            } else {
+                getErrPrintWriter().println("Error: unknown option: " + opt);
+                return -1;
+            }
+        }
+        if (userId == UserHandle.USER_CURRENT) {
+            userId = ActivityManager.getCurrentUser();
+        }
+
+        mService.clearLastUsedTimestamps(packageName, userId);
+        return 0;
+    }
+}
diff --git a/services/usb/java/com/android/server/usb/UsbDirectMidiDevice.java b/services/usb/java/com/android/server/usb/UsbDirectMidiDevice.java
index 0fa79df..04c52f7 100644
--- a/services/usb/java/com/android/server/usb/UsbDirectMidiDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbDirectMidiDevice.java
@@ -84,7 +84,7 @@
     private final Object mLock = new Object();
     private boolean mIsOpen;
 
-    private final UsbMidiPacketConverter mUsbMidiPacketConverter = new UsbMidiPacketConverter();
+    private UsbMidiPacketConverter mUsbMidiPacketConverter;
 
     private final MidiDeviceServer.Callback mCallback = new MidiDeviceServer.Callback() {
 
@@ -264,6 +264,11 @@
         Log.d(TAG, "openLocked()");
         UsbManager manager = mContext.getSystemService(UsbManager.class);
 
+        // Converting from raw MIDI to USB MIDI is not thread-safe.
+        // UsbMidiPacketConverter creates a converter from raw MIDI
+        // 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());
@@ -415,7 +420,7 @@
                             } else {
                                 convertedArray =
                                         mUsbMidiPacketConverter.rawMidiToUsbMidi(
-                                                 event.data, event.count);
+                                                 event.data, event.count, portFinal);
                             }
 
                             if (DEBUG) {
@@ -518,6 +523,8 @@
         mInputUsbEndpoints = null;
         mOutputUsbEndpoints = null;
 
+        mUsbMidiPacketConverter = null;
+
         mIsOpen = false;
     }
 
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index a70b0332..dd58d38 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -496,11 +496,13 @@
                 // MIDI
                 ArrayList<UsbDirectMidiDevice> midiDevices =
                         mMidiDevices.remove(deviceAddress);
-                for (UsbDirectMidiDevice midiDevice : midiDevices) {
-                    if (midiDevice != null) {
-                        Slog.i(TAG, "USB MIDI Device Removed: " + deviceAddress);
-                        IoUtils.closeQuietly(midiDevice);
+                if (midiDevices != null) {
+                    for (UsbDirectMidiDevice midiDevice : midiDevices) {
+                        if (midiDevice != null) {
+                            IoUtils.closeQuietly(midiDevice);
+                        }
                     }
+                    Slog.i(TAG, "USB MIDI Devices Removed: " + deviceAddress);
                 }
 
                 getCurrentUserSettings().usbDeviceRemoved(device);
diff --git a/services/usb/java/com/android/server/usb/UsbMidiPacketConverter.java b/services/usb/java/com/android/server/usb/UsbMidiPacketConverter.java
index 7c93c76..56bb236 100644
--- a/services/usb/java/com/android/server/usb/UsbMidiPacketConverter.java
+++ b/services/usb/java/com/android/server/usb/UsbMidiPacketConverter.java
@@ -74,8 +74,15 @@
     private static final byte SYSEX_START_EXCLUSIVE = (byte) 0xF0;
     private static final byte SYSEX_END_EXCLUSIVE = (byte) 0xF7;
 
-    private UsbMidiEncoder mUsbMidiEncoder = new UsbMidiEncoder();
     private UsbMidiDecoder mUsbMidiDecoder = new UsbMidiDecoder();
+    private UsbMidiEncoder[] mUsbMidiEncoders;
+
+    public UsbMidiPacketConverter(int numEncoders) {
+        mUsbMidiEncoders = new UsbMidiEncoder[numEncoders];
+        for (int i = 0; i < numEncoders; i++) {
+            mUsbMidiEncoders[i] = new UsbMidiEncoder();
+        }
+    }
 
     /**
      * Converts a USB MIDI array into a raw MIDI array.
@@ -93,10 +100,11 @@
      *
      * @param midiBytes the raw MIDI bytes to convert
      * @param size the size of usbMidiBytes
+     * @param encoderId which encoder to use
      * @return byte array of USB MIDI packets
      */
-    public byte[] rawMidiToUsbMidi(byte[] midiBytes, int size) {
-        return mUsbMidiEncoder.encode(midiBytes, size);
+    public byte[] rawMidiToUsbMidi(byte[] midiBytes, int size, int encoderId) {
+        return mUsbMidiEncoders[encoderId].encode(midiBytes, size);
     }
 
     private class UsbMidiDecoder {
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
index 1db018e..8c9e80f 100644
--- a/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
@@ -296,8 +296,8 @@
                             + operationID + " key:" + key);
                 }
                 try {
-                    sCallbacks.put(operationID, callback);
-                    mProxy.resetUsbPort(portName, operationID);
+                    sCallbacks.put(key, callback);
+                    mProxy.resetUsbPort(portName, key);
                 } catch (RemoteException e) {
                     logAndPrintException(mPw,
                             "resetUsbPort: Failed to resetUsbPort: portID="
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index 24ce7e7..ee2d235 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -84,6 +84,9 @@
 
     private static final int INVALID_VALUE = Integer.MIN_VALUE;
 
+    /** Maximum time to wait for a model stop confirmation before giving up. */
+    private static final long STOP_TIMEOUT_MS = 5000;
+
     /** The {@link ModuleProperties} for the system, or null if none exists. */
     final ModuleProperties mModuleProperties;
 
@@ -831,7 +834,7 @@
         }
 
         if (!event.recognitionStillActive) {
-            model.setStopped();
+            model.setStoppedLocked();
         }
 
         try {
@@ -918,9 +921,12 @@
         MetricsLogger.count(mContext, "sth_recognition_aborted", 1);
         ModelData modelData = getModelDataForLocked(event.soundModelHandle);
         if (modelData != null && modelData.isModelStarted()) {
-            modelData.setStopped();
+            modelData.setStoppedLocked();
             try {
-                modelData.getCallback().onRecognitionPaused();
+                IRecognitionStatusCallback callback = modelData.getCallback();
+                if (callback != null) {
+                    callback.onRecognitionPaused();
+                }
             } catch (DeadObjectException e) {
                 forceStopAndUnloadModelLocked(modelData, e);
             } catch (RemoteException e) {
@@ -972,7 +978,7 @@
         }
 
         if (!event.recognitionStillActive) {
-            modelData.setStopped();
+            modelData.setStoppedLocked();
         }
 
         try {
@@ -1200,7 +1206,7 @@
         if (modelData.isModelStarted()) {
             Slog.d(TAG, "Stopping previously started dangling model " + modelData.getHandle());
             if (mModule.stopRecognition(modelData.getHandle()) == STATUS_OK) {
-                modelData.setStopped();
+                modelData.setStoppedLocked();
                 modelData.setRequested(false);
             } else {
                 Slog.e(TAG, "Failed to stop model " + modelData.getHandle());
@@ -1249,7 +1255,7 @@
     private ModelData getOrCreateGenericModelDataLocked(UUID modelId) {
         ModelData modelData = mModelDataMap.get(modelId);
         if (modelData == null) {
-            modelData = ModelData.createGenericModelData(modelId);
+            modelData = createGenericModelData(modelId);
             mModelDataMap.put(modelId, modelData);
         } else if (!modelData.isGenericModel()) {
             Slog.e(TAG, "UUID already used for non-generic model.");
@@ -1281,7 +1287,7 @@
         mKeyphraseUuidMap.remove(keyphraseId);
         mModelDataMap.remove(modelId);
         mKeyphraseUuidMap.put(keyphraseId, modelId);
-        ModelData modelData = ModelData.createKeyphraseModelData(modelId);
+        ModelData modelData = createKeyphraseModelData(modelId);
         mModelDataMap.put(modelId, modelData);
         return modelData;
     }
@@ -1413,18 +1419,26 @@
                     Slog.w(TAG, "RemoteException in onError", e);
                 }
             }
-        } else {
-            modelData.setStopped();
-            MetricsLogger.count(mContext, "sth_stop_recognition_success", 1);
-            // Notify of pause if needed.
-            if (notify) {
-                try {
-                    callback.onRecognitionPaused();
-                } catch (DeadObjectException e) {
-                    forceStopAndUnloadModelLocked(modelData, e);
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "RemoteException in onRecognitionPaused", e);
-                }
+            return status;
+        }
+
+        // Wait for model to be stopped.
+        try {
+            modelData.waitStoppedLocked(STOP_TIMEOUT_MS);
+        } catch (InterruptedException e) {
+            Slog.e(TAG, "Didn't receive model stop callback");
+            return SoundTrigger.STATUS_ERROR;
+        }
+
+        MetricsLogger.count(mContext, "sth_stop_recognition_success", 1);
+        // Notify of pause if needed.
+        if (notify) {
+            try {
+                callback.onRecognitionPaused();
+            } catch (DeadObjectException e) {
+                forceStopAndUnloadModelLocked(modelData, e);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "RemoteException in onRecognitionPaused", e);
             }
         }
         if (DBG) {
@@ -1459,7 +1473,7 @@
 
     // This class encapsulates the callbacks, state, handles and any other information that
     // represents a model.
-    private static class ModelData {
+    private class ModelData {
         // Model not loaded (and hence not started).
         static final int MODEL_NOTLOADED = 0;
 
@@ -1516,17 +1530,9 @@
             mModelType = modelType;
         }
 
-        static ModelData createKeyphraseModelData(UUID modelId) {
-            return new ModelData(modelId, SoundModel.TYPE_KEYPHRASE);
-        }
-
-        static ModelData createGenericModelData(UUID modelId) {
-            return new ModelData(modelId, SoundModel.TYPE_GENERIC_SOUND);
-        }
-
         // Note that most of the functionality in this Java class will not work for
         // SoundModel.TYPE_UNKNOWN nevertheless we have it since lower layers support it.
-        static ModelData createModelDataOfUnknownType(UUID modelId) {
+        ModelData createModelDataOfUnknownType(UUID modelId) {
             return new ModelData(modelId, SoundModel.TYPE_UNKNOWN);
         }
 
@@ -1550,8 +1556,20 @@
             mModelState = MODEL_STARTED;
         }
 
-        synchronized void setStopped() {
+        synchronized void setStoppedLocked() {
             mModelState = MODEL_LOADED;
+            mLock.notifyAll();
+        }
+
+        void waitStoppedLocked(long timeoutMs) throws InterruptedException {
+            long deadline = System.currentTimeMillis() + timeoutMs;
+            while (mModelState == MODEL_STARTED) {
+                long waitTime = deadline - System.currentTimeMillis();
+                if (waitTime <= 0) {
+                    throw new InterruptedException();
+                }
+                mLock.wait(waitTime);
+            }
         }
 
         synchronized void setLoaded() {
@@ -1571,6 +1589,7 @@
             mRecognitionConfig = null;
             mRequested = false;
             mCallback = null;
+            notifyAll();
         }
 
         synchronized void clearCallback() {
@@ -1675,4 +1694,12 @@
             return "Model type: " + type + "\n";
         }
     }
+
+    ModelData createKeyphraseModelData(UUID modelId) {
+        return new ModelData(modelId, SoundModel.TYPE_KEYPHRASE);
+    }
+
+    ModelData createGenericModelData(UUID modelId) {
+        return new ModelData(modelId, SoundModel.TYPE_GENERIC_SOUND);
+    }
 }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index a597fc6..c86f38d 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -20,9 +20,29 @@
 import static android.Manifest.permission.RECORD_AUDIO;
 import static android.service.voice.HotwordDetectionService.AUDIO_SOURCE_EXTERNAL;
 import static android.service.voice.HotwordDetectionService.AUDIO_SOURCE_MICROPHONE;
+import static android.service.voice.HotwordDetectionService.INITIALIZATION_STATUS_SUCCESS;
 import static android.service.voice.HotwordDetectionService.INITIALIZATION_STATUS_UNKNOWN;
 import static android.service.voice.HotwordDetectionService.KEY_INITIALIZATION_STATUS;
 
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_ERROR;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_SUCCESS;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_UNKNOWN_NO_VALUE;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_UNKNOWN_OVER_MAX_CUSTOM_VALUE;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_UNKNOWN_TIMEOUT;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_RESTARTED__REASON__AUDIO_SERVICE_DIED;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_RESTARTED__REASON__SCHEDULE;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__CALLBACK_UPDATE_STATE_AFTER_TIMEOUT;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__ON_CONNECTED;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__REQUEST_BIND_SERVICE;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__REQUEST_BIND_SERVICE_FAIL;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__REQUEST_UPDATE_STATE;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__NORMAL_DETECTOR;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECTED;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_EXCEPTION;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_TIMEOUT;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__KEYPHRASE_TRIGGER;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__REJECTED;
 import static com.android.server.voiceinteraction.SoundTriggerSessionPermissionsDecorator.enforcePermissionForPreflight;
 
 import android.annotation.NonNull;
@@ -48,6 +68,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SharedMemory;
+import android.provider.DeviceConfig;
 import android.service.voice.HotwordDetectedResult;
 import android.service.voice.HotwordDetectionService;
 import android.service.voice.HotwordDetector;
@@ -91,33 +112,56 @@
     private static final String TAG = "HotwordDetectionConnection";
     static final boolean DEBUG = false;
 
+    private static final String KEY_RESTART_PERIOD_IN_SECONDS = "restart_period_in_seconds";
     // TODO: These constants need to be refined.
-    private static final long VALIDATION_TIMEOUT_MILLIS = 3000;
+    private static final long VALIDATION_TIMEOUT_MILLIS = 4000;
     private static final long MAX_UPDATE_TIMEOUT_MILLIS = 6000;
     private static final Duration MAX_UPDATE_TIMEOUT_DURATION =
             Duration.ofMillis(MAX_UPDATE_TIMEOUT_MILLIS);
     private static final long RESET_DEBUG_HOTWORD_LOGGING_TIMEOUT_MILLIS = 60 * 60 * 1000; // 1 hour
+    /**
+     * Time after which each HotwordDetectionService process is stopped and replaced by a new one.
+     * 0 indicates no restarts.
+     */
+    private static final int RESTART_PERIOD_SECONDS =
+            DeviceConfig.getInt(DeviceConfig.NAMESPACE_VOICE_INTERACTION,
+                    KEY_RESTART_PERIOD_IN_SECONDS, 0);
     private static final int MAX_ISOLATED_PROCESS_NUMBER = 10;
 
+    // Hotword metrics
+    private static final int METRICS_INIT_UNKNOWN_TIMEOUT =
+            HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_UNKNOWN_TIMEOUT;
+    private static final int METRICS_INIT_UNKNOWN_NO_VALUE =
+            HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_UNKNOWN_NO_VALUE;
+    private static final int METRICS_INIT_UNKNOWN_OVER_MAX_CUSTOM_VALUE =
+            HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_UNKNOWN_OVER_MAX_CUSTOM_VALUE;
+    private static final int METRICS_INIT_CALLBACK_STATE_ERROR =
+            HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_ERROR;
+    private static final int METRICS_INIT_CALLBACK_STATE_SUCCESS =
+            HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_SUCCESS;
+
     private final Executor mAudioCopyExecutor = Executors.newCachedThreadPool();
     // TODO: This may need to be a Handler(looper)
     private final ScheduledExecutorService mScheduledExecutorService =
             Executors.newSingleThreadScheduledExecutor();
+    @Nullable private final ScheduledFuture<?> mCancellationTaskFuture;
     private final AtomicBoolean mUpdateStateAfterStartFinished = new AtomicBoolean(false);
     private final IBinder.DeathRecipient mAudioServerDeathRecipient = this::audioServerDied;
     private final @NonNull ServiceConnectionFactory mServiceConnectionFactory;
     private final IHotwordRecognitionStatusCallback mCallback;
+    private final int mDetectorType;
 
     final Object mLock;
     final int mVoiceInteractionServiceUid;
     final ComponentName mDetectionComponentName;
     final int mUser;
     final Context mContext;
+
     volatile HotwordDetectionServiceIdentity mIdentity;
     private IMicrophoneHotwordDetectionVoiceInteractionCallback mSoftwareCallback;
     private Instant mLastRestartInstant;
 
-    private ScheduledFuture<?> mCancellationTaskFuture;
+    private ScheduledFuture<?> mCancellationKeyPhraseDetectionFuture;
     private ScheduledFuture<?> mDebugHotwordLoggingTimeoutFuture = null;
 
     /** Identity used for attributing app ops when delivering data to the Interactor. */
@@ -133,7 +177,6 @@
     private @NonNull ServiceConnection mRemoteHotwordDetectionService;
     private IBinder mAudioFlinger;
     private boolean mDebugHotwordLogging = false;
-    private final int mDetectorType;
 
     HotwordDetectionConnection(Object lock, Context context, int voiceInteractionServiceUid,
             Identity voiceInteractorIdentity, ComponentName serviceName, int userId,
@@ -163,14 +206,20 @@
         mLastRestartInstant = Instant.now();
         updateStateAfterProcessStart(options, sharedMemory);
 
-        // TODO(volnov): we need to be smarter here, e.g. schedule it a bit more often, but wait
-        // until the current session is closed.
-        mCancellationTaskFuture = mScheduledExecutorService.scheduleAtFixedRate(() -> {
-            Slog.v(TAG, "Time to restart the process, TTL has passed");
-            synchronized (mLock) {
-                restartProcessLocked();
-            }
-        }, 30, 30, TimeUnit.MINUTES);
+        if (RESTART_PERIOD_SECONDS <= 0) {
+            mCancellationTaskFuture = null;
+        } else {
+            // TODO(volnov): we need to be smarter here, e.g. schedule it a bit more often, but wait
+            // until the current session is closed.
+            mCancellationTaskFuture = mScheduledExecutorService.scheduleAtFixedRate(() -> {
+                Slog.v(TAG, "Time to restart the process, TTL has passed");
+                synchronized (mLock) {
+                    restartProcessLocked();
+                    HotwordMetricsLogger.writeServiceRestartEvent(mDetectorType,
+                            HOTWORD_DETECTION_SERVICE_RESTARTED__REASON__SCHEDULE);
+                }
+            }, RESTART_PERIOD_SECONDS, RESTART_PERIOD_SECONDS, TimeUnit.SECONDS);
+        }
     }
 
     private void initAudioFlingerLocked() {
@@ -201,6 +250,8 @@
             // We restart the process instead of simply sending over the new binder, to avoid race
             // conditions with audio reading in the service.
             restartProcessLocked();
+            HotwordMetricsLogger.writeServiceRestartEvent(mDetectorType,
+                    HOTWORD_DETECTION_SERVICE_RESTARTED__REASON__AUDIO_SERVICE_DIED);
         }
     }
 
@@ -220,26 +271,32 @@
                     future.complete(null);
                     if (mUpdateStateAfterStartFinished.getAndSet(true)) {
                         Slog.w(TAG, "call callback after timeout");
+                        HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
+                                HOTWORD_DETECTOR_EVENTS__EVENT__CALLBACK_UPDATE_STATE_AFTER_TIMEOUT,
+                                mVoiceInteractionServiceUid);
                         return;
                     }
-                    int status = bundle != null ? bundle.getInt(
-                            KEY_INITIALIZATION_STATUS,
-                            INITIALIZATION_STATUS_UNKNOWN)
-                            : INITIALIZATION_STATUS_UNKNOWN;
-                    // Add the protection to avoid unexpected status
-                    if (status > HotwordDetectionService.getMaxCustomInitializationStatus()
-                            && status != INITIALIZATION_STATUS_UNKNOWN) {
-                        status = INITIALIZATION_STATUS_UNKNOWN;
-                    }
+                    Pair<Integer, Integer> statusResultPair = getInitStatusAndMetricsResult(bundle);
+                    int status = statusResultPair.first;
+                    int initResultMetricsResult = statusResultPair.second;
                     try {
                         mCallback.onStatusReported(status);
+                        HotwordMetricsLogger.writeServiceInitResultEvent(mDetectorType,
+                                initResultMetricsResult);
                     } catch (RemoteException e) {
+                        // TODO: Add a new atom for RemoteException case, the error doesn't very
+                        // correct here
                         Slog.w(TAG, "Failed to report initialization status: " + e);
+                        HotwordMetricsLogger.writeServiceInitResultEvent(mDetectorType,
+                                METRICS_INIT_CALLBACK_STATE_ERROR);
                     }
                 }
             };
             try {
                 service.updateState(options, sharedMemory, statusCallback);
+                HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
+                        HOTWORD_DETECTOR_EVENTS__EVENT__REQUEST_UPDATE_STATE,
+                        mVoiceInteractionServiceUid);
             } catch (RemoteException e) {
                 // TODO: (b/181842909) Report an error to voice interactor
                 Slog.w(TAG, "Failed to updateState for HotwordDetectionService", e);
@@ -254,8 +311,12 @@
                         }
                         try {
                             mCallback.onStatusReported(INITIALIZATION_STATUS_UNKNOWN);
+                            HotwordMetricsLogger.writeServiceInitResultEvent(mDetectorType,
+                                    METRICS_INIT_UNKNOWN_TIMEOUT);
                         } catch (RemoteException e) {
                             Slog.w(TAG, "Failed to report initialization status UNKNOWN", e);
+                            HotwordMetricsLogger.writeServiceInitResultEvent(mDetectorType,
+                                    METRICS_INIT_CALLBACK_STATE_ERROR);
                         }
                     } else if (err != null) {
                         Slog.w(TAG, "Failed to update state: " + err);
@@ -265,6 +326,24 @@
                 });
     }
 
+    private static Pair<Integer, Integer> getInitStatusAndMetricsResult(Bundle bundle) {
+        if (bundle == null) {
+            return new Pair<>(INITIALIZATION_STATUS_UNKNOWN, METRICS_INIT_UNKNOWN_NO_VALUE);
+        }
+        int status = bundle.getInt(KEY_INITIALIZATION_STATUS, INITIALIZATION_STATUS_UNKNOWN);
+        if (status > HotwordDetectionService.getMaxCustomInitializationStatus()) {
+            return new Pair<>(INITIALIZATION_STATUS_UNKNOWN,
+                    status == INITIALIZATION_STATUS_UNKNOWN
+                    ? METRICS_INIT_UNKNOWN_NO_VALUE
+                    : METRICS_INIT_UNKNOWN_OVER_MAX_CUSTOM_VALUE);
+        }
+        // TODO: should guard against negative here
+        int metricsResult = status == INITIALIZATION_STATUS_SUCCESS
+                ? METRICS_INIT_CALLBACK_STATE_SUCCESS
+                : METRICS_INIT_CALLBACK_STATE_ERROR;
+        return new Pair<>(status, metricsResult);
+    }
+
     private boolean isBound() {
         synchronized (mLock) {
             return mRemoteHotwordDetectionService.isBound();
@@ -282,7 +361,9 @@
             removeServiceUidForAudioPolicy(mIdentity.getIsolatedUid());
         }
         mIdentity = null;
-        mCancellationTaskFuture.cancel(/* may interrupt */ true);
+        if (mCancellationTaskFuture != null) {
+            mCancellationTaskFuture.cancel(/* may interrupt */ true);
+        }
         if (mAudioFlinger != null) {
             mAudioFlinger.unlinkToDeath(mAudioServerDeathRecipient, /* flags= */ 0);
         }
@@ -481,12 +562,31 @@
                     Slog.d(TAG, "onDetected");
                 }
                 synchronized (mLock) {
+                    // TODO: If the dsp trigger comes in after the timeout, we will log both events.
+                    // Because we don't enforce the timeout yet. We should add some synchronizations
+                    // within the runnable to prevent the race condition to log both events.
+                    if (mCancellationKeyPhraseDetectionFuture != null) {
+                        mCancellationKeyPhraseDetectionFuture.cancel(true);
+                    }
+                    HotwordMetricsLogger.writeKeyphraseTriggerEvent(
+                            mDetectorType,
+                            HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECTED);
                     if (!mValidatingDspTrigger) {
                         Slog.i(TAG, "Ignoring #onDetected due to a process restart");
+                        HotwordMetricsLogger.writeKeyphraseTriggerEvent(
+                                mDetectorType,
+                                HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_EXCEPTION);
                         return;
                     }
                     mValidatingDspTrigger = false;
-                    enforcePermissionsForDataDelivery();
+                    try {
+                        enforcePermissionsForDataDelivery();
+                    } catch (SecurityException e) {
+                        HotwordMetricsLogger.writeKeyphraseTriggerEvent(
+                                mDetectorType,
+                                HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_EXCEPTION);
+                        throw e;
+                    }
                     externalCallback.onKeyphraseDetected(recognitionEvent, result);
                     if (result != null) {
                         Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result)
@@ -504,8 +604,17 @@
                     Slog.d(TAG, "onRejected");
                 }
                 synchronized (mLock) {
+                    if (mCancellationKeyPhraseDetectionFuture != null) {
+                        mCancellationKeyPhraseDetectionFuture.cancel(true);
+                    }
+                    HotwordMetricsLogger.writeKeyphraseTriggerEvent(
+                            mDetectorType,
+                            HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__REJECTED);
                     if (!mValidatingDspTrigger) {
                         Slog.i(TAG, "Ignoring #onRejected due to a process restart");
+                        HotwordMetricsLogger.writeKeyphraseTriggerEvent(
+                                mDetectorType,
+                                HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_EXCEPTION);
                         return;
                     }
                     mValidatingDspTrigger = false;
@@ -520,11 +629,20 @@
         synchronized (mLock) {
             mValidatingDspTrigger = true;
             mRemoteHotwordDetectionService.run(
-                    service -> service.detectFromDspSource(
-                            recognitionEvent,
-                            recognitionEvent.getCaptureFormat(),
-                            VALIDATION_TIMEOUT_MILLIS,
-                            internalCallback));
+                    service -> {
+                        // TODO: avoid allocate every time
+                        mCancellationKeyPhraseDetectionFuture = mScheduledExecutorService.schedule(
+                                () -> HotwordMetricsLogger
+                                        .writeKeyphraseTriggerEvent(mDetectorType,
+                                        HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_TIMEOUT),
+                                VALIDATION_TIMEOUT_MILLIS,
+                                TimeUnit.MILLISECONDS);
+                        service.detectFromDspSource(
+                                recognitionEvent,
+                                recognitionEvent.getCaptureFormat(),
+                                VALIDATION_TIMEOUT_MILLIS,
+                                internalCallback);
+                    });
         }
     }
 
@@ -561,6 +679,7 @@
     private void restartProcessLocked() {
         Slog.v(TAG, "Restarting hotword detection process");
         ServiceConnection oldConnection = mRemoteHotwordDetectionService;
+        HotwordDetectionServiceIdentity previousIdentity = mIdentity;
 
         // TODO(volnov): this can be done after connect() has been successful.
         if (mValidatingDspTrigger) {
@@ -604,6 +723,9 @@
         }
         oldConnection.ignoreConnectionStatusEvents();
         oldConnection.unbind();
+        if (previousIdentity != null) {
+            removeServiceUidForAudioPolicy(previousIdentity.getIsolatedUid());
+        }
     }
 
     static final class SoundTriggerCallback extends IRecognitionStatusCallback.Stub {
@@ -625,10 +747,16 @@
             }
             final boolean useHotwordDetectionService = mHotwordDetectionConnection != null;
             if (useHotwordDetectionService) {
+                HotwordMetricsLogger.writeKeyphraseTriggerEvent(
+                        HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP,
+                        HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__KEYPHRASE_TRIGGER);
                 mRecognitionEvent = recognitionEvent;
                 mHotwordDetectionConnection.detectFromDspSource(
                         recognitionEvent, mExternalCallback);
             } else {
+                HotwordMetricsLogger.writeKeyphraseTriggerEvent(
+                        HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__NORMAL_DETECTOR,
+                        HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__KEYPHRASE_TRIGGER);
                 mExternalCallback.onKeyphraseDetected(recognitionEvent, null);
             }
         }
@@ -657,6 +785,7 @@
     }
 
     public void dump(String prefix, PrintWriter pw) {
+        pw.print(prefix); pw.print("RESTART_PERIOD_SECONDS="); pw.println(RESTART_PERIOD_SECONDS);
         pw.print(prefix);
         pw.print("mBound=" + mRemoteHotwordDetectionService.isBound());
         pw.print(", mValidatingDspTrigger=" + mValidatingDspTrigger);
@@ -793,6 +922,7 @@
 
         private boolean mRespectServiceConnectionStatusChanged = true;
         private boolean mIsBound = false;
+        private boolean mIsLoggedFirstConnect = false;
 
         ServiceConnection(@NonNull Context context,
                 @NonNull Intent intent, int bindingFlags, int userId,
@@ -816,6 +946,12 @@
                     return;
                 }
                 mIsBound = connected;
+                if (connected && !mIsLoggedFirstConnect) {
+                    mIsLoggedFirstConnect = true;
+                    HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
+                            HOTWORD_DETECTOR_EVENTS__EVENT__ON_CONNECTED,
+                            mVoiceInteractionServiceUid);
+                }
             }
         }
 
@@ -846,13 +982,25 @@
         protected boolean bindService(
                 @NonNull android.content.ServiceConnection serviceConnection) {
             try {
-                return mContext.bindIsolatedService(
+                HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
+                        HOTWORD_DETECTOR_EVENTS__EVENT__REQUEST_BIND_SERVICE,
+                        mVoiceInteractionServiceUid);
+                boolean bindResult = mContext.bindIsolatedService(
                         mIntent,
                         Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE | mBindingFlags,
                         "hotword_detector_" + mInstanceNumber,
                         mExecutor,
                         serviceConnection);
+                if (!bindResult) {
+                    HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
+                            HOTWORD_DETECTOR_EVENTS__EVENT__REQUEST_BIND_SERVICE_FAIL,
+                            mVoiceInteractionServiceUid);
+                }
+                return bindResult;
             } catch (IllegalArgumentException e) {
+                HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
+                        HOTWORD_DETECTOR_EVENTS__EVENT__REQUEST_BIND_SERVICE_FAIL,
+                        mVoiceInteractionServiceUid);
                 Slog.wtf(TAG, "Can't bind to the hotword detection service!", e);
                 return false;
             }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java
index de0b960..940aed3 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java
@@ -16,6 +16,24 @@
 
 package com.android.server.voiceinteraction;
 
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__NORMAL_DETECTOR;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_RESTARTED__DETECTOR_TYPE__NORMAL_DETECTOR;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_RESTARTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_RESTARTED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_CREATE_REQUESTED__DETECTOR_TYPE__NORMAL_DETECTOR;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_CREATE_REQUESTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_CREATE_REQUESTED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__DETECTOR_TYPE__NORMAL_DETECTOR;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__NORMAL_DETECTOR;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
+
+import android.service.voice.HotwordDetector;
+
 import com.android.internal.util.FrameworkStatsLog;
 
 /**
@@ -23,6 +41,13 @@
  */
 public final class HotwordMetricsLogger {
 
+    private static final int METRICS_INIT_DETECTOR_SOFTWARE =
+            HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
+    private static final int METRICS_INIT_DETECTOR_DSP =
+            HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
+    private static final int METRICS_INIT_NORMAL_DETECTOR =
+            HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__NORMAL_DETECTOR;
+
     private HotwordMetricsLogger() {
         // Class only contains static utility functions, and should not be instantiated
     }
@@ -31,39 +56,99 @@
      * Logs information related to create hotword detector.
      */
     public static void writeDetectorCreateEvent(int detectorType, boolean isCreated, int uid) {
-        FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_DETECTOR_CREATE_REQUESTED, detectorType,
-                isCreated, uid);
+        int metricsDetectorType = getCreateMetricsDetectorType(detectorType);
+        FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_DETECTOR_CREATE_REQUESTED,
+                metricsDetectorType, isCreated, uid);
     }
 
     /**
      * Logs information related to hotword detection service init result.
      */
     public static void writeServiceInitResultEvent(int detectorType, int result) {
+        int metricsDetectorType = getInitMetricsDetectorType(detectorType);
         FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED,
-                detectorType, result);
+                metricsDetectorType, result);
     }
 
     /**
      * Logs information related to hotword detection service restarting.
      */
     public static void writeServiceRestartEvent(int detectorType, int reason) {
+        int metricsDetectorType = getRestartMetricsDetectorType(detectorType);
         FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_RESTARTED,
-                detectorType, reason);
+                metricsDetectorType, reason);
     }
 
     /**
      * Logs information related to keyphrase trigger.
      */
     public static void writeKeyphraseTriggerEvent(int detectorType, int result) {
+        int metricsDetectorType = getKeyphraseMetricsDetectorType(detectorType);
         FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED,
-                detectorType, result);
+                metricsDetectorType, result);
     }
 
     /**
      * Logs information related to hotword detector events.
      */
     public static void writeDetectorEvent(int detectorType, int event, int uid) {
+        int metricsDetectorType = getDetectorMetricsDetectorType(detectorType);
         FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS,
-                detectorType, event, uid);
+                metricsDetectorType, event, uid);
+    }
+
+    private static int getCreateMetricsDetectorType(int detectorType) {
+        switch (detectorType) {
+            case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE:
+                return HOTWORD_DETECTOR_CREATE_REQUESTED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
+            case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP:
+                return HOTWORD_DETECTOR_CREATE_REQUESTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
+            default:
+                return HOTWORD_DETECTOR_CREATE_REQUESTED__DETECTOR_TYPE__NORMAL_DETECTOR;
+        }
+    }
+
+    private static int getRestartMetricsDetectorType(int detectorType) {
+        switch (detectorType) {
+            case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE:
+                return HOTWORD_DETECTION_SERVICE_RESTARTED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
+            case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP:
+                return HOTWORD_DETECTION_SERVICE_RESTARTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
+            default:
+                return HOTWORD_DETECTION_SERVICE_RESTARTED__DETECTOR_TYPE__NORMAL_DETECTOR;
+        }
+    }
+
+    private static int getInitMetricsDetectorType(int detectorType) {
+        switch (detectorType) {
+            case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE:
+                return METRICS_INIT_DETECTOR_SOFTWARE;
+            case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP:
+                return METRICS_INIT_DETECTOR_DSP;
+            default:
+                return METRICS_INIT_NORMAL_DETECTOR;
+        }
+    }
+
+    private static int getKeyphraseMetricsDetectorType(int detectorType) {
+        switch (detectorType) {
+            case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE:
+                return HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
+            case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP:
+                return HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
+            default:
+                return HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__NORMAL_DETECTOR;
+        }
+    }
+
+    private static int getDetectorMetricsDetectorType(int detectorType) {
+        switch (detectorType) {
+            case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE:
+                return HOTWORD_DETECTOR_EVENTS__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
+            case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP:
+                return HOTWORD_DETECTOR_EVENTS__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
+            default:
+                return HOTWORD_DETECTOR_EVENTS__DETECTOR_TYPE__NORMAL_DETECTOR;
+        }
     }
 }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index fb4d73c..0519873 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -462,24 +462,33 @@
             IHotwordRecognitionStatusCallback callback,
             int detectorType) {
         Slog.v(TAG, "updateStateLocked");
+        int voiceInteractionServiceUid = mInfo.getServiceInfo().applicationInfo.uid;
         if (mHotwordDetectionComponentName == null) {
             Slog.w(TAG, "Hotword detection service name not found");
+            logDetectorCreateEventIfNeeded(callback, detectorType, false,
+                    voiceInteractionServiceUid);
             throw new IllegalStateException("Hotword detection service name not found");
         }
         ServiceInfo hotwordDetectionServiceInfo = getServiceInfoLocked(
                 mHotwordDetectionComponentName, mUser);
         if (hotwordDetectionServiceInfo == null) {
             Slog.w(TAG, "Hotword detection service info not found");
+            logDetectorCreateEventIfNeeded(callback, detectorType, false,
+                    voiceInteractionServiceUid);
             throw new IllegalStateException("Hotword detection service info not found");
         }
         if (!isIsolatedProcessLocked(hotwordDetectionServiceInfo)) {
             Slog.w(TAG, "Hotword detection service not in isolated process");
+            logDetectorCreateEventIfNeeded(callback, detectorType, false,
+                    voiceInteractionServiceUid);
             throw new IllegalStateException("Hotword detection service not in isolated process");
         }
         if (!Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE.equals(
                 hotwordDetectionServiceInfo.permission)) {
             Slog.w(TAG, "Hotword detection service does not require permission "
                     + Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE);
+            logDetectorCreateEventIfNeeded(callback, detectorType, false,
+                    voiceInteractionServiceUid);
             throw new SecurityException("Hotword detection service does not require permission "
                     + Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE);
         }
@@ -488,17 +497,23 @@
                 mInfo.getServiceInfo().packageName) == PackageManager.PERMISSION_GRANTED) {
             Slog.w(TAG, "Voice interaction service should not hold permission "
                     + Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE);
+            logDetectorCreateEventIfNeeded(callback, detectorType, false,
+                    voiceInteractionServiceUid);
             throw new SecurityException("Voice interaction service should not hold permission "
                     + Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE);
         }
 
         if (sharedMemory != null && !sharedMemory.setProtect(OsConstants.PROT_READ)) {
             Slog.w(TAG, "Can't set sharedMemory to be read-only");
+            logDetectorCreateEventIfNeeded(callback, detectorType, false,
+                    voiceInteractionServiceUid);
             throw new IllegalStateException("Can't set sharedMemory to be read-only");
         }
 
         mDetectorType = detectorType;
 
+        logDetectorCreateEventIfNeeded(callback, detectorType, true,
+                voiceInteractionServiceUid);
         if (mHotwordDetectionConnection == null) {
             mHotwordDetectionConnection = new HotwordDetectionConnection(mServiceStub, mContext,
                     mInfo.getServiceInfo().applicationInfo.uid, voiceInteractorIdentity,
@@ -509,6 +524,15 @@
         }
     }
 
+    private void logDetectorCreateEventIfNeeded(IHotwordRecognitionStatusCallback callback,
+            int detectorType, boolean isCreated, int voiceInteractionServiceUid) {
+        if (callback != null) {
+            HotwordMetricsLogger.writeDetectorCreateEvent(detectorType, true,
+                    voiceInteractionServiceUid);
+        }
+
+    }
+
     public void shutdownHotwordDetectionServiceLocked() {
         if (DEBUG) {
             Slog.d(TAG, "shutdownHotwordDetectionServiceLocked");
diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java
index 98db291..78b0b84 100644
--- a/telephony/common/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/common/com/android/internal/telephony/SmsApplication.java
@@ -68,7 +68,7 @@
 public final class SmsApplication {
     static final String LOG_TAG = "SmsApplication";
     public static final String PHONE_PACKAGE_NAME = "com.android.phone";
-    public static final String BLUETOOTH_PACKAGE_NAME = "com.android.bluetooth";
+    public static final String BLUETOOTH_PACKAGE_NAME = "com.android.bluetooth.services";
     public static final String MMS_SERVICE_PACKAGE_NAME = "com.android.mms.service";
     public static final String TELEPHONY_PROVIDER_PACKAGE_NAME = "com.android.providers.telephony";
 
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 837cf8b..3691fb0 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -504,7 +504,12 @@
     /** Control whether users can choose a network operator. */
     public static final String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool";
 
-    /** Used in Cellular Network Settings for preferred network type. */
+    /**
+     * Used in the Preferred Network Types menu to determine if the 2G option is displayed.
+     * Value defaults to false as of Android T to discourage the use of insecure 2G protocols.
+     *
+     * @see #KEY_HIDE_ENABLE_2G
+     */
     public static final String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
 
     /**
@@ -8488,8 +8493,9 @@
      *     <item value="source=GERAN|UTRAN, target:IWLAN, type=disallowed"/>
      *     <!-- Handover from IWLAN to 3G/4G/5G is not allowed if the device is roaming. -->
      *     <item value="source=IWLAN, target=UTRAN|EUTRAN|NGRAN, roaming=true, type=disallowed"/>
-     *     <!-- Handover from 4G to IWLAN is not allowed -->
-     *     <item value="source=EUTRAN, target=IWLAN, type=disallowed"/>
+     *     <!-- Handover from 4G to IWLAN is not allowed if the device has capability in either IMS
+     *     or EIMS-->
+     *     <item value="source=EUTRAN, target=IWLAN, type=disallowed, capabilities=IMS|EIMS"/>
      *     <!-- Handover is always allowed in any condition. -->
      *     <item value="source=GERAN|UTRAN|EUTRAN|NGRAN|IWLAN,
      *         target=GERAN|UTRAN|EUTRAN|NGRAN|IWLAN, type=allowed"/>
@@ -8594,7 +8600,7 @@
         sDefaults.putBoolean(KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL, false);
         sDefaults.putBoolean(KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL, false);
         sDefaults.putBoolean(KEY_OPERATOR_SELECTION_EXPAND_BOOL, true);
-        sDefaults.putBoolean(KEY_PREFER_2G_BOOL, true);
+        sDefaults.putBoolean(KEY_PREFER_2G_BOOL, false);
         sDefaults.putBoolean(KEY_4G_ONLY_BOOL, false);
         sDefaults.putBoolean(KEY_SHOW_APN_SETTING_CDMA_BOOL, false);
         sDefaults.putBoolean(KEY_SHOW_CDMA_CHOICES_BOOL, false);
@@ -9493,42 +9499,26 @@
     private void addConfig(String key, Object value, PersistableBundle configs) {
         if (value instanceof String) {
             configs.putString(key, (String) value);
-        }
-
-        if (value instanceof String[]) {
+        } else if (value instanceof String[]) {
             configs.putStringArray(key, (String[]) value);
-        }
-
-        if (value instanceof Integer) {
+        } else if (value instanceof Integer) {
             configs.putInt(key, (Integer) value);
-        }
-
-        if (value instanceof Long) {
+        } else if (value instanceof Long) {
             configs.putLong(key, (Long) value);
-        }
-
-        if (value instanceof Double) {
+        } else if (value instanceof Double) {
             configs.putDouble(key, (Double) value);
-        }
-
-        if (value instanceof Boolean) {
+        } else if (value instanceof Boolean) {
             configs.putBoolean(key, (Boolean) value);
-        }
-
-        if (value instanceof int[]) {
+        } else if (value instanceof int[]) {
             configs.putIntArray(key, (int[]) value);
-        }
-
-        if (value instanceof double[]) {
+        } else if (value instanceof double[]) {
             configs.putDoubleArray(key, (double[]) value);
-        }
-
-        if (value instanceof boolean[]) {
+        } else if (value instanceof boolean[]) {
             configs.putBooleanArray(key, (boolean[]) value);
-        }
-
-        if (value instanceof long[]) {
+        } else if (value instanceof long[]) {
             configs.putLongArray(key, (long[]) value);
+        } else if (value instanceof PersistableBundle) {
+            configs.putPersistableBundle(key, (PersistableBundle) value);
         }
     }
 }
diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java
index 730a9d1..2d0135a 100644
--- a/telephony/java/android/telephony/ModemActivityInfo.java
+++ b/telephony/java/android/telephony/ModemActivityInfo.java
@@ -383,8 +383,6 @@
      * activity.
      */
     public @NonNull ModemActivityInfo getDelta(@NonNull ModemActivityInfo other) {
-        int[] txTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
-
         ActivityStatsTechSpecificInfo[] mDeltaSpecificInfo;
         mDeltaSpecificInfo = new ActivityStatsTechSpecificInfo[other.getSpecificInfoLength()];
 
@@ -399,6 +397,7 @@
                         if (other.mActivityStatsTechSpecificInfo[i].getFrequencyRange()
                                 == mActivityStatsTechSpecificInfo[j].getFrequencyRange()) {
                             int freq = mActivityStatsTechSpecificInfo[j].getFrequencyRange();
+                            int[] txTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
                             for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
                                 txTimeMs[lvl] =
                                         (int) (other.getTransmitDurationMillisAtPowerLevel(
@@ -416,6 +415,7 @@
                                                         - getReceiveTimeMillis(rat, freq)));
                         }
                     } else {
+                        int[] txTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
                         for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
                             txTimeMs[lvl] =
                                     (int) (other.getTransmitDurationMillisAtPowerLevel(lvl, rat)
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 1eb391d..ade5543 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -41,6 +41,7 @@
 import android.annotation.TestApi;
 import android.annotation.WorkerThread;
 import android.app.PendingIntent;
+import android.app.PropertyInvalidatedCache;
 import android.app.role.RoleManager;
 import android.compat.Compatibility;
 import android.compat.annotation.ChangeId;
@@ -361,6 +362,42 @@
     @GuardedBy("sCacheLock")
     private static final DeathRecipient sServiceDeath = new DeathRecipient();
 
+    /**
+     * Cache key for a {@link PropertyInvalidatedCache} which maps from {@link PhoneAccountHandle}
+     * to subscription Id.  The cache is initialized in {@code PhoneInterfaceManager}'s constructor
+     * when {@link PropertyInvalidatedCache#invalidateCache(String)} is called.
+     * The cache is cleared from {@code TelecomAccountRegistry#tearDown} when all phone accounts are
+     * removed from Telecom.
+     * @hide
+     */
+    public static final String CACHE_KEY_PHONE_ACCOUNT_TO_SUBID =
+            "cache_key.telephony.phone_account_to_subid";
+    private static final int CACHE_MAX_SIZE = 4;
+
+    /**
+     * A {@link PropertyInvalidatedCache} which lives in an app's {@link TelephonyManager} instance.
+     * Caches any queries for a mapping between {@link PhoneAccountHandle} and {@code subscription
+     * id}.  The cache may be invalidated from Telephony when phone account re-registration takes
+     * place.
+     */
+    private PropertyInvalidatedCache<PhoneAccountHandle, Integer> mPhoneAccountHandleToSubIdCache =
+            new PropertyInvalidatedCache<PhoneAccountHandle, Integer>(CACHE_MAX_SIZE,
+                    CACHE_KEY_PHONE_ACCOUNT_TO_SUBID) {
+                @Override
+                public Integer recompute(PhoneAccountHandle phoneAccountHandle) {
+                    try {
+                        ITelephony telephony = getITelephony();
+                        if (telephony != null) {
+                            return telephony.getSubIdForPhoneAccountHandle(phoneAccountHandle,
+                                    mContext.getOpPackageName(), mContext.getAttributionTag());
+                        }
+                    } catch (RemoteException e) {
+                        throw e.rethrowAsRuntimeException();
+                    }
+                    return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+                }
+            };
+
     /** Enum indicating multisim variants
      *  DSDS - Dual SIM Dual Standby
      *  DSDA - Dual SIM Dual Active
@@ -8352,24 +8389,6 @@
     }
 
     /**
-     * Get P-CSCF address from PCO after data connection is established or modified.
-     * @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
-     * @return array of P-CSCF address
-     * @hide
-     */
-    public String[] getPcscfAddress(String apnType) {
-        try {
-            ITelephony telephony = getITelephony();
-            if (telephony == null)
-                return new String[0];
-            return telephony.getPcscfAddress(apnType, getOpPackageName(), getAttributionTag());
-        } catch (RemoteException e) {
-            return new String[0];
-        }
-    }
-
-
-    /**
      * Resets the {@link android.telephony.ims.ImsService} associated with the specified sim slot.
      * Used by diagnostic apps to force the IMS stack to be disabled and re-enabled in an effort to
      * recover from scenarios where the {@link android.telephony.ims.ImsService} gets in to a bad
@@ -9833,15 +9852,7 @@
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public @Nullable String getCarrierServicePackageName() {
-        // TODO(b/205736323) plumb this through to CarrierPrivilegesTracker, which will cache the
-        // value instead of re-querying every time.
-        List<String> carrierServicePackages =
-                getCarrierPackageNamesForIntent(
-                        new Intent(CarrierService.CARRIER_SERVICE_INTERFACE));
-        if (carrierServicePackages != null && !carrierServicePackages.isEmpty()) {
-            return carrierServicePackages.get(0);
-        }
-        return null;
+        return getCarrierServicePackageNameForLogicalSlot(getPhoneId());
     }
 
     /**
@@ -9858,13 +9869,15 @@
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public @Nullable String getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex) {
-        // TODO(b/205736323) plumb this through to CarrierPrivilegesTracker, which will cache the
-        // value instead of re-querying every time.
-        List<String> carrierServicePackages =
-                getCarrierPackageNamesForIntentAndPhone(
-                        new Intent(CarrierService.CARRIER_SERVICE_INTERFACE), logicalSlotIndex);
-        if (carrierServicePackages != null && !carrierServicePackages.isEmpty()) {
-            return carrierServicePackages.get(0);
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getCarrierServicePackageNameForLogicalSlot(logicalSlotIndex);
+            }
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "getCarrierServicePackageNameForLogicalSlot RemoteException", ex);
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "getCarrierServicePackageNameForLogicalSlot NPE", ex);
         }
         return null;
     }
@@ -11904,19 +11917,7 @@
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public int getSubscriptionId(@NonNull PhoneAccountHandle phoneAccountHandle) {
-        int retval = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-        try {
-            ITelephony service = getITelephony();
-            if (service != null) {
-                retval = service.getSubIdForPhoneAccountHandle(
-                        phoneAccountHandle, mContext.getOpPackageName(),
-                        mContext.getAttributionTag());
-            }
-        } catch (RemoteException ex) {
-            Log.e(TAG, "getSubscriptionId RemoteException", ex);
-            ex.rethrowAsRuntimeException();
-        }
-        return retval;
+        return mPhoneAccountHandleToSubIdCache.query(phoneAccountHandle);
     }
 
     /**
@@ -14942,7 +14943,7 @@
             }
             ITelephony service = getITelephony();
             if (service != null) {
-                return service.isMvnoMatched(getSubId(), mvnoType, mvnoMatchData);
+                return service.isMvnoMatched(getSlotIndex(), mvnoType, mvnoMatchData);
             }
         } catch (RemoteException ex) {
             Rlog.e(TAG, "Telephony#matchesCurrentSimOperator RemoteException" + ex);
@@ -16787,12 +16788,15 @@
     }
 
     /**
-     * Callback to listen for when the set of packages with carrier privileges for a SIM changes.
+     * Callbacks to listen for when the set of packages with carrier privileges for a SIM changes.
+     *
+     * <p>Of note, when multiple callbacks are registered, they may be triggered one after another.
+     * The ordering of them is not guaranteed and thus should not be depend on.
      *
      * @hide
      */
     @SystemApi
-    public interface CarrierPrivilegesListener {
+    public interface CarrierPrivilegesCallback {
         /**
          * Called when the set of packages with carrier privileges has changed.
          *
@@ -16802,60 +16806,33 @@
          * <p>At registration, the callback will receive the current set of privileged packages.
          *
          * @param privilegedPackageNames The updated set of package names that have carrier
-         *     privileges
-         * @param privilegedUids The updated set of UIDs that have carrier privileges
+         *                               privileges
+         * @param privilegedUids         The updated set of UIDs that have carrier privileges
          */
         void onCarrierPrivilegesChanged(
-                @NonNull List<String> privilegedPackageNames, @NonNull int[] privilegedUids);
-    }
+                @NonNull Set<String> privilegedPackageNames, @NonNull Set<Integer> privilegedUids);
 
-    /**
-     * Registers a {@link CarrierPrivilegesListener} on the given {@code logicalSlotIndex} to
-     * receive callbacks when the set of packages with carrier privileges changes. The callback will
-     * immediately be called with the latest state.
-     *
-     * @param logicalSlotIndex The SIM slot to listen on
-     * @param executor The executor where {@code listener} will be invoked
-     * @param listener The callback to register
-     * @hide
-     */
-    @SystemApi
-    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public void addCarrierPrivilegesListener(
-            int logicalSlotIndex,
-            @NonNull @CallbackExecutor Executor executor,
-            @NonNull CarrierPrivilegesListener listener) {
-        if (mContext == null) {
-            throw new IllegalStateException("Telephony service is null");
-        } else if (executor == null || listener == null) {
-            throw new IllegalArgumentException(
-                    "CarrierPrivilegesListener and executor must be non-null");
+        /**
+         * Called when the {@link CarrierService} for the current user profile has changed.
+         *
+         * <p>This method does nothing by default. Clients that are interested in the carrier
+         * service change should override this method to get package name and UID info.
+         *
+         * <p>At registration, the callback will receive the current carrier service info.
+         *
+         * <p>Of note, this callback will <b>not</b> be fired if a carrier triggers a SIM profile
+         * switch and the same carrier service remains after switch.
+         *
+         * @param carrierServicePackageName package name of the {@link CarrierService}. May be
+         *                                  {@code null} when no carrier service is detected.
+         * @param carrierServiceUid         UID of the {@link CarrierService}. May be
+         *                                  {@link android.os.Process#INVALID_UID} if no carrier
+         *                                  service is detected.
+         */
+        default void onCarrierServiceChanged(
+                @Nullable String carrierServicePackageName, int carrierServiceUid) {
+            // do nothing by default
         }
-        mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class);
-        if (mTelephonyRegistryMgr == null) {
-            throw new IllegalStateException("Telephony registry service is null");
-        }
-        mTelephonyRegistryMgr.addCarrierPrivilegesListener(logicalSlotIndex, executor, listener);
-    }
-
-    /**
-     * Unregisters an existing {@link CarrierPrivilegesListener}.
-     *
-     * @hide
-     */
-    @SystemApi
-    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public void removeCarrierPrivilegesListener(@NonNull CarrierPrivilegesListener listener) {
-        if (mContext == null) {
-            throw new IllegalStateException("Telephony service is null");
-        } else if (listener == null) {
-            throw new IllegalArgumentException("CarrierPrivilegesListener must be non-null");
-        }
-        mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class);
-        if (mTelephonyRegistryMgr == null) {
-            throw new IllegalStateException("Telephony registry service is null");
-        }
-        mTelephonyRegistryMgr.removeCarrierPrivilegesListener(listener);
     }
 
     /**
@@ -16890,4 +16867,53 @@
             ex.rethrowAsRuntimeException();
         }
     }
+
+    /**
+     * Registers a {@link CarrierPrivilegesCallback} on the given {@code logicalSlotIndex} to
+     * receive callbacks when the set of packages with carrier privileges changes. The callback will
+     * immediately be called with the latest state.
+     *
+     * @param logicalSlotIndex The SIM slot to listen on
+     * @param executor The executor where {@code callback} will be invoked
+     * @param callback The callback to register
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public void registerCarrierPrivilegesCallback(
+            int logicalSlotIndex,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull CarrierPrivilegesCallback callback) {
+        if (mContext == null) {
+            throw new IllegalStateException("Telephony service is null");
+        } else if (executor == null || callback == null) {
+            throw new IllegalArgumentException(
+                    "CarrierPrivilegesCallback and executor must be non-null");
+        }
+        mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class);
+        if (mTelephonyRegistryMgr == null) {
+            throw new IllegalStateException("Telephony registry service is null");
+        }
+        mTelephonyRegistryMgr.addCarrierPrivilegesCallback(logicalSlotIndex, executor, callback);
+    }
+
+    /**
+     * Unregisters an existing {@link CarrierPrivilegesCallback}.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public void unregisterCarrierPrivilegesCallback(@NonNull CarrierPrivilegesCallback callback) {
+        if (mContext == null) {
+            throw new IllegalStateException("Telephony service is null");
+        } else if (callback == null) {
+            throw new IllegalArgumentException("CarrierPrivilegesCallback must be non-null");
+        }
+        mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class);
+        if (mTelephonyRegistryMgr == null) {
+            throw new IllegalStateException("Telephony registry service is null");
+        }
+        mTelephonyRegistryMgr.removeCarrierPrivilegesCallback(callback);
+    }
 }
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index fc94ebf..8143da5 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -549,7 +549,6 @@
      * Returns the profile id to which the APN saved in modem.
      *
      * @return the profile id of the APN
-     * @hide
      */
     public int getProfileId() {
         return mProfileId;
@@ -558,8 +557,7 @@
     /**
      * Returns if the APN setting is persistent on the modem.
      *
-     * @return is the APN setting to be set in modem
-     * @hide
+     * @return {@code true} if the APN setting is persistent on the modem.
      */
     public boolean isPersistent() {
         return mPersistent;
@@ -1103,8 +1101,10 @@
         sb.append(", ").append(MVNO_TYPE_INT_MAP.get(mMvnoType));
         sb.append(", ").append(mMvnoMatchData);
         sb.append(", ").append(mPermanentFailed);
-        sb.append(", ").append(mNetworkTypeBitmask);
-        sb.append(", ").append(mLingeringNetworkTypeBitmask);
+        sb.append(", ").append(TelephonyManager.convertNetworkTypeBitmaskToString(
+                mNetworkTypeBitmask));
+        sb.append(", ").append(TelephonyManager.convertNetworkTypeBitmaskToString(
+                mLingeringNetworkTypeBitmask));
         sb.append(", ").append(mApnSetId);
         sb.append(", ").append(mCarrierId);
         sb.append(", ").append(mSkip464Xlat);
diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java
index 892eb29..bd346d5 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -31,6 +31,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
+import android.telephony.AccessNetworkConstants.RadioAccessNetworkType;
 import android.util.Log;
 import android.util.SparseArray;
 
@@ -166,7 +167,8 @@
          *        link properties of the existing data connection, otherwise null.
          * @param callback The result callback for this request.
          */
-        public void setupDataCall(int accessNetworkType, @NonNull DataProfile dataProfile,
+        public void setupDataCall(
+                @RadioAccessNetworkType int accessNetworkType, @NonNull DataProfile dataProfile,
                 boolean isRoaming, boolean allowRoaming,
                 @SetupDataReason int reason, @Nullable LinkProperties linkProperties,
                 @NonNull DataServiceCallback callback) {
@@ -214,7 +216,8 @@
          *        for example, a zero-rating slice.
          * @param callback The result callback for this request.
          */
-        public void setupDataCall(int accessNetworkType, @NonNull DataProfile dataProfile,
+        public void setupDataCall(
+                @RadioAccessNetworkType int accessNetworkType, @NonNull DataProfile dataProfile,
                 boolean isRoaming, boolean allowRoaming,
                 @SetupDataReason int reason,
                 @Nullable LinkProperties linkProperties,
@@ -294,6 +297,9 @@
          * with reason {@link DataService.REQUEST_REASON_HANDOVER}. The target transport now owns
          * the transferred resources and is responsible for releasing them.
          *
+         * <p/>
+         * Note that the callback will be executed on binder thread.
+         *
          * @param cid The identifier of the data call which is provided in {@link DataCallResponse}
          * @param callback The result callback for this request.
          *
@@ -322,6 +328,9 @@
          * </li>
          * </ul>
          *
+         * <p/>
+         * Note that the callback will be executed on binder thread.
+         *
          * @param cid The identifier of the data call which is provided in {@link DataCallResponse}
          * @param callback The result callback for this request.
          *
diff --git a/telephony/java/android/telephony/data/DataServiceCallback.java b/telephony/java/android/telephony/data/DataServiceCallback.java
index 77d4837..8287a03 100644
--- a/telephony/java/android/telephony/data/DataServiceCallback.java
+++ b/telephony/java/android/telephony/data/DataServiceCallback.java
@@ -50,8 +50,7 @@
      */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({RESULT_SUCCESS, RESULT_ERROR_UNSUPPORTED, RESULT_ERROR_INVALID_ARG, RESULT_ERROR_BUSY,
-            RESULT_ERROR_ILLEGAL_STATE, RESULT_ERROR_TEMPORARILY_UNAVAILABLE,
-            RESULT_ERROR_INVALID_RESPONSE})
+            RESULT_ERROR_ILLEGAL_STATE, RESULT_ERROR_TEMPORARILY_UNAVAILABLE})
     public @interface ResultCode {}
 
     /** Request is completed successfully */
@@ -69,11 +68,6 @@
      * @hide
      */
     public static final int RESULT_ERROR_TEMPORARILY_UNAVAILABLE = 5;
-    /**
-     * Request failed to complete due to an invalid response.
-     * @hide
-     */
-    public static final int RESULT_ERROR_INVALID_RESPONSE = 6;
 
     private final IDataServiceCallback mCallback;
 
@@ -261,8 +255,6 @@
                 return "RESULT_ERROR_ILLEGAL_STATE";
             case RESULT_ERROR_TEMPORARILY_UNAVAILABLE:
                 return "RESULT_ERROR_TEMPORARILY_UNAVAILABLE";
-            case RESULT_ERROR_INVALID_RESPONSE:
-                return "RESULT_ERROR_INVALID_RESPONSE";
             default:
                 return "Unknown(" + resultCode + ")";
         }
diff --git a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
index fe44530..5ffee56 100644
--- a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
+++ b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
@@ -32,7 +32,12 @@
 import java.util.Objects;
 
 /**
- * Provides Qos attributes of an EPS bearer.
+ * Provides QOS attributes of an EPS bearer.
+ *
+ * <p> The dedicated EPS bearer along with QOS is allocated by the LTE network and notified to the
+ * device. The Telephony framework creates the {@link EpsBearerQosSessionAttributes} object which
+ * represents the QOS of the dedicated bearer and notifies the same to applications via
+ * {@link QosCallback}.
  *
  * {@hide}
  */
diff --git a/telephony/java/android/telephony/data/QualifiedNetworksService.java b/telephony/java/android/telephony/data/QualifiedNetworksService.java
index 4e85d89..a846088 100644
--- a/telephony/java/android/telephony/data/QualifiedNetworksService.java
+++ b/telephony/java/android/telephony/data/QualifiedNetworksService.java
@@ -129,17 +129,31 @@
         }
 
         /**
-         * Update the qualified networks list. Network availability provider must invoke this method
-         * whenever the qualified networks changes. If this method is never invoked for certain
-         * APN types, then frameworks will always use the default (i.e. cellular) data and network
-         * service.
+         * Update the suggested qualified networks list. Network availability provider must invoke
+         * this method whenever the suggested qualified networks changes. If this method is never
+         * invoked for certain APN types, then frameworks uses its own logic to determine the
+         * transport to setup the data network.
+         *
+         * For example, QNS can suggest frameworks to setup IMS on IWLAN by specifying
+         * {@link ApnSetting#TYPE_IMS} with a list containing single element
+         * {@link AccessNetworkType#IWLAN}.
+         *
+         * Or if QNS consider multiple access networks are qualified for certain APN type, it can
+         * suggest frameworks by specifying the APN type with multiple elements in the list like
+         * {{@link AccessNetworkType#EUTRAN}, {@link AccessNetworkType#IWLAN}}. Frameworks will then
+         * first attempt to setup data on LTE network. If the device moves from LTE to UMTS, then
+         * frameworks can perform handover the data network to the second preferred access network
+         * if available.
+         *
+         * If the {@code qualifiedNetworkTypes} list is empty, it means QNS has no suggestion to the
+         * frameworks, and frameworks will decide the transport to setup the data network.
          *
          * @param apnTypes APN types of the qualified networks. This must be a bitmask combination
          * of {@link ApnType}.
          * @param qualifiedNetworkTypes List of network types which are qualified for data
          * connection setup for {@link @apnType} in the preferred order. Each element in the list
-         * is a {@link AccessNetworkType}. An empty list indicates no networks are qualified
-         * for data setup.
+         * is a {@link AccessNetworkType}. Note that {@link AccessNetworkType#UNKNOWN} is not a
+         * valid input here.
          */
         public final void updateQualifiedNetworkTypes(
                 @ApnType int apnTypes, @NonNull List<Integer> qualifiedNetworkTypes) {
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index bce210f..5bae1ad 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -621,9 +621,9 @@
 
         ITelephony iTelephony = getITelephony();
         if (iTelephony == null) {
-            throw new RuntimeException("Could not find Telephony Service.");
+            Log.w("ImsMmTelManager", "Could not find Telephony Service.");
+            return;
         }
-
         try {
             iTelephony.unregisterMmTelCapabilityCallback(mSubId, c.getBinder());
         } catch (RemoteException e) {
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index b56aa96..f5b158f 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -375,12 +375,16 @@
      */
     @SystemApi
     public final void setFeatureState(@ImsState int state) {
+        boolean isNotify = false;
         synchronized (mLock) {
             if (mState != state) {
                 mState = state;
-                notifyFeatureState(state);
+                isNotify = true;
             }
         }
+        if (isNotify) {
+            notifyFeatureState(state);
+        }
     }
 
     /**
@@ -412,14 +416,16 @@
      * Internal method called by ImsFeature when setFeatureState has changed.
      */
     private void notifyFeatureState(@ImsState int state) {
-        mStatusCallbacks.broadcastAction((c) -> {
-            try {
-                c.notifyImsFeatureStatus(state);
-            } catch (RemoteException e) {
-                Log.w(LOG_TAG, e + " notifyFeatureState() - Skipping "
-                        + "callback.");
-            }
-        });
+        synchronized (mStatusCallbacks) {
+            mStatusCallbacks.broadcastAction((c) -> {
+                try {
+                    c.notifyImsFeatureStatus(state);
+                } catch (RemoteException e) {
+                    Log.w(LOG_TAG, e + " notifyFeatureState() - Skipping "
+                            + "callback.");
+                }
+            });
+        }
     }
 
     /**
@@ -491,14 +497,19 @@
         synchronized (mLock) {
             mCapabilityStatus = caps.copy();
         }
-        mCapabilityCallbacks.broadcastAction((callback) -> {
-            try {
-                callback.onCapabilitiesStatusChanged(caps.mCapabilities);
-            } catch (RemoteException e) {
-                Log.w(LOG_TAG, e + " notifyCapabilitiesStatusChanged() - Skipping "
-                        + "callback.");
-            }
-        });
+
+        synchronized (mCapabilityCallbacks) {
+            mCapabilityCallbacks.broadcastAction((callback) -> {
+                try {
+                    Log.d(LOG_TAG, "ImsFeature notifyCapabilitiesStatusChanged Capabilities = "
+                            + caps.mCapabilities);
+                    callback.onCapabilitiesStatusChanged(caps.mCapabilities);
+                } catch (RemoteException e) {
+                    Log.w(LOG_TAG, e + " notifyCapabilitiesStatusChanged() - Skipping "
+                            + "callback.");
+                }
+            });
+        }
     }
 
     /**
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
index 11fc328..f371ec3 100644
--- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -587,13 +587,15 @@
         if (mCallbacks == null) {
             return;
         }
-        mCallbacks.broadcastAction(c -> {
-            try {
-                c.onIntConfigChanged(item, value);
-            } catch (RemoteException e) {
-                Log.w(TAG, "notifyConfigChanged(int): dead binder in notify, skipping.");
-            }
-        });
+        synchronized (mCallbacks) {
+            mCallbacks.broadcastAction(c -> {
+                try {
+                    c.onIntConfigChanged(item, value);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "notifyConfigChanged(int): dead binder in notify, skipping.");
+                }
+            });
+        }
     }
 
     private void notifyConfigChanged(int item, String value) {
@@ -601,13 +603,15 @@
         if (mCallbacks == null) {
             return;
         }
-        mCallbacks.broadcastAction(c -> {
-            try {
-                c.onStringConfigChanged(item, value);
-            } catch (RemoteException e) {
-                Log.w(TAG, "notifyConfigChanged(string): dead binder in notify, skipping.");
-            }
-        });
+        synchronized (mCallbacks) {
+            mCallbacks.broadcastAction(c -> {
+                try {
+                    c.onStringConfigChanged(item, value);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "notifyConfigChanged(string): dead binder in notify, skipping.");
+                }
+            });
+        }
     }
 
     private void addRcsConfigCallback(IRcsConfigCallback c) {
@@ -635,13 +639,15 @@
 
         // can be null in testing
         if (mRcsCallbacks != null) {
-            mRcsCallbacks.broadcastAction(c -> {
-                try {
-                    c.onConfigurationChanged(mRcsConfigData);
-                } catch (RemoteException e) {
-                    Log.w(TAG, "dead binder in notifyRcsAutoConfigurationReceived, skipping.");
-                }
-            });
+            synchronized (mRcsCallbacks) {
+                mRcsCallbacks.broadcastAction(c -> {
+                    try {
+                        c.onConfigurationChanged(mRcsConfigData);
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "dead binder in notifyRcsAutoConfigurationReceived, skipping.");
+                    }
+                });
+            }
         }
         notifyRcsAutoConfigurationReceived(config, isCompressed);
     }
@@ -649,13 +655,15 @@
     private void onNotifyRcsAutoConfigurationRemoved() {
         mRcsConfigData = null;
         if (mRcsCallbacks != null) {
-            mRcsCallbacks.broadcastAction(c -> {
-                try {
-                    c.onConfigurationReset();
-                } catch (RemoteException e) {
-                    Log.w(TAG, "dead binder in notifyRcsAutoConfigurationRemoved, skipping.");
-                }
-            });
+            synchronized (mRcsCallbacks) {
+                mRcsCallbacks.broadcastAction(c -> {
+                    try {
+                        c.onConfigurationReset();
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "dead binder in notifyRcsAutoConfigurationRemoved, skipping.");
+                    }
+                });
+            }
         }
         notifyRcsAutoConfigurationRemoved();
     }
@@ -801,13 +809,15 @@
         if (mRcsCallbacks == null) {
             return;
         }
-        mRcsCallbacks.broadcastAction(c -> {
-            try {
-                c.onAutoConfigurationErrorReceived(errorCode, errorString);
-            } catch (RemoteException e) {
-                Log.w(TAG, "dead binder in notifyAutoConfigurationErrorReceived, skipping.");
-            }
-        });
+        synchronized (mRcsCallbacks) {
+            mRcsCallbacks.broadcastAction(c -> {
+                try {
+                    c.onAutoConfigurationErrorReceived(errorCode, errorString);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "dead binder in notifyAutoConfigurationErrorReceived, skipping.");
+                }
+            });
+        }
     }
 
     /**
@@ -825,13 +835,15 @@
         if (mRcsCallbacks == null) {
             return;
         }
-        mRcsCallbacks.broadcastAction(c -> {
-            try {
-                c.onPreProvisioningReceived(configXml);
-            } catch (RemoteException e) {
-                Log.w(TAG, "dead binder in notifyPreProvisioningReceived, skipping.");
-            }
-        });
+        synchronized (mRcsCallbacks) {
+            mRcsCallbacks.broadcastAction(c -> {
+                try {
+                    c.onPreProvisioningReceived(configXml);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "dead binder in notifyPreProvisioningReceived, skipping.");
+                }
+            });
+        }
     }
 
     /**
diff --git a/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java b/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java
index 2783e29..fb997d1 100644
--- a/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java
@@ -219,22 +219,25 @@
      */
     public final void onSmsReceived(int token, @SmsMessage.Format String format, byte[] pdu)
             throws RuntimeException {
+        IImsSmsListener listener = null;
         synchronized (mLock) {
-            if (mListener == null) {
-                throw new RuntimeException("Feature not ready.");
-            }
-            try {
-                mListener.onSmsReceived(token, format, pdu);
-            } catch (RemoteException e) {
-                Log.e(LOG_TAG, "Can not deliver sms: " + e.getMessage());
-                SmsMessage message = SmsMessage.createFromPdu(pdu, format);
-                if (message != null && message.mWrappedSmsMessage != null) {
-                    acknowledgeSms(token, message.mWrappedSmsMessage.mMessageRef,
-                            DELIVER_STATUS_ERROR_GENERIC);
-                } else {
-                    Log.w(LOG_TAG, "onSmsReceived: Invalid pdu entered.");
-                    acknowledgeSms(token, 0, DELIVER_STATUS_ERROR_GENERIC);
-                }
+            listener = mListener;
+        }
+
+        if (listener == null) {
+            throw new RuntimeException("Feature not ready.");
+        }
+        try {
+            listener.onSmsReceived(token, format, pdu);
+        } catch (RemoteException e) {
+            Log.e(LOG_TAG, "Can not deliver sms: " + e.getMessage());
+            SmsMessage message = SmsMessage.createFromPdu(pdu, format);
+            if (message != null && message.mWrappedSmsMessage != null) {
+                acknowledgeSms(token, message.mWrappedSmsMessage.mMessageRef,
+                        DELIVER_STATUS_ERROR_GENERIC);
+            } else {
+                Log.w(LOG_TAG, "onSmsReceived: Invalid pdu entered.");
+                acknowledgeSms(token, 0, DELIVER_STATUS_ERROR_GENERIC);
             }
         }
     }
@@ -254,16 +257,19 @@
      */
     public final void onSendSmsResultSuccess(int token,
             @IntRange(from = 0, to = 65535) int messageRef) throws RuntimeException {
+        IImsSmsListener listener = null;
         synchronized (mLock) {
-            if (mListener == null) {
-                throw new RuntimeException("Feature not ready.");
-            }
-            try {
-                mListener.onSendSmsResult(token, messageRef, SEND_STATUS_OK,
-                        SmsManager.RESULT_ERROR_NONE, RESULT_NO_NETWORK_ERROR);
-            } catch (RemoteException e) {
-                e.rethrowFromSystemServer();
-            }
+            listener = mListener;
+        }
+
+        if (listener == null) {
+            throw new RuntimeException("Feature not ready.");
+        }
+        try {
+            listener.onSendSmsResult(token, messageRef, SEND_STATUS_OK,
+                    SmsManager.RESULT_ERROR_NONE, RESULT_NO_NETWORK_ERROR);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -288,16 +294,19 @@
     @Deprecated
     public final void onSendSmsResult(int token, @IntRange(from = 0, to = 65535) int messageRef,
             @SendStatusResult int status, @SmsManager.Result int reason) throws RuntimeException {
+        IImsSmsListener listener = null;
         synchronized (mLock) {
-            if (mListener == null) {
-                throw new RuntimeException("Feature not ready.");
-            }
-            try {
-                mListener.onSendSmsResult(token, messageRef, status, reason,
-                        RESULT_NO_NETWORK_ERROR);
-            } catch (RemoteException e) {
-                e.rethrowFromSystemServer();
-            }
+            listener = mListener;
+        }
+
+        if (listener == null) {
+            throw new RuntimeException("Feature not ready.");
+        }
+        try {
+            listener.onSendSmsResult(token, messageRef, status, reason,
+                    RESULT_NO_NETWORK_ERROR);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -322,15 +331,18 @@
     public final void onSendSmsResultError(int token,
             @IntRange(from = 0, to = 65535) int messageRef, @SendStatusResult int status,
             @SmsManager.Result int reason, int networkErrorCode) throws RuntimeException {
+        IImsSmsListener listener = null;
         synchronized (mLock) {
-            if (mListener == null) {
-                throw new RuntimeException("Feature not ready.");
-            }
-            try {
-                mListener.onSendSmsResult(token, messageRef, status, reason, networkErrorCode);
-            } catch (RemoteException e) {
-                e.rethrowFromSystemServer();
-            }
+            listener = mListener;
+        }
+
+        if (listener == null) {
+            throw new RuntimeException("Feature not ready.");
+        }
+        try {
+            listener.onSendSmsResult(token, messageRef, status, reason, networkErrorCode);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -357,16 +369,19 @@
     public final void onSmsStatusReportReceived(int token,
             @IntRange(from = 0, to = 65535) int messageRef, @SmsMessage.Format String format,
             byte[] pdu) throws RuntimeException {
+        IImsSmsListener listener = null;
         synchronized (mLock) {
-            if (mListener == null) {
-                throw new RuntimeException("Feature not ready.");
-            }
-            try {
-                mListener.onSmsStatusReportReceived(token, format, pdu);
-            } catch (RemoteException e) {
-                Log.e(LOG_TAG, "Can not process sms status report: " + e.getMessage());
-                acknowledgeSmsReport(token, messageRef, STATUS_REPORT_STATUS_ERROR);
-            }
+            listener = mListener;
+        }
+
+        if (listener == null) {
+            throw new RuntimeException("Feature not ready.");
+        }
+        try {
+            listener.onSmsStatusReportReceived(token, format, pdu);
+        } catch (RemoteException e) {
+            Log.e(LOG_TAG, "Can not process sms status report: " + e.getMessage());
+            acknowledgeSmsReport(token, messageRef, STATUS_REPORT_STATUS_ERROR);
         }
     }
 
@@ -386,24 +401,27 @@
      */
     public final void onSmsStatusReportReceived(int token, @SmsMessage.Format String format,
             byte[] pdu) throws RuntimeException {
+        IImsSmsListener listener = null;
         synchronized (mLock) {
-            if (mListener == null) {
-                throw new RuntimeException("Feature not ready.");
-            }
-            try {
-                mListener.onSmsStatusReportReceived(token, format, pdu);
-            } catch (RemoteException e) {
-                Log.e(LOG_TAG, "Can not process sms status report: " + e.getMessage());
-                SmsMessage message = SmsMessage.createFromPdu(pdu, format);
-                if (message != null && message.mWrappedSmsMessage != null) {
-                    acknowledgeSmsReport(
-                            token,
-                            message.mWrappedSmsMessage.mMessageRef,
-                            STATUS_REPORT_STATUS_ERROR);
-                } else {
-                    Log.w(LOG_TAG, "onSmsStatusReportReceived: Invalid pdu entered.");
-                    acknowledgeSmsReport(token, 0, STATUS_REPORT_STATUS_ERROR);
-                }
+            listener = mListener;
+        }
+
+        if (listener == null) {
+            throw new RuntimeException("Feature not ready.");
+        }
+        try {
+            listener.onSmsStatusReportReceived(token, format, pdu);
+        } catch (RemoteException e) {
+            Log.e(LOG_TAG, "Can not process sms status report: " + e.getMessage());
+            SmsMessage message = SmsMessage.createFromPdu(pdu, format);
+            if (message != null && message.mWrappedSmsMessage != null) {
+                acknowledgeSmsReport(
+                        token,
+                        message.mWrappedSmsMessage.mMessageRef,
+                        STATUS_REPORT_STATUS_ERROR);
+            } else {
+                Log.w(LOG_TAG, "onSmsStatusReportReceived: Invalid pdu entered.");
+                acknowledgeSmsReport(token, 0, STATUS_REPORT_STATUS_ERROR);
             }
         }
     }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index dc96b35..cfd940d 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -978,14 +978,6 @@
      boolean isManualNetworkSelectionAllowed(int subId);
 
     /**
-     * Get P-CSCF address from PCO after data connection is established or modified.
-     * @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
-     * @param callingPackage The package making the call.
-     * @param callingFeatureId The feature in the package.
-     */
-    String[] getPcscfAddress(String apnType, String callingPackage, String callingFeatureId);
-
-    /**
      * Set IMS registration state
      */
     void setImsRegistrationState(boolean registered);
@@ -2150,7 +2142,7 @@
 
     List<RadioAccessSpecifier> getSystemSelectionChannels(int subId);
 
-    boolean isMvnoMatched(int subId, int mvnoType, String mvnoMatchData);
+    boolean isMvnoMatched(int slotIndex, int mvnoType, String mvnoMatchData);
 
     /**
      * Enqueue a pending sms Consumer, which will answer with the user specified selection for an
@@ -2549,4 +2541,15 @@
      * PhoneAccount#CAPABILITY_VOICE_CALLING_AVAILABLE.
      */
     void setVoiceServiceStateOverride(int subId, boolean hasService, String callingPackage);
+
+    /**
+     * Returns the package name that provides the {@link CarrierService} implementation for the
+     * specified {@code logicalSlotIndex}, or {@code null} if no package with carrier privileges
+     * declares one.
+     *
+     * @param logicalSlotIndex The slot index to fetch the {@link CarrierService} package for
+     * @return The system-selected package that provides the {@link CarrierService} implementation
+     * for the slot, or {@code null} if none is resolved
+     */
+    String getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex);
 }
diff --git a/tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestService.java b/tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestService.java
index 35f1e58..644d450 100644
--- a/tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestService.java
+++ b/tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestService.java
@@ -24,6 +24,8 @@
 import android.os.Environment;
 import android.util.Log;
 
+import libcore.io.Streams;
+
 import java.io.BufferedWriter;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -37,8 +39,6 @@
 import java.net.URL;
 import java.util.Random;
 
-import libcore.io.Streams;
-
 /*
  * Test Service that tries to connect to the web via different methods and outputs the results to
  * the log and a output file.
@@ -146,7 +146,7 @@
         final ConnectivityManager mCM = context.getSystemService(ConnectivityManager.class);
         final Network network = mCM.getActiveNetwork();
 
-        if (client.requestTime("0.pool.ntp.org", 10000, network)) {
+        if (client.requestTime("0.pool.ntp.org", SntpClient.STANDARD_NTP_PORT, 10000, network)) {
             return true;
         }
         return false;
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt
new file mode 100644
index 0000000..2dbf304
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt
@@ -0,0 +1,34 @@
+/*
+ * 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.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.common.FlickerComponentName
+import com.android.server.wm.traces.parser.toFlickerComponent
+
+ class FixedOrientationAppHelper @JvmOverloads constructor(
+     instr: Instrumentation,
+     launcherName: String = ActivityOptions.PORTRAIT_ONLY_ACTIVITY_LAUNCHER_NAME,
+     component: FlickerComponentName =
+             ActivityOptions.PORTRAIT_ONLY_ACTIVITY_COMPONENT_NAME.toFlickerComponent(),
+     launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+             .getInstance(instr)
+             .launcherStrategy
+ ) : StandardAppHelper(instr, launcherName, component, launcherStrategy)
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
new file mode 100644
index 0000000..2a296b7
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
@@ -0,0 +1,113 @@
+/*
+ * 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.server.wm.flicker.ime
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.view.Surface
+import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.*
+import com.android.server.wm.flicker.annotation.Group2
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.*
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test IME window layer will become visible when switching from the fixed orientation activity.
+ * To run this test: `atest FlickerTests:OpenImeWindowFromFixedOrientationAppTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
+class OpenImeWindowFromFixedOrientationAppTest(private val testSpec: FlickerTestParameter) {
+    private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    private val fixedOrientationApp = FixedOrientationAppHelper(instrumentation)
+    private val imeTestApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
+
+    @FlickerBuilderProvider
+    fun buildFlicker(): FlickerBuilder {
+        return FlickerBuilder(instrumentation).apply {
+            setup {
+                eachRun {
+                    fixedOrientationApp.launchViaIntent(wmHelper)
+                    this.setRotation(Surface.ROTATION_90)
+                }
+            }
+            transitions {
+                imeTestApp.launchViaIntent(wmHelper)
+            }
+            teardown {
+                test {
+                    fixedOrientationApp.exit(wmHelper)
+                }
+            }
+        }
+    }
+
+    @Postsubmit
+    @Test
+    fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
+
+    @Postsubmit
+    @Test
+    fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
+
+    @Postsubmit
+    @Test
+    fun imeWindowBecomesVisible() = testSpec.imeWindowBecomesVisible()
+
+    @Postsubmit
+    @Test
+    fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
+
+    @FlakyTest(bugId = 206753786)
+    fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
+
+    @Postsubmit
+    @Test
+    fun imeLayerBecomesVisible() = testSpec.imeLayerBecomesVisible()
+
+    companion object {
+        /**
+         * Creates the test configurations.
+         *
+         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+         * repetitions, screen orientation and navigation modes.
+         */
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun getParams(): Collection<FlickerTestParameter> {
+            return FlickerTestParameterFactory.getInstance()
+                    .getConfigNonRotationTests(
+                            repetitions = 3,
+                            supportedRotations = listOf(Surface.ROTATION_0),
+                            supportedNavigationModes = listOf(
+                                    WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+                            )
+                    )
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt
new file mode 100644
index 0000000..6f2edd0
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt
@@ -0,0 +1,169 @@
+/*
+ * 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.server.wm.flicker.ime
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.RequiresDevice
+import android.view.Surface
+import android.view.WindowManagerPolicyConstants
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.*
+import com.android.server.wm.flicker.annotation.Group4
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
+import com.android.server.wm.traces.common.FlickerComponentName
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import org.junit.Assume.assumeTrue
+import org.junit.Assume.assumeFalse
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test IME window layer will be associated with the app task when going to the overview screen.
+ * To run this test: `atest FlickerTests:OpenImeWindowToOverViewTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group4
+class OpenImeWindowToOverViewTest(private val testSpec: FlickerTestParameter) {
+    private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    private val imeTestApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
+
+    @FlickerBuilderProvider
+    fun buildFlicker(): FlickerBuilder {
+        return FlickerBuilder(instrumentation).apply {
+            setup {
+                eachRun {
+                    imeTestApp.launchViaIntent(wmHelper)
+                }
+            }
+            transitions {
+                device.pressRecentApps()
+                waitForRecentsActivityVisible(wmHelper)
+            }
+            teardown {
+                test {
+                    device.pressHome()
+                    imeTestApp.exit(wmHelper)
+                }
+            }
+        }
+    }
+    @Postsubmit
+    @Test
+    fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
+
+    @Postsubmit
+    @Test
+    fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
+
+    @Postsubmit
+    @Test
+    fun imeWindowIsAlwaysVisible() {
+        testSpec.imeWindowIsAlwaysVisible()
+    }
+
+    @Postsubmit
+    @Test
+    fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
+
+    @Postsubmit
+    @Test
+    fun statusBarLayerIsVisibleInPortrait() {
+        assumeFalse(testSpec.isLandscapeOrSeascapeAtStart)
+        testSpec.statusBarLayerIsVisible()
+    }
+
+    @Postsubmit
+    @Test
+    fun statusBarLayerIsInVisibleInLandscape() {
+        assumeTrue(testSpec.isLandscapeOrSeascapeAtStart)
+        testSpec.assertLayersStart {
+            this.isVisible(FlickerComponentName.STATUS_BAR)
+        }
+        testSpec.assertLayersEnd {
+            this.isInvisible(FlickerComponentName.STATUS_BAR)
+        }
+    }
+
+    @Postsubmit
+    @Test
+    fun imeLayerIsVisibleAndAssociatedWithAppWidow() {
+        testSpec.assertLayersStart {
+            isVisible(FlickerComponentName.IME).visibleRegion(FlickerComponentName.IME)
+                    .coversAtMost(isVisible(imeTestApp.component)
+                            .visibleRegion(imeTestApp.component).region)
+        }
+        testSpec.assertLayers {
+            this.invoke("imeLayerIsVisibleAndAlignAppWidow") {
+                val imeVisibleRegion = it.visibleRegion(FlickerComponentName.IME)
+                val appVisibleRegion = it.visibleRegion(imeTestApp.component)
+                if (imeVisibleRegion.region.isNotEmpty) {
+                    it.isVisible(FlickerComponentName.IME)
+                    imeVisibleRegion.coversAtMost(appVisibleRegion.region)
+                }
+            }
+        }
+    }
+
+    private fun waitForRecentsActivityVisible(
+        wmHelper: WindowManagerStateHelper
+    ) {
+        val waitMsg = "state of Recents activity to be visible"
+        require(
+                wmHelper.waitFor(waitMsg) {
+                    it.wmState.homeActivity?.let { act ->
+                        it.wmState.isActivityVisible(act.name)
+                    } == true ||
+                            it.wmState.recentsActivity?.let { act ->
+                                it.wmState.isActivityVisible(act.name)
+                            } == true
+                }
+        ) { "Recents activity should be visible" }
+        wmHelper.waitForAppTransitionIdle()
+        // Ensure WindowManagerService wait until all animations have completed
+        instrumentation.uiAutomation.syncInputTransactions()
+    }
+
+    companion object {
+        /**
+         * Creates the test configurations.
+         *
+         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+         * repetitions, screen orientation and navigation modes.
+         */
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun getParams(): Collection<FlickerTestParameter> {
+            return FlickerTestParameterFactory.getInstance()
+                    .getConfigNonRotationTests(
+                            repetitions = 1,
+                            supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90),
+                            supportedNavigationModes = listOf(
+                                    WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
+                                    WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+                            )
+                    )
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
index b0e53e9..c3a4769 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
@@ -74,7 +74,7 @@
      * Checks that the nav bar layer starts invisible, becomes visible during unlocking animation
      * and remains visible at the end
      */
-    @Postsubmit
+    @Presubmit
     @Test
     fun navBarLayerVisibilityChanges() {
         testSpec.assertLayers {
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 9e371e5..739fe02 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -108,5 +108,16 @@
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
+        <activity android:name=".PortraitOnlyActivity"
+            android:taskAffinity="com.android.server.wm.flicker.testapp.PortraitOnlyActivity"
+            android:theme="@style/CutoutShortEdges"
+            android:screenOrientation="portrait"
+            android:configChanges="orientation|screenSize"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index 13adb68..3040a09 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -60,4 +60,9 @@
     public static final ComponentName DIALOG_THEMED_ACTIVITY_COMPONENT_NAME =
             new ComponentName(FLICKER_APP_PACKAGE,
                     FLICKER_APP_PACKAGE + ".DialogThemedActivity");
+
+    public static final String PORTRAIT_ONLY_ACTIVITY_LAUNCHER_NAME = "PortraitOnlyActivity";
+    public static final ComponentName PORTRAIT_ONLY_ACTIVITY_COMPONENT_NAME =
+            new ComponentName(FLICKER_APP_PACKAGE,
+                    FLICKER_APP_PACKAGE + ".PortraitOnlyActivity");
 }
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PortraitOnlyActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PortraitOnlyActivity.java
new file mode 100644
index 0000000..b1876b5
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PortraitOnlyActivity.java
@@ -0,0 +1,33 @@
+/*
+ * 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.server.wm.flicker.testapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+public class PortraitOnlyActivity extends Activity {
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        WindowManager.LayoutParams p = getWindow().getAttributes();
+        p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
+                .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+        getWindow().setAttributes(p);
+        setContentView(R.layout.activity_simple);
+    }
+}
diff --git a/tests/InputMethodStressTest/AndroidTest.xml b/tests/InputMethodStressTest/AndroidTest.xml
index fc54ca6..5fb260f 100644
--- a/tests/InputMethodStressTest/AndroidTest.xml
+++ b/tests/InputMethodStressTest/AndroidTest.xml
@@ -19,8 +19,8 @@
     <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
 
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="run-command" value="adb shell settings put secure show_ime_with_hard_keyboard 1" />
-        <option name="teardown-command" value="adb shell settings delete secure show_ime_with_hard_keyboard" />
+        <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1" />
+        <option name="teardown-command" value="settings delete secure show_ime_with_hard_keyboard" />
     </target_preparer>
 
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
diff --git a/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeOpenCloseStressTest.java b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeOpenCloseStressTest.java
index 0e86bc8..b3c63c8 100644
--- a/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeOpenCloseStressTest.java
+++ b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeOpenCloseStressTest.java
@@ -18,16 +18,19 @@
 
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
 
+import static com.android.inputmethod.stresstest.ImeStressTestUtil.isImeShown;
 import static com.android.inputmethod.stresstest.ImeStressTestUtil.waitOnMainUntil;
-import static com.android.inputmethod.stresstest.ImeStressTestUtil.waitOnMainUntilImeIsHidden;
-import static com.android.inputmethod.stresstest.ImeStressTestUtil.waitOnMainUntilImeIsShown;
 
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Intent;
 import android.os.Bundle;
+import android.os.SystemClock;
 import android.platform.test.annotations.RootPermissionTest;
+import android.view.WindowInsets;
+import android.view.WindowInsetsAnimation;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.EditText;
 import android.widget.LinearLayout;
@@ -39,11 +42,13 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.List;
+
 @RootPermissionTest
 @RunWith(AndroidJUnit4.class)
 public final class ImeOpenCloseStressTest {
 
-    private static final int NUM_TEST_ITERATIONS = 100;
+    private static final int NUM_TEST_ITERATIONS = 10;
 
     @Test
     public void test() {
@@ -57,16 +62,46 @@
         EditText editText = activity.getEditText();
         waitOnMainUntil("activity should gain focus", editText::hasWindowFocus);
         for (int i = 0; i < NUM_TEST_ITERATIONS; i++) {
+            String msgPrefix = "Iteration #" + i + " ";
             instrumentation.runOnMainSync(activity::showIme);
-            waitOnMainUntilImeIsShown(editText);
+            waitOnMainUntil(msgPrefix + "IME should be visible",
+                    () -> !activity.isAnimating() && isImeShown(editText));
             instrumentation.runOnMainSync(activity::hideIme);
-            waitOnMainUntilImeIsHidden(editText);
+            waitOnMainUntil(msgPrefix + "IME should be hidden",
+                    () -> !activity.isAnimating() && !isImeShown(editText));
+            // b/b/221483132, wait until IMS and IMMS handles IMM#notifyImeHidden.
+            // There is no good signal, so we just wait a second.
+            SystemClock.sleep(1000);
         }
     }
 
     public static class TestActivity extends Activity {
 
         private EditText mEditText;
+        private boolean mIsAnimating;
+
+        private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback =
+                new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {
+                    @Override
+                    public WindowInsetsAnimation.Bounds onStart(WindowInsetsAnimation animation,
+                            WindowInsetsAnimation.Bounds bounds) {
+                        mIsAnimating = true;
+                        return super.onStart(animation, bounds);
+                    }
+
+                    @Override
+                    public void onEnd(WindowInsetsAnimation animation) {
+                        super.onEnd(animation);
+                        mIsAnimating = false;
+                    }
+
+                    @Override
+                    public WindowInsets onProgress(WindowInsets insets,
+                            List<WindowInsetsAnimation> runningAnimations) {
+                        return insets;
+                    }
+                };
+
 
         @Override
         protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -76,6 +111,9 @@
             mEditText = new EditText(this);
             rootView.addView(mEditText, new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
             setContentView(rootView);
+            // Enable WindowInsetsAnimation.
+            getWindow().setDecorFitsSystemWindows(false);
+            mEditText.setWindowInsetsAnimationCallback(mWindowInsetsAnimationCallback);
         }
 
         public EditText getEditText() {
@@ -92,5 +130,9 @@
             InputMethodManager imm = getSystemService(InputMethodManager.class);
             imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
         }
+
+        public boolean isAnimating() {
+            return mIsAnimating;
+        }
     }
 }
diff --git a/tests/SoundTriggerTestApp/OWNERS b/tests/SoundTriggerTestApp/OWNERS
index 816bc6b..9db19a3 100644
--- a/tests/SoundTriggerTestApp/OWNERS
+++ b/tests/SoundTriggerTestApp/OWNERS
@@ -1 +1,2 @@
 include /core/java/android/media/soundtrigger/OWNERS
+mdooley@google.com
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestActivity.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestActivity.java
index 72aa38d..103d516 100644
--- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestActivity.java
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestActivity.java
@@ -97,13 +97,8 @@
 
         setVolumeControlStream(AudioManager.STREAM_MUSIC);
 
-        // Make sure that the service is started, so even if our activity goes down, we'll still
-        // have a request for it to run.
-        startService(new Intent(getBaseContext(), SoundTriggerTestService.class));
-
-        // Bind to SoundTriggerTestService.
-        Intent intent = new Intent(this, SoundTriggerTestService.class);
-        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
+        requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO},
+                AUDIO_PERMISSIONS_REQUEST);
     }
 
     @Override
@@ -267,12 +262,16 @@
 
     public synchronized void onCaptureAudioCheckboxClicked(View v) {
         // See if we have the right permissions
-        if (!mService.hasMicrophonePermission()) {
-            requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO},
-                    AUDIO_PERMISSIONS_REQUEST);
-            return;
+        if (mService == null) {
+            Log.e(TAG, "Can't set capture audio: not bound to SoundTriggerTestService");
         } else {
-            mService.setCaptureAudio(mSelectedModelUuid, mCaptureAudioCheckBox.isChecked());
+            if (!mService.hasMicrophonePermission()) {
+                requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO},
+                        AUDIO_PERMISSIONS_REQUEST);
+                return;
+            } else {
+                mService.setCaptureAudio(mSelectedModelUuid, mCaptureAudioCheckBox.isChecked());
+            }
         }
     }
 
@@ -283,8 +282,15 @@
             if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
                 // Make sure that the check box is set to false.
                 mCaptureAudioCheckBox.setChecked(false);
+            } else {
+                // After granted Record_Audio permission, start and bind the service.
+                // so we can run that sound trigger capability,
+                // even if our activity goes down, we'll still have a request for it to run.
+                startService(new Intent(getBaseContext(), SoundTriggerTestService.class));
+                // Bind to SoundTriggerTestService.
+                Intent intent = new Intent(this, SoundTriggerTestService.class);
+                bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
             }
-            mService.setCaptureAudio(mSelectedModelUuid, mCaptureAudioCheckBox.isChecked());
         }
     }
 
diff --git a/tests/TrustTests/Android.bp b/tests/TrustTests/Android.bp
index c9c6c5c..77f98e8 100644
--- a/tests/TrustTests/Android.bp
+++ b/tests/TrustTests/Android.bp
@@ -25,6 +25,8 @@
         "androidx.test.rules",
         "androidx.test.ext.junit",
         "androidx.test.uiautomator",
+        "mockito-target-minus-junit4",
+        "servicestests-utils",
         "truth-prebuilt",
     ],
     libs: [
diff --git a/tests/TrustTests/AndroidManifest.xml b/tests/TrustTests/AndroidManifest.xml
index c94152d..8b4cbfd 100644
--- a/tests/TrustTests/AndroidManifest.xml
+++ b/tests/TrustTests/AndroidManifest.xml
@@ -23,7 +23,9 @@
     <uses-permission android:name="android.permission.BIND_DEVICE_ADMIN" />
     <uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
     <uses-permission android:name="android.permission.DEVICE_POWER" />
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+    <uses-permission android:name="android.permission.MANAGE_USERS" />
     <uses-permission android:name="android.permission.PROVIDE_TRUST_AGENT" />
     <uses-permission android:name="android.permission.TRUST_LISTENER" />
 
@@ -66,6 +68,16 @@
                 <action android:name="android.service.trust.TrustAgentService" />
             </intent-filter>
         </service>
+
+        <service
+            android:name=".TemporaryAndRenewableTrustAgent"
+            android:exported="true"
+            android:label="Test Agent"
+            android:permission="android.permission.BIND_TRUST_AGENT">
+            <intent-filter>
+                <action android:name="android.service.trust.TrustAgentService" />
+            </intent-filter>
+        </service>
     </application>
 
     <!--  self-instrumenting test package. -->
diff --git a/tests/TrustTests/src/android/trust/BaseTrustAgentService.kt b/tests/TrustTests/src/android/trust/BaseTrustAgentService.kt
index 493f3bd..cf4965f 100644
--- a/tests/TrustTests/src/android/trust/BaseTrustAgentService.kt
+++ b/tests/TrustTests/src/android/trust/BaseTrustAgentService.kt
@@ -41,7 +41,7 @@
         private const val TAG = "BaseTrustAgentService"
 
         fun instance(serviceClass: KClass<out BaseTrustAgentService>): BaseTrustAgentService? {
-            return instances[serviceClass]!!
+            return instances[serviceClass]
         }
     }
 }
diff --git a/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt b/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
index 790afd3..f864fed 100644
--- a/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
+++ b/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
@@ -16,6 +16,7 @@
 
 package android.trust.test
 
+import android.service.trust.GrantTrustResult
 import android.trust.BaseTrustAgentService
 import android.trust.TrustTestActivity
 import android.trust.test.lib.LockStateTrackingRule
@@ -25,11 +26,13 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
 import androidx.test.uiautomator.UiDevice
+import com.android.server.testutils.mock
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.rules.RuleChain
 import org.junit.runner.RunWith
+import org.mockito.Mockito.verifyZeroInteractions
 
 /**
  * Test for testing revokeTrust & grantTrust for non-renewable trust.
@@ -60,31 +63,37 @@
     @Test
     fun sleepingDeviceWithoutGrantLocksDevice() {
         uiDevice.sleep()
-        await()
 
         lockStateTrackingRule.assertLocked()
     }
 
     @Test
     fun grantKeepsDeviceUnlocked() {
-        trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 10000, 0)
+        trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 10000, 0) {}
         uiDevice.sleep()
-        await()
 
         lockStateTrackingRule.assertUnlocked()
     }
 
     @Test
     fun grantKeepsDeviceUnlocked_untilRevoked() {
-        trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 0, 0)
+        trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 0, 0) {}
         await()
         uiDevice.sleep()
         trustAgentRule.agent.revokeTrust()
-        await()
 
         lockStateTrackingRule.assertLocked()
     }
 
+    @Test
+    fun grantDoesNotCallBack() {
+        val callback = mock<(GrantTrustResult) -> Unit>()
+        trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 0, 0, callback)
+        await()
+
+        verifyZeroInteractions(callback)
+    }
+
     companion object {
         private const val TAG = "GrantAndRevokeTrustTest"
         private const val GRANT_MESSAGE = "granted by test"
diff --git a/tests/TrustTests/src/android/trust/test/LockUserTest.kt b/tests/TrustTests/src/android/trust/test/LockUserTest.kt
index 83fc28f..1194afa 100644
--- a/tests/TrustTests/src/android/trust/test/LockUserTest.kt
+++ b/tests/TrustTests/src/android/trust/test/LockUserTest.kt
@@ -24,8 +24,6 @@
 import android.util.Log
 import androidx.test.ext.junit.rules.ActivityScenarioRule
 import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.google.common.truth.Truth.assertThat
-import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.rules.RuleChain
@@ -49,19 +47,16 @@
         .around(lockStateTrackingRule)
         .around(trustAgentRule)
 
-    @Ignore("Causes issues with subsequent tests") // TODO: Enable test
     @Test
     fun lockUser_locksTheDevice() {
         Log.i(TAG, "Locking user")
         trustAgentRule.agent.lockUser()
-        await()
 
-        assertThat(lockStateTrackingRule.lockState.locked).isTrue()
+        lockStateTrackingRule.assertLocked()
     }
 
     companion object {
         private const val TAG = "LockUserTest"
-        private fun await() = Thread.sleep(250)
     }
 }
 
diff --git a/tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt b/tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt
new file mode 100644
index 0000000..3c6d54d
--- /dev/null
+++ b/tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt
@@ -0,0 +1,159 @@
+/*
+ * 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 android.trust.test
+
+import android.service.trust.GrantTrustResult
+import android.service.trust.GrantTrustResult.STATUS_UNLOCKED_BY_GRANT
+import android.service.trust.TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE
+import android.trust.BaseTrustAgentService
+import android.trust.TrustTestActivity
+import android.trust.test.lib.LockStateTrackingRule
+import android.trust.test.lib.ScreenLockRule
+import android.trust.test.lib.TrustAgentRule
+import android.util.Log
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import androidx.test.uiautomator.UiDevice
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.RuleChain
+import org.junit.runner.RunWith
+
+/**
+ * Test for testing revokeTrust & grantTrust for renewable trust.
+ *
+ * atest TrustTests:TemporaryAndRenewableTrustTest
+ */
+@RunWith(AndroidJUnit4::class)
+class TemporaryAndRenewableTrustTest {
+    private val uiDevice = UiDevice.getInstance(getInstrumentation())
+    private val activityScenarioRule = ActivityScenarioRule(TrustTestActivity::class.java)
+    private val lockStateTrackingRule = LockStateTrackingRule()
+    private val trustAgentRule = TrustAgentRule<TemporaryAndRenewableTrustAgent>()
+
+    @get:Rule
+    val rule: RuleChain = RuleChain
+        .outerRule(activityScenarioRule)
+        .around(ScreenLockRule())
+        .around(lockStateTrackingRule)
+        .around(trustAgentRule)
+
+    @Before
+    fun manageTrust() {
+        trustAgentRule.agent.setManagingTrust(true)
+    }
+
+    // This test serves a baseline for Grant tests, verifying that the default behavior of the
+    // device is to lock when put to sleep
+    @Test
+    fun sleepingDeviceWithoutGrantLocksDevice() {
+        uiDevice.sleep()
+
+        lockStateTrackingRule.assertLocked()
+    }
+
+    @Test
+    fun grantTrustLockedDevice_deviceStaysLocked() {
+        uiDevice.sleep()
+        lockStateTrackingRule.assertLocked()
+
+        trustAgentRule.agent.grantTrust(
+            GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) {}
+        uiDevice.wakeUp()
+
+        lockStateTrackingRule.assertLocked()
+    }
+
+    @Test
+    fun grantTrustUnlockedDevice_deviceLocksOnScreenOff() {
+        trustAgentRule.agent.grantTrust(
+            GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) {}
+        uiDevice.sleep()
+
+        lockStateTrackingRule.assertLocked()
+    }
+
+    @Test
+    fun grantTrustLockedDevice_grantTrustOnLockedDeviceUnlocksDevice() {
+        trustAgentRule.agent.grantTrust(
+            GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) {}
+        uiDevice.sleep()
+
+        lockStateTrackingRule.assertLocked()
+
+        trustAgentRule.agent.grantTrust(
+            GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) {}
+        uiDevice.wakeUp()
+
+        lockStateTrackingRule.assertUnlocked()
+    }
+
+    @Test
+    fun grantTrustLockedDevice_callsBackWhenUnlocked() {
+        Log.i(TAG, "Granting renewable trust while unlocked")
+        trustAgentRule.agent.grantTrust(
+            GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) {}
+        await(1000)
+
+        Log.i(TAG, "Locking device")
+        uiDevice.sleep()
+
+        lockStateTrackingRule.assertLocked()
+
+        Log.i(TAG, "Renewing trust and unlocking")
+        var result: GrantTrustResult? = null
+        trustAgentRule.agent.grantTrust(
+                GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) {
+            Log.i(TAG, "Callback received; status=${it.status}")
+            result = it
+        }
+        uiDevice.wakeUp()
+        lockStateTrackingRule.assertUnlocked()
+
+        assertThat(result?.status).isEqualTo(STATUS_UNLOCKED_BY_GRANT)
+    }
+
+    @Test
+    fun grantTrustLockedDevice_revokeTrustPreventsSubsequentUnlock() {
+        trustAgentRule.agent.grantTrust(
+            GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) {}
+        uiDevice.sleep()
+
+        lockStateTrackingRule.assertLocked()
+
+        trustAgentRule.agent.revokeTrust()
+        await(500)
+        uiDevice.wakeUp()
+        await(500)
+
+        trustAgentRule.agent.grantTrust(
+            GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) {}
+
+        lockStateTrackingRule.assertLocked()
+    }
+
+    companion object {
+        private const val TAG = "TemporaryAndRenewableTrustTest"
+        private const val GRANT_MESSAGE = "granted by test"
+        private fun await(millis: Long) = Thread.sleep(millis)
+    }
+}
+
+class TemporaryAndRenewableTrustAgent : BaseTrustAgentService()
diff --git a/tests/TrustTests/src/android/trust/test/UserUnlockRequestTest.kt b/tests/TrustTests/src/android/trust/test/UserUnlockRequestTest.kt
index f8783fb..8bd8340 100644
--- a/tests/TrustTests/src/android/trust/test/UserUnlockRequestTest.kt
+++ b/tests/TrustTests/src/android/trust/test/UserUnlockRequestTest.kt
@@ -32,7 +32,7 @@
 import org.junit.runner.RunWith
 
 /**
- * Test for testing the user unlock trigger.
+ * Test for the user unlock triggers.
  *
  * atest TrustTests:UserUnlockRequestTest
  */
@@ -53,13 +53,32 @@
     @Test
     fun reportUserRequestedUnlock_propagatesToAgent() {
         val oldCount = trustAgentRule.agent.onUserRequestedUnlockCallCount
-        trustManager.reportUserRequestedUnlock(userId)
+        trustManager.reportUserRequestedUnlock(userId, false)
         await()
 
         assertThat(trustAgentRule.agent.onUserRequestedUnlockCallCount)
             .isEqualTo(oldCount + 1)
     }
 
+    @Test
+    fun reportUserRequestedUnlock_propagatesToAgentWithDismissKeyguard() {
+        trustManager.reportUserRequestedUnlock(userId, true)
+        await()
+
+        assertThat(trustAgentRule.agent.lastCallDismissKeyguard)
+            .isTrue()
+    }
+
+    @Test
+    fun reportUserMayRequestUnlock_propagatesToAgent() {
+        val oldCount = trustAgentRule.agent.onUserMayRequestUnlockCallCount
+        trustManager.reportUserMayRequestUnlock(userId)
+        await()
+
+        assertThat(trustAgentRule.agent.onUserMayRequestUnlockCallCount)
+            .isEqualTo(oldCount + 1)
+    }
+
     companion object {
         private const val TAG = "UserUnlockRequestTest"
         private fun await() = Thread.sleep(250)
@@ -69,10 +88,20 @@
 class UserUnlockRequestTrustAgent : BaseTrustAgentService() {
     var onUserRequestedUnlockCallCount: Long = 0
         private set
+    var onUserMayRequestUnlockCallCount: Long = 0
+        private set
+    var lastCallDismissKeyguard: Boolean = false
+        private set
 
-    override fun onUserRequestedUnlock() {
-        Log.i(TAG, "onUserRequestedUnlock")
+    override fun onUserRequestedUnlock(dismissKeyguard: Boolean) {
+        Log.i(TAG, "onUserRequestedUnlock($dismissKeyguard)")
         onUserRequestedUnlockCallCount++
+        lastCallDismissKeyguard = dismissKeyguard
+    }
+
+    override fun onUserMayRequestUnlock() {
+        Log.i(TAG, "onUserMayRequestUnlock")
+        onUserMayRequestUnlockCallCount++
     }
 
     companion object {
diff --git a/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt b/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
index 0023af8..2031af2 100644
--- a/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
+++ b/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
@@ -22,7 +22,6 @@
 import android.util.Log
 import android.view.WindowManagerGlobal
 import androidx.test.core.app.ApplicationProvider.getApplicationContext
-import com.google.common.truth.Truth.assertThat
 import org.junit.rules.TestRule
 import org.junit.runner.Description
 import org.junit.runners.model.Statement
@@ -52,8 +51,14 @@
         }
     }
 
-    fun assertLocked() = assertThat(lockState.locked).isTrue()
-    fun assertUnlocked() = assertThat(lockState.locked).isFalse()
+    fun assertLocked() {
+        wait("un-locked per TrustListener") { lockState.locked == true }
+        wait("keyguard lock") { windowManager.isKeyguardLocked }
+    }
+
+    fun assertUnlocked() {
+        wait("locked per TrustListener") { lockState.locked == false }
+    }
 
     inner class Listener : TrustListener {
         override fun onTrustChanged(
diff --git a/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt b/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt
index bc100ba..7eb8157 100644
--- a/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt
+++ b/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt
@@ -20,6 +20,8 @@
 import android.util.Log
 import android.view.WindowManagerGlobal
 import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import androidx.test.uiautomator.UiDevice
 import com.android.internal.widget.LockPatternUtils
 import com.android.internal.widget.LockscreenCredential
 import com.google.common.truth.Truth.assertWithMessage
@@ -32,6 +34,7 @@
  */
 class ScreenLockRule : TestRule {
     private val context: Context = getApplicationContext()
+    private val uiDevice = UiDevice.getInstance(getInstrumentation())
     private val windowManager = WindowManagerGlobal.getWindowManagerService()
     private val lockPatternUtils = LockPatternUtils(context)
     private var instantLockSavedValue = false
@@ -39,7 +42,7 @@
     override fun apply(base: Statement, description: Description) = object : Statement() {
         override fun evaluate() {
             verifyNoScreenLockAlreadySet()
-            verifyKeyguardDismissed()
+            dismissKeyguard()
             setScreenLock()
             setLockOnPowerButton()
 
@@ -48,39 +51,41 @@
             } finally {
                 removeScreenLock()
                 revertLockOnPowerButton()
+                dismissKeyguard()
             }
         }
     }
 
     private fun verifyNoScreenLockAlreadySet() {
         assertWithMessage("Screen Lock must not already be set on device")
-            .that(lockPatternUtils.isSecure(context.userId))
-            .isFalse()
+                .that(lockPatternUtils.isSecure(context.userId))
+                .isFalse()
     }
 
-    private fun verifyKeyguardDismissed() {
-        val maxWaits = 30
-        var waitCount = 0
-        while (windowManager.isKeyguardLocked && waitCount < maxWaits) {
-            Log.i(TAG, "Keyguard still showing; attempting to dismiss and wait 50ms ($waitCount)")
+    fun dismissKeyguard() {
+        wait("keyguard dismissed") { count ->
             windowManager.dismissKeyguard(null, null)
-            Thread.sleep(50)
-            waitCount++
+
+            // Sometimes, bouncer gets shown due to a race, so we have to put display to sleep
+            // and wake it back up to get it to go away
+            if (count >= 10 && count % 5 == 0) {
+                Log.i(TAG, "Escalation: attempting screen off/on to get rid of bouncer")
+                uiDevice.sleep()
+                Thread.sleep(250)
+                uiDevice.wakeUp()
+            }
+
+            !windowManager.isKeyguardLocked
         }
-        assertWithMessage("Keyguard should be unlocked")
-            .that(windowManager.isKeyguardLocked)
-            .isFalse()
     }
 
     private fun setScreenLock() {
         lockPatternUtils.setLockCredential(
-            LockscreenCredential.createPin(PIN),
-            LockscreenCredential.createNone(),
-            context.userId
+                LockscreenCredential.createPin(PIN),
+                LockscreenCredential.createNone(),
+                context.userId
         )
-        assertWithMessage("Screen Lock should now be set")
-            .that(lockPatternUtils.isSecure(context.userId))
-            .isTrue()
+        wait("screen lock set") { lockPatternUtils.isSecure(context.userId) }
         Log.i(TAG, "Device PIN set to $PIN")
     }
 
@@ -90,14 +95,20 @@
     }
 
     private fun removeScreenLock() {
-        lockPatternUtils.setLockCredential(
-            LockscreenCredential.createNone(),
-            LockscreenCredential.createPin(PIN),
-            context.userId
-        )
-        Log.i(TAG, "Device PIN cleared; waiting 50 ms then dismissing Keyguard")
-        Thread.sleep(50)
-        windowManager.dismissKeyguard(null, null)
+        var lockCredentialUnset = lockPatternUtils.setLockCredential(
+                LockscreenCredential.createNone(),
+                LockscreenCredential.createPin(PIN),
+                context.userId)
+        Log.i(TAG, "Removing screen lock")
+        assertWithMessage("Lock screen credential should be unset")
+                .that(lockCredentialUnset)
+                .isTrue()
+
+        lockPatternUtils.setLockScreenDisabled(true, context.userId)
+        wait("screen lock un-set") {
+            lockPatternUtils.isLockScreenDisabled(context.userId)
+        }
+        wait("screen lock insecure") { !lockPatternUtils.isSecure(context.userId) }
     }
 
     private fun revertLockOnPowerButton() {
diff --git a/tests/TrustTests/src/android/trust/test/lib/TrustAgentRule.kt b/tests/TrustTests/src/android/trust/test/lib/TrustAgentRule.kt
index 2a9e002..18bc029 100644
--- a/tests/TrustTests/src/android/trust/test/lib/TrustAgentRule.kt
+++ b/tests/TrustTests/src/android/trust/test/lib/TrustAgentRule.kt
@@ -50,7 +50,6 @@
             verifyTrustServiceRunning()
             unlockDeviceWithCredential()
             enableTrustAgent()
-            waitForEnablement()
 
             try {
                 verifyAgentIsRunning()
@@ -80,15 +79,10 @@
         lockPatternUtils.setEnabledTrustAgents(agents, userId)
     }
 
-    private fun waitForEnablement() {
-        Log.d(TAG, "Waiting for $WAIT_TIME ms")
-        Thread.sleep(WAIT_TIME)
-        Log.d(TAG, "Done waiting")
-    }
-
     private fun verifyAgentIsRunning() {
-        assertWithMessage("${serviceClass.simpleName} should be running")
-            .that(BaseTrustAgentService.instance(serviceClass)).isNotNull()
+        wait("${serviceClass.simpleName} to be running") {
+            BaseTrustAgentService.instance(serviceClass) != null
+        }
     }
 
     private fun disableTrustAgent() {
@@ -112,6 +106,5 @@
             TrustAgentRule(T::class)
 
         private const val TAG = "TrustAgentRule"
-        private val WAIT_TIME = 1000L
     }
 }
diff --git a/tests/TrustTests/src/android/trust/test/lib/utils.kt b/tests/TrustTests/src/android/trust/test/lib/utils.kt
new file mode 100644
index 0000000..78140ab
--- /dev/null
+++ b/tests/TrustTests/src/android/trust/test/lib/utils.kt
@@ -0,0 +1,51 @@
+/*
+ * 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 android.trust.test.lib
+
+import android.util.Log
+import com.google.common.truth.Truth.assertWithMessage
+
+private const val TAG = "TrustTestUtils"
+
+/**
+ * Waits for [conditionFunction] to be true with a failed assertion if it is not after [maxWait]
+ * ms.
+ *
+ * The condition function can perform additional logic (for example, logging or attempting to make
+ * the condition become true).
+ *
+ * @param conditionFunction function which takes the attempt count & returns whether the condition
+ *                          is met
+ */
+internal fun wait(
+    description: String? = null,
+    maxWait: Long = 1500L,
+    rate: Long = 50L,
+    conditionFunction: (count: Int) -> Boolean
+) {
+    var waited = 0L
+    var count = 0
+    while (!conditionFunction.invoke(count)) {
+        assertWithMessage("Condition exceeded maximum wait time of $maxWait ms: $description")
+            .that(waited <= maxWait)
+            .isTrue()
+        waited += rate
+        count++
+        Log.i(TAG, "Waiting for $description ($waited/$maxWait) #$count")
+        Thread.sleep(rate)
+    }
+}
diff --git a/tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java b/tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java
index 9658d6f..164f61c 100644
--- a/tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java
+++ b/tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java
@@ -37,7 +37,7 @@
     protected static final Context sContext = InstrumentationRegistry.getTargetContext();
 
     protected static final DeviceConfigStateHelper sDeviceConfig = new DeviceConfigStateHelper(
-            DeviceConfig.NAMESPACE_ACTIVITY_MANAGER);
+            DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS);
     @Before
     public void enableComponentAliasWithCompatFlag() throws Exception {
         Assume.assumeTrue(Build.isDebuggable());
diff --git a/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasEnableWithDeviceConfigTest.java b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasEnableWithDeviceConfigTest.java
index 52c6d5b..ee20379 100644
--- a/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasEnableWithDeviceConfigTest.java
+++ b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasEnableWithDeviceConfigTest.java
@@ -28,7 +28,7 @@
 
 public class ComponentAliasEnableWithDeviceConfigTest {
     protected static final DeviceConfigStateHelper sDeviceConfig = new DeviceConfigStateHelper(
-            DeviceConfig.NAMESPACE_ACTIVITY_MANAGER);
+            DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS);
 
     @AfterClass
     public static void restoreDeviceConfig() throws Exception {
diff --git a/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasNotSupportedOnUserBuildTest.java b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasNotSupportedOnUserBuildTest.java
index 7935476..0899886 100644
--- a/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasNotSupportedOnUserBuildTest.java
+++ b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasNotSupportedOnUserBuildTest.java
@@ -32,7 +32,7 @@
  */
 public class ComponentAliasNotSupportedOnUserBuildTest {
     protected static final DeviceConfigStateHelper sDeviceConfig = new DeviceConfigStateHelper(
-            DeviceConfig.NAMESPACE_ACTIVITY_MANAGER);
+            DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS);
 
     @AfterClass
     public static void restoreDeviceConfig() throws Exception {
diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
index 7b1f7a5..b673957 100644
--- a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
@@ -60,7 +60,7 @@
 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
 import android.telephony.TelephonyCallback;
 import android.telephony.TelephonyManager;
-import android.telephony.TelephonyManager.CarrierPrivilegesListener;
+import android.telephony.TelephonyManager.CarrierPrivilegesCallback;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 
@@ -187,11 +187,11 @@
         return captor.getValue();
     }
 
-    private List<CarrierPrivilegesListener> getCarrierPrivilegesListeners() {
-        final ArgumentCaptor<CarrierPrivilegesListener> captor =
-                ArgumentCaptor.forClass(CarrierPrivilegesListener.class);
+    private List<CarrierPrivilegesCallback> getCarrierPrivilegesCallbacks() {
+        final ArgumentCaptor<CarrierPrivilegesCallback> captor =
+                ArgumentCaptor.forClass(CarrierPrivilegesCallback.class);
         verify(mTelephonyManager, atLeastOnce())
-                .addCarrierPrivilegesListener(anyInt(), any(), captor.capture());
+                .registerCarrierPrivilegesCallback(anyInt(), any(), captor.capture());
 
         return captor.getAllValues();
     }
@@ -270,12 +270,12 @@
         assertNotNull(getOnSubscriptionsChangedListener());
 
         verify(mTelephonyManager, times(2))
-                .addCarrierPrivilegesListener(anyInt(), any(HandlerExecutor.class), any());
+                .registerCarrierPrivilegesCallback(anyInt(), any(HandlerExecutor.class), any());
         verify(mTelephonyManager)
-                .addCarrierPrivilegesListener(eq(0), any(HandlerExecutor.class), any());
+                .registerCarrierPrivilegesCallback(eq(0), any(HandlerExecutor.class), any());
         verify(mTelephonyManager)
-                .addCarrierPrivilegesListener(eq(1), any(HandlerExecutor.class), any());
-        assertEquals(2, getCarrierPrivilegesListeners().size());
+                .registerCarrierPrivilegesCallback(eq(1), any(HandlerExecutor.class), any());
+        assertEquals(2, getCarrierPrivilegesCallbacks().size());
     }
 
     @Test
@@ -287,10 +287,10 @@
         final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener();
         verify(mSubscriptionManager).removeOnSubscriptionsChangedListener(eq(listener));
 
-        for (CarrierPrivilegesListener carrierPrivilegesListener :
-                getCarrierPrivilegesListeners()) {
+        for (CarrierPrivilegesCallback carrierPrivilegesCallback :
+                getCarrierPrivilegesCallbacks()) {
             verify(mTelephonyManager)
-                    .removeCarrierPrivilegesListener(eq(carrierPrivilegesListener));
+                    .unregisterCarrierPrivilegesCallback(eq(carrierPrivilegesCallback));
         }
     }
 
@@ -303,15 +303,15 @@
         mTelephonySubscriptionTracker.setReadySubIdsBySlotId(readySubIdsBySlotId);
         doReturn(1).when(mTelephonyManager).getActiveModemCount();
 
-        List<CarrierPrivilegesListener> carrierPrivilegesListeners =
-                getCarrierPrivilegesListeners();
+        List<CarrierPrivilegesCallback> carrierPrivilegesCallbacks =
+                getCarrierPrivilegesCallbacks();
 
         mTelephonySubscriptionTracker.onReceive(mContext, buildTestMultiSimConfigBroadcastIntent());
         mTestLooper.dispatchAll();
 
-        for (CarrierPrivilegesListener carrierPrivilegesListener : carrierPrivilegesListeners) {
+        for (CarrierPrivilegesCallback carrierPrivilegesCallback : carrierPrivilegesCallbacks) {
             verify(mTelephonyManager)
-                    .removeCarrierPrivilegesListener(eq(carrierPrivilegesListener));
+                    .unregisterCarrierPrivilegesCallback(eq(carrierPrivilegesCallback));
         }
 
         // Expect cache cleared for inactive slots.
@@ -323,9 +323,9 @@
         // Expect a new CarrierPrivilegesListener to have been registered for slot 0, and none other
         // (2 previously registered during startup, for slots 0 & 1)
         verify(mTelephonyManager, times(3))
-                .addCarrierPrivilegesListener(anyInt(), any(HandlerExecutor.class), any());
+                .registerCarrierPrivilegesCallback(anyInt(), any(HandlerExecutor.class), any());
         verify(mTelephonyManager, times(2))
-                .addCarrierPrivilegesListener(eq(0), any(HandlerExecutor.class), any());
+                .registerCarrierPrivilegesCallback(eq(0), any(HandlerExecutor.class), any());
 
         // Verify that this triggers a re-evaluation
         verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES)));
@@ -391,8 +391,8 @@
     public void testOnCarrierPrivilegesChanged() throws Exception {
         setupReadySubIds();
 
-        final CarrierPrivilegesListener listener = getCarrierPrivilegesListeners().get(0);
-        listener.onCarrierPrivilegesChanged(Collections.emptyList(), new int[] {});
+        final CarrierPrivilegesCallback callback = getCarrierPrivilegesCallbacks().get(0);
+        callback.onCarrierPrivilegesChanged(Collections.emptySet(), Collections.emptySet());
         mTestLooper.dispatchAll();
 
         verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES)));
diff --git a/tools/locked_region_code_injection/Android.bp b/tools/locked_region_code_injection/Android.bp
index 3e12971..6efd1f6 100644
--- a/tools/locked_region_code_injection/Android.bp
+++ b/tools/locked_region_code_injection/Android.bp
@@ -12,10 +12,10 @@
     manifest: "manifest.txt",
     srcs: ["src/**/*.java"],
     static_libs: [
-        "asm-7.0",
-        "asm-commons-7.0",
-        "asm-tree-7.0",
-        "asm-analysis-7.0",
+        "asm-9.2",
+        "asm-commons-9.2",
+        "asm-tree-9.2",
+        "asm-analysis-9.2",
         "guava-21.0",
     ],
 }
diff --git a/tools/sdkparcelables/Android.bp b/tools/sdkparcelables/Android.bp
index ec2bffd..6ebacd8 100644
--- a/tools/sdkparcelables/Android.bp
+++ b/tools/sdkparcelables/Android.bp
@@ -14,7 +14,7 @@
         "src/**/*.kt",
     ],
     static_libs: [
-        "asm-7.0",
+        "asm-9.2",
     ],
 }
 
diff --git a/tools/traceinjection/Android.bp b/tools/traceinjection/Android.bp
new file mode 100644
index 0000000..39d1b1c
--- /dev/null
+++ b/tools/traceinjection/Android.bp
@@ -0,0 +1,49 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+java_binary_host {
+    name: "traceinjection",
+    manifest: "manifest.txt",
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "asm-9.2",
+        "asm-commons-9.2",
+        "asm-tree-9.2",
+        "asm-analysis-9.2",
+        "guava-21.0",
+    ],
+}
+
+java_library_host {
+    name: "TraceInjectionTests-Uninjected",
+    srcs: ["test/**/*.java"],
+    static_libs: [
+        "junit",
+    ],
+}
+
+java_genrule_host {
+    name: "TraceInjectionTests-Injected",
+    srcs: [":TraceInjectionTests-Uninjected"],
+    tools: ["traceinjection"],
+    cmd: "$(location traceinjection) " +
+        "  --annotation \"com/android/traceinjection/Trace\"" +
+        "  --start \"com/android/traceinjection/InjectionTests.traceStart\"" +
+        "  --end \"com/android/traceinjection/InjectionTests.traceEnd\"" +
+        "  -o $(out) " +
+        "  -i $(in)",
+    out: ["TraceInjectionTests-Injected.jar"],
+}
+
+java_test_host {
+    name: "TraceInjectionTests",
+    static_libs: [
+        "TraceInjectionTests-Injected",
+    ],
+}
diff --git a/tools/traceinjection/manifest.txt b/tools/traceinjection/manifest.txt
new file mode 100644
index 0000000..7f4ee1d
--- /dev/null
+++ b/tools/traceinjection/manifest.txt
@@ -0,0 +1 @@
+Main-Class: com.android.traceinjection.Main
diff --git a/tools/traceinjection/src/com/android/traceinjection/Main.java b/tools/traceinjection/src/com/android/traceinjection/Main.java
new file mode 100644
index 0000000..190df81
--- /dev/null
+++ b/tools/traceinjection/src/com/android/traceinjection/Main.java
@@ -0,0 +1,121 @@
+/*
+ * 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.traceinjection;
+
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+
+import java.io.BufferedInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+public class Main {
+    public static void main(String[] args) throws IOException {
+        String inJar = null;
+        String outJar = null;
+        String annotation = null;
+        String traceStart = null;
+        String traceEnd = null;
+
+        // All arguments require a value currently, so just make sure we have an even number and
+        // then process them all two at a time.
+        if (args.length % 2 != 0) {
+            throw new IllegalArgumentException("Argument is missing corresponding value");
+        }
+        for (int i = 0; i < args.length - 1; i += 2) {
+            final String arg = args[i].trim();
+            final String argValue = args[i + 1].trim();
+            if ("-i".equals(arg)) {
+                inJar = argValue;
+            } else if ("-o".equals(arg)) {
+                outJar = argValue;
+            } else if ("--annotation".equals(arg)) {
+                annotation = argValue;
+            } else if ("--start".equals(arg)) {
+                traceStart = argValue;
+            } else if ("--end".equals(arg)) {
+                traceEnd = argValue;
+            } else {
+                throw new IllegalArgumentException("Unknown argument: " + arg);
+            }
+        }
+
+        if (inJar == null) {
+            throw new IllegalArgumentException("input jar is required");
+        }
+
+        if (outJar == null) {
+            throw new IllegalArgumentException("output jar is required");
+        }
+
+        if (annotation == null) {
+            throw new IllegalArgumentException("trace annotation is required");
+        }
+
+        if (traceStart == null) {
+            throw new IllegalArgumentException("start trace method is required");
+        }
+
+        if (traceEnd == null) {
+            throw new IllegalArgumentException("end trace method is required");
+        }
+
+        TraceInjectionConfiguration params =
+                new TraceInjectionConfiguration(annotation, traceStart, traceEnd);
+
+        try (
+                ZipFile zipSrc = new ZipFile(inJar);
+                ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(outJar));
+        ) {
+            Enumeration<? extends ZipEntry> srcEntries = zipSrc.entries();
+            while (srcEntries.hasMoreElements()) {
+                ZipEntry entry = srcEntries.nextElement();
+                ZipEntry newEntry = new ZipEntry(entry.getName());
+                newEntry.setTime(entry.getTime());
+                zos.putNextEntry(newEntry);
+                BufferedInputStream bis = new BufferedInputStream(zipSrc.getInputStream(entry));
+
+                if (entry.getName().endsWith(".class")) {
+                    convert(bis, zos, params);
+                } else {
+                    while (bis.available() > 0) {
+                        zos.write(bis.read());
+                    }
+                    zos.closeEntry();
+                    bis.close();
+                }
+            }
+            zos.finish();
+        }
+    }
+
+    private static void convert(InputStream in, OutputStream out,
+            TraceInjectionConfiguration params) throws IOException {
+        ClassReader cr = new ClassReader(in);
+        ClassWriter cw = new ClassWriter(0);
+        TraceInjectionClassVisitor cv = new TraceInjectionClassVisitor(cw, params);
+        cr.accept(cv, ClassReader.EXPAND_FRAMES);
+        byte[] data = cw.toByteArray();
+        out.write(data);
+    }
+}
diff --git a/tools/traceinjection/src/com/android/traceinjection/TraceInjectionClassVisitor.java b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionClassVisitor.java
new file mode 100644
index 0000000..863f976
--- /dev/null
+++ b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionClassVisitor.java
@@ -0,0 +1,41 @@
+/*
+ * 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.traceinjection;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * {@link ClassVisitor} that injects tracing code to methods annotated with the configured
+ * annotation.
+ */
+public class TraceInjectionClassVisitor extends ClassVisitor {
+    private final TraceInjectionConfiguration mParams;
+    public TraceInjectionClassVisitor(ClassVisitor classVisitor,
+            TraceInjectionConfiguration params) {
+        super(Opcodes.ASM7, classVisitor);
+        mParams = params;
+    }
+
+    @Override
+    public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+            String[] exceptions) {
+        MethodVisitor chain = super.visitMethod(access, name, desc, signature, exceptions);
+        return new TraceInjectionMethodAdapter(chain, access, name, desc, mParams);
+    }
+}
diff --git a/tools/traceinjection/src/com/android/traceinjection/TraceInjectionConfiguration.java b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionConfiguration.java
new file mode 100644
index 0000000..f9595bd
--- /dev/null
+++ b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionConfiguration.java
@@ -0,0 +1,52 @@
+/*
+ * 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.traceinjection;
+
+/**
+ * Configuration data for trace method injection.
+ */
+public class TraceInjectionConfiguration {
+    public final String annotation;
+    public final String startMethodClass;
+    public final String startMethodName;
+    public final String endMethodClass;
+    public final String endMethodName;
+
+    public TraceInjectionConfiguration(String annotation, String startMethod, String endMethod) {
+        this.annotation = annotation;
+        String[] startMethodComponents = parseMethod(startMethod);
+        String[] endMethodComponents = parseMethod(endMethod);
+        startMethodClass = startMethodComponents[0];
+        startMethodName = startMethodComponents[1];
+        endMethodClass = endMethodComponents[0];
+        endMethodName = endMethodComponents[1];
+    }
+
+    public String toString() {
+        return "TraceInjectionParams{annotation=" + annotation
+                + ", startMethod=" + startMethodClass + "." + startMethodName
+                + ", endMethod=" + endMethodClass + "." + endMethodName + "}";
+    }
+
+    private static String[] parseMethod(String method) {
+        String[] methodComponents = method.split("\\.");
+        if (methodComponents.length != 2) {
+            throw new IllegalArgumentException("Invalid method descriptor: " + method);
+        }
+        return methodComponents;
+    }
+}
diff --git a/tools/traceinjection/src/com/android/traceinjection/TraceInjectionMethodAdapter.java b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionMethodAdapter.java
new file mode 100644
index 0000000..c2bbddc
--- /dev/null
+++ b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionMethodAdapter.java
@@ -0,0 +1,183 @@
+/*
+ * 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.traceinjection;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.AdviceAdapter;
+import org.objectweb.asm.commons.Method;
+
+/**
+ * Adapter that injects tracing code to methods annotated with the configured annotation.
+ *
+ * Assuming the configured annotation is {@code @Trace} and the configured methods are
+ * {@code Tracing.begin()} and {@code Tracing.end()}, it effectively transforms:
+ *
+ * <pre>{@code
+ * @Trace
+ * void method() {
+ *     doStuff();
+ * }
+ * }</pre>
+ *
+ * into:
+ * <pre>{@code
+ * @Trace
+ * void method() {
+ *     Tracing.begin();
+ *     try {
+ *         doStuff();
+ *     } finally {
+ *         Tracing.end();
+ *     }
+ * }
+ * }</pre>
+ */
+public class TraceInjectionMethodAdapter extends AdviceAdapter {
+    private final TraceInjectionConfiguration mParams;
+    private final Label mStartFinally = newLabel();
+    private final boolean mIsConstructor;
+
+    private boolean mShouldTrace;
+    private long mTraceId;
+    private String mTraceLabel;
+
+    public TraceInjectionMethodAdapter(MethodVisitor methodVisitor, int access,
+            String name, String descriptor, TraceInjectionConfiguration params) {
+        super(Opcodes.ASM7, methodVisitor, access, name, descriptor);
+        mParams = params;
+        mIsConstructor = "<init>".equals(name);
+    }
+
+    @Override
+    public void visitCode() {
+        super.visitCode();
+        if (mShouldTrace) {
+            visitLabel(mStartFinally);
+        }
+    }
+
+    @Override
+    protected void onMethodEnter() {
+        if (!mShouldTrace) {
+            return;
+        }
+        Type type = Type.getType(toJavaSpecifier(mParams.startMethodClass));
+        Method trace = Method.getMethod("void " + mParams.startMethodName + " (long, String)");
+        push(mTraceId);
+        push(getTraceLabel());
+        invokeStatic(type, trace);
+    }
+
+    private String getTraceLabel() {
+        return !isEmpty(mTraceLabel) ? mTraceLabel : getName();
+    }
+
+    @Override
+    protected void onMethodExit(int opCode) {
+        // Any ATHROW exits will be caught as part of our exception-handling block, so putting it
+        // here would cause us to call the end trace method multiple times.
+        if (opCode != ATHROW) {
+            onFinally();
+        }
+    }
+
+    private void onFinally() {
+        if (!mShouldTrace) {
+            return;
+        }
+        Type type = Type.getType(toJavaSpecifier(mParams.endMethodClass));
+        Method trace = Method.getMethod("void " + mParams.endMethodName + " (long)");
+        push(mTraceId);
+        invokeStatic(type, trace);
+    }
+
+    @Override
+    public void visitMaxs(int maxStack, int maxLocals) {
+        final int minStackSize;
+        if (mShouldTrace) {
+            Label endFinally = newLabel();
+            visitLabel(endFinally);
+            catchException(mStartFinally, endFinally, null);
+            // The stack will always contain exactly one element: the exception we caught
+            final Object[] stack = new Object[]{ "java/lang/Throwable"};
+            // Because we use EXPAND_FRAMES, the frame type must always be F_NEW.
+            visitFrame(F_NEW, /* numLocal= */ 0, /* local= */ null, stack.length, stack);
+            onFinally();
+            // Rethrow the exception that we caught in the finally block.
+            throwException();
+
+            // Make sure we have at least enough stack space to push the trace arguments
+            // (long, String)
+            minStackSize = Type.LONG_TYPE.getSize() + Type.getType(String.class).getSize();
+        } else {
+            // We didn't inject anything, so no need for additional stack space.
+            minStackSize = 0;
+        }
+
+        super.visitMaxs(Math.max(minStackSize, maxStack), maxLocals);
+    }
+
+    @Override
+    public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
+        AnnotationVisitor av = super.visitAnnotation(descriptor, visible);
+        if (descriptor.equals(toJavaSpecifier(mParams.annotation))) {
+            if (mIsConstructor) {
+                // TODO: Support constructor tracing. At the moment, constructors aren't supported
+                //  because you can't put an exception handler around a super() call within the
+                //  constructor itself.
+                throw new IllegalStateException("Cannot trace constructors");
+            }
+            av = new TracingAnnotationVisitor(av);
+        }
+        return av;
+    }
+
+    /**
+     * An AnnotationVisitor that pulls the trace ID and label information from the configured
+     * annotation.
+     */
+    class TracingAnnotationVisitor extends AnnotationVisitor {
+
+        TracingAnnotationVisitor(AnnotationVisitor annotationVisitor) {
+            super(Opcodes.ASM7, annotationVisitor);
+        }
+
+        @Override
+        public void visit(String name, Object value) {
+            if ("tag".equals(name)) {
+                mTraceId = (long) value;
+                // If we have a trace annotation and ID, then we have everything we need to trace
+                mShouldTrace = true;
+            } else if ("label".equals(name)) {
+                mTraceLabel = (String) value;
+            }
+            super.visit(name, value);
+        }
+    }
+
+    private static String toJavaSpecifier(String klass) {
+        return "L" + klass + ";";
+    }
+
+    private static boolean isEmpty(String str) {
+        return str == null || "".equals(str);
+    }
+}
diff --git a/tools/traceinjection/test/com/android/traceinjection/InjectionTests.java b/tools/traceinjection/test/com/android/traceinjection/InjectionTests.java
new file mode 100644
index 0000000..81bf235
--- /dev/null
+++ b/tools/traceinjection/test/com/android/traceinjection/InjectionTests.java
@@ -0,0 +1,246 @@
+/*
+ * 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.traceinjection;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@RunWith(JUnit4.class)
+public class InjectionTests {
+    public static final int TRACE_TAG = 42;
+    public static final String CUSTOM_TRACE_NAME = "Custom";
+
+    public static final TraceTracker TRACKER = new TraceTracker();
+
+    @After
+    public void tearDown() {
+        TRACKER.reset();
+    }
+
+    @Test
+    public void testDefaultLabel() {
+        assertTraces(this::tracedMethod, "tracedMethod");
+        tracedMethodThrowsAndCatches();
+    }
+
+    @Test
+    public void testCustomLabel() {
+        assertTraces(this::tracedMethodHasCustomName, CUSTOM_TRACE_NAME);
+    }
+
+    @Test
+    public void testTracedMethodsStillThrow() {
+        assertTraces(() -> assertThrows(IllegalArgumentException.class, this::tracedMethodThrows),
+                "tracedMethodThrows");
+        // Also test that we rethrow exceptions from method calls. This is slightly different from
+        // the previous case because the ATHROW instruction is not actually present at all in the
+        // bytecode of the instrumented method.
+        TRACKER.reset();
+        assertTraces(() -> assertThrows(NullPointerException.class,
+                        this::tracedMethodCallsThrowingMethod),
+                "tracedMethodCallsThrowingMethod");
+    }
+
+    @Test
+    public void testNestedTracedMethods() {
+        assertTraces(this::outerTracedMethod, "outerTracedMethod", "innerTracedMethod");
+    }
+
+    @Test
+    public void testTracedMethodWithCatchBlock() {
+        assertTraces(this::tracedMethodThrowsAndCatches, "tracedMethodThrowsAndCatches");
+    }
+
+    @Test
+    public void testTracedMethodWithFinallyBlock() {
+        assertTraces(() -> assertThrows(IllegalArgumentException.class,
+                this::tracedMethodThrowWithFinally), "tracedMethodThrowWithFinally");
+    }
+
+    @Test
+    public void testNonVoidMethod() {
+        assertTraces(this::tracedNonVoidMethod, "tracedNonVoidMethod");
+    }
+
+    @Test
+    public void testNonVoidMethodReturnsWithinCatches() {
+        assertTraces(this::tracedNonVoidMethodReturnsWithinCatches,
+                "tracedNonVoidMethodReturnsWithinCatches");
+    }
+
+    @Test
+    public void testNonVoidMethodReturnsWithinFinally() {
+        assertTraces(this::tracedNonVoidMethodReturnsWithinFinally,
+                "tracedNonVoidMethodReturnsWithinFinally");
+    }
+
+    @Test
+    public void testTracedStaticMethod() {
+        assertTraces(InjectionTests::tracedStaticMethod, "tracedStaticMethod");
+    }
+
+    @Trace(tag = TRACE_TAG)
+    public void tracedMethod() {
+        assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+    }
+
+    @Trace(tag = TRACE_TAG)
+    public void tracedMethodThrows() {
+        throw new IllegalArgumentException();
+    }
+
+    @Trace(tag = TRACE_TAG)
+    public void tracedMethodCallsThrowingMethod() {
+        throwingMethod();
+    }
+
+    private void throwingMethod() {
+        throw new NullPointerException();
+    }
+
+
+    @Trace(tag = TRACE_TAG)
+    public void tracedMethodThrowsAndCatches() {
+        try {
+            throw new IllegalArgumentException();
+        } catch (IllegalArgumentException ignored) {
+            assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+        }
+    }
+
+    @Trace(tag = TRACE_TAG)
+    public void tracedMethodThrowWithFinally() {
+        try {
+            throw new IllegalArgumentException();
+        } finally {
+            assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+        }
+    }
+
+    @Trace(tag = TRACE_TAG, label = CUSTOM_TRACE_NAME)
+    public void tracedMethodHasCustomName() {
+    }
+
+    @Trace(tag = TRACE_TAG)
+    public void outerTracedMethod() {
+        innerTracedMethod();
+        assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+    }
+
+    @Trace(tag = TRACE_TAG)
+    public void innerTracedMethod() {
+        assertEquals(2, TRACKER.getTraceCount(TRACE_TAG));
+    }
+
+    @Trace(tag = TRACE_TAG)
+    public int tracedNonVoidMethod() {
+        assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+        return 0;
+    }
+
+    @Trace(tag = TRACE_TAG)
+    public int tracedNonVoidMethodReturnsWithinCatches() {
+        try {
+            throw new IllegalArgumentException();
+        } catch (IllegalArgumentException ignored) {
+            assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+            return 0;
+        }
+    }
+
+    @Trace(tag = TRACE_TAG)
+    public int tracedNonVoidMethodReturnsWithinFinally() {
+        try {
+            throw new IllegalArgumentException();
+        } finally {
+            assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+            return 0;
+        }
+    }
+
+    @Trace(tag = TRACE_TAG)
+    public static void tracedStaticMethod() {
+        assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+    }
+
+    public void assertTraces(Runnable r, String... traceLabels) {
+        r.run();
+        assertEquals(Arrays.asList(traceLabels), TRACKER.getTraceLabels(TRACE_TAG));
+        TRACKER.assertAllTracesClosed();
+    }
+
+    public static void traceStart(long tag, String name) {
+        TRACKER.onTraceStart(tag, name);
+    }
+
+    public static void traceEnd(long tag) {
+        TRACKER.onTraceEnd(tag);
+    }
+
+    static class TraceTracker {
+        private final Map<Long, List<String>> mTraceLabelsByTag = new HashMap<>();
+        private final Map<Long, Integer> mTraceCountsByTag = new HashMap<>();
+
+        public void onTraceStart(long tag, String name) {
+            getTraceLabels(tag).add(name);
+            mTraceCountsByTag.put(tag, mTraceCountsByTag.getOrDefault(tag, 0) + 1);
+        }
+
+        public void onTraceEnd(long tag) {
+            final int newCount = getTraceCount(tag) - 1;
+            if (newCount < 0) {
+                throw new IllegalStateException("Trace count has gone negative for tag " + tag);
+            }
+            mTraceCountsByTag.put(tag, newCount);
+        }
+
+        public void reset() {
+            mTraceLabelsByTag.clear();
+            mTraceCountsByTag.clear();
+        }
+
+        public List<String> getTraceLabels(long tag) {
+            if (!mTraceLabelsByTag.containsKey(tag)) {
+                mTraceLabelsByTag.put(tag, new ArrayList<>());
+            }
+            return mTraceLabelsByTag.get(tag);
+        }
+
+        public int getTraceCount(long tag) {
+            return mTraceCountsByTag.getOrDefault(tag, 0);
+        }
+
+        public void assertAllTracesClosed() {
+            for (Map.Entry<Long, Integer> count: mTraceCountsByTag.entrySet()) {
+                final String errorMsg = "Tag " + count.getKey() + " is not fully closed (count="
+                        + count.getValue() + ")";
+                assertEquals(errorMsg, 0, (int) count.getValue());
+            }
+        }
+    }
+}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecTunnelInterfaceResponse.aidl b/tools/traceinjection/test/com/android/traceinjection/Trace.java
similarity index 76%
rename from packages/ConnectivityT/framework-t/src/android/net/IpSecTunnelInterfaceResponse.aidl
rename to tools/traceinjection/test/com/android/traceinjection/Trace.java
index 7239221..9e1c545 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/IpSecTunnelInterfaceResponse.aidl
+++ b/tools/traceinjection/test/com/android/traceinjection/Trace.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
-package android.net;
+package com.android.traceinjection;
 
-/** @hide */
-parcelable IpSecTunnelInterfaceResponse;
+public @interface Trace {
+    long tag();
+    String label() default "";
+}
diff --git a/tools/validatekeymaps/Android.bp b/tools/validatekeymaps/Android.bp
index 0423b7a..ff24d16 100644
--- a/tools/validatekeymaps/Android.bp
+++ b/tools/validatekeymaps/Android.bp
@@ -32,7 +32,7 @@
         "libui-types",
     ],
     target: {
-        linux_glibc: {
+        host_linux: {
             static_libs: [
                 // libbinder is only available for linux
                 "libbinder",
diff --git a/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java b/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
index 8630ec4..d85a5bd 100644
--- a/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
+++ b/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
@@ -967,16 +967,16 @@
      *
      * @param ifaceName Name of the interface.
      */
-    public int getMaxNumScanSsids(@NonNull String ifaceName) {
+    public int getMaxSsidsPerScan(@NonNull String ifaceName) {
         IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
         if (scannerImpl == null) {
             Log.e(TAG, "No valid wificond scanner interface handler for iface=" + ifaceName);
             return 0;
         }
         try {
-            return scannerImpl.getMaxNumScanSsids();
+            return scannerImpl.getMaxSsidsPerScan();
         } catch (RemoteException e1) {
-            Log.e(TAG, "Failed to getMaxNumScanSsids");
+            Log.e(TAG, "Failed to getMaxSsidsPerScan");
         }
         return 0;
     }